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-25 09:51:22 +0200
commit9700c1b2170ad04453a361ed5647937833ac3c18 (patch)
treeb193db3dd41a6da1e940d8b4067802a1185716ba /writerfilter
parentf17aec9f573f87e4a8fa5ccdf504897d745bb0a6 (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 Change-Id: Ifaf581be884a683de6c8b932008a03ba43734b75 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137399 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
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 c3742cdbaa47..826404d640be 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1067,6 +1067,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
@@ -1107,6 +1108,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);
@@ -2754,6 +2764,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)
@@ -3753,7 +3771,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 f37e7c2d9032..ba66d5c340f7 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -978,6 +978,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 8f5e809efdec..0301264bbaef 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -443,6 +443,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 c817285095e7..441fa927b045 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.