diff options
author | Vasily Melenchuk <vasily.melenchuk@cib.de> | 2021-11-11 10:39:32 +0300 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2022-02-18 08:20:09 +0100 |
commit | 43bbcc0d71b2b25970f4d5730c42b0eb7187cf85 (patch) | |
tree | f1beaf24cc54e3ace1fda0316c71c273acf2f2f2 | |
parent | writerfilter: extend SdtHelper for better support control types (diff) | |
download | core-43bbcc0d71b2b25970f4d5730c42b0eb7187cf85.tar.gz core-43bbcc0d71b2b25970f4d5730c42b0eb7187cf85.zip |
tdf#81507: word content control support for w:multiLine
<w:text multiLine="1"/> is now supported for import/export
to DOCX. Like other content control items it is stored in
grabbag.
Change-Id: Id6f1aa0072dc5db980d0fa43cab4b38a0aa047fc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125024
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127128
Tested-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130038
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf81507.docx | bin | 0 -> 20183 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport15.cxx | 22 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 59 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 3 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 3 | ||||
-rw-r--r-- | writerfilter/source/ooxml/model.xml | 5 |
6 files changed, 85 insertions, 7 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/tdf81507.docx b/sw/qa/extras/ooxmlexport/data/tdf81507.docx Binary files differnew file mode 100644 index 000000000000..2c00ee44cb24 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf81507.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx index 8b29a9adaf6c..e1c6bc533206 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx @@ -217,6 +217,28 @@ DECLARE_OOXMLEXPORT_TEST(testCommentDoneModel, "CommentDone.docx") CPPUNIT_ASSERT_EQUAL(false, xComment->getPropertyValue("Resolved").get<bool>()); } +DECLARE_OOXMLEXPORT_TEST(testTdf81507, "tdf81507.docx") +{ + xmlDocPtr pXmlDoc = parseExport("word/document.xml"); + if (!pXmlDoc) + return; // initial import, no futher checks + + // Ensure that we have <w:text w:multiLine="1"/> + CPPUNIT_ASSERT_EQUAL(OUString("1"), getXPath(pXmlDoc, "/w:document/w:body/w:sdt[1]/w:sdtPr/w:text", "multiLine")); + + // Ensure that we have <w:text w:multiLine="0"/> + CPPUNIT_ASSERT_EQUAL(OUString("0"), getXPath(pXmlDoc, "/w:document/w:body/w:sdt[2]/w:sdtPr/w:text", "multiLine")); + + // Ensure that we have <w:text/> + getXPath(pXmlDoc, "/w:document/w:body/w:sdt[3]/w:sdtPr/w:text", ""); + + // Ensure that we have no <w:text/> (not quite correct case, but to ensure import/export are okay) + xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "/w:document/w:body/w:sdt[4]/w:sdtPr/w:text"); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), + static_cast<sal_Int32>(xmlXPathNodeSetGetLength(pXmlObj->nodesetval))); + xmlXPathFreeObject(pXmlObj); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 7310e7d5f395..eb96baa880c4 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -574,12 +574,18 @@ static OString convertToOOXMLHoriOrientRel(sal_Int16 nOrientRel) } } -static void lcl_deleteAndResetTheLists( rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs, OUString& rSdtPrAlias) +static void lcl_deleteAndResetTheLists( + rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren, + rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs, + rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTextAttrs, + OUString& rSdtPrAlias) { if( pSdtPrTokenChildren.is() ) pSdtPrTokenChildren.clear(); if( pSdtPrDataBindingAttrs.is() ) pSdtPrDataBindingAttrs.clear(); + if (pSdtPrTextAttrs.is()) + pSdtPrTextAttrs.clear(); if (!rSdtPrAlias.isEmpty()) rSdtPrAlias.clear(); } @@ -778,14 +784,14 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT m_pSerializer->endElementNS( XML_w, XML_p ); // on export sdt blocks are never nested ATM if( !m_bAnchorLinkedToNode && !m_bStartedParaSdt ) - WriteSdtBlock( m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrTokenAttributes, m_pParagraphSdtPrDataBindingAttrs, m_aParagraphSdtPrAlias, /*bPara=*/true ); + WriteSdtBlock( m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrTokenAttributes, m_pParagraphSdtPrDataBindingAttrs, m_pParagraphSdtPrTextAttrs, m_aParagraphSdtPrAlias, /*bPara=*/true ); else { //These should be written out to the actual Node and not to the anchor. //Clear them as they will be repopulated when the node is processed. m_nParagraphSdtPrToken = 0; m_bParagraphSdtHasId = false; - lcl_deleteAndResetTheLists( m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs, m_aParagraphSdtPrAlias ); + lcl_deleteAndResetTheLists( m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs, m_pParagraphSdtPrTextAttrs, m_aParagraphSdtPrAlias ); } //sdtcontent is written so Set m_bParagraphHasDrawing to false @@ -817,6 +823,7 @@ void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenAttributes, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs, + rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTextAttrs, OUString& rSdtPrAlias, bool bPara ) { @@ -875,6 +882,13 @@ void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken, m_pSerializer->singleElementNS(XML_w, XML_dataBinding, xAttrList); } + if (pSdtPrTextAttrs.is()) + { + XFastAttributeListRef xAttrList( pSdtPrTextAttrs.get() ); + pSdtPrTextAttrs.clear(); + m_pSerializer->singleElementNS(XML_w, XML_text, xAttrList); + } + if (!rSdtPrAlias.isEmpty()) m_pSerializer->singleElementNS(XML_w, XML_alias, FSNS(XML_w, XML_val), rSdtPrAlias.toUtf8()); @@ -904,6 +918,7 @@ void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken, nSdtPrToken = 0; pSdtPrTokenChildren.clear(); pSdtPrDataBindingAttrs.clear(); + pSdtPrTextAttrs.clear(); rSdtPrAlias.clear(); } @@ -1549,14 +1564,14 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / if ( !m_bAnchorLinkedToNode && !m_bStartedCharSdt ) { rtl::Reference<sax_fastparser::FastAttributeList> pRunSdtPrTokenAttributes; - WriteSdtBlock( m_nRunSdtPrToken, m_pRunSdtPrTokenChildren, pRunSdtPrTokenAttributes, m_pRunSdtPrDataBindingAttrs, m_aRunSdtPrAlias, /*bPara=*/false ); + WriteSdtBlock( m_nRunSdtPrToken, m_pRunSdtPrTokenChildren, pRunSdtPrTokenAttributes, m_pRunSdtPrDataBindingAttrs, m_pRunSdtPrTextAttrs, m_aRunSdtPrAlias, /*bPara=*/false ); } else { //These should be written out to the actual Node and not to the anchor. //Clear them as they will be repopulated when the node is processed. m_nRunSdtPrToken = 0; - lcl_deleteAndResetTheLists( m_pRunSdtPrTokenChildren, m_pRunSdtPrDataBindingAttrs, m_aRunSdtPrAlias ); + lcl_deleteAndResetTheLists( m_pRunSdtPrTokenChildren, m_pRunSdtPrDataBindingAttrs, m_pRunSdtPrTextAttrs, m_aRunSdtPrAlias ); } if (bCloseEarlierSDT) @@ -9178,7 +9193,26 @@ void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem) else if (aPropertyValue.Name == "ooxml:CT_SdtPr_group") m_nParagraphSdtPrToken = FSNS( XML_w, XML_group ); else if (aPropertyValue.Name == "ooxml:CT_SdtPr_text") - m_nParagraphSdtPrToken = FSNS(XML_w, XML_text); + { + uno::Sequence<beans::PropertyValue> aGrabBag; + aPropertyValue.Value >>= aGrabBag; + if (aGrabBag.hasElements()) + { + for (const auto& rProp : std::as_const(aGrabBag)) + { + OUString sValue = rProp.Value.get<OUString>(); + if (rProp.Name == "ooxml:LN_CT_SdtText_multiLine") + AddToAttrList(m_pParagraphSdtPrTextAttrs, + FSNS(XML_w, XML_multiLine), + OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr()); + } + } + else + { + // We still have w:text, but no attrs + m_nParagraphSdtPrToken = FSNS(XML_w, XML_text); + } + } else if (aPropertyValue.Name == "ooxml:CT_SdtPr_dataBinding" && !m_pParagraphSdtPrDataBindingAttrs.is()) { uno::Sequence<beans::PropertyValue> aGrabBag; @@ -9394,6 +9428,19 @@ void DocxAttributeOutput::CharGrabBag( const SfxGrabBagItem& rItem ) OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() ); } } + else if (aPropertyValue.Name == "ooxml:CT_SdtPr_text") + { + uno::Sequence<beans::PropertyValue> aGrabBag; + aPropertyValue.Value >>= aGrabBag; + for (const auto& rProp : std::as_const(aGrabBag)) + { + OUString sValue = rProp.Value.get<OUString>(); + if (rProp.Name == "ooxml:LN_CT_SdtText_multiLine") + AddToAttrList(m_pRunSdtPrTextAttrs, + FSNS(XML_w, XML_multiLine), + OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr()); + } + } else if (aPropertyValue.Name == "ooxml:CT_SdtPr_dataBinding" && !m_pRunSdtPrDataBindingAttrs.is()) { uno::Sequence<beans::PropertyValue> aGrabBag; diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index dd91f1668e10..de1bcf49a079 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -714,6 +714,7 @@ private: rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenAttributes, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs, + rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTextAttrs, OUString& rSdtPrAlias, bool bPara); /// Closes a currently open SDT block. @@ -974,12 +975,14 @@ private: rtl::Reference<sax_fastparser::FastAttributeList> m_pParagraphSdtPrTokenChildren; rtl::Reference<sax_fastparser::FastAttributeList> m_pParagraphSdtPrTokenAttributes; rtl::Reference<sax_fastparser::FastAttributeList> m_pParagraphSdtPrDataBindingAttrs; + rtl::Reference<sax_fastparser::FastAttributeList> m_pParagraphSdtPrTextAttrs; /// members to control the existence of grabbagged SDT properties in the text run sal_Int32 m_nRunSdtPrToken; /// State of the Fly at current position FlyProcessingState m_nStateOfFlyFrame; rtl::Reference<sax_fastparser::FastAttributeList> m_pRunSdtPrTokenChildren; rtl::Reference<sax_fastparser::FastAttributeList> m_pRunSdtPrDataBindingAttrs; + rtl::Reference<sax_fastparser::FastAttributeList> m_pRunSdtPrTextAttrs; /// Value of the <w:alias> paragraph SDT element. OUString m_aParagraphSdtPrAlias; /// Same as m_aParagraphSdtPrAlias, but its content is available till the SDT is closed. diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index b3c6b5d0c7c5..367772ab88ed 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1113,6 +1113,9 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) case NS_ooxml::LN_CT_DataBinding_storeItemID: m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_storeItemID", sStringValue); break; + case NS_ooxml::LN_CT_SdtText_multiLine: + m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:LN_CT_SdtText_multiLine", sStringValue); + break; case NS_ooxml::LN_CT_PTab_leader: case NS_ooxml::LN_CT_PTab_relativeTo: case NS_ooxml::LN_CT_PTab_alignment: diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml index 969eca1d84e3..3a22dee99bb8 100644 --- a/writerfilter/source/ooxml/model.xml +++ b/writerfilter/source/ooxml/model.xml @@ -13981,7 +13981,7 @@ <ref name="CT_Empty"/> </element> <element name="text"> - <ref name="CT_OnOff"/> + <ref name="CT_SdtText"/> </element> <element name="citation"> <ref name="CT_OnOff"/> @@ -18222,6 +18222,9 @@ <attribute name="val" tokenid="ooxml:CT_CalendarType_val" action="setValue"/> <action name="start" action="setDefaultStringValue"/> </resource> + <resource name="CT_SdtText" resource="Properties"> + <attribute name="multiLine" tokenid="ooxml:CT_SdtText_multiLine"/> + </resource> <resource name="CT_DataBinding" resource="Properties"> <attribute name="prefixMappings" tokenid="ooxml:CT_DataBinding_prefixMappings"/> <attribute name="xpath" tokenid="ooxml:CT_DataBinding_xpath"/> |