sw/qa/extras/ooxmlexport/data/test_sdt_datepicker.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx          |   25 ++++++
 sw/source/filter/ww8/docxattributeoutput.cxx           |   62 ++++++++++-------
 sw/source/filter/ww8/docxattributeoutput.hxx           |    3 
 writerfilter/source/dmapper/DomainMapper.cxx           |    9 +-
 writerfilter/source/dmapper/SdtHelper.cxx              |    3 
 writerfilter/source/dmapper/SdtHelper.hxx              |   15 ++++
 7 files changed, 88 insertions(+), 29 deletions(-)

New commits:
commit 83ce54624c7f0a17b9e0ebcf8eebdbc8bae33d46
Author:     Vasily Melenchuk <vasily.melenc...@cib.de>
AuthorDate: Thu Nov 18 20:06:08 2021 +0300
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Feb 18 08:25:24 2022 +0100

    sw: support for other sdt attributes roundtrip in datepicker
    
    Word Control Field with datepicker is implemented with LO datepicker,
    but during this conversion we lose some field data, like control
    color, data mapping, etc. This data is already retrieved and stored
    in grab bag, so we need just to keep this grabbag in field and use
    it again on export.
    
    Change-Id: I6af8204fe1a7d2f9081d83372a6786b2f86260d8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125486
    Tested-by: Jenkins
    Reviewed-by: Vasily Melenchuk <vasily.melenc...@cib.de>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127196
    Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130041
    Tested-by: Miklos Vajna <vmik...@collabora.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/extras/ooxmlexport/data/test_sdt_datepicker.docx 
b/sw/qa/extras/ooxmlexport/data/test_sdt_datepicker.docx
new file mode 100644
index 000000000000..3ff04cb60b89
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/test_sdt_datepicker.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index 094a9262ace7..4a4877cdb9b4 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -758,6 +758,31 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testConditionalText, 
"conditional-text.fodt"
     assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/w:instrText", 
aExpected);
 }
 
+DECLARE_OOXMLEXPORT_TEST( testSdtDatePicker, "test_sdt_datepicker.docx" )
+{
+    // Check that roundtrip for date picker field does not lose essential data
+    xmlDocPtr pXmlDoc = parseExport("word/document.xml");
+    if (!pXmlDoc)
+       return; // initial import, no futher checks
+
+    // Placeholder is here
+    OUString sDocPart = getXPath(pXmlDoc, 
"/w:document/w:body/w:p/w:sdt/w:sdtPr/w:placeholder/w:docPart", "val");
+    CPPUNIT_ASSERT_EQUAL(OUString("DefaultPlaceholder_-1854013437"), sDocPart);
+
+    // Ensure that we have data binding stuff
+    OUString sDBprefix = getXPath(pXmlDoc, 
"/w:document/w:body/w:p/w:sdt/w:sdtPr/w:dataBinding", "prefixMappings");
+    
CPPUNIT_ASSERT_EQUAL(OUString("xmlns:ns0='http://schemas.microsoft.com/vsto/samples'
 "), sDBprefix);
+
+    OUString sDBxpath = getXPath(pXmlDoc, 
"/w:document/w:body/w:p/w:sdt/w:sdtPr/w:dataBinding", "xpath");
+    
CPPUNIT_ASSERT_EQUAL(OUString("/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]"),
 sDBxpath);
+
+    OUString sDBstoreid = getXPath(pXmlDoc, 
"/w:document/w:body/w:p/w:sdt/w:sdtPr/w:dataBinding", "storeItemID");
+    CPPUNIT_ASSERT_EQUAL(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}"), 
sDBstoreid);
+
+    OUString sColor = getXPath(pXmlDoc, 
"/w:document/w:body/w:p/w:sdt/w:sdtPr/w15:color", "val");
+    CPPUNIT_ASSERT_EQUAL(OUString("008000"), sColor);
+}
+
 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 84269fc05f5a..e56117df2f02 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -656,12 +656,36 @@ void 
SdtBlockHelper::WriteSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer, b
         }
     }
 
+    WriteExtraParams(pSerializer);
+
+    pSerializer->endElementNS(XML_w, XML_sdtPr);
+
+    // sdt contents start tag
+    pSerializer->startElementNS(XML_w, XML_sdtContent);
+
+    // prepend the tags since the sdt start mark before the paragraph
+    pSerializer->mergeTopMarks(Tag_WriteSdtBlock, 
sax_fastparser::MergeMarks::PREPEND);
+
+    // write the ending tags after the paragraph
+    m_bStartedSdt = true;
+
+    // clear sdt status
+    m_nSdtPrToken = 0;
+    m_pTokenChildren.clear();
+    m_pDataBindingAttrs.clear();
+    m_pTextAttrs.clear();
+    m_aAlias.clear();
+    m_bHasId = false;
+}
+
+void SdtBlockHelper::WriteExtraParams(::sax_fastparser::FSHelperPtr& 
pSerializer)
+{
     if (m_nSdtPrToken == FSNS(XML_w, XML_id) || m_bHasId)
         //Word won't open a document with an empty id tag, we fill it with a 
random number
         pSerializer->singleElementNS(XML_w, XML_id, FSNS(XML_w, XML_val),
             OString::number(comphelper::rng::uniform_int_distribution(0, 
std::numeric_limits<int>::max())));
 
-    if (m_pDataBindingAttrs.is() && !bParagraphHasDrawing)
+    if (m_pDataBindingAttrs.is())
     {
         XFastAttributeListRef xAttrList( m_pDataBindingAttrs.get() );
         m_pDataBindingAttrs.clear();
@@ -688,25 +712,6 @@ void 
SdtBlockHelper::WriteSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer, b
 
     if (!m_aAlias.isEmpty())
         pSerializer->singleElementNS(XML_w, XML_alias, FSNS(XML_w, XML_val), 
m_aAlias.toUtf8() );
-
-    pSerializer->endElementNS(XML_w, XML_sdtPr);
-
-    // sdt contents start tag
-    pSerializer->startElementNS(XML_w, XML_sdtContent);
-
-    // prepend the tags since the sdt start mark before the paragraph
-    pSerializer->mergeTopMarks(Tag_WriteSdtBlock, 
sax_fastparser::MergeMarks::PREPEND);
-
-    // write the ending tags after the paragraph
-    m_bStartedSdt = true;
-
-    // clear sdt status
-    m_nSdtPrToken = 0;
-    m_pTokenChildren.clear();
-    m_pDataBindingAttrs.clear();
-    m_pTextAttrs.clear();
-    m_aAlias.clear();
-    m_bHasId = false;
 }
 
 void SdtBlockHelper::EndSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer)
@@ -2098,7 +2103,7 @@ void DocxAttributeOutput::WriteFFData(  const FieldInfos& 
rInfos )
     }
 }
 
-void DocxAttributeOutput::WriteFormDateStart(const OUString& sFullDate, const 
OUString& sDateFormat, const OUString& sLang)
+void DocxAttributeOutput::WriteFormDateStart(const OUString& sFullDate, const 
OUString& sDateFormat, const OUString& sLang, const 
uno::Sequence<beans::PropertyValue>& aGrabBagSdt)
 {
     m_pSerializer->startElementNS(XML_w, XML_sdt);
     m_pSerializer->startElementNS(XML_w, XML_sdtPr);
@@ -2119,8 +2124,16 @@ void DocxAttributeOutput::WriteFormDateStart(const 
OUString& sFullDate, const OU
                                    FSNS(XML_w, XML_val), "dateTime");
     m_pSerializer->singleElementNS(XML_w, XML_calendar,
                                    FSNS(XML_w, XML_val), "gregorian");
-
     m_pSerializer->endElementNS(XML_w, XML_date);
+
+    if (aGrabBagSdt.hasElements())
+    {
+        // There are some extra sdt parameters came from grab bag
+        SdtBlockHelper aSdtBlock;
+        aSdtBlock.GetSdtParamsFromGrabBag(aGrabBagSdt);
+        aSdtBlock.WriteExtraParams(m_pSerializer);
+    }
+
     m_pSerializer->endElementNS(XML_w, XML_sdtPr);
 
     m_pSerializer->startElementNS(XML_w, XML_sdtContent);
@@ -2223,7 +2236,10 @@ void DocxAttributeOutput::StartField_Impl( const 
SwTextNode* pNode, sal_Int32 nP
         OUString sLang;
         params.extractParam( ODF_FORMDATE_DATEFORMAT_LANGUAGE, sLang );
 
-        WriteFormDateStart( sFullDate, sDateFormat, sLang );
+        uno::Sequence<beans::PropertyValue> aSdtParams;
+        params.extractParam("SdtParams", aSdtParams);
+
+        WriteFormDateStart( sFullDate, sDateFormat, sLang, aSdtParams);
     }
     else if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField)
     {
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx 
b/sw/source/filter/ww8/docxattributeoutput.hxx
index c5fa0cf38e08..814a84c1a5c8 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -142,6 +142,7 @@ public:
     void DeleteAndResetTheLists();
 
     void WriteSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer, bool 
bRunTextIsOn, bool bParagraphHasDrawing);
+    void WriteExtraParams(::sax_fastparser::FSHelperPtr& pSerializer);
 
     /// Closes a currently open SDT block.
     void EndSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer);
@@ -740,7 +741,7 @@ private:
     void WritePostponedDMLDrawing();
     void WritePostponedCustomShape();
 
-    void WriteFormDateStart(const OUString& sFullDate, const OUString& 
sDateFormat, const OUString& sLang);
+    void WriteFormDateStart(const OUString& sFullDate, const OUString& 
sDateFormat, const OUString& sLang, const uno::Sequence<beans::PropertyValue>& 
aGrabBagSdt);
     void WriteSdtDropDownStart(OUString const& rName, OUString const& 
rSelected, uno::Sequence<OUString> const& rListItems);
     void WriteSdtDropDownEnd(OUString const& rSelected, 
uno::Sequence<OUString> const& rListItems);
     void WriteSdtEnd();
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index 441a6d3cbd67..2d983a496e1e 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1105,12 +1105,15 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
         }
         break;
         case NS_ooxml::LN_CT_DataBinding_prefixMappings:
+            m_pImpl->m_pSdtHelper->setDataBindingPrefixMapping(sStringValue);
             m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, 
"ooxml:CT_DataBinding_prefixMappings", sStringValue);
             break;
         case NS_ooxml::LN_CT_DataBinding_xpath:
+            m_pImpl->m_pSdtHelper->setDataBindingXPath(sStringValue);
             m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, 
"ooxml:CT_DataBinding_xpath", sStringValue);
             break;
         case NS_ooxml::LN_CT_DataBinding_storeItemID:
+            m_pImpl->m_pSdtHelper->setDataBindingStoreItemID(sStringValue);
             m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, 
"ooxml:CT_DataBinding_storeItemID", sStringValue);
             break;
         case NS_ooxml::LN_CT_SdtPlaceholder_docPart_val:
@@ -3427,11 +3430,7 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, 
size_t len)
     }
     else if (m_pImpl->m_pSdtHelper->getControlType() == 
SdtControlType::datePicker)
     {
-        if (!m_pImpl->m_pSdtHelper->isInteropGrabBagEmpty())
-        {
-            m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
-        }
-        else if (IsInHeaderFooter() && m_pImpl->IsDiscardHeaderFooter())
+        if (IsInHeaderFooter() && m_pImpl->IsDiscardHeaderFooter())
         {
             m_pImpl->m_pSdtHelper->getDateFormat().truncate();
             m_pImpl->m_pSdtHelper->getLocale().truncate();
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx 
b/writerfilter/source/dmapper/SdtHelper.cxx
index a1918d1f3756..d64f6aaf5b55 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -196,6 +196,9 @@ void SdtHelper::createDateContentControl()
                     sFullDate = sFullDate.copy(0, nTimeSep);
                 xNameCont->insertByName(ODF_FORMDATE_CURRENTDATE, 
uno::makeAny(sFullDate));
             }
+
+            // Store all unused sdt parameters from grabbag
+            xNameCont->insertByName("SdtParams", 
uno::makeAny(getInteropGrabBagAndClear()));
         }
     }
 
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx 
b/writerfilter/source/dmapper/SdtHelper.hxx
index 3eb18e5d9e65..ed2c3c690f7a 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -66,6 +66,14 @@ class SdtHelper final : public virtual SvRefBase
     OUStringBuffer m_sDate;
     /// Date format string as it comes from the ooxml document.
     OUStringBuffer m_sDateFormat;
+
+    /// <w:dataBinding w:prefixMappings="">
+    OUString m_sDataBindingPrefixMapping;
+    /// <w:dataBinding w:xpath="">
+    OUString m_sDataBindingXPath;
+    /// <w:dataBinding w:storeItemID="">
+    OUString m_sDataBindingStoreItemID;
+
     /// Start range of the date field
     css::uno::Reference<css::text::XTextRange> m_xDateFieldStartRange;
     /// Locale string as it comes from the ooxml document.
@@ -93,6 +101,13 @@ public:
 
     OUStringBuffer& getDateFormat() { return m_sDateFormat; }
 
+    void setDataBindingPrefixMapping(const OUString& sValue)
+    {
+        m_sDataBindingPrefixMapping = sValue;
+    }
+    void setDataBindingXPath(const OUString& sValue) { m_sDataBindingXPath = 
sValue; }
+    void setDataBindingStoreItemID(const OUString& sValue) { 
m_sDataBindingStoreItemID = sValue; }
+
     void setDateFieldStartRange(const 
css::uno::Reference<css::text::XTextRange>& xStartRange)
     {
         m_xDateFieldStartRange = xStartRange;

Reply via email to