sw/qa/extras/rtfexport/data/section-break-after-section.rtf |   10 +++++++
 sw/qa/extras/rtfexport/rtfexport8.cxx                       |   17 ++++++++++++
 sw/source/filter/ww8/rtfattributeoutput.cxx                 |    7 ++--
 sw/source/filter/ww8/rtfexport.cxx                          |   12 +++++++-
 4 files changed, 42 insertions(+), 4 deletions(-)

New commits:
commit 10059349e601b172e10dc9fd17bb392d4d7a0ad8
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jun 10 09:10:48 2025 +0200
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Thu Jun 12 14:15:35 2025 +0200

    tdf#166879 RTF export: handle section break right after a section
    
    The RTF file opens fine, but saving and opening in either Writer or Word
    loses the section break between the two paragraphs.
    
    What happens is that the first paragraph is in a Writer section, and the
    second paragraph has an SwFormatPageDesc associated with it. And
    RtfExport::OutputEndNode() only emits section breaks for end nodes if
    they are the end of a table.
    
    Fix the problem by also handling the end of Writer sections, similar to
    how it already works for the DOCX export since commit
    7060c7b642fdc0a369505e430652ee44205e7eed (tdf#95367 DOCX: allow r-t of
    changed first/follow sections, 2016-10-10).
    
    The original scenario was around saving a file for the 2nd time, the
    testcase includes a subset of Writer's own RTF export result, so just
    one import + export is needed.
    
    Conflicts:
            sw/qa/extras/rtfexport/rtfexport8.cxx
    
    Change-Id: I5cbb9d1ac740158f798fa43c4357c23d8037ba27
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186404
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/extras/rtfexport/data/section-break-after-section.rtf 
b/sw/qa/extras/rtfexport/data/section-break-after-section.rtf
new file mode 100644
index 000000000000..26e31d93079f
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/section-break-after-section.rtf
@@ -0,0 +1,10 @@
+{ tf1
+\paperw11906\paperh16838\margl1588\margr1588\margt1276\margb1276
+\sectd\sbknone
+\pard\plain\pagebb
+first page\par
+\pard\plain
+\sect
+\sectd \pgwsxn16840\pghsxn11907
+second page\par
+}
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index 5557837f83da..9c75ddc7ffff 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -416,6 +416,23 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf160976_headerFooter3)
     verify();
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testSectionBreakAfterSection)
+{
+    // Given a document that is modeled with a Writer section, followed by a 
paragraph with a new
+    // page style ("section break"):
+    createSwDoc("section-break-after-section.rtf");
+
+    // When saving that document to RTF:
+    saveAndReload(mpFilter);
+
+    // Then make sure the 2nd paragraph starts on a new page after export, too:
+    uno::Reference<text::XTextRange> xParagraph = getParagraph(2);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - the property is of unexpected type or void: PageDescName
+    // i.e. the 2nd paragraph was on the same page as the 1st one.
+    auto aPageDescName = getProperty<OUString>(xParagraph, "PageDescName");
+    CPPUNIT_ASSERT(!aPageDescName.isEmpty());
+}
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index b6508007b42e..13092cef6d90 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -365,11 +365,12 @@ void RtfAttributeOutput::SectionBreaks(const SwNode& 
rNode)
     }
     else if (rNode.IsEndNode())
     {
-        // End of something: make sure that it's the end of a table.
-        assert(rNode.StartOfSectionNode()->IsTableNode());
+        // End of something: make sure that it's the end of a table or section.
+        assert(rNode.StartOfSectionNode()->IsTableNode()
+               || rNode.StartOfSectionNode()->IsSectionNode());
         if (aNextIndex.GetNode().IsTextNode())
         {
-            // Handle section break between a table and a text node following 
it.
+            // Handle section break between the end node and a text node 
following it.
             const SwTextNode* pTextNode = aNextIndex.GetNode().GetTextNode();
             m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), 
*pTextNode);
         }
diff --git a/sw/source/filter/ww8/rtfexport.cxx 
b/sw/source/filter/ww8/rtfexport.cxx
index 15c004793970..49feeff8083f 100644
--- a/sw/source/filter/ww8/rtfexport.cxx
+++ b/sw/source/filter/ww8/rtfexport.cxx
@@ -1060,7 +1060,17 @@ bool RtfExport::DisallowInheritingOutlineNumbering(const 
SwFormat& rFormat)
 
 void RtfExport::OutputEndNode(const SwEndNode& rEndNode)
 {
-    if (TXT_MAINTEXT == m_nTextTyp && 
rEndNode.StartOfSectionNode()->IsTableNode())
+    if (TXT_MAINTEXT == m_nTextTyp && 
rEndNode.StartOfSectionNode()->IsSectionNode())
+    {
+        // Only consider the end of toplevel sections.
+        SwPosition aNodePosition(rEndNode);
+        SwSection* pSect = SwDoc::GetCurrSection(aNodePosition);
+        if (pSect && pSect->GetParent())
+            return;
+
+        AttrOutput().SectionBreaks(rEndNode);
+    }
+    else if (TXT_MAINTEXT == m_nTextTyp && 
rEndNode.StartOfSectionNode()->IsTableNode())
         // End node of a table: see if a section break should be written after 
the table.
         AttrOutput().SectionBreaks(rEndNode);
 }

Reply via email to