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;

Reply via email to