diff options
author | Vasily Melenchuk <vasily.melenchuk@cib.de> | 2021-11-18 20:06:08 +0300 |
---|---|---|
committer | Vasily Melenchuk <vasily.melenchuk@cib.de> | 2021-12-02 21:16:01 +0100 |
commit | 41a9ff8d9ef6e0dbb4a71b0f923079eb8ffd1851 (patch) | |
tree | 53fba8de69665ab2aa0b884aa0846f1428e47880 | |
parent | cd9bb2dfcf07e5274be85e6a8906056ab08a1ca3 (diff) |
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.melenchuk@cib.de>
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/test_sdt_datepicker.docx | bin | 0 -> 20357 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx | 25 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 62 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 3 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 9 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.cxx | 3 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.hxx | 15 |
7 files changed, 88 insertions, 29 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/test_sdt_datepicker.docx b/sw/qa/extras/ooxmlexport/data/test_sdt_datepicker.docx Binary files differnew file mode 100644 index 000000000000..3ff04cb60b89 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/test_sdt_datepicker.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx index 5c0e0685ecec..610820c40f33 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx @@ -770,6 +770,31 @@ DECLARE_OOXMLEXPORT_TEST(testTdf142464_ampm, "tdf142464_ampm.docx") } } +DECLARE_OOXMLEXPORT_TEST( testSdtDatePicker, "test_sdt_datepicker.docx" ) +{ + // Check that roundtrip for date picker field does not lose essential data + xmlDocUniquePtr 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 71fa753bd44c..51a8ac155cad 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -663,12 +663,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()) { rtl::Reference<FastAttributeList> xAttrList = std::move(m_pDataBindingAttrs); pSerializer->singleElementNS(XML_w, XML_dataBinding, xAttrList); @@ -693,25 +717,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); - - 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) @@ -2152,7 +2157,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); @@ -2172,8 +2177,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); @@ -2276,7 +2289,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 595b30e7329b..3897073ffe1f 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -144,6 +144,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); @@ -750,7 +751,7 @@ private: void WritePostponedCustomShape(); void WriteFlyFrame(const ww8::Frame& rFrame); - 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(std::u16string_view 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 ea16e51e0f9f..b247e0156b38 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1132,12 +1132,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: @@ -3539,11 +3542,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 46f834280404..5466baec8fc1 100644 --- a/writerfilter/source/dmapper/SdtHelper.cxx +++ b/writerfilter/source/dmapper/SdtHelper.cxx @@ -196,6 +196,9 @@ void SdtHelper::createDateContentControl() } setControlType(SdtControlType::unknown); + + // Store all unused sdt parameters from grabbag + xNameCont->insertByName("SdtParams", uno::makeAny(getInteropGrabBagAndClear())); } void SdtHelper::createControlShape(awt::Size aSize, diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx index 5a39177c4a56..9d31e1621504 100644 --- a/writerfilter/source/dmapper/SdtHelper.hxx +++ b/writerfilter/source/dmapper/SdtHelper.hxx @@ -54,6 +54,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. @@ -81,6 +89,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; |