From de90c192cb8f1f03a4028493d8bfe9a127a76b2a Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Mon, 19 Sep 2022 10:01:36 +0200 Subject: 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. Change-Id: I749a845b5a25454c51066b8ded892682f523b6b4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140134 Reviewed-by: Miklos Vajna Tested-by: Jenkins --- 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(-) 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 073918d31c48..f5db919b4c7e 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx @@ -596,7 +596,8 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtBeforeField) loadAndReload("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); } CPPUNIT_TEST_FIXTURE(Test, testfdo81946) @@ -901,36 +902,26 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf104823) OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf104823.docx"; loadURL(aURL, nullptr); - css::uno::Reference 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 xField1(xFields->nextElement(), uno::UNO_QUERY); - CPPUNIT_ASSERT(xFields->hasMoreElements()); + // First paragraph: content from core properties + uno::Reference xParagraph1 = getParagraph(1); + auto xContentControl1 = getProperty>(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 xField1Props(xField1, uno::UNO_QUERY); - xField1Props->setPropertyValue("Content", uno::Any(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 xField2(xFields->nextElement(), uno::UNO_QUERY); - CPPUNIT_ASSERT(xFields->hasMoreElements()); + // Third paragraph: content from custom properties + uno::Reference xParagraph3 = getParagraph(3); + auto xContentControl3 = getProperty>(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 xField2Props(xField2, uno::UNO_QUERY); - xField2Props->setPropertyValue("Content", uno::Any(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 xField3(xFields->nextElement(), uno::UNO_QUERY); - CPPUNIT_ASSERT(!xFields->hasMoreElements()); + // Second paragraph: content from extended properties + uno::Reference xParagraph2 = getParagraph(2); + auto xContentControl2 = getProperty>(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 xField3Props(xField3, uno::UNO_QUERY); - xField3Props->setPropertyValue("Content", uno::Any(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 a7740970347d..d8a8be3e8f7f 100644 --- a/sw/source/filter/ww8/attributeoutputbase.hxx +++ b/sw/source/filter/ww8/attributeoutputbase.hxx @@ -173,7 +173,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; @@ -370,12 +370,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 49ac7c64a9cf..f8fc5429fb97 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -136,6 +136,7 @@ #include #include #include +#include #include #include @@ -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_CONTENTCONTROL)) - { - ++m_nCloseContentControlInPreviousRun; - } - else - { - ++m_nCloseContentControlInThisRun; - } -} - static void checkAndWriteFloatingTables(DocxAttributeOutput& rDocxAttributeOutput) { const auto& rExport = rDocxAttributeOutput.GetExport(); @@ -1584,7 +1568,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 @@ -1641,12 +1625,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 ) @@ -1744,8 +1722,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 ); @@ -1791,6 +1767,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(pAttr); + m_pContentControl = pTextContentControl->GetContentControl().GetContentControl(); + WriteContentControlStart(); + } + } + m_pSerializer->startElementNS(XML_w, XML_r); if(GetExport().m_bTabInTOC && m_pHyperlinkAttrList.is()) { @@ -1809,6 +1796,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 ); @@ -1856,12 +1853,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 ) @@ -2445,6 +2436,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; } @@ -3387,11 +3398,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 blah's by line breaks etc. const sal_Unicode *pBegin = rText.getStr(); @@ -3463,7 +3469,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); @@ -3507,7 +3513,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); @@ -3517,7 +3523,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 b1b5d22ff456..9de8f6fed332 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; @@ -404,12 +404,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. /// @@ -914,9 +908,6 @@ private: o3tl::sorted_vector 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 52090fc74891..a8ec459c79a5 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -1969,7 +1969,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 ); diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index a7f7086f0657..4c3c2c5a74af 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -419,7 +419,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 17de105ed4f6..a20719df6777 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.hxx +++ b/sw/source/filter/ww8/rtfattributeoutput.hxx @@ -75,7 +75,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 692086fa709d..a9ff9a6b9b56 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -1402,14 +1402,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 @@ -1464,17 +1456,6 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos) --nRet; } break; - case RES_TXTATR_CONTENTCONTROL: - if (nPos == pHt->GetStart()) - { - auto pFormatContentControl - = static_cast(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 @@ -2427,7 +2408,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 ); } } @@ -2481,7 +2462,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); } @@ -2778,7 +2759,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) { if (FLY_PROCESSED == nStateOfFlyFrame || FLY_NONE == nStateOfFlyFrame) { - AttrOutput().EndRun(&rNode, nCurrentPos, /*bLastRun=*/false); + AttrOutput().EndRun(&rNode, nCurrentPos, -1, /*bLastRun=*/false); if (!aSavedSnippet.isEmpty()) bStartedPostponedRunProperties = false; @@ -2796,10 +2777,10 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) AttrOutput().WritePostitFieldReference(); } AttrOutput().RunText( aSavedSnippet, eChrSet ); - AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd); + AttrOutput().EndRun(&rNode, nCurrentPos, nLen, 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 5afd5b0c8de2..3fce91b9b436 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -1099,7 +1099,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); @@ -2573,7 +2573,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 9ea43ef885b5..32ad12cdadb3 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 9fa547675c8a..9286f6261287 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1111,11 +1111,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(); } } @@ -2781,11 +2777,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::Pointer_t pProperties = rSprm.getProps(); @@ -3786,7 +3779,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 8966e096dd59..22c75bfb7800 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -892,6 +892,14 @@ void DomainMapper_Impl::PopSdt() xCursor->goRight(1, /*bExpand=*/false); } xCursor->gotoRange(xEnd, /*bExpand=*/true); + + std::optional 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 xContentControl( m_xTextFactory->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx index 7be862cd45f4..1db71cdc9a92 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 const& xControlModel, const css::uno::Sequence& rGrabBag); - std::optional getValueFromDataBinding(); - void loadPropertiesXMLs(); /// 's . @@ -204,6 +202,8 @@ public: void SetColor(const OUString& rColor); const OUString& GetColor() const; + + std::optional getValueFromDataBinding(); }; } // namespace writerfilter::dmapper -- cgit v1.2.3