sw/qa/extras/uiwriter/data/tdf135083-simple-text-plus-list.fodt | 34 ++++++++++ sw/qa/extras/uiwriter/uiwriter9.cxx | 19 +++++ writerfilter/inc/dmapper/resourcemodel.hxx | 1 writerfilter/source/dmapper/DomainMapper.cxx | 5 - writerfilter/source/dmapper/DomainMapper.hxx | 2 writerfilter/source/rtftok/rtfdocumentimpl.cxx | 9 ++ 6 files changed, 67 insertions(+), 3 deletions(-)
New commits: commit 7e95e3868ff6a4d87b9051fa6219d8818c47c517 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Jan 16 13:15:01 2024 +0600 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Jan 17 03:40:33 2024 +0100 tdf#135083: make sure to apply pending paragraph properties, even without ... trailing \par. Commit a6ae84cc296d4d28e9a48a57406e955138c87a80 (tdf#70318: Prevent extra empty paragraph in clipboard RTF content, 2015-11-10) made sure to not emit trailing \par for RTF clipboard content. The problem was, that in the absense of the \par, the settings of the last paragraph were not applied (this happens in DomainMapper_Impl::finishParagraph). This change makes sure to call dispatchSymbol(RTFKeyword::PAR) (which eventually calls the mentioned method and applies pending para properties). Since this also adds a new paragraph (which needs to be avoided), a new flag is introduced, set by Stream::markLastParagraph. Its purpose is to make sure that all properties are applied to para, as opposed to bRemove argument to DomainMapper::finishParagraph, which prevents setting some properties (e.g., related to numbering - see DomainMapper::lcl_utext). Change-Id: Ia5e368e540c30f95058c81a280a62205aa85398b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162154 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/uiwriter/data/tdf135083-simple-text-plus-list.fodt b/sw/qa/extras/uiwriter/data/tdf135083-simple-text-plus-list.fodt new file mode 100644 index 000000000000..cf2aaac6fce9 --- /dev/null +++ b/sw/qa/extras/uiwriter/data/tdf135083-simple-text-plus-list.fodt @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:font-face-decls> + <style:font-face style:name="OpenSymbol" svg:font-family="OpenSymbol" style:font-charset="x-symbol"/> + </office:font-face-decls> + <office:styles> + <style:style style:name="Bullet_20_Symbols" style:display-name="Bullet Symbols" style:family="text"> + <style:text-properties style:font-name="OpenSymbol" fo:font-family="OpenSymbol" style:font-charset="x-symbol"/> + </style:style> + </office:styles> + <office:automatic-styles> + <text:list-style style:name="L1"> + <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" text:bullet-char="•"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="0.5in" fo:text-indent="-0.25in" fo:margin-left="0.5in"/> + </style:list-level-properties> + </text:list-level-style-bullet> + </text:list-style> + </office:automatic-styles> + <office:body> + <office:text> + <text:p>Lorem</text:p> + <text:list text:style-name="L1"> + <text:list-item> + <text:p>ipsum</text:p> + </text:list-item> + <text:list-item> + <text:p>dolor</text:p> + </text:list-item> + </text:list> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx b/sw/qa/extras/uiwriter/uiwriter9.cxx index 4d7c87c9ed0f..b7d638a25b73 100644 --- a/sw/qa/extras/uiwriter/uiwriter9.cxx +++ b/sw/qa/extras/uiwriter/uiwriter9.cxx @@ -216,6 +216,25 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159049) CPPUNIT_ASSERT_EQUAL(u"Abreak here"_ustr, getParagraph(1)->getString()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf135083) +{ + createSwDoc("tdf135083-simple-text-plus-list.fodt"); + + dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); + dispatchCommand(mxComponent, u".uno:Copy"_ustr, {}); + + // Paste special as RTF + uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence( + { { u"SelectedFormat"_ustr, + uno::Any(static_cast<sal_uInt32>(SotClipboardFormatId::RTF)) } })); + dispatchCommand(mxComponent, ".uno:ClipboardFormatItems", aArgs); + + auto xLastPara = getParagraph(3); + CPPUNIT_ASSERT_EQUAL(u"dolor"_ustr, xLastPara->getString()); + // Without the fix in place, the last paragraph would loose its settings. ListId would be empty. + CPPUNIT_ASSERT(!getProperty<OUString>(xLastPara, u"ListId"_ustr).isEmpty()); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/writerfilter/inc/dmapper/resourcemodel.hxx b/writerfilter/inc/dmapper/resourcemodel.hxx index b983dec88f78..5b64de51ba2c 100644 --- a/writerfilter/inc/dmapper/resourcemodel.hxx +++ b/writerfilter/inc/dmapper/resourcemodel.hxx @@ -220,6 +220,7 @@ public: virtual void endParagraphGroup() = 0; virtual void markLastParagraphInSection(){}; + virtual void markLastParagraph() {} // When finishing this paragraph, do not add new paragraph /** Receives start mark for group with the same character properties. diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 142d7f2f12eb..00f1d005a5e2 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -4417,8 +4417,6 @@ void DomainMapper::lcl_utext(const sal_Unicode *const data_, size_t len) xContext->Erase(PROP_NUMBERING_LEVEL); } finishParagraph(bRemove, bNoNumbering); - if (bRemove) - m_pImpl->RemoveLastParagraph(); m_pImpl->SetParaSectpr(false); } @@ -4947,6 +4945,9 @@ void DomainMapper::finishParagraph(const bool bRemove, const bool bNoNumbering) if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::datePicker) m_pImpl->m_pSdtHelper->createDateContentControl(); m_pImpl->finishParagraph(m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH), bRemove, bNoNumbering); + if (bRemove || mbIsLastPara) + m_pImpl->RemoveLastParagraph(); + mbIsLastPara = false; // handle other subdocuments } void DomainMapper::commentProps(const OUString& sId, const CommentProperties& rProps) diff --git a/writerfilter/source/dmapper/DomainMapper.hxx b/writerfilter/source/dmapper/DomainMapper.hxx index a5110a7cc921..db29f10d45eb 100644 --- a/writerfilter/source/dmapper/DomainMapper.hxx +++ b/writerfilter/source/dmapper/DomainMapper.hxx @@ -83,6 +83,7 @@ public: // Stream virtual void markLastParagraphInSection() override; + virtual void markLastParagraph() override { mbIsLastPara = true; } virtual void markLastSectionGroup() override; // BinaryObj @@ -188,6 +189,7 @@ private: bool mbIsSplitPara; bool mbHasControls; bool mbWasShapeInPara; + bool mbIsLastPara = false; std::unique_ptr< GraphicZOrderHelper > m_zOrderHelper; OUString m_sGlossaryEntryName; }; diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx index 62e346e2cfda..b8d15fb70474 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -3655,8 +3655,15 @@ RTFError RTFDocumentImpl::popState() // \par means an empty paragraph at the end of footnotes/endnotes, but // not in case of other substreams, like headers. if (m_bNeedCr && m_nStreamType != NS_ooxml::LN_footnote - && m_nStreamType != NS_ooxml::LN_endnote && m_bIsNewDoc) + && m_nStreamType != NS_ooxml::LN_endnote) + { + if (!m_bIsNewDoc) + { + // Make sure all the paragraph settings are set, but do not add next paragraph + Mapper().markLastParagraph(); + } dispatchSymbol(RTFKeyword::PAR); + } if (m_bNeedSect) // may be set by dispatchSymbol above! sectBreak(true); else if (!m_pSuperstream)