summaryrefslogtreecommitdiff
path: root/writerfilter
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-07-25 09:13:03 +0200
committerMiklos Vajna <vmiklos@collabora.com>2022-07-27 13:38:30 +0200
commit8c0ab5555c373a2aeb44b71d04ae80c67e704ec8 (patch)
tree8a59396b092735bc7251453c20a1f46f791eb4fc /writerfilter
parent1fdfda440ae62ca40e757cf14af238d18b9b550a (diff)
sw content controls, plain text: add DOCX import
- the core of this is the writerfilter/ change to call PopSdt() for SdtControlType::plainText, which maps inline plain text SDTs to Writer content controls, not to input fields - disable the grab-bag in this case, otherwise we would run duplicated <w:sdt> elements on export - fix CppunitTest_sw_ooxmlexport7's testSdtAndShapeOverlapping by postponing the SDT start in DocxAttributeOutput::WriteContentControlStart() in case a shape is anchored at the same position as the SDT start: if the shape should start inside the content control, then it should be anchored after the dummy character - reduce the debug output in VMLExport::Commit(), which could write control characters to the terminal on test failure, potentially breaking it (requiring a 'reset' to recover) - fix CppunitTest_sw_ooxmlexport5's testSdt2Run: now we merge two runs inside a plain text content control into a single one, and there is no problem with that, so adapt the test instead - fix CppunitTest_sw_ooxmlexport17's testTdf148361: plain text inline SDT is now a content control, not a field - fix CppunitTest_sw_ooxmlfieldexport's testfdo82492: explicitly assert that there is 1 text run inside the SDT and there is a shape after it (outside). Also extend DocxAttributeOutput::EndContentControl(), so it ends the content control at the correct, earlier position in case it's followed by an as-char shape - fix CppunitTest_sw_ooxmlfieldexport's testfdo82123: again assert that the SDT has 1 run with text, and there is a drawing after the SDT - fix CppunitTest_sw_ooxmlfieldexport's testTdf104823: this revealed that some more complex logic is needed to support data bindings, so exclude text-with-databinding from the scope of this commit and continue to map those to input fields for now - fix CppunitTest_sw_ooxmlfieldexport's testFdo81945: this had a similar problem as as-char shapes, but this time a new SDT is starting right after a previous SDT. Adapt DocxAttributeOutput::EndContentControl() accordingly, though perhaps this should be generalized later, so we always close SDTs in the previous run, unless this is the last run, or something similar (cherry picked from commit 9700c1b2170ad04453a361ed5647937833ac3c18) Conflicts: oox/source/export/vmlexport.cxx Change-Id: Ifaf581be884a683de6c8b932008a03ba43734b75 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137494 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'writerfilter')
-rw-r--r--writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx30
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-plain-text.docxbin0 -> 4179 bytes
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx20
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx5
-rw-r--r--writerfilter/source/dmapper/SdtHelper.cxx1
-rw-r--r--writerfilter/source/dmapper/SdtHelper.hxx4
6 files changed, 59 insertions, 1 deletions
diff --git a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
index b2e7f1058f88..6b568619785e 100644
--- a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
@@ -88,6 +88,36 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtRunRichText)
CPPUNIT_ASSERT_EQUAL(24.f, fCharheight);
}
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunPlainText)
+{
+ // Given a document with a plain text inline/run SDT:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-run-plain-text.docx";
+
+ // When loading the document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the text inside the SDT is not rich:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortionEnum = xPara->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY);
+ OUString aTextPortionType;
+ xPortion->getPropertyValue("TextPortionType") >>= aTextPortionType;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: ContentControl
+ // - Actual : TextField
+ // i.e. the SDT was imported as a text field, not as a content control.
+ CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aTextPortionType);
+ uno::Reference<beans::XPropertySet> xContentControl;
+ xPortion->getPropertyValue("ContentControl") >>= xContentControl;
+ bool bPlainText{};
+ xContentControl->getPropertyValue("PlainText") >>= bPlainText;
+ CPPUNIT_ASSERT(bPlainText);
+}
+
CPPUNIT_TEST_FIXTURE(Test, testSdtRunCheckbox)
{
// Given a document with a checkbox inline/run SDT:
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-plain-text.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-plain-text.docx
new file mode 100644
index 000000000000..127d81fd966b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-plain-text.docx
Binary files differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index 33929cdddf1c..93e0b4f1bd0e 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1070,6 +1070,7 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
break;
case NS_ooxml::LN_CT_SdtBlock_sdtContent:
case NS_ooxml::LN_CT_SdtRun_sdtContent:
+ m_pImpl->m_pSdtHelper->SetSdtType(nName);
if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::unknown)
{
// Still not determined content type? and it is even not unsupported? Then it is plain text field
@@ -1110,6 +1111,15 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
default:
break;
}
+
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ // The plain text && data binding case needs more work before it can be enabled.
+ if (m_pImpl->m_pSdtHelper->GetDataBindingPrefixMapping().isEmpty())
+ {
+ m_pImpl->PopSdt();
+ }
+ }
}
m_pImpl->SetSdt(false);
@@ -2751,6 +2761,14 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
case NS_ooxml::LN_CT_SdtPr_text:
{
m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ if (m_pImpl->m_pSdtHelper->GetSdtType() == NS_ooxml::LN_CT_SdtRun_sdtContent)
+ {
+ if (m_pImpl->m_pSdtHelper->GetDataBindingPrefixMapping().isEmpty())
+ {
+ m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ break;
+ }
+ }
enableInteropGrabBag("ooxml:CT_SdtPr_text");
writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
if (pProperties)
@@ -3739,7 +3757,7 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
return;
}
}
- else if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ else if ((m_pImpl->m_pSdtHelper->GetSdtType() != NS_ooxml::LN_CT_SdtRun_sdtContent || !m_pImpl->m_pSdtHelper->GetDataBindingPrefixMapping().isEmpty()) && m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
{
m_pImpl->m_pSdtHelper->getSdtTexts().append(sText);
if (bNewLine)
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index a1c280a9869a..0cf793f480b0 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -973,6 +973,11 @@ void DomainMapper_Impl::PopSdt()
uno::Any(m_pSdtHelper->getDate().makeStringAndClear()));
}
+ if (m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ xContentControlProps->setPropertyValue("PlainText", uno::Any(true));
+ }
+
xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
m_pSdtHelper->clear();
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx
index a3bd08ec807a..013581a038c8 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -445,6 +445,7 @@ void SdtHelper::clear()
m_aDropDownItems.clear();
m_aDropDownDisplayTexts.clear();
setControlType(SdtControlType::unknown);
+ m_nSdtType = 0;
m_sDataBindingPrefixMapping.clear();
m_sDataBindingXPath.clear();
m_sDataBindingStoreItemID.clear();
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx
index 3d616067211e..a986da304df0 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -66,6 +66,7 @@ class SdtHelper final : public virtual SvRefBase
std::vector<OUString> m_aDropDownDisplayTexts;
/// Type of sdt control
SdtControlType m_aControlType;
+ sal_uInt32 m_nSdtType = 0;
/// Pieces of the default text -- currently used only by the dropdown control.
OUStringBuffer m_aSdtTexts;
/// Date ISO string contained in the w:date element, used by the date control.
@@ -169,6 +170,9 @@ public:
SdtControlType getControlType() { return m_aControlType; }
void setControlType(SdtControlType aType) { m_aControlType = aType; }
+ void SetSdtType(sal_uInt32 nSdtType) { m_nSdtType = nSdtType; }
+ sal_uInt32 GetSdtType() const { return m_nSdtType; }
+
/// Create drop-down control from w:sdt's w:dropDownList.
void createDropDownControl();
/// Create date control from w:sdt's w:date.