writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx                       |  
 34 ++++++++++
 writerfilter/qa/cppunittests/dmapper/data/sdt-dropdown-no-display-text.docx 
|binary
 writerfilter/source/dmapper/DomainMapper.cxx                                |  
 15 ++++
 3 files changed, 49 insertions(+)

New commits:
commit f726fbc2699b05199a8dec3055710a7131e0aad6
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Oct 10 10:07:10 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Oct 10 16:05:53 2022 +0200

    tdf#151261 DOCX import: fix dropdown SDT when the item display text is 
missing
    
    Dropdown content controls have list items, and each list item can have a
    display text and a value. These are optional, and the bugdoc has a list
    item where the value is set, but not the display text.
    
    The trouble is that later in DomainMapper_Impl::PopSdt() we check if the
    length of the display texts and values array match and if not, then we
    throw away these arrays to avoid creating an inconsistent document
    model.
    
    Fix the problem by checking what display text and value we got at the end
    of each list item; if any of them is missing, we add an empty string,
    which matches the internal representation in SwContentControlListItem.
    
    This also helps in case these array sizes matched by accident, but
    display texts and values from different list items were mixed
    previously.
    
    Change-Id: Ib1eeabd2479963af4a84d4229d4f0ce4572e0f01
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141151
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx 
b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx
index 21d5c84cae4e..639c8e9e0303 100644
--- a/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx
@@ -13,6 +13,7 @@
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/text/XTextDocument.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
 
 #include <tools/UnitConversion.hxx>
 
@@ -95,6 +96,39 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtRunInPara)
     // i.e. the block-SDT-only string was lost.
     CPPUNIT_ASSERT_EQUAL(OUString("first-second"), xPara->getString());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtDropdownNoDisplayText)
+{
+    // Given a document with <w:listItem w:value="..."/> (no display text):
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"sdt-dropdown-no-display-text.docx";
+
+    // When loading that document:
+    getComponent() = loadFromDesktop(aURL);
+
+    // Then make sure we create a dropdown content control, not a rich text 
one:
+    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);
+    uno::Sequence<beans::PropertyValues> aListItems;
+    xContentControlProps->getPropertyValue("ListItems") >>= aListItems;
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 0
+    // i.e. the list item was lost on import.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aListItems.getLength());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git 
a/writerfilter/qa/cppunittests/dmapper/data/sdt-dropdown-no-display-text.docx 
b/writerfilter/qa/cppunittests/dmapper/data/sdt-dropdown-no-display-text.docx
new file mode 100644
index 000000000000..ed6d7ac54052
Binary files /dev/null and 
b/writerfilter/qa/cppunittests/dmapper/data/sdt-dropdown-no-display-text.docx 
differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx 
b/writerfilter/source/dmapper/DomainMapper.cxx
index 94e273a0fdcd..95694c270a8e 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -2744,8 +2744,23 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const 
PropertyMapPtr& rContext )
     case NS_ooxml::LN_CT_SdtDropDownList_listItem:
     {
         writerfilter::Reference<Properties>::Pointer_t pProperties = 
rSprm.getProps();
+
+        size_t nDropDownDisplayTexts = 
m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().size();
+        size_t nDropDownItems = 
m_pImpl->m_pSdtHelper->getDropDownItems().size();
+
         if (pProperties)
             pProperties->resolve(*this);
+
+        if (m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().size() != 
nDropDownDisplayTexts + 1)
+        {
+            // w:displayText="..." is optional, add empty value if it was not 
provided.
+            
m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().push_back(OUString());
+        }
+        if (m_pImpl->m_pSdtHelper->getDropDownItems().size() != nDropDownItems 
+ 1)
+        {
+            // w:value="..." is optional, add empty value if it was not 
provided.
+            m_pImpl->m_pSdtHelper->getDropDownItems().push_back(OUString());
+        }
     }
     break;
     case NS_ooxml::LN_CT_SdtPr_placeholder:

Reply via email to