writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx                  |  
 24 +++
 writerfilter/qa/cppunittests/dmapper/data/floating-table-section-break.docx 
|binary
 writerfilter/source/dmapper/DomainMapper_Impl.cxx                           |  
 75 ++++++++++
 3 files changed, 99 insertions(+)

New commits:
commit 2a380dba73d57f825128fbada91c7a9fe79e8a06
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Wed May 31 08:19:24 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed May 31 09:04:22 2023 +0200

    tdf#150769 sw floattable: fix lost PageDescName if section starts with a 
table
    
    The bugdoc has 2 tables in it, separated by a section break (next page).
    This page break was missing in Writer, so the tables overlapped.
    
    The page break was lost because the 2nd section started with a table,
    where we insert a dummy initial paragraph (to side-step the problem that
    you can't have a selection starting in a table and finishing outside
    that table), and once it's disposed, its properties are lost.
    
    Fix the problem by copying the PageDescName property from the dummy
    paragraph to the next paragraph before dispose. Note that we need this
    combination of creating a range (using gotoNextParagraph()) and then
    enumerate over the range, because gotoNextParagraph() would skip a
    leading non-floating table, which would lead to an additional, not
    wanted page break, as pointed out by CppunitTest_sw_ooxmlexport15's
    testTdf134649_pageBreak.
    
    This went wrong in ce5f82dbaf1c22f45a08c60eb213bc9bc821c1d1 (DOCX
    import: floating table with negative top margin has to be a fly frame,
    2022-01-21), and it turns out to be related to normal floating tables,
    unrelated to multi-page floating tables.
    
    Change-Id: I83245c78c63ec8f3d6015ce3e72ab232220a9fdb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152411
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
index 359c051fb0df..858faf709fd4 100644
--- a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
@@ -19,6 +19,8 @@
 #include <com/sun/star/lang/XServiceInfo.hpp>
 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
 #include <com/sun/star/document/XDocumentInsertable.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <com/sun/star/text/XPageCursor.hpp>
 
 #include <vcl/scheduler.hxx>
 
@@ -324,6 +326,28 @@ CPPUNIT_TEST_FIXTURE(Test, 
testContentControlDataBindingColor)
     // i.e. the char color was red, not the default / automatic.
     CPPUNIT_ASSERT_EQUAL(COL_AUTO, nColor);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFloatingTableSectionBreak)
+{
+    // Given a document with 2 floating tables and 2 pages, section break 
(next page) between the
+    // two:
+    loadFromURL(u"floating-table-section-break.docx");
+
+    // When going to the last page:
+    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+    uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
+        xModel->getCurrentController(), uno::UNO_QUERY);
+    uno::Reference<text::XPageCursor> 
xCursor(xTextViewCursorSupplier->getViewCursor(),
+                                              uno::UNO_QUERY);
+    xCursor->jumpToLastPage();
+
+    // Then make sure that we're on page 2:
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2
+    // - Actual  : 1
+    // i.e. the document was of 1 page, the section break was lost.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(2), xCursor->getPage());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git 
a/writerfilter/qa/cppunittests/dmapper/data/floating-table-section-break.docx 
b/writerfilter/qa/cppunittests/dmapper/data/floating-table-section-break.docx
new file mode 100644
index 000000000000..e5c0cb19b342
Binary files /dev/null and 
b/writerfilter/qa/cppunittests/dmapper/data/floating-table-section-break.docx 
differ
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 1eb5753110c8..b4405517eab0 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -576,6 +576,79 @@ void DomainMapper_Impl::SetDocumentSettingsProperty( const 
OUString& rPropName,
         }
     }
 }
+
+namespace
+{
+void CopyPageDescNameToNextParagraph(const uno::Reference<lang::XComponent>& 
xParagraph,
+                                     const uno::Reference<text::XTextCursor>& 
xCursor)
+{
+    // First check if xParagraph has a non-empty page style name to copy from.
+    uno::Reference<beans::XPropertySet> xParagraphProps(xParagraph, 
uno::UNO_QUERY);
+    if (!xParagraphProps.is())
+    {
+        return;
+    }
+
+    uno::Any aPageDescName = xParagraphProps->getPropertyValue("PageDescName");
+    OUString sPageDescName;
+    aPageDescName >>= sPageDescName;
+    if (sPageDescName.isEmpty())
+    {
+        return;
+    }
+
+    // If so, search for the next paragraph.
+    uno::Reference<text::XParagraphCursor> xParaCursor(xCursor, 
uno::UNO_QUERY);
+    if (!xParaCursor.is())
+    {
+        return;
+    }
+
+    // Create a range till the next paragraph and then enumerate on the range.
+    if (!xParaCursor->gotoNextParagraph(/*bExpand=*/true))
+    {
+        return;
+    }
+
+    uno::Reference<container::XEnumerationAccess> 
xEnumerationAccess(xParaCursor, uno::UNO_QUERY);
+    if (!xEnumerationAccess.is())
+    {
+        return;
+    }
+
+    uno::Reference<container::XEnumeration> xEnumeration = 
xEnumerationAccess->createEnumeration();
+    if (!xEnumeration.is())
+    {
+        return;
+    }
+
+    xEnumeration->nextElement();
+    if (!xEnumeration->hasMoreElements())
+    {
+        return;
+    }
+
+    // We found a next item in the enumeration: it's usually a paragraph, but 
may be a table as
+    // well.
+    uno::Reference<beans::XPropertySet> 
xNextParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
+    if (!xNextParagraph.is())
+    {
+        return;
+    }
+
+    // See if there is page style set already: if so, don't touch it.
+    OUString sNextPageDescName;
+    xNextParagraph->getPropertyValue("PageDescName") >>= sNextPageDescName;
+    if (!sNextPageDescName.isEmpty())
+    {
+        return;
+    }
+
+    // Finally copy it over, so it's not lost.
+    xNextParagraph->setPropertyValue("PageDescName", aPageDescName);
+}
+}
+
 void DomainMapper_Impl::RemoveDummyParaForTableInSection()
 {
     SetIsDummyParaAddedForTableInSection(false);
@@ -603,6 +676,8 @@ void DomainMapper_Impl::RemoveDummyParaForTableInSection()
     {
         uno::Reference<container::XEnumeration> xEnumeration = 
xEnumerationAccess->createEnumeration();
         uno::Reference<lang::XComponent> 
xParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
+        // Make sure no page breaks are lost.
+        CopyPageDescNameToNextParagraph(xParagraph, xCursor);
         xParagraph->dispose();
     }
 }

Reply via email to