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>
Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162191
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
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 868dbe8..1a3e49c 100644
--- a/sw/qa/extras/uiwriter/uiwriter9.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter9.cxx
@@ -103,7 +103,26 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159049)
    CPPUNIT_ASSERT_EQUAL(u"Abreak\nhere"_ustr, getParagraph(1)->getString());
}

} // end of anonymouse namespace
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();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/inc/dmapper/resourcemodel.hxx b/writerfilter/inc/dmapper/resourcemodel.hxx
index 695c6c9..9cd5af2 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 7e81cfd..46d5200 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 f9c163a..e19dcd4 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 1d0c2d7..52c8311 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -3654,8 +3654,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)