diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2022-09-22 10:01:26 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2022-09-22 12:29:15 +0200 |
commit | 01b1f57a90172a76faa1489b3b72250ee76169a6 (patch) | |
tree | 0f67e749f0ba0272aa314285bb52df3fa704f9d1 | |
parent | 21d93d8d2ffd9c5d5cfe9064590b35e0727295c9 (diff) |
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.
Change-Id: I50e0b961bca99f4ecca86d6784d2e6a13f469314
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140399
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
-rw-r--r-- | sw/qa/filter/ww8/ww8.cxx | 26 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 18 | ||||
-rw-r--r-- | writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx | 30 | ||||
-rw-r--r-- | writerfilter/qa/cppunittests/dmapper/data/sdt-run-combobox.docx | bin | 0 -> 4274 bytes | |||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 23 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 7 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.cxx | 3 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.hxx | 1 |
8 files changed, 100 insertions, 8 deletions
diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx index 4f33e781d05d..ea8c4d9a9553 100644 --- a/sw/qa/filter/ww8/ww8.cxx +++ b/sw/qa/filter/ww8/ww8.cxx @@ -11,6 +11,10 @@ #include <com/sun/star/text/XTextDocument.hpp> +#include <docsh.hxx> +#include <formatcontentcontrol.hxx> +#include <wrtsh.hxx> + namespace { constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/filter/ww8/data/"; @@ -81,6 +85,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"); + SwDoc* pDoc = getSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->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 f8fc5429fb97..5833dd62dbca 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -2393,14 +2393,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 Binary files differnew file mode 100644 index 000000000000..2ae80047cc1b --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-combobox.docx diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 9286f6261287..675a8b37e869 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1101,6 +1101,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(); @@ -1127,6 +1128,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: @@ -2723,9 +2725,16 @@ 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(); if (pProperties) @@ -3758,7 +3767,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) @@ -3813,7 +3824,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::Any(aGrabBag), true, CHAR_GRAB_BAG); } @@ -3822,7 +3835,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::Any(aGrabBag), true, PARA_GRAB_BAG); diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 22c75bfb7800..f1a2583d6809 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -950,7 +950,8 @@ void DomainMapper_Impl::PopSdt() uno::Any(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(); @@ -967,6 +968,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 32570db71813..50ddf4b99b21 100644 --- a/writerfilter/source/dmapper/SdtHelper.cxx +++ b/writerfilter/source/dmapper/SdtHelper.cxx @@ -209,7 +209,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 1db71cdc9a92..2cfa19f5e95e 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 }; |