sw/qa/extras/ooxmlexport/data/tdf81507.docx  |binary
 sw/qa/extras/ooxmlexport/ooxmlexport15.cxx   |   22 ++++++++++
 sw/source/filter/ww8/docxattributeoutput.cxx |   59 ++++++++++++++++++++++++---
 sw/source/filter/ww8/docxattributeoutput.hxx |    3 +
 writerfilter/source/dmapper/DomainMapper.cxx |    3 +
 writerfilter/source/ooxml/model.xml          |    5 +-
 6 files changed, 85 insertions(+), 7 deletions(-)

New commits:
commit 43bbcc0d71b2b25970f4d5730c42b0eb7187cf85
Author:     Vasily Melenchuk <vasily.melenc...@cib.de>
AuthorDate: Thu Nov 11 10:39:32 2021 +0300
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Feb 18 08:20:09 2022 +0100

    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.behr...@allotropia.de>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127128
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130038
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

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
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf81507.docx 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"/>

Reply via email to