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 );

Reply via email to