sw/qa/filter/ww8/ww8.cxx                                        |   27 
+++++++++
 sw/source/filter/ww8/docxattributeoutput.cxx                    |   18 +++++-
 writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx              |   30 
++++++++++
 writerfilter/qa/cppunittests/dmapper/data/sdt-run-combobox.docx |binary
 writerfilter/source/dmapper/DomainMapper.cxx                    |   23 ++++++-
 writerfilter/source/dmapper/DomainMapper_Impl.cxx               |    7 ++
 writerfilter/source/dmapper/SdtHelper.cxx                       |    3 -
 writerfilter/source/dmapper/SdtHelper.hxx                       |    1 
 8 files changed, 101 insertions(+), 8 deletions(-)

New commits:
commit 321aa90f483d4c458e20c96da4f8d70943184283
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Sep 22 10:01:26 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Sep 23 09:35:25 2022 +0200

    sw content controls, combo box: add DOCX filter
    
    Map the ComboBox UNO property to:
    
            <w:sdtPr>
              <w:comboBox>
              ...
              </w:comboBox>
            </w:sdtPr>
    
    and the opposite on import.
    
    (cherry picked from commit 01b1f57a90172a76faa1489b3b72250ee76169a6)
    
    Change-Id: I50e0b961bca99f4ecca86d6784d2e6a13f469314
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140432
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx
index d98ff7dae151..d537cee04188 100644
--- a/sw/qa/filter/ww8/ww8.cxx
+++ b/sw/qa/filter/ww8/ww8.cxx
@@ -11,6 +11,11 @@
 
 #include <com/sun/star/text/XTextDocument.hpp>
 
+#include <docsh.hxx>
+#include <formatcontentcontrol.hxx>
+#include <wrtsh.hxx>
+#include <unotxdoc.hxx>
+
 namespace
 {
 /**
@@ -56,6 +61,28 @@ CPPUNIT_TEST_FIXTURE(Test, testPlainTextContentControlExport)
     // i.e. the plain text content control was turned into a rich text one on 
export.
     assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:text", 1);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testDocxComboBoxContentControlExport)
+{
+    // Given a document with a combo box content control around a text portion:
+    mxComponent = loadFromDesktop("private:factory/swriter");
+    SwDocShell* pDocShell = 
dynamic_cast<SwXTextDocument*>(mxComponent.get())->GetDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->InsertContentControl(SwContentControlType::COMBO_BOX);
+
+    // 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 accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 0
+    // - XPath '//w:sdt/w:sdtPr/w:comboBox' number of nodes is incorrect
+    // i.e. the combo box content control was turned into a drop-down one on 
export.
+    assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:comboBox", 1);
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 67e87965e5f0..42c5c0cdef15 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -2395,14 +2395,28 @@ void DocxAttributeOutput::WriteContentControlStart()
 
     if (m_pContentControl->HasListItems())
     {
-        m_pSerializer->startElementNS(XML_w, XML_dropDownList);
+        if (m_pContentControl->GetComboBox())
+        {
+            m_pSerializer->startElementNS(XML_w, XML_comboBox);
+        }
+        else
+        {
+            m_pSerializer->startElementNS(XML_w, XML_dropDownList);
+        }
         for (const auto& rItem : m_pContentControl->GetListItems())
         {
             m_pSerializer->singleElementNS(XML_w, XML_listItem,
                     FSNS(XML_w, XML_displayText), rItem.m_aDisplayText,
                     FSNS(XML_w, XML_value), rItem.m_aValue);
         }
-        m_pSerializer->endElementNS(XML_w, XML_dropDownList);
+        if (m_pContentControl->GetComboBox())
+        {
+            m_pSerializer->endElementNS(XML_w, XML_comboBox);
+        }
+        else
+        {
+            m_pSerializer->endElementNS(XML_w, XML_dropDownList);
+        }
     }
 
     if (m_pContentControl->GetDate())
diff --git a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx 
b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
index 6b568619785e..7b842e667104 100644
--- a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
@@ -212,6 +212,36 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtRunDropdown)
     CPPUNIT_ASSERT_EQUAL(OUString("choose a color"), xContent->getString());
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunComboBox)
+{
+    // Given a document with a combo box inline/run SDT:
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"sdt-run-combobox.docx";
+
+    // When loading the document:
+    getComponent() = loadFromDesktop(aURL);
+
+    // Then make sure that the doc model has a clickable combo box content 
control:
+    uno::Reference<text::XTextDocument> xTextDocument(getComponent(), 
uno::UNO_QUERY);
+    uno::Reference<container::XEnumerationAccess> 
xParagraphsAccess(xTextDocument->getText(),
+                                                                    
uno::UNO_QUERY);
+    uno::Reference<container::XEnumeration> xParagraphs = 
xParagraphsAccess->createEnumeration();
+    uno::Reference<container::XEnumerationAccess> 
xParagraph(xParagraphs->nextElement(),
+                                                             uno::UNO_QUERY);
+    uno::Reference<container::XEnumeration> xPortions = 
xParagraph->createEnumeration();
+    uno::Reference<beans::XPropertySet> xTextPortion(xPortions->nextElement(), 
uno::UNO_QUERY);
+    OUString aPortionType;
+    xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+    CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType);
+    uno::Reference<text::XTextContent> xContentControl;
+    xTextPortion->getPropertyValue("ContentControl") >>= xContentControl;
+    uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, 
uno::UNO_QUERY);
+    bool bComboBox{};
+    xContentControlProps->getPropertyValue("ComboBox") >>= bComboBox;
+    // Without the accompanying fix in place, this failed as the content 
control was a drop-down,
+    // not a combo box.
+    CPPUNIT_ASSERT(bComboBox);
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testSdtRunPicture)
 {
     // Given a document with a dropdown inline/run SDT:
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-combobox.docx 
b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-combobox.docx
new file mode 100644
index 000000000000..2ae80047cc1b
Binary files /dev/null and 
b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-combobox.docx differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index e79a46784dab..20165d7a7bcf 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1104,6 +1104,7 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
                     case SdtControlType::richText:
                     case SdtControlType::checkBox:
                     case SdtControlType::dropDown:
+                    case SdtControlType::comboBox:
                     case SdtControlType::picture:
                     case SdtControlType::datePicker:
                         m_pImpl->PopSdt();
@@ -1130,6 +1131,7 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
             switch (m_pImpl->m_pSdtHelper->getControlType())
             {
                 case SdtControlType::dropDown:
+                case SdtControlType::comboBox:
                     m_pImpl->m_pSdtHelper->createDropDownControl();
                     break;
                 case SdtControlType::plainText:
@@ -2705,8 +2707,15 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
         }
     }
     break;
-    case NS_ooxml::LN_CT_SdtPr_dropDownList:
     case NS_ooxml::LN_CT_SdtPr_comboBox:
+    {
+        m_pImpl->m_pSdtHelper->setControlType(SdtControlType::comboBox);
+        writerfilter::Reference<Properties>::Pointer_t pProperties = 
rSprm.getProps();
+        if (pProperties)
+            pProperties->resolve(*this);
+    }
+    break;
+    case NS_ooxml::LN_CT_SdtPr_dropDownList:
     {
         m_pImpl->m_pSdtHelper->setControlType(SdtControlType::dropDown);
         writerfilter::Reference<Properties>::Pointer_t pProperties = 
rSprm.getProps();
@@ -3729,7 +3738,9 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, 
size_t len)
     }
 
     bool bNewLine = len == 1 && (sText[0] == 0x0d || sText[0] == 0x07);
-    if (m_pImpl->GetSdtStarts().empty() && 
m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::dropDown)
+    if (m_pImpl->GetSdtStarts().empty()
+        && (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::dropDown
+            || m_pImpl->m_pSdtHelper->getControlType() == 
SdtControlType::comboBox))
     {
         // Block, cell or row SDT.
         if (bNewLine)
@@ -3784,7 +3795,9 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, 
size_t len)
                 pContext = m_pImpl->GetTopFieldContext()->getProperties();
 
             uno::Sequence<beans::PropertyValue> aGrabBag = 
m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
-            if (m_pImpl->GetSdtStarts().empty() || 
m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::dropDown)
+            if (m_pImpl->GetSdtStarts().empty()
+                || (m_pImpl->m_pSdtHelper->getControlType() != 
SdtControlType::dropDown
+                    && m_pImpl->m_pSdtHelper->getControlType() != 
SdtControlType::comboBox))
             {
                 pContext->Insert(PROP_SDTPR, uno::makeAny(aGrabBag), true, 
CHAR_GRAB_BAG);
             }
@@ -3793,7 +3806,9 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, 
size_t len)
         {
             uno::Sequence<beans::PropertyValue> aGrabBag = 
m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
             if (m_pImpl->GetSdtStarts().empty()
-                || (m_pImpl->m_pSdtHelper->getControlType() != 
SdtControlType::dropDown && m_pImpl->m_pSdtHelper->getControlType() != 
SdtControlType::richText))
+                || (m_pImpl->m_pSdtHelper->getControlType() != 
SdtControlType::dropDown
+                    && m_pImpl->m_pSdtHelper->getControlType() != 
SdtControlType::comboBox
+                    && m_pImpl->m_pSdtHelper->getControlType() != 
SdtControlType::richText))
             {
                 
m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)->Insert(PROP_SDTPR,
                         uno::makeAny(aGrabBag), true, PARA_GRAB_BAG);
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 25498306b737..5ddb03d7c405 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -944,7 +944,8 @@ void DomainMapper_Impl::PopSdt()
                                                
uno::makeAny(m_pSdtHelper->GetUncheckedState()));
     }
 
-    if (m_pSdtHelper->getControlType() == SdtControlType::dropDown)
+    if (m_pSdtHelper->getControlType() == SdtControlType::dropDown
+        || m_pSdtHelper->getControlType() == SdtControlType::comboBox)
     {
         std::vector<OUString>& rDisplayTexts = 
m_pSdtHelper->getDropDownDisplayTexts();
         std::vector<OUString>& rValues = m_pSdtHelper->getDropDownItems();
@@ -961,6 +962,10 @@ void DomainMapper_Impl::PopSdt()
                 pItems[i] = aItem;
             }
             xContentControlProps->setPropertyValue("ListItems", 
uno::Any(aItems));
+            if (m_pSdtHelper->getControlType() == SdtControlType::comboBox)
+            {
+                xContentControlProps->setPropertyValue("ComboBox", 
uno::Any(true));
+            }
         }
     }
 
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx 
b/writerfilter/source/dmapper/SdtHelper.cxx
index 013581a038c8..53359a4e69e2 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -210,7 +210,8 @@ std::optional<OUString> SdtHelper::getValueFromDataBinding()
 
 void SdtHelper::createDropDownControl()
 {
-    assert(getControlType() == SdtControlType::dropDown);
+    assert(getControlType() == SdtControlType::dropDown
+           || getControlType() == SdtControlType::comboBox);
 
     const bool bDropDown
         = 
officecfg::Office::Writer::Filter::Import::DOCX::ImportComboBoxAsDropDown::get();
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx 
b/writerfilter/source/dmapper/SdtHelper.hxx
index e8b8ab34ed38..b1ec0dd6c77f 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -45,6 +45,7 @@ enum class SdtControlType
     richText,
     checkBox,
     picture,
+    comboBox,
     unsupported, // Sdt block is defined, but we still do not support such 
type of field
     unknown
 };

Reply via email to