summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-09-22 10:01:26 +0200
committerMiklos Vajna <vmiklos@collabora.com>2022-09-22 12:29:15 +0200
commit01b1f57a90172a76faa1489b3b72250ee76169a6 (patch)
tree0f67e749f0ba0272aa314285bb52df3fa704f9d1
parent21d93d8d2ffd9c5d5cfe9064590b35e0727295c9 (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.cxx26
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx18
-rw-r--r--writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx30
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-combobox.docxbin0 -> 4274 bytes
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx23
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx7
-rw-r--r--writerfilter/source/dmapper/SdtHelper.cxx3
-rw-r--r--writerfilter/source/dmapper/SdtHelper.hxx1
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
new file mode 100644
index 000000000000..2ae80047cc1b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-combobox.docx
Binary files differ
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
};