sw/inc/unoprnms.hxx                                                  |    2 
 sw/qa/core/layout/data/floattable-2cols.docx                         |binary
 sw/qa/core/layout/data/floattable-compat14-body.docx                 |binary
 sw/qa/core/layout/data/floattable-compat14-nosplit.docx              |binary
 sw/qa/core/layout/data/floattable-compat14.docx                      |binary
 sw/qa/core/layout/data/floattable-footer-2rows.docx                  |binary
 sw/qa/core/layout/data/floattable-footer.docx                        |binary
 sw/qa/core/layout/data/floattable-widow.docx                         |binary
 sw/qa/extras/layout/data/tdf116256.docx                              |binary
 sw/qa/extras/layout/data/tdf136613.docx                              |binary
 sw/qa/extras/layout/layout2.cxx                                      |   13 
 sw/qa/extras/ooxmlexport/data/lastEmptyLineWithDirectFormatting.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport19.cxx                           |   11 
 sw/qa/extras/rtfexport/rtfexport6.cxx                                |    4 
 sw/qa/extras/rtfimport/rtfimport.cxx                                 |    7 
 sw/source/core/doc/DocumentContentOperationsManager.cxx              |    7 
 sw/source/core/doc/docfmt.cxx                                        |    6 
 sw/source/core/unocore/unoobj.cxx                                    |    9 
 writerfilter/source/dmapper/DomainMapper_Impl.cxx                    |  169 
++++++----
 xmloff/source/text/txtparai.cxx                                      |   30 -
 20 files changed, 155 insertions(+), 103 deletions(-)

New commits:
commit 0e6ad9029b8e6b0e912610d2e446682a16ceb402
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Fri Jun 23 09:31:01 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Sat Jun 24 11:08:35 2023 +0200

    tdf#133560: re-anchor objects, to use paragraph's dispose for bEndOfDocument
    
    1. During import, XParagraphAppend::finishParagraph(Insert) are called,
       which are implemented using SwXText::Impl::finishOrAppendParagraph,
       and the latter calls
    
        m_pDoc->getIDocumentContentOperations().AppendTextNode( 
*aPam.GetPoint() );
        // remove attributes from the previous paragraph
        m_pDoc->ResetAttrs(aPam);
    
       so that there is always another (empty) paragraph after the finalized
       one;
    
    2. During import, lcl_AddRange is called to create anchored text content;
       the start and end of it may reference the very end of the document
       (using xTextAppend->getEnd()) - i.e., that last (maybe empty, maybe
       extra) paragraph.
    
    3. In many places, and in particular, in DomainMapper_Impl destructor,
       DomainMapper_Impl::RemoveLastParagraph is called; and the latter uses
       one of the two techniques to remove that last paragraph:
    
    3.1. It either obtains the paragraph's lang::XComponent interface, and
         calls its dispose (SwXParagraph::dispose), which eventually calls
         DocumentContentOperationsManager::DelFullPara;
    
    3.2. Or it uses cursor to select 1 ch back, and replace the resulting
         selection with nothing.
    
    3.1 has an advantage of keeping the formatting of the remaining (second-
    to-last) paragraph, but DocumentContentOperationsManager::DelFullPara,
    among other things, removes all anchored objects, thus this mode is not
    used for the end-of-document case (e.g., see commit message of commit
    e521930ea1c855c236efb67793e540d07c201d35 "fdo#58327: writerfilter:
    RemoveLastParagraph is tricky:", 2013-01-10);
    
    3.2 keeps the anchored objects, but needs workarounds to keep bookmarks,
    and destroys the remaining paragraph character formatting.
    
    Let me try to use #3.1 also in the end-of-document case, by introducing
    code to move anchored objects to previous paragraph before calling
    XComponent::dispose. Indeed, it may happen that more processing could be
    needed, if more properties would happen to be bound to the very last
    extra paragraph.
    
    This change adds a call to DocumentRedlineManager::CompressRedlines in
    DocumentContentOperationsManager::DelFullPara, because previously, this
    was called during #3.2 inside setString. testTdf150086 failed without
    this change.
    
    testTdf131386 and testTdf152872 were changed to the now-correct import of
    last paragraph properties (previously both of them relied on the hidden
    property not present there, while it is there in Word).
    
    In DomainMapper_Impl::RemoveLastParagraph, the check of the content of
    selection made by moving backward one character was generalized to be run
    before both cases, because RTF sometimes has only one paragraph after a
    table (see e.g. testTdf148515), which now could be removed in the absence
    of the check.
    
    testTdf104390 was changed to not check the number of runs, because now
    the paragraph keeps the trailing "paragraph mark formatting" empty run,
    which previously was dropped using setString path.
    
    Also, the fix for tdf#148273 is re-implemented here, by dropping
    RES_PARATR_LIST_AUTOFMT in lcl_RstAttr. Likely keeping it was an
    unintended side effect of placing RES_PARATR_LIST_AUTOFMT inside
    RES_PARATR_LIST_BEGIN/END. After the change, explicit drop of it will be
    not needed at arbitrary boundary, which is section break; this property
    should only be applied where it's defined. This change can't be done
    separately, because of interrelated unit test failures left and right.
    
    In XMLParaContext::endFastElement, setting ListAutoFormat property must
    be set only after setting style now, because otherwise it will be reset
    in lcl_RstAttr when the style is set.
    
    Some test documents were modified, to drop font from the last paragraph
    properties, because their respective tests started to crash (see commit
    172270a8f04388a8f8062f672f9c3f3144a01a1f "abort writer layout tests if a
    font isn't found", 2022-05-01). Before this change, these paragraphs had
    lost their formatting, so those fonts weren't used in layout.
    
    Change-Id: I7e41c20e68e24c78fae1d2005c3fd75fb146ba2c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153481
    Tested-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    (cherry picked from commit fc1b9ab2913bc8c2d8414b6d8de3ceed3910c5d8)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153520
    Tested-by: Jenkins

diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 58e21ddc3523..13fded52aeeb 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -542,8 +542,6 @@ inline constexpr OUStringLiteral 
UNO_NAME_SEPARATOR_LINE_VERTIVAL_ALIGNMENT
 inline constexpr OUStringLiteral UNO_NAME_SEPARATOR_LINE_IS_ON = 
u"SeparatorLineIsOn";
 inline constexpr OUStringLiteral UNO_NAME_IS_SKIP_HIDDEN_TEXT = 
u"IsSkipHiddenText";
 inline constexpr OUStringLiteral UNO_NAME_IS_SKIP_PROTECTED_TEXT = 
u"IsSkipProtectedText";
-inline constexpr OUStringLiteral UNO_NAME_RESET_PARAGRAPH_LIST_ATTRIBUTES
-    = u"ResetParagraphListAttributes";
 inline constexpr OUStringLiteral UNO_NAME_NO_FORMAT_ATTR = u"NoFormatAttr";
 inline constexpr OUStringLiteral UNO_NAME_DOCUMENT_INDEX_MARKS = 
u"DocumentIndexMarks";
 inline constexpr OUStringLiteral UNO_NAME_FOOTNOTE_IS_COLLECT_AT_TEXT_END
diff --git a/sw/qa/core/layout/data/floattable-2cols.docx 
b/sw/qa/core/layout/data/floattable-2cols.docx
index c43779f2aac9..b55bc8dd49b8 100644
Binary files a/sw/qa/core/layout/data/floattable-2cols.docx and 
b/sw/qa/core/layout/data/floattable-2cols.docx differ
diff --git a/sw/qa/core/layout/data/floattable-compat14-body.docx 
b/sw/qa/core/layout/data/floattable-compat14-body.docx
index 134128348ce2..fc25b867afc9 100644
Binary files a/sw/qa/core/layout/data/floattable-compat14-body.docx and 
b/sw/qa/core/layout/data/floattable-compat14-body.docx differ
diff --git a/sw/qa/core/layout/data/floattable-compat14-nosplit.docx 
b/sw/qa/core/layout/data/floattable-compat14-nosplit.docx
index 7d24d95aa92f..bd3f09c69e65 100644
Binary files a/sw/qa/core/layout/data/floattable-compat14-nosplit.docx and 
b/sw/qa/core/layout/data/floattable-compat14-nosplit.docx differ
diff --git a/sw/qa/core/layout/data/floattable-compat14.docx 
b/sw/qa/core/layout/data/floattable-compat14.docx
index 5afb0af477d8..19221609ddee 100644
Binary files a/sw/qa/core/layout/data/floattable-compat14.docx and 
b/sw/qa/core/layout/data/floattable-compat14.docx differ
diff --git a/sw/qa/core/layout/data/floattable-footer-2rows.docx 
b/sw/qa/core/layout/data/floattable-footer-2rows.docx
index 72013be28fbd..0d3db047c125 100644
Binary files a/sw/qa/core/layout/data/floattable-footer-2rows.docx and 
b/sw/qa/core/layout/data/floattable-footer-2rows.docx differ
diff --git a/sw/qa/core/layout/data/floattable-footer.docx 
b/sw/qa/core/layout/data/floattable-footer.docx
index 52cc73b17dfb..731e4fdb23a5 100644
Binary files a/sw/qa/core/layout/data/floattable-footer.docx and 
b/sw/qa/core/layout/data/floattable-footer.docx differ
diff --git a/sw/qa/core/layout/data/floattable-widow.docx 
b/sw/qa/core/layout/data/floattable-widow.docx
index 4a70c942c976..c3f17e6cd9ed 100644
Binary files a/sw/qa/core/layout/data/floattable-widow.docx and 
b/sw/qa/core/layout/data/floattable-widow.docx differ
diff --git a/sw/qa/extras/layout/data/tdf116256.docx 
b/sw/qa/extras/layout/data/tdf116256.docx
index f067e04f0614..6939bc99b9db 100644
Binary files a/sw/qa/extras/layout/data/tdf116256.docx and 
b/sw/qa/extras/layout/data/tdf116256.docx differ
diff --git a/sw/qa/extras/layout/data/tdf136613.docx 
b/sw/qa/extras/layout/data/tdf136613.docx
index a67e2f6c3b2c..cbfa8896765c 100644
Binary files a/sw/qa/extras/layout/data/tdf136613.docx and 
b/sw/qa/extras/layout/data/tdf136613.docx differ
diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx
index e9654dc7c9b6..9cbae8ae114a 100644
--- a/sw/qa/extras/layout/layout2.cxx
+++ b/sw/qa/extras/layout/layout2.cxx
@@ -714,8 +714,8 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872)
 
     assertXPath(pXmlDoc, "/root/page[1]/body/txt", 2);
     assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 
"portion", "C DE");
-    assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion", 0); // 5 is 
empty
-    assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height", 
"379");
+    assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion", 0); // 5 is 
empty and hidden
+    assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height", "0");
 
     dispatchCommand(mxComponent, ".uno:ControlCodes", {});
 
@@ -730,8 +730,11 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872)
     // and be a full-height frame now, but that needs more work...
     assertXPath(pXmlDoc, "/root/page/body/txt[3]/infos/bounds", "height", "0");
     assertXPath(pXmlDoc, "/root/page/body/txt[4]/SwParaPortion/SwLineLayout", 
"portion", "E");
+    // 5 is an empty paragraph with RES_CHRATR_HIDDEN which results in 0-height
+    // frame; ideally it should only be hidden when control codes are hidden
+    // and be a full-height frame now, but that needs more work...
     assertXPath(pXmlDoc, "/root/page/body/txt[5]/SwParaPortion", 0); // 5 is 
empty
-    assertXPath(pXmlDoc, "/root/page/body/txt[5]/infos/bounds", "height", 
"379");
+    assertXPath(pXmlDoc, "/root/page/body/txt[5]/infos/bounds", "height", "0");
 
     dispatchCommand(mxComponent, ".uno:ControlCodes", {});
 
@@ -740,8 +743,8 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872)
 
     assertXPath(pXmlDoc, "/root/page[1]/body/txt", 2);
     assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 
"portion", "C DE");
-    assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion", 0); // 5 is 
empty
-    assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height", 
"379");
+    assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion", 0); // 5 is 
empty and hidden
+    assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height", "0");
 }
 
 CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf151954)
diff --git 
a/sw/qa/extras/ooxmlexport/data/lastEmptyLineWithDirectFormatting.docx 
b/sw/qa/extras/ooxmlexport/data/lastEmptyLineWithDirectFormatting.docx
new file mode 100644
index 000000000000..5cfb4fcce170
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/lastEmptyLineWithDirectFormatting.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx
index ae45bc3376ac..a7c4b2c068d1 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport19.cxx
@@ -1017,6 +1017,17 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf155945)
     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(2), 
"ParaBottomMargin"));
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf133560)
+{
+    createSwDoc("lastEmptyLineWithDirectFormatting.docx");
+
+    CPPUNIT_ASSERT_EQUAL(4, getParagraphs());
+    // Without a fix in place, this would fail with
+    // - Expected: 12
+    // - Actual  : 48
+    CPPUNIT_ASSERT_EQUAL(12.0f, getProperty<float>(getParagraph(4), 
"CharHeight"));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/rtfexport/rtfexport6.cxx 
b/sw/qa/extras/rtfexport/rtfexport6.cxx
index 051ad343ec30..13afa440cd2d 100644
--- a/sw/qa/extras/rtfexport/rtfexport6.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport6.cxx
@@ -695,8 +695,8 @@ DECLARE_RTFEXPORT_TEST(testTdf104390, "tdf104390.rtf")
     CPPUNIT_ASSERT_EQUAL(36.f, getProperty<float>(xRun, "CharHeight"));
     CPPUNIT_ASSERT_EQUAL(OUString("Courier New"), getProperty<OUString>(xRun, 
"CharFontName"));
 
-    // Ensure there is only one run
-    CPPUNIT_ASSERT_MESSAGE("Extra elements in paragraph", 
!xRunEnum->hasMoreElements());
+    // Ensure this run covers whole paragraph text (ignore possible empty 
"paragraph marker" run)
+    CPPUNIT_ASSERT_EQUAL(xPara->getString().getLength(), 
xRun->getString().getLength());
 }
 
 DECLARE_RTFEXPORT_TEST(testTdf153681, "tdf153681.odt")
diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx 
b/sw/qa/extras/rtfimport/rtfimport.cxx
index 40e31e2695f4..4ae5e90043f4 100644
--- a/sw/qa/extras/rtfimport/rtfimport.cxx
+++ b/sw/qa/extras/rtfimport/rtfimport.cxx
@@ -1010,7 +1010,12 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf131386)
     createSwDoc("hidden-para-separator.rtf");
     SwDoc const* const pDoc = getSwDoc();
     SwNodeIndex ix(pDoc->GetNodes().GetEndOfContent(), -1);
-    
CPPUNIT_ASSERT(!ix.GetNode().GetTextNode()->GetAttr(RES_PARATR_LIST_AUTOFMT).GetStyleHandle());
+    CPPUNIT_ASSERT(ix.GetNode()
+                       .GetTextNode()
+                       ->GetAttr(RES_PARATR_LIST_AUTOFMT)
+                       .GetStyleHandle()
+                       ->Get(RES_CHRATR_HIDDEN)
+                       .GetValue());
     --ix;
     --ix;
     CPPUNIT_ASSERT(ix.GetNode()
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 373532db1eab..470a018eb0ef 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -2328,6 +2328,13 @@ bool DocumentContentOperationsManager::DelFullPara( 
SwPaM& rPam )
         rPam.DeleteMark();
         m_rDoc.GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
     }
+
+    if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
+        && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
+    {
+        m_rDoc.getIDocumentRedlineAccess().CompressRedlines();
+    }
+
     m_rDoc.getIDocumentState().SetModified();
 
     return true;
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 8ed9c4c9d249..5119bf15c04b 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -112,10 +112,10 @@ static bool lcl_RstAttr( SwNode* pNd, void* pArgs )
         SwDoc& rDoc = pNode->GetDoc();
 
         // remove unused attribute RES_LR_SPACE
-        // add list attributes
+        // add list attributes, except RES_PARATR_LIST_AUTOFMT
         SfxItemSetFixed<
                 RES_PARATR_NUMRULE, RES_PARATR_NUMRULE,
-                RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END - 1,
+                RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_AUTOFMT - 1,
                 RES_PAGEDESC, RES_BREAK,
                 RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME> 
aSavedAttrsSet(rDoc.GetAttrPool());
         const SfxItemSet* pAttrSetOfNode = pNode->GetpSwAttrSet();
@@ -123,7 +123,7 @@ static bool lcl_RstAttr( SwNode* pNd, void* pArgs )
         std::vector<sal_uInt16> aClearWhichIds;
         // restoring all paragraph list attributes
         {
-            SfxItemSetFixed<RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END - 1> 
aListAttrSet( rDoc.GetAttrPool() );
+            SfxItemSetFixed<RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_AUTOFMT - 
1> aListAttrSet( rDoc.GetAttrPool() );
             aListAttrSet.Set(*pAttrSetOfNode);
             if ( aListAttrSet.Count() )
             {
diff --git a/sw/source/core/unocore/unoobj.cxx 
b/sw/source/core/unocore/unoobj.cxx
index 55baec88c7ea..221929e4c04b 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -2255,15 +2255,6 @@ SwXTextCursor::setPropertyValue(
         }
         rUnoCursor.SetSkipOverProtectSections(bSet);
     }
-    else if (rPropertyName == UNO_NAME_RESET_PARAGRAPH_LIST_ATTRIBUTES)
-    {
-        SwTextNode* pTextNode= GetPaM()->GetPointNode().GetTextNode();
-
-        if(pTextNode)
-        {
-            pTextNode->ResetAttr(RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END);
-        }
-    }
     else if (rPropertyName == UNO_NAME_NO_FORMAT_ATTR)
     {
         bool bSet(false);
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index f75fbf529c96..4e410c0b0be9 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -95,6 +95,7 @@
 #include <rtl/uri.hxx>
 #include <unotools/ucbstreamhelper.hxx>
 #include <unotools/streamwrap.hxx>
+#include <comphelper/scopeguard.hxx>
 #include <comphelper/string.hxx>
 
 #include <dmapper/GraphicZOrderHelper.hxx>
@@ -698,28 +699,31 @@ void DomainMapper_Impl::AddDummyParaForTableInSection()
     }
 }
 
- static OUString lcl_FindLastBookmark(const uno::Reference<text::XTextCursor>& 
xCursor)
+ static OUString lcl_FindLastBookmark(const uno::Reference<text::XTextCursor>& 
xCursor,
+                                     bool bAlreadyExpanded)
  {
      OUString sName;
      if (!xCursor.is())
          return sName;
 
      // Select 1 previous element
-     xCursor->goLeft(1, true);
+     if (!bAlreadyExpanded)
+         xCursor->goLeft(1, true);
+     comphelper::ScopeGuard unselectGuard(
+         [xCursor, bAlreadyExpanded]()
+         {
+             if (!bAlreadyExpanded)
+                 xCursor->goRight(1, true);
+         });
+
      uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xCursor, 
uno::UNO_QUERY);
      if (!xParaEnumAccess.is())
-     {
-         xCursor->goRight(1, true);
          return sName;
-     }
 
      // Iterate through selection paragraphs
      uno::Reference<container::XEnumeration> xParaEnum = 
xParaEnumAccess->createEnumeration();
      if (!xParaEnum->hasMoreElements())
-     {
-         xCursor->goRight(1, true);
          return sName;
-     }
 
      // Iterate through first para portions
      uno::Reference<container::XEnumerationAccess> 
xRunEnumAccess(xParaEnum->nextElement(),
@@ -740,7 +744,6 @@ void DomainMapper_Impl::AddDummyParaForTableInSection()
          }
      }
 
-     xCursor->goRight(1, true);
      return sName;
  }
 
@@ -771,80 +774,114 @@ void DomainMapper_Impl::RemoveLastParagraph( )
             xCursor->gotoEnd(false);
         }
         else
-            xCursor = m_aTextAppendStack.top().xCursor;
-        uno::Reference<container::XEnumerationAccess> 
xEnumerationAccess(xCursor, uno::UNO_QUERY);
+            xCursor.set(m_aTextAppendStack.top().xCursor, uno::UNO_SET_THROW);
+
         // Keep the character properties of the last but one paragraph, even if
         // it's empty. This works for headers/footers, and maybe in other cases
         // as well, but surely not in textboxes.
         // fdo#58327: also do this at the end of the document: when pasting,
         // a table before the cursor position would be deleted
-        // (but only for paste/insert, not load; otherwise it can happen that
-        // flys anchored at the disposed paragraph are deleted (fdo47036.rtf))
         bool const bEndOfDocument(m_aTextAppendStack.size() == 1);
 
-        // Try to find and remember last bookmark in document: it potentially
-        // can be deleted by xCursor->setString() but not by 
xParagraph->dispose()
-        OUString sLastBookmarkName;
-        if (bEndOfDocument)
-            sLastBookmarkName = lcl_FindLastBookmark(xCursor);
-
-        if ((IsInHeaderFooter() || (bEndOfDocument && !m_bIsNewDoc))
-            && xEnumerationAccess.is())
-        {
-            uno::Reference<container::XEnumeration> xEnumeration = 
xEnumerationAccess->createEnumeration();
-            uno::Reference<lang::XComponent> 
xParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
-            xParagraph->dispose();
-        }
-        else if (xCursor.is())
+        uno::Reference<lang::XComponent> xParagraph;
+        if (IsInHeaderFooter() || bEndOfDocument)
         {
-            xCursor->goLeft( 1, true );
-            // If this is a text on a shape, possibly the text has the trailing
-            // newline removed already.
-            if (xCursor->getString() == SAL_NEWLINE_STRING ||
-                    // tdf#105444 comments need an exception, if 
SAL_NEWLINE_STRING defined as "\r\n"
-                    (sizeof(SAL_NEWLINE_STRING)-1 == 2 && xCursor->getString() 
== "\n"))
+            if (uno::Reference<container::XEnumerationAccess> xEA{ xCursor, 
uno::UNO_QUERY })
             {
-                uno::Reference<beans::XPropertySet> 
xDocProps(GetTextDocument(), uno::UNO_QUERY);
-                static const OUStringLiteral aRecordChanges(u"RecordChanges");
-                uno::Any 
aPreviousValue(xDocProps->getPropertyValue(aRecordChanges));
+                xParagraph.set(xEA->createEnumeration()->nextElement(), 
uno::UNO_QUERY);
+            }
+        }
+
+        xCursor->goLeft(1, true);
+        // If this is a text on a shape, possibly the text has the trailing
+        // newline removed already. RTF may also not have the trailing newline.
+        if (!(xCursor->getString() == SAL_NEWLINE_STRING ||
+              // tdf#105444 comments need an exception, if SAL_NEWLINE_STRING 
defined as "\r\n"
+              (sizeof(SAL_NEWLINE_STRING) - 1 == 2 && xCursor->getString() == 
"\n")))
+            return;
 
-                // disable redlining for this operation, otherwise we might
-                // end up with an unwanted recorded deletion
-                xDocProps->setPropertyValue(aRecordChanges, uno::Any(false));
+        uno::Reference<beans::XPropertySet> xDocProps(GetTextDocument(), 
uno::UNO_QUERY_THROW);
+        static constexpr OUStringLiteral RecordChanges(u"RecordChanges");
 
-                // delete
-                xCursor->setString(OUString());
+        comphelper::ScopeGuard redlineRestore(
+            [xDocProps, aPreviousValue = 
xDocProps->getPropertyValue(RecordChanges)]()
+            { xDocProps->setPropertyValue(RecordChanges, aPreviousValue); });
 
-                // While removing paragraphs that contain section properties, 
reset list
-                // related attributes to prevent them leaking into the 
following section's lists
-                if (GetParaSectpr())
-                {
-                    uno::Reference<beans::XPropertySet> XCursorProps(xCursor, 
uno::UNO_QUERY);
-                    
XCursorProps->setPropertyValue("ResetParagraphListAttributes", uno::Any());
-                }
+        // disable redlining, otherwise we might end up with an unwanted 
recorded operations
+        xDocProps->setPropertyValue(RecordChanges, uno::Any(false));
 
-                // call to xCursor->setString possibly did remove final 
bookmark
-                // from previous paragraph. We need to restore it, if there 
was any.
-                if (sLastBookmarkName.getLength())
+        if (xParagraph)
+        {
+            // move all anchored objects to the previous paragraph
+            uno::Reference<drawing::XDrawPageSupplier> 
xDrawPageSupplier(GetTextDocument(),
+                                                                         
uno::UNO_QUERY_THROW);
+            auto xDrawPage = xDrawPageSupplier->getDrawPage();
+            if (xDrawPage && xDrawPage->hasElements())
+            {
+                // Cursor already spans two paragraphs
+                uno::Reference<container::XEnumerationAccess> xEA(xCursor,
+                                                                  
uno::UNO_QUERY_THROW);
+                auto xEnumeration = xEA->createEnumeration();
+                uno::Reference<text::XTextRange> 
xPrevParagraph(xEnumeration->nextElement(),
+                                                                
uno::UNO_QUERY_THROW);
+
+                uno::Reference<text::XTextRange> xParaRange(xParagraph, 
uno::UNO_QUERY_THROW);
+                uno::Reference<text::XTextRangeCompare> 
xRegionCompare(xParaRange->getText(),
+                                                                       
uno::UNO_QUERY_THROW);
+                const sal_Int32 count = xDrawPage->getCount();
+                for (sal_Int32 i = 0; i < count; ++i)
                 {
-                    OUString sBookmarkNameAfterRemoval = 
lcl_FindLastBookmark(xCursor);
-                    if (sBookmarkNameAfterRemoval.isEmpty())
+                    try
                     {
-                        // Yes, it was removed. Restore
-                        uno::Reference<text::XTextContent> xBookmark(
-                            
m_xTextFactory->createInstance("com.sun.star.text.Bookmark"),
-                            uno::UNO_QUERY_THROW);
-
-                        uno::Reference<container::XNamed> xBkmNamed(xBookmark,
-                                                                    
uno::UNO_QUERY_THROW);
-                        xBkmNamed->setName(sLastBookmarkName);
-                        xTextAppend->insertTextContent(
-                            uno::Reference<text::XTextRange>(xCursor, 
uno::UNO_QUERY_THROW),
-                            xBookmark, !xCursor->isCollapsed());
+                        uno::Reference<text::XTextContent> 
xShape(xDrawPage->getByIndex(i),
+                                                                  
uno::UNO_QUERY_THROW);
+                        uno::Reference<text::XTextRange> 
xAnchor(xShape->getAnchor(),
+                                                                 
uno::UNO_SET_THROW);
+                        if (xRegionCompare->compareRegionStarts(xAnchor, 
xParaRange) <= 0
+                            && xRegionCompare->compareRegionEnds(xAnchor, 
xParaRange) >= 0)
+                        {
+                            xShape->attach(xPrevParagraph);
+                        }
                     }
+                    catch (const uno::Exception&)
+                    {
+                        // Can happen e.g. in compareRegion*, when the shape 
is in a header,
+                        // and paragraph in body
+                    }
+                }
+            }
+
+            xParagraph->dispose();
+        }
+        else
+        {
+            // Try to find and remember last bookmark in document: it 
potentially
+            // can be deleted by xCursor->setString() but not by 
xParagraph->dispose()
+            OUString sLastBookmarkName;
+            if (bEndOfDocument)
+                sLastBookmarkName = lcl_FindLastBookmark(xCursor, true);
+
+            // The cursor already selects across the paragraph break
+            // delete
+            xCursor->setString(OUString());
+
+            // call to xCursor->setString possibly did remove final bookmark
+            // from previous paragraph. We need to restore it, if there was 
any.
+            if (sLastBookmarkName.getLength())
+            {
+                OUString sBookmarkNameAfterRemoval = 
lcl_FindLastBookmark(xCursor, false);
+                if (sBookmarkNameAfterRemoval.isEmpty())
+                {
+                    // Yes, it was removed. Restore
+                    uno::Reference<text::XTextContent> xBookmark(
+                        
m_xTextFactory->createInstance("com.sun.star.text.Bookmark"),
+                        uno::UNO_QUERY_THROW);
+
+                    uno::Reference<container::XNamed> xBkmNamed(xBookmark,
+                                                                
uno::UNO_QUERY_THROW);
+                    xBkmNamed->setName(sLastBookmarkName);
+                    xTextAppend->insertTextContent(xCursor, xBookmark, 
!xCursor->isCollapsed());
                 }
-                // restore redline options again
-                xDocProps->setPropertyValue(aRecordChanges, aPreviousValue);
             }
         }
     }
diff --git a/xmloff/source/text/txtparai.cxx b/xmloff/source/text/txtparai.cxx
index bf905114a89c..5dc1b882b1b2 100644
--- a/xmloff/source/text/txtparai.cxx
+++ b/xmloff/source/text/txtparai.cxx
@@ -1725,21 +1725,6 @@ void XMLParaContext::endFastElement(sal_Int32 )
     // insert a paragraph break
     xTxtImport->InsertControlCharacter( ControlCharacter::APPEND_PARAGRAPH );
 
-    if (m_aMarkerStyleName.hasValue())
-    {
-        if (auto xPropSet = xStart.query<css::beans::XPropertySet>())
-        {
-            try
-            {
-                xPropSet->setPropertyValue("ListAutoFormat", 
m_aMarkerStyleName);
-            }
-            catch (const css::beans::UnknownPropertyException&)
-            {
-                // no problem
-            }
-        }
-    }
-
     // create a cursor that select the whole last paragraph
     Reference < XTextCursor > xAttrCursor;
     try {
@@ -1806,6 +1791,21 @@ void XMLParaContext::endFastElement(sal_Int32 )
                                                true,
                                                mbOutlineContentVisible);
 
+    if (m_aMarkerStyleName.hasValue())
+    {
+        if (auto xPropSet = xStart.query<css::beans::XPropertySet>())
+        {
+            try
+            {
+                xPropSet->setPropertyValue("ListAutoFormat", 
m_aMarkerStyleName);
+            }
+            catch (const css::beans::UnknownPropertyException&)
+            {
+                // no problem
+            }
+        }
+    }
+
     // handle list style header
     if (bHeading && (bIsListHeader || bIsRestart))
     {

Reply via email to