summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVasily Melenchuk <vasily.melenchuk@cib.de>2021-11-11 10:39:32 +0300
committerMiklos Vajna <vmiklos@collabora.com>2022-02-18 08:20:09 +0100
commit43bbcc0d71b2b25970f4d5730c42b0eb7187cf85 (patch)
treef1beaf24cc54e3ace1fda0316c71c273acf2f2f2
parentwriterfilter: extend SdtHelper for better support control types (diff)
downloadcore-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.docxbin0 -> 20183 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport15.cxx22
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx59
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx3
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx3
-rw-r--r--writerfilter/source/ooxml/model.xml5
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
new file mode 100644
index 000000000000..2c00ee44cb24
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf81507.docx
Binary files differ
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"/>