summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-06-28 08:53:15 +0200
committerMiklos Vajna <vmiklos@collabora.com>2022-06-28 09:31:51 +0200
commitbab023ce3b584e815067a207adc7a8aca1f964af (patch)
treec3e16e93d86ccde6d288161defd511849115ef66
parentsw: document UndoManager (diff)
downloadcore-bab023ce3b584e815067a207adc7a8aca1f964af.tar.gz
core-bab023ce3b584e815067a207adc7a8aca1f964af.zip
tdf#149654 sw content controls: fix missing string before inline SDT from DOCX
The document had a block SDT and inside that, a run SDT. The content that is before the run SDT but already inside the block SDT was lost. To work incrementally, it was intentional that once commit 5ee8670f18cb8b1913a23d04590d6a31ac9730de (sw content controls, date: add DOCX import, 2022-05-30) changed most of run SDTs to content controls, it left block SDTs (and cell/row SDTs, too) unchanged, so they are still mapped to fields. What was forgotten is that m_pImpl->m_pSdtHelper in DomainMapper is a shared state: once a run SDT starts, it assumes that no non-run SDTs are in progress. Fix the problem by explicitly checking for non-run SDTs before PushSdt(), that keeps the separation (content control for run SDT, fields for the rest) but fixes the lost content. This is for plain text SDTs, but other types can be added if necessary. Change-Id: I46b029a3a945d7416028aa196ac3160e6d96eae8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136524 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx21
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docxbin0 -> 11987 bytes
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx10
3 files changed, 31 insertions, 0 deletions
diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx
index 88ba238fae29..21d5c84cae4e 100644
--- a/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx
@@ -74,6 +74,27 @@ CPPUNIT_TEST_FIXTURE(Test, testLargeParaTopMargin)
// -> wrap around a TextBox), which shifted the triangle shape out of the page frame.
CPPUNIT_ASSERT_EQUAL(nExpected, nParaTopMargin);
}
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunInPara)
+{
+ // Given a document with a block SDT, and inside that some content + a run SDT:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-run-in-para.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the content inside the block SDT but outside the run SDT is not lost:
+ 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<text::XTextRange> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: first-second
+ // - Actual : second
+ // i.e. the block-SDT-only string was lost.
+ CPPUNIT_ASSERT_EQUAL(OUString("first-second"), xPara->getString());
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docx
new file mode 100644
index 000000000000..863bc9213b5b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docx
Binary files differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index cd89b3d7d7ae..224f8c2aa902 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1074,6 +1074,16 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
}
if (nName == NS_ooxml::LN_CT_SdtRun_sdtContent)
{
+ if (m_pImpl->GetSdtStarts().empty() && !m_pImpl->m_pSdtHelper->getSdtTexts().isEmpty())
+ {
+ // A non-inline SDT is already started, first convert that to a field and only
+ // then map the inline SDT to a content control.
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ }
+ }
+
m_pImpl->m_pSdtHelper->setControlType(SdtControlType::richText);
m_pImpl->PushSdt();
break;