sw/qa/extras/ooxmlexport/ooxmlexport17.cxx | 36 ++++++++++++++ sw/source/filter/ww8/docxattributeoutput.cxx | 66 ++++++++++++++++++--------- sw/source/filter/ww8/docxattributeoutput.hxx | 3 - 3 files changed, 84 insertions(+), 21 deletions(-)
New commits: commit 38ae2a54e2efc1c957868b6d8e93bd49bb3e08c7 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Apr 28 10:12:29 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon May 2 13:49:06 2022 +0200 sw content controls, checkbox: add DOCX export Map the 4 UNO properties to the following XML construct: <w14:checkbox> <w14:checked w14:val="0"/> <w14:checkedState w14:val="2612"/> <w14:uncheckedState w14:val="2610"/> </w14:checkbox> (cherry picked from commit 8642389b954a0b8f5673c85f44d8b0ea34eb3430) Conflicts: sw/qa/extras/ooxmlexport/ooxmlexport17.cxx Change-Id: I6457754e5dc9750204da7f2e5e479589380f3992 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133644 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index b72a470978cc..38a17bca714b 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -146,6 +146,42 @@ CPPUNIT_TEST_FIXTURE(Test, testContentControlExport) assertXPath(pXmlDoc, "//w:sdt/w:sdtContent", 1); } +CPPUNIT_TEST_FIXTURE(Test, testCheckboxContentControlExport) +{ + // Given a document with a checkbox content control around a text portion: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + xText->insertString(xCursor, OUString(u"☐"), /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference<text::XTextContent> xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("Checkbox", uno::makeAny(true)); + xContentControlProps->setPropertyValue("Checked", uno::makeAny(true)); + xContentControlProps->setPropertyValue("CheckedState", uno::makeAny(OUString(u"☒"))); + xContentControlProps->setPropertyValue("UncheckedState", uno::makeAny(OUString(u"☐"))); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // When exporting to DOCX: + save("Office Open XML Text", maTempFile); + mbExported = true; + + // Then make sure the expected markup is used: + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + // Without the fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // - XPath '//w:sdt/w:sdtPr/w14:checkbox/w14:checked' number of nodes is incorrect + // i.e. <w14:checkbox> and its child elements were lost. + assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w14:checkbox/w14:checked", "val", "1"); + assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w14:checkbox/w14:checkedState", "val", "2612"); + assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w14:checkbox/w14:uncheckedState", "val", "2610"); +} + DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx") { xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 059c7204b01f..2fd7a442c77d 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -1635,8 +1635,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / for (; m_nCloseContentControlInPreviousRun > 0; --m_nCloseContentControlInPreviousRun) { // Not the last run of this paragraph. - m_pSerializer->endElementNS(XML_w, XML_sdtContent); - m_pSerializer->endElementNS(XML_w, XML_sdt); + WriteContentControlEnd(); } if ( m_closeHyperlinkInPreviousRun ) @@ -1736,18 +1735,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / m_nHyperLinkCount++; } - if (m_pContentControl) - { - m_pSerializer->startElementNS(XML_w, XML_sdt); - m_pSerializer->startElementNS(XML_w, XML_sdtPr); - if (m_pContentControl->GetShowingPlaceHolder()) - { - m_pSerializer->singleElementNS(XML_w, XML_showingPlcHdr); - } - m_pSerializer->endElementNS(XML_w, XML_sdtPr); - m_pSerializer->startElementNS(XML_w, XML_sdtContent); - m_pContentControl = nullptr; - } + WriteContentControlStart(); // if there is some redlining in the document, output it StartRedline( m_pRedlineData ); @@ -1862,8 +1850,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool / for (; m_nCloseContentControlInThisRun > 0; --m_nCloseContentControlInThisRun) { // Last run of this paragraph. - m_pSerializer->endElementNS(XML_w, XML_sdtContent); - m_pSerializer->endElementNS(XML_w, XML_sdt); + WriteContentControlEnd(); } if ( m_closeHyperlinkInThisRun ) @@ -2342,7 +2329,46 @@ void DocxAttributeOutput::WriteSdtPlainText(const OUString & sValue, const uno:: m_pSerializer->startElementNS(XML_w, XML_sdtContent); } -void DocxAttributeOutput::WriteSdtEnd() +void DocxAttributeOutput::WriteContentControlStart() +{ + if (!m_pContentControl) + { + return; + } + + m_pSerializer->startElementNS(XML_w, XML_sdt); + m_pSerializer->startElementNS(XML_w, XML_sdtPr); + if (m_pContentControl->GetShowingPlaceHolder()) + { + m_pSerializer->singleElementNS(XML_w, XML_showingPlcHdr); + } + + if (m_pContentControl->GetCheckbox()) + { + m_pSerializer->startElementNS(XML_w14, XML_checkbox); + m_pSerializer->singleElementNS(XML_w14, XML_checked, FSNS(XML_w14, XML_val), + OString::number(int(m_pContentControl->GetChecked()))); + OUString aCheckedState = m_pContentControl->GetCheckedState(); + if (!aCheckedState.isEmpty()) + { + m_pSerializer->singleElementNS(XML_w14, XML_checkedState, FSNS(XML_w14, XML_val), + OString::number(aCheckedState[0], /*radix=*/16)); + } + OUString aUncheckedState = m_pContentControl->GetUncheckedState(); + if (!aUncheckedState.isEmpty()) + { + m_pSerializer->singleElementNS(XML_w14, XML_uncheckedState, FSNS(XML_w14, XML_val), + OString::number(aUncheckedState[0], /*radix=*/16)); + } + m_pSerializer->endElementNS(XML_w14, XML_checkbox); + } + + m_pSerializer->endElementNS(XML_w, XML_sdtPr); + m_pSerializer->startElementNS(XML_w, XML_sdtContent); + m_pContentControl = nullptr; +} + +void DocxAttributeOutput::WriteContentControlEnd() { m_pSerializer->endElementNS(XML_w, XML_sdtContent); m_pSerializer->endElementNS(XML_w, XML_sdt); @@ -2403,7 +2429,7 @@ void DocxAttributeOutput::WriteSdtDropDownEnd(OUString const& rSelected, m_pSerializer->endElementNS(XML_w, XML_r); } - WriteSdtEnd(); + WriteContentControlEnd(); } void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun ) @@ -2702,7 +2728,7 @@ void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos { if (rInfos.eType == ww::eFORMDATE) { - WriteSdtEnd(); + WriteContentControlEnd(); return; } else if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField) @@ -2718,7 +2744,7 @@ void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos SwInputField const& rField(*static_cast<SwInputField const*>(rInfos.pField.get())); if (rField.getGrabBagParams().hasElements()) { - WriteSdtEnd(); + WriteContentControlEnd(); return; } } diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 88ed18db6a6b..eec6b438e498 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -772,7 +772,8 @@ private: void WriteSdtPlainText(const OUString& sValue, 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(); + void WriteContentControlStart(); + void WriteContentControlEnd(); void StartField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos const & rInfos, bool bWriteRun = false ); void DoWriteCmd( const OUString& rCmd );