sw/inc/txatbase.hxx                               |    2 
 sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx     |   43 ++++-------
 sw/source/filter/ww8/attributeoutputbase.hxx      |    8 --
 sw/source/filter/ww8/docxattributeoutput.cxx      |   86 +++++++++++-----------
 sw/source/filter/ww8/docxattributeoutput.hxx      |   11 --
 sw/source/filter/ww8/docxexport.cxx               |    2 
 sw/source/filter/ww8/rtfattributeoutput.cxx       |    3 
 sw/source/filter/ww8/rtfattributeoutput.hxx       |    3 
 sw/source/filter/ww8/wrtw8nds.cxx                 |   29 +------
 sw/source/filter/ww8/ww8atr.cxx                   |    4 -
 sw/source/filter/ww8/ww8attributeoutput.hxx       |    2 
 writerfilter/source/dmapper/DomainMapper.cxx      |   15 +--
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |    8 ++
 writerfilter/source/dmapper/SdtHelper.hxx         |    4 -
 14 files changed, 93 insertions(+), 127 deletions(-)

New commits:
commit faff21eae051e85f46720414dcbba8cc98888660
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Sep 19 10:01:36 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Sep 20 09:34:41 2022 +0200

    sw content controls, plain text: enable DOCX filter with data binding
    
    - writerfilter/ had explicit code to not map plain text SDT to Writer 
content
      controls if it has data bindings specified, lift this limitation and set 
the
      value of content control from data binding, like Word does and Writer did 
it
      for input fields since b5c616d10bff3213840d4893d13b4493de71fa56 
(tdf#104823:
      support for sdt plain text fields, 2021-11-24)
    
    - call DocxExport::AddSdtData() on the export side to do the opposite on 
export
    
    - give up on the idea to export content controls to DOCX by finding the text
      attribute in SwWW8AttrIter::OutAttrWithRange(): this needs buffering in 
both
      directions (need to start the SDT before the start of the run, need to 
end it
      after the end of the run), and solving this using marks and merges at a
      fast-serializer level looks like hacks on top of hacks. To be more 
specific,
      CppunitTest_sw_ooxmlexport7's testSdtAndShapeOverlapping seems to be very 
hard
      to fix with this design
    
    - instead, give not only the start position but also the length of the run 
to
      DocxAttributeOutput::EndRun(), which has random access to the doc model 
and can
      look up if there is a content control start or end that needs writing at 
the
      current position of the XML output, without any buffering, which also
      means less code
    
    - adapt CppunitTest_sw_ooxmlfieldexport's testSdtBeforeField, which didn't 
like
      the empty run at the start of content controls, which seems to be harmless
      otherwise
    
    - fix CppunitTest_sw_ooxmlfieldexport 
CPPUNIT_TEST_NAME=testSdtDateDuplicate by
      disabling the "set content control value from data binding" logic for date
      pickers because that logic in writerfilter/ sets the value as-is and it 
has to
      consider the requested date format before this can be enabled
    
    As a side effect, this gives PDF export for plain text SDTs, even if they 
have
    data binding set. CppunitTest_sw_ooxmlfieldexport's testTdf104823 is now
    updated to ensure that we import such SDTs as Writer content controls.
    
    (cherry picked from commit de90c192cb8f1f03a4028493d8bfe9a127a76b2a)
    
    Conflicts:
            sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
            sw/source/filter/ww8/docxattributeoutput.cxx
            sw/source/filter/ww8/wrtw8nds.cxx
            writerfilter/source/dmapper/SdtHelper.hxx
    
    Change-Id: I749a845b5a25454c51066b8ded892682f523b6b4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140180
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/inc/txatbase.hxx b/sw/inc/txatbase.hxx
index 183e254f8817..00e2f9b51470 100644
--- a/sw/inc/txatbase.hxx
+++ b/sw/inc/txatbase.hxx
@@ -132,7 +132,7 @@ public:
     virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
 };
 
-class SAL_DLLPUBLIC_RTTI SwTextAttrEnd : public virtual SwTextAttr
+class SW_DLLPUBLIC SwTextAttrEnd : public virtual SwTextAttr
 {
 protected:
     sal_Int32 m_nEnd;
diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index 98a5b6ab6a15..9cf424f8aa07 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -549,7 +549,8 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testSdtBeforeField, 
"sdt-before-field.docx")
 {
     xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
     // Make sure the field doesn't sneak inside the SDT: the SDT should 
contain only a single run (there were 6 ones).
-    assertXPath(pXmlDoc, "//w:sdt/w:sdtContent/w:r", 1);
+    assertXPath(pXmlDoc, "//w:p/w:sdt/w:sdtContent/w:r/w:t", 1);
+    assertXPath(pXmlDoc, "//w:p/w:r/w:fldChar", 3);
 }
 
 DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testfdo81946, "fdo81946.docx")
@@ -823,36 +824,26 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf104823)
     OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf104823.docx";
     loadURL(aURL, nullptr);
 
-    css::uno::Reference<css::text::XTextFieldsSupplier> xTextFieldsSupplier(
-        mxComponent, css::uno::UNO_QUERY_THROW);
-    auto xFields(xTextFieldsSupplier->getTextFields()->createEnumeration());
-
-    // FIXME: seems order of fields is different than in source document
-    // so feel free to modify testcase if order is changed
-
-    // First field: content from core properties
-    uno::Reference<text::XTextField> xField1(xFields->nextElement(), 
uno::UNO_QUERY);
-    CPPUNIT_ASSERT(xFields->hasMoreElements());
+    // First paragraph: content from core properties
+    uno::Reference<text::XTextRange> xParagraph1 = getParagraph(1);
+    auto xContentControl1 = 
getProperty<uno::Reference<text::XText>>(getRun(xParagraph1, 2), 
"ContentControl");
     // Check field value (it should be value from data source) and set new
-    CPPUNIT_ASSERT_EQUAL(OUString("True Core Property Value"), 
xField1->getPresentation(false));
-    uno::Reference<beans::XPropertySet> xField1Props(xField1, uno::UNO_QUERY);
-    xField1Props->setPropertyValue("Content", uno::makeAny(OUString("New Core 
Property Value")));
+    CPPUNIT_ASSERT_EQUAL(OUString("True Core Property Value"), 
xContentControl1->getString());
+    xContentControl1->setString("New Core Property Value");
 
-    // Third field: content from custom properties
-    uno::Reference<text::XTextField> xField2(xFields->nextElement(), 
uno::UNO_QUERY);
-    CPPUNIT_ASSERT(xFields->hasMoreElements());
+    // Third paragraph: content from custom properties
+    uno::Reference<text::XTextRange> xParagraph3 = getParagraph(3);
+    auto xContentControl3 = 
getProperty<uno::Reference<text::XText>>(getRun(xParagraph3, 2), 
"ContentControl");
     // Check field value (it should be value from data source) and set new
-    CPPUNIT_ASSERT_EQUAL(OUString("True Custom XML Value"), 
xField2->getPresentation(false));
-    uno::Reference<beans::XPropertySet> xField2Props(xField2, uno::UNO_QUERY);
-    xField2Props->setPropertyValue("Content", uno::makeAny(OUString("New 
Custom XML Value")));
+    CPPUNIT_ASSERT_EQUAL(OUString("True Custom XML Value"), 
xContentControl3->getString());
+    xContentControl3->setString("New Custom XML Value");
 
-    // Second field: content from extended properties
-    uno::Reference<text::XTextField> xField3(xFields->nextElement(), 
uno::UNO_QUERY);
-    CPPUNIT_ASSERT(!xFields->hasMoreElements());
+    // Second paragraph: content from extended properties
+    uno::Reference<text::XTextRange> xParagraph2 = getParagraph(2);
+    auto xContentControl2 = 
getProperty<uno::Reference<text::XText>>(getRun(xParagraph2, 2), 
"ContentControl");
     // Check field value (it should be value from data source) and set new
-    CPPUNIT_ASSERT_EQUAL(OUString("True Extended Property Value"), 
xField3->getPresentation(false));
-    uno::Reference<beans::XPropertySet> xField3Props(xField3, uno::UNO_QUERY);
-    xField3Props->setPropertyValue("Content", uno::makeAny(OUString("New 
Extended Property Value")));
+    CPPUNIT_ASSERT_EQUAL(OUString("True Extended Property Value"), 
xContentControl2->getString());
+    xContentControl2->setString("New Extended Property Value");
 
     // Save and check saved data
     save("Office Open XML Text", maTempFile);
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx 
b/sw/source/filter/ww8/attributeoutputbase.hxx
index 35ac50057786..ffa81eb161fd 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -172,7 +172,7 @@ public:
     virtual void StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, 
bool bSingleEmptyRun = false ) = 0;
 
     /// End of the text run.
-    virtual void EndRun( const SwTextNode* pNode, sal_Int32 nPos, bool 
bLastRun = false ) = 0;
+    virtual void EndRun( const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 
nLen, bool bLastRun = false ) = 0;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() = 0;
@@ -369,12 +369,6 @@ public:
         const OUString &rNumberingString,
         const SvxBrushItem* pBrush) = 0; // #i120928 export graphic of bullet
 
-    /// Output content control start.
-    virtual void StartContentControl(const SwFormatContentControl& 
/*rFormatContentControl*/) {}
-
-    /// Output content control end.
-    virtual void EndContentControl( const SwTextNode& /*rNode*/, sal_Int32 
/*nPos*/ ) {}
-
 protected:
 
     static void GetNumberPara( OUString& rStr, const SwField& rField );
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 84189eaf5e81..67e87965e5f0 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -137,6 +137,7 @@
 #include <frmatr.hxx>
 #include <txtatr.hxx>
 #include <frameformats.hxx>
+#include <textcontentcontrol.hxx>
 
 #include <o3tl/string_view.hxx>
 #include <o3tl/unit_conversion.hxx>
@@ -363,23 +364,6 @@ void DocxAttributeOutput::WriteFloatingTable(ww8::Frame 
const* pParentFrame)
     m_rExport.SetFloatingTableFrame(nullptr);
 }
 
-void DocxAttributeOutput::StartContentControl(const SwFormatContentControl& 
rFormatContentControl)
-{
-    m_pContentControl = rFormatContentControl.GetContentControl();
-}
-
-void DocxAttributeOutput::EndContentControl(const SwTextNode& rNode, sal_Int32 
nPos)
-{
-    if (rNode.GetTextAttrForCharAt(nPos, RES_TXTATR_FLYCNT) || 
rNode.GetTextAttrForCharAt(nPos, RES_TXTATR_CONTENTCONTROL))
-    {
-        ++m_nCloseContentControlInPreviousRun;
-    }
-    else
-    {
-        ++m_nCloseContentControlInThisRun;
-    }
-}
-
 static void checkAndWriteFloatingTables(DocxAttributeOutput& 
rDocxAttributeOutput)
 {
     const auto& rExport = rDocxAttributeOutput.GetExport();
@@ -1582,7 +1566,7 @@ void DocxAttributeOutput::StartRun( const SwRedlineData* 
pRedlineData, sal_Int32
     m_pSerializer->mark(Tag_StartRun_3); // let's call it "postponed text"
 }
 
-void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool 
/*bLastRun*/)
+void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, 
sal_Int32 nLen, bool /*bLastRun*/)
 {
     int nFieldsInPrevHyperlink = m_nFieldsInHyperlink;
     // Reset m_nFieldsInHyperlink if a new hyperlink is about to start
@@ -1639,12 +1623,6 @@ void DocxAttributeOutput::EndRun(const SwTextNode* 
pNode, sal_Int32 nPos, bool /
         m_bEndCharSdt = false;
     }
 
-    for (; m_nCloseContentControlInPreviousRun > 0; 
--m_nCloseContentControlInPreviousRun)
-    {
-        // Not the last run of this paragraph.
-        WriteContentControlEnd();
-    }
-
     if ( m_closeHyperlinkInPreviousRun )
     {
         if ( m_startedHyperlink )
@@ -1742,8 +1720,6 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, 
sal_Int32 nPos, bool /
         m_nHyperLinkCount++;
     }
 
-    WriteContentControlStart();
-
     // if there is some redlining in the document, output it
     StartRedline( m_pRedlineData );
 
@@ -1789,6 +1765,17 @@ void DocxAttributeOutput::EndRun(const SwTextNode* 
pNode, sal_Int32 nPos, bool /
 
     DoWriteBookmarkStartIfExist(nPos);
 
+    if (nLen != -1)
+    {
+        SwTextAttr* pAttr = pNode->GetTextAttrAt(nPos, 
RES_TXTATR_CONTENTCONTROL, SwTextNode::DEFAULT);
+        if (pAttr && pAttr->GetStart() == nPos)
+        {
+            auto pTextContentControl = 
static_txtattr_cast<SwTextContentControl*>(pAttr);
+            m_pContentControl = 
pTextContentControl->GetContentControl().GetContentControl();
+            WriteContentControlStart();
+        }
+    }
+
     m_pSerializer->startElementNS(XML_w, XML_r);
     if(GetExport().m_bTabInTOC && m_pHyperlinkAttrList.is())
     {
@@ -1807,6 +1794,16 @@ void DocxAttributeOutput::EndRun(const SwTextNode* 
pNode, sal_Int32 nPos, bool /
     // append the actual run end
     m_pSerializer->endElementNS( XML_w, XML_r );
 
+    if (nLen != -1)
+    {
+        sal_Int32 nEnd = nPos + nLen;
+        SwTextAttr* pAttr = pNode->GetTextAttrAt(nPos, 
RES_TXTATR_CONTENTCONTROL, SwTextNode::DEFAULT);
+        if (pAttr && *pAttr->GetEnd() == nEnd)
+        {
+            WriteContentControlEnd();
+        }
+    }
+
     // if there is some redlining in the document, output it
     // (except in the case of fields with multiple runs)
     EndRedline( m_pRedlineData );
@@ -1854,12 +1851,6 @@ void DocxAttributeOutput::EndRun(const SwTextNode* 
pNode, sal_Int32 nPos, bool /
         m_pRedlineData = nullptr;
     }
 
-    for (; m_nCloseContentControlInThisRun > 0; 
--m_nCloseContentControlInThisRun)
-    {
-        // Last run of this paragraph.
-        WriteContentControlEnd();
-    }
-
     if ( m_closeHyperlinkInThisRun )
     {
         if ( m_startedHyperlink )
@@ -2447,6 +2438,26 @@ void DocxAttributeOutput::WriteContentControlStart()
 
     m_pSerializer->endElementNS(XML_w, XML_sdtPr);
     m_pSerializer->startElementNS(XML_w, XML_sdtContent);
+
+    const OUString& rPrefixMapping = 
m_pContentControl->GetDataBindingPrefixMappings();
+    const OUString& rXpath = m_pContentControl->GetDataBindingXpath();
+    if (!rXpath.isEmpty())
+    {
+        // This content control has a data binding, update the data source.
+        SwTextContentControl* pTextAttr = m_pContentControl->GetTextAttr();
+        SwTextNode* pTextNode = m_pContentControl->GetTextNode();
+        SwPosition aPoint(*pTextNode, pTextAttr->GetStart());
+        SwPosition aMark(*pTextNode, *pTextAttr->GetEnd());
+        SwPaM aPam(aMark, aPoint);
+        OUString aSnippet = aPam.GetText();
+        static sal_Unicode const aForbidden[] = {
+            CH_TXTATR_BREAKWORD,
+            0
+        };
+        aSnippet = comphelper::string::removeAny(aSnippet, aForbidden);
+        m_rExport.AddSdtData(rPrefixMapping, rXpath, aSnippet);
+    }
+
     m_pContentControl = nullptr;
 }
 
@@ -3386,11 +3397,6 @@ void DocxAttributeOutput::RunText( const OUString& 
rText, rtl_TextEncoding /*eCh
     {
         m_closeHyperlinkInPreviousRun = true;
     }
-    if (m_nCloseContentControlInThisRun > 0)
-    {
-        ++m_nCloseContentControlInPreviousRun;
-        --m_nCloseContentControlInThisRun;
-    }
     m_bRunTextIsOn = true;
     // one text can be split into more <w:t>blah</w:t>'s by line breaks etc.
     const sal_Unicode *pBegin = rText.getStr();
@@ -3457,7 +3463,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& 
rNode, sal_Int32 nPos, co
 {
     WW8Ruby aWW8Ruby( rNode, rRuby, GetExport() );
     SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::StartRuby( const SwTextNode& 
rNode, const SwFormatRuby& rRuby )" );
-    EndRun( &rNode, nPos ); // end run before starting ruby to avoid nested 
runs, and overlap
+    EndRun( &rNode, nPos, -1 ); // end run before starting ruby to avoid 
nested runs, and overlap
     assert(!m_closeHyperlinkInThisRun); // check that no hyperlink overlaps 
ruby
     assert(!m_closeHyperlinkInPreviousRun);
     m_pSerializer->startElementNS(XML_w, XML_r);
@@ -3501,7 +3507,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& 
rNode, sal_Int32 nPos, co
 
     EndRunProperties( nullptr );
     RunText( rRuby.GetText( ) );
-    EndRun( &rNode, nPos );
+    EndRun( &rNode, nPos, -1 );
     m_pSerializer->endElementNS( XML_w, XML_rt );
 
     m_pSerializer->startElementNS(XML_w, XML_rubyBase);
@@ -3511,7 +3517,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& 
rNode, sal_Int32 nPos, co
 void DocxAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
 {
     SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::EndRuby()" );
-    EndRun( &rNode, nPos );
+    EndRun( &rNode, nPos, -1 );
     m_pSerializer->endElementNS( XML_w, XML_rubyBase );
     m_pSerializer->endElementNS( XML_w, XML_ruby );
     m_pSerializer->endElementNS( XML_w, XML_r );
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx 
b/sw/source/filter/ww8/docxattributeoutput.hxx
index def5a955f363..2fbdece0cc08 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -185,7 +185,7 @@ public:
     virtual void StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, 
bool bSingleEmptyRun = false ) override;
 
     /// End of the text run.
-    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun 
= false) override;
+    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 
nLen, bool bLastRun = false) override;
 
     /// Called before we start outputting the attributes.
     virtual void StartRunProperties() override;
@@ -405,12 +405,6 @@ public:
 
     void WriteFloatingTable(ww8::Frame const* pParentFrame);
 
-    /// See AttributeOutputBase::StartContentControl().
-    void StartContentControl(const SwFormatContentControl& 
rFormatContentControl) override;
-
-    /// See AttributeOutputBase::EndContentControl().
-    void EndContentControl( const SwTextNode& rNode, sal_Int32 nPos ) override;
-
 private:
     /// Initialize the structures where we are going to collect some of the 
paragraph properties.
     ///
@@ -912,9 +906,6 @@ private:
     o3tl::sorted_vector<const SwFrameFormat*> m_aFloatingTablesOfParagraph;
     sal_Int32 m_nTextFrameLevel;
 
-    sal_Int32 m_nCloseContentControlInThisRun = 0;
-    sal_Int32 m_nCloseContentControlInPreviousRun = 0;
-
     // close of hyperlink needed
     bool m_closeHyperlinkInThisRun;
     bool m_closeHyperlinkInPreviousRun;
diff --git a/sw/source/filter/ww8/docxexport.cxx 
b/sw/source/filter/ww8/docxexport.cxx
index 6a4ba2dd58cd..90d33ec15aa4 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1949,7 +1949,7 @@ sal_Int32 DocxExport::WriteOutliner(const 
OutlinerParaObject& rParaObj, sal_uInt
             eChrSet = eNextChrSet;
             aAttrIter.NextPos();
 
-            AttrOutput().EndRun( nullptr, 0 );
+            AttrOutput().EndRun( nullptr, 0, -1 );
 
         } while( nCurrentPos < nEnd );
 //        aAttrIter.OutParaAttr(false);
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index d7c8bef9b41a..6a859f4f0b87 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -406,7 +406,8 @@ void RtfAttributeOutput::StartRun(const SwRedlineData* 
pRedlineData, sal_Int32 /
     OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty");
 }
 
-void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 
/*nPos*/, bool /*bLastRun*/)
+void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 
/*nPos*/, sal_Int32 /*nLen*/,
+                                bool /*bLastRun*/)
 {
     m_aRun->append(SAL_NEWLINE_STRING);
     m_aRun.appendAndClear(m_aRunText);
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx 
b/sw/source/filter/ww8/rtfattributeoutput.hxx
index aedef264b7d2..e5f53fa4d355 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -74,7 +74,8 @@ public:
                   bool bSingleEmptyRun = false) override;
 
     /// End of the text run.
-    void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = 
false) override;
+    void EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 nLen,
+                bool bLastRun = false) override;
 
     /// Called before we start outputting the attributes.
     void StartRunProperties() override;
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx 
b/sw/source/filter/ww8/wrtw8nds.cxx
index e980efa238b7..595b700fc663 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -1412,14 +1412,6 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& 
rNode, sal_Int32 nPos)
                         --nRet;
                     }
                     break;
-                case RES_TXTATR_CONTENTCONTROL:
-                    pEnd = pHt->End();
-                    if (nPos == *pEnd && nPos != pHt->GetStart())
-                    {
-                        m_rExport.AttrOutput().EndContentControl(rNode, nPos);
-                        --nRet;
-                    }
-                    break;
             }
             if (nPos < pHt->GetAnyEnd())
                 break; // sorted by end
@@ -1474,17 +1466,6 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& 
rNode, sal_Int32 nPos)
                         --nRet;
                     }
                     break;
-                case RES_TXTATR_CONTENTCONTROL:
-                    if (nPos == pHt->GetStart())
-                    {
-                        auto pFormatContentControl
-                            = static_cast<const 
SwFormatContentControl*>(pItem);
-                        
m_rExport.AttrOutput().StartContentControl(*pFormatContentControl);
-                        ++nRet;
-                    }
-                    // We know that the content control is never empty as it 
has a dummy character
-                    // at least.
-                    break;
             }
             if (nPos < pHt->GetStart())
                 break; // sorted by start
@@ -2441,7 +2422,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
             {
                 if( AttrOutput().FootnoteEndnoteRefTag() )
                 {
-                    AttrOutput().EndRun( &rNode, nCurrentPos, nNextAttr == 
nEnd );
+                    AttrOutput().EndRun( &rNode, nCurrentPos, -1, nNextAttr == 
nEnd );
                     AttrOutput().StartRun( pRedlineData, nCurrentPos, 
bSingleEmptyRun );
                 }
             }
@@ -2495,7 +2476,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
                     && nStateOfFlyFrame == FLY_PROCESSED)
                 {
                     // write flys in a separate run before field character
-                    AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == 
nEnd);
+                    AttrOutput().EndRun(&rNode, nCurrentPos, -1, nNextAttr == 
nEnd);
                     AttrOutput().StartRun(pRedlineData, nCurrentPos, 
bSingleEmptyRun);
                 }
 
@@ -2790,7 +2771,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
             if (bPostponeWritingText
                 && (FLY_PROCESSED == nStateOfFlyFrame || FLY_NONE == 
nStateOfFlyFrame))
             {
-                AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
+                AttrOutput().EndRun(&rNode, nCurrentPos, -1, nNextAttr == 
nEnd);
                 //write the postponed text run
                 AttrOutput().StartRun( pRedlineData, nCurrentPos, 
bSingleEmptyRun );
                 AttrOutput().SetAnchorIsLinkedToNode( false );
@@ -2802,7 +2783,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
                     AttrOutput().EndRunProperties( pRedlineData );
                 }
                 AttrOutput().RunText( aSavedSnippet, eChrSet );
-                AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
+                AttrOutput().EndRun(&rNode, nCurrentPos, nLen, nNextAttr == 
nEnd);
             }
             else if( bPostponeWritingText && !aSavedSnippet.isEmpty() )
             {
@@ -2811,7 +2792,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
                 AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
             }
             else
-                AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
+                AttrOutput().EndRun(&rNode, nCurrentPos, nLen, nNextAttr == 
nEnd);
 
             nCurrentPos = nNextAttr;
             UpdatePosition( &aAttrIter, nCurrentPos );
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 1b6c22f26d00..ed1da4c90f4a 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -1087,7 +1087,7 @@ void WW8AttributeOutput::OnTOXEnding()
     mbOnTOXEnding = true;
 }
 
-void WW8AttributeOutput::EndRun( const SwTextNode* /*pNode*/, sal_Int32 nPos, 
bool bLastRun )
+void WW8AttributeOutput::EndRun( const SwTextNode* /*pNode*/, sal_Int32 nPos, 
sal_Int32 /*nLen*/, bool bLastRun )
 {
     /// Insert bookmarks ended after this run
     auto aRange = m_aBookmarksOfParagraphEnd.equal_range(nPos);
@@ -2561,7 +2561,7 @@ void AttributeOutputBase::StartTOX( const SwSection& 
rSect )
                 FieldFlags::CmdEnd );
             if (GetExport().GetExportFormat() == 
MSWordExportBase::ExportFormat::RTF)
             {
-                EndRun(nullptr, -42, true);
+                EndRun(nullptr, -42, -1, true);
             }
         }
     }
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx 
b/sw/source/filter/ww8/ww8attributeoutput.hxx
index f459a7bf8a9c..f15bfe07aa52 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -58,7 +58,7 @@ public:
     /// End of the text run.
     ///
     /// No-op for binary filters.
-    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun 
= false) override;
+    virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 
nLen, bool bLastRun = false) override;
 
     /// Before we start outputting the attributes.
     virtual void StartRunProperties() override;
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index 93e0b4f1bd0e..26f564acbe4c 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1114,11 +1114,7 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
 
                 if (m_pImpl->m_pSdtHelper->getControlType() == 
SdtControlType::plainText)
                 {
-                    // The plain text && data binding case needs more work 
before it can be enabled.
-                    if 
(m_pImpl->m_pSdtHelper->GetDataBindingPrefixMapping().isEmpty())
-                    {
-                        m_pImpl->PopSdt();
-                    }
+                    m_pImpl->PopSdt();
                 }
             }
 
@@ -2763,11 +2759,8 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
         m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
         if (m_pImpl->m_pSdtHelper->GetSdtType() == 
NS_ooxml::LN_CT_SdtRun_sdtContent)
         {
-            if (m_pImpl->m_pSdtHelper->GetDataBindingPrefixMapping().isEmpty())
-            {
-                m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
-                break;
-            }
+            m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+            break;
         }
         enableInteropGrabBag("ooxml:CT_SdtPr_text");
         writerfilter::Reference<Properties>::Pointer_t pProperties = 
rSprm.getProps();
@@ -3757,7 +3750,7 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, 
size_t len)
             return;
         }
     }
-    else if ((m_pImpl->m_pSdtHelper->GetSdtType() != 
NS_ooxml::LN_CT_SdtRun_sdtContent || 
!m_pImpl->m_pSdtHelper->GetDataBindingPrefixMapping().isEmpty()) && 
m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+    else if (m_pImpl->m_pSdtHelper->GetSdtType() != 
NS_ooxml::LN_CT_SdtRun_sdtContent && m_pImpl->m_pSdtHelper->getControlType() == 
SdtControlType::plainText)
     {
         m_pImpl->m_pSdtHelper->getSdtTexts().append(sText);
         if (bNewLine)
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 51df60d3f093..25498306b737 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -886,6 +886,14 @@ void DomainMapper_Impl::PopSdt()
         xCursor->goRight(1, /*bExpand=*/false);
     }
     xCursor->gotoRange(xEnd, /*bExpand=*/true);
+
+    std::optional<OUString> oData = m_pSdtHelper->getValueFromDataBinding();
+    if (oData.has_value() && m_pSdtHelper->getControlType() != 
SdtControlType::datePicker)
+    {
+        // Data binding has a value for us, prefer that over the in-document 
value.
+        xCursor->setString(*oData);
+    }
+
     uno::Reference<text::XTextContent> xContentControl(
         m_xTextFactory->createInstance("com.sun.star.text.ContentControl"), 
uno::UNO_QUERY);
     uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, 
uno::UNO_QUERY);
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx 
b/writerfilter/source/dmapper/SdtHelper.hxx
index a986da304df0..e8b8ab34ed38 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -116,8 +116,6 @@ class SdtHelper final : public virtual SvRefBase
                             css::uno::Reference<css::awt::XControlModel> 
const& xControlModel,
                             const 
css::uno::Sequence<css::beans::PropertyValue>& rGrabBag);
 
-    std::optional<OUString> getValueFromDataBinding();
-
     void loadPropertiesXMLs();
 
     /// <w:placeholder>'s <w:docPart w:val="...">.
@@ -204,6 +202,8 @@ public:
 
     void SetColor(const OUString& rColor);
     OUString GetColor() const;
+
+    std::optional<OUString> getValueFromDataBinding();
 };
 
 } // namespace writerfilter::dmapper

Reply via email to