diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2022-07-25 09:13:03 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2022-07-27 13:38:30 +0200 |
commit | 8c0ab5555c373a2aeb44b71d04ae80c67e704ec8 (patch) | |
tree | 8a59396b092735bc7251453c20a1f46f791eb4fc /writerfilter | |
parent | 1fdfda440ae62ca40e757cf14af238d18b9b550a (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.cxx | 30 | ||||
-rw-r--r-- | writerfilter/qa/cppunittests/dmapper/data/sdt-run-plain-text.docx | bin | 0 -> 4179 bytes | |||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 20 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 5 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.cxx | 1 | ||||
-rw-r--r-- | writerfilter/source/dmapper/SdtHelper.hxx | 4 |
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 Binary files differnew file mode 100644 index 000000000000..127d81fd966b --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-plain-text.docx 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. |