sw/qa/extras/layout/data/sdt+framePr.docx |binary sw/qa/extras/layout/layout2.cxx | 34 +++++++++++++++++++++++++++ writerfilter/source/dmapper/DomainMapper.cxx | 18 +++++++++++--- writerfilter/source/dmapper/SdtHelper.hxx | 1 4 files changed, 49 insertions(+), 4 deletions(-)
New commits: commit 122b086e4f388df817ba46763e97fe4c7210b229 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Mon Jan 22 19:10:29 2024 +0600 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Thu Jan 25 08:40:45 2024 +0100 tdf#159259: make sure to set FieldStartRange in sdt helper ... also for field case. Unfortunately, it is not really clear, if the anagement of this could be moved to DomainMapper_Impl. There are several insertion contexts; they may use different insertion points; there maybe could be cases when an inserted content should not go into the current sdt (?). Thus, I didn't put the code into DomainMapper_Impl::appendTextContent(), where the field character is inserted. Instead, I added code to check and set the start range in the same place as for the normal text: we know for sure, that if it were a normal text, we would append it to GetCurrentTextRange()->getEnd() - so do the same for fields. My concern that still stays is that the use of hasUnusedText looks hackish and fragile. Inserted fields don't set it - so the code that depends on empty sdt will not notice it. OTOH, it can't set it: this would break inserting field result for an already inserted command. Possibly all handling of sdt should be refactored at some point. Change-Id: I7a783aab2400d9a9c1f9f2e5607c872cb58d346b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162398 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162427 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162506 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/layout/data/sdt+framePr.docx b/sw/qa/extras/layout/data/sdt+framePr.docx new file mode 100644 index 000000000000..d46bcbfaa774 Binary files /dev/null and b/sw/qa/extras/layout/data/sdt+framePr.docx differ diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx index 27072238dc5c..adb9e7a4276f 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -2918,6 +2918,40 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf156725) "/root/page[2]/body/txt/anchored/fly/column[2]/body/section/column[2]/body/txt", 1); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf159259) +{ + // Given a document with a block sdt with a single field, having framePr aligned to right + createSwDoc("sdt+framePr.docx"); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // Make sure there is only one page and one paragraph with one line and one anchored object + assertXPath(pXmlDoc, "/root/page", 1); + // Without the fix, this would fail: there were two paragraphs + assertXPath(pXmlDoc, "/root/page/body/txt", 1); + assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion", 1); + assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout", 1); + // Without the fix, this would fail: there was a field portion in the line + assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout/SwFieldPortion", 0); + // Without the fix, this would fail: there was no anchored objects + assertXPath(pXmlDoc, "/root/page/body/txt/anchored", 1); + assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly", 1); + + const sal_Int32 paraRight + = getXPath(pXmlDoc, "/root/page/body/txt/infos/bounds", "right").toInt32(); + const sal_Int32 paraHeight + = getXPath(pXmlDoc, "/root/page/body/txt/infos/bounds", "height").toInt32(); + + CPPUNIT_ASSERT_GREATER(sal_Int32(0), paraRight); + CPPUNIT_ASSERT_GREATER(sal_Int32(0), paraHeight); + + const sal_Int32 flyRight + = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "right").toInt32(); + const sal_Int32 flyHeight + = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "height").toInt32(); + + CPPUNIT_ASSERT_EQUAL(paraRight, flyRight); // The fly is right-aligned + CPPUNIT_ASSERT_EQUAL(paraHeight, flyHeight); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 6813736dc4c5..c2d7eb73ba64 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -4362,14 +4362,24 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len) } else if (m_pImpl->IsOpenFieldCommand() && !m_pImpl->IsForceGenericFields()) { - if (bInSdtBlockText && m_pImpl->m_pSdtHelper->hasUnusedText()) - m_pImpl->m_pSdtHelper->createPlainTextControl(); + if (bInSdtBlockText) + { + if (m_pImpl->m_pSdtHelper->hasUnusedText()) + m_pImpl->m_pSdtHelper->createPlainTextControl(); + else if (!m_pImpl->m_pSdtHelper->isFieldStartRangeSet()) + m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd()); + } m_pImpl->AppendFieldCommand(sText); } else if( m_pImpl->IsOpenField() && m_pImpl->IsFieldResultAsString()) { - if (bInSdtBlockText && m_pImpl->m_pSdtHelper->hasUnusedText()) - m_pImpl->m_pSdtHelper->createPlainTextControl(); + if (bInSdtBlockText) + { + if (m_pImpl->m_pSdtHelper->hasUnusedText()) + m_pImpl->m_pSdtHelper->createPlainTextControl(); + else if (!m_pImpl->m_pSdtHelper->isFieldStartRangeSet()) + m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd()); + } /*depending on the success of the field insert operation this result will be set at the field or directly inserted into the text*/ m_pImpl->AppendFieldResult(sText); diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx index 5db799bd1fd2..85b95a48818b 100644 --- a/writerfilter/source/dmapper/SdtHelper.hxx +++ b/writerfilter/source/dmapper/SdtHelper.hxx @@ -171,6 +171,7 @@ public: void setDataBindingStoreItemID(const OUString& sValue) { m_sDataBindingStoreItemID = sValue; } const OUString& GetDataBindingStoreItemID() const { return m_sDataBindingStoreItemID; } + bool isFieldStartRangeSet() const { return m_xFieldStartRange.is(); } void setFieldStartRange(const css::uno::Reference<css::text::XTextRange>& xStartRange) { m_xFieldStartRange = xStartRange;