writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx | 21 ++++++++++ writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docx |binary writerfilter/source/dmapper/DomainMapper.cxx | 10 ++++ 3 files changed, 31 insertions(+)
New commits: commit c6f09675e991be0b596600fdd5d7f177149dacc6 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jun 28 08:53:15 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Jun 30 12:39:21 2022 +0200 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. (cherry picked from commit bab023ce3b584e815067a207adc7a8aca1f964af) Change-Id: I46b029a3a945d7416028aa196ac3160e6d96eae8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136664 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> 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 Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docx differ diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index e42257fdf93b..33929cdddf1c 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1077,6 +1077,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;