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.kaganski@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 0000000..cf2aaac
--- /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 4d7c87c..b7d638a 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\nhere"_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 b983dec..5b64de5 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 142d7f2..00f1d00 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 a5110a7..db29f10 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 62e346e..b8d15fb 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)