sw/qa/extras/layout/data/hidden-sections-with-pagestyles.odt |binary
 sw/qa/extras/layout/layout3.cxx                              |   87 +++++++++++
 sw/source/core/layout/laycache.cxx                           |   66 ++++----
 sw/source/core/layout/layhelp.hxx                            |    3 
 sw/source/core/layout/sectfrm.cxx                            |   60 +++++++
 5 files changed, 185 insertions(+), 31 deletions(-)

New commits:
commit a97e245ba11598050e1800fde9ace796d20e9df2
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Aug 29 13:27:03 2024 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Fri Aug 30 13:44:34 2024 +0200

    sw: layout: fix page breaks when unhiding a hidden section
    
    Commit ff7f1b59e22092d8548459e75fe912db852f056f removed the
    DelFrames()/MakeFrames() in SwSection::ImplSetHiddenFlag(), which was
    handling the page breaks previously.
    
    Add some code to SwSectionFrame::SwClientNotify() to call
    SwLayHelper::CheckInsertPage() which appears to be the important part
    called by InsertCnt_() previously.
    
    Change-Id: Id6560d8706abf92fba259a5d534d6cd5067c8e6a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172609
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/qa/extras/layout/data/hidden-sections-with-pagestyles.odt 
b/sw/qa/extras/layout/data/hidden-sections-with-pagestyles.odt
new file mode 100644
index 000000000000..5b33e7cc86a1
Binary files /dev/null and 
b/sw/qa/extras/layout/data/hidden-sections-with-pagestyles.odt differ
diff --git a/sw/qa/extras/layout/layout3.cxx b/sw/qa/extras/layout/layout3.cxx
index 9a8c1cca08ca..2ebac8b4ea17 100644
--- a/sw/qa/extras/layout/layout3.cxx
+++ b/sw/qa/extras/layout/layout3.cxx
@@ -1743,6 +1743,93 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf156724)
     assertXPath(pXmlDoc, "/root/page"_ostr, 2);
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testHiddenSectionPageDescs)
+{
+    createSwDoc("hidden-sections-with-pagestyles.odt");
+
+    {
+        xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+        assertXPath(pXmlDoc, "/root/page"_ostr, 2);
+        assertXPath(pXmlDoc, "/root/page[1]"_ostr, "formatName"_ostr, "Hotti");
+        assertXPath(pXmlDoc, "/root/page[1]/body/section"_ostr, 1);
+        assertXPath(pXmlDoc, "/root/page[1]/body/section[1]"_ostr, 
"formatName"_ostr,
+                    u"Verfügung"_ustr);
+        assertXPath(pXmlDoc, "/root/page[2]/body/section"_ostr, 2);
+        assertXPath(pXmlDoc, "/root/page[2]/body/section[1]"_ostr, 
"formatName"_ostr,
+                    u"Verfügung"_ustr);
+        // should be > 0, no idea why it's different on Windows
+#ifdef _WIN32
+        assertXPath(pXmlDoc, 
"/root/page[2]/body/section[1]/infos/bounds"_ostr, "height"_ostr,
+                    "552");
+#else
+        assertXPath(pXmlDoc, 
"/root/page[2]/body/section[1]/infos/bounds"_ostr, "height"_ostr,
+                    "532");
+#endif
+        assertXPath(pXmlDoc, "/root/page[2]/body/section[2]"_ostr, 
"formatName"_ostr,
+                    "Rueckantwort");
+        assertXPath(pXmlDoc, 
"/root/page[2]/body/section[2]/infos/bounds"_ostr, "height"_ostr, "0");
+        assertXPath(pXmlDoc, "/root/page[2]"_ostr, "formatName"_ostr, 
"Folgeseite");
+    }
+
+    // toggle one section hidden and other visible
+    executeMacro(
+        
u"vnd.sun.star.script:Standard.Module1.Main?language=Basic&location=document"_ustr);
+    Scheduler::ProcessEventsToIdle();
+
+    {
+        xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+        assertXPath(pXmlDoc, "/root/page"_ostr, 3);
+        assertXPath(pXmlDoc, "/root/page[1]"_ostr, "formatName"_ostr, "Hotti");
+        assertXPath(pXmlDoc, "/root/page[1]/body/section"_ostr, 2);
+        assertXPath(pXmlDoc, "/root/page[1]/body/section[1]"_ostr, 
"formatName"_ostr,
+                    u"Verfügung"_ustr);
+        assertXPath(pXmlDoc, "/root/page[1]/body/section[2]"_ostr, 
"formatName"_ostr,
+                    "Rueckantwort");
+        assertXPath(pXmlDoc, "/root/page[2]"_ostr, "formatName"_ostr, "Empty 
Page");
+        assertXPath(pXmlDoc, "/root/page[3]/body/section"_ostr, 1);
+        assertXPath(pXmlDoc, "/root/page[3]/body/section[1]"_ostr, 
"formatName"_ostr,
+                    "Rueckantwort");
+        // should be > 0, no idea why it's different on Windows
+#ifdef _WIN32
+        assertXPath(pXmlDoc, 
"/root/page[3]/body/section[1]/infos/bounds"_ostr, "height"_ostr,
+                    "552");
+#else
+        assertXPath(pXmlDoc, 
"/root/page[3]/body/section[1]/infos/bounds"_ostr, "height"_ostr,
+                    "532");
+#endif
+        assertXPath(pXmlDoc, "/root/page[3]"_ostr, "formatName"_ostr, 
"RueckantwortRechts");
+    }
+
+    // toggle one section hidden and other visible
+    executeMacro(
+        
u"vnd.sun.star.script:Standard.Module1.Main?language=Basic&location=document"_ustr);
+    Scheduler::ProcessEventsToIdle();
+
+    {
+        xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+        assertXPath(pXmlDoc, "/root/page"_ostr, 2);
+        assertXPath(pXmlDoc, "/root/page[1]"_ostr, "formatName"_ostr, "Hotti");
+        assertXPath(pXmlDoc, "/root/page[1]/body/section"_ostr, 1);
+        assertXPath(pXmlDoc, "/root/page[1]/body/section[1]"_ostr, 
"formatName"_ostr,
+                    u"Verfügung"_ustr);
+        assertXPath(pXmlDoc, "/root/page[2]/body/section"_ostr, 2);
+        assertXPath(pXmlDoc, "/root/page[2]/body/section[1]"_ostr, 
"formatName"_ostr,
+                    u"Verfügung"_ustr);
+        // should be > 0, no idea why it's different on Windows
+#ifdef _WIN32
+        assertXPath(pXmlDoc, 
"/root/page[2]/body/section[1]/infos/bounds"_ostr, "height"_ostr,
+                    "552");
+#else
+        assertXPath(pXmlDoc, 
"/root/page[2]/body/section[1]/infos/bounds"_ostr, "height"_ostr,
+                    "532");
+#endif
+        assertXPath(pXmlDoc, "/root/page[2]/body/section[2]"_ostr, 
"formatName"_ostr,
+                    "Rueckantwort");
+        assertXPath(pXmlDoc, 
"/root/page[2]/body/section[2]/infos/bounds"_ostr, "height"_ostr, "0");
+        assertXPath(pXmlDoc, "/root/page[2]"_ostr, "formatName"_ostr, 
"Folgeseite");
+    }
+}
+
 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf156725)
 {
     createSwDoc("tdf156725.fodt");
diff --git a/sw/source/core/layout/laycache.cxx 
b/sw/source/core/layout/laycache.cxx
index c2c03bb19f17..75ccf1ac4686 100644
--- a/sw/source/core/layout/laycache.cxx
+++ b/sw/source/core/layout/laycache.cxx
@@ -635,20 +635,25 @@ sal_uLong SwLayHelper::CalcPageCount()
  * The break after flag is set, if the actual content
  * wants a break after.
  */
-bool SwLayHelper::CheckInsertPage()
+bool SwLayHelper::CheckInsertPage(
+    SwPageFrame *& rpPage,
+    SwLayoutFrame *& rpLay,
+    SwFrame *& rpFrame,
+    bool & rIsBreakAfter,
+    bool const isForceBreak)
 {
-    bool bEnd = nullptr == mrpPage->GetNext();
-    const SvxFormatBreakItem& rBrk = mrpFrame->GetBreakItem();
-    const SwFormatPageDesc& rDesc = mrpFrame->GetPageDescItem();
+    bool bEnd = nullptr == rpPage->GetNext();
+    const SvxFormatBreakItem& rBrk = rpFrame->GetBreakItem();
+    const SwFormatPageDesc& rDesc = rpFrame->GetPageDescItem();
     // #118195# Do not evaluate page description if frame
     // is a follow frame!
-    const SwPageDesc* pDesc = mrpFrame->IsFlowFrame() &&
-                              SwFlowFrame::CastFlowFrame( mrpFrame 
)->IsFollow() ?
-                              nullptr :
-                              rDesc.GetPageDesc();
+    const SwPageDesc* pDesc = rpFrame->IsFlowFrame()
+                            && SwFlowFrame::CastFlowFrame(rpFrame)->IsFollow()
+                          ? nullptr
+                          : rDesc.GetPageDesc();
 
-    bool bBrk = mnParagraphCnt > mnMaxParaPerPage || mbBreakAfter;
-    mbBreakAfter = rBrk.GetBreak() == SvxBreak::PageAfter ||
+    bool bBrk = isForceBreak || rIsBreakAfter;
+    rIsBreakAfter = rBrk.GetBreak() == SvxBreak::PageAfter ||
                    rBrk.GetBreak() == SvxBreak::PageBoth;
     if ( !bBrk )
         bBrk = rBrk.GetBreak() == SvxBreak::PageBefore ||
@@ -659,47 +664,48 @@ bool SwLayHelper::CheckInsertPage()
         ::std::optional<sal_uInt16> oPgNum;
         if ( !pDesc )
         {
-            pDesc = mrpPage->GetPageDesc()->GetFollow();
+            pDesc = rpPage->GetPageDesc()->GetFollow();
         }
         else
         {
             oPgNum = rDesc.GetNumOffset();
             if ( oPgNum )
-                
static_cast<SwRootFrame*>(mrpPage->GetUpper())->SetVirtPageNum(true);
+                
static_cast<SwRootFrame*>(rpPage->GetUpper())->SetVirtPageNum(true);
         }
-        bool bNextPageRight = !mrpPage->OnRightPage();
+        bool bNextPageRight = !rpPage->OnRightPage();
         bool bInsertEmpty = false;
-        assert(mrpPage->GetUpper()->GetLower());
+        assert(rpPage->GetUpper()->GetLower());
         if (oPgNum && bNextPageRight != IsRightPageByNumber(
-                    *static_cast<SwRootFrame*>(mrpPage->GetUpper()), *oPgNum))
+                    *static_cast<SwRootFrame*>(rpPage->GetUpper()), *oPgNum))
         {
             bNextPageRight = !bNextPageRight;
             bInsertEmpty = true;
         }
         // If the page style is changing, we'll have a first page.
-        bool bNextPageFirst = pDesc != mrpPage->GetPageDesc();
-        ::InsertNewPage( const_cast<SwPageDesc&>(*pDesc), mrpPage->GetUpper(),
-             bNextPageRight, bNextPageFirst, bInsertEmpty, false, 
mrpPage->GetNext());
+        bool bNextPageFirst = pDesc != rpPage->GetPageDesc();
+        ::InsertNewPage( const_cast<SwPageDesc&>(*pDesc), rpPage->GetUpper(),
+             bNextPageRight, bNextPageFirst, bInsertEmpty, false, 
rpPage->GetNext());
         if ( bEnd )
         {
-            OSL_ENSURE( mrpPage->GetNext(), "No new page?" );
+            OSL_ENSURE( rpPage->GetNext(), "No new page?" );
             do
-            {   mrpPage = static_cast<SwPageFrame*>(mrpPage->GetNext());
-            } while ( mrpPage->GetNext() );
+            {
+                rpPage = static_cast<SwPageFrame*>(rpPage->GetNext());
+            } while (rpPage->GetNext());
         }
         else
         {
-            OSL_ENSURE( mrpPage->GetNext(), "No new page?" );
-            mrpPage = static_cast<SwPageFrame*>(mrpPage->GetNext());
-            if ( mrpPage->IsEmptyPage() )
+            OSL_ENSURE( rpPage->GetNext(), "No new page?" );
+            rpPage = static_cast<SwPageFrame*>(rpPage->GetNext());
+            if (rpPage->IsEmptyPage())
             {
-                OSL_ENSURE( mrpPage->GetNext(), "No new page?" );
-                mrpPage = static_cast<SwPageFrame*>(mrpPage->GetNext());
+                OSL_ENSURE( rpPage->GetNext(), "No new page?" );
+                rpPage = static_cast<SwPageFrame*>(rpPage->GetNext());
             }
         }
-        mrpLay = mrpPage->FindBodyCont();
-        while( mrpLay->Lower() )
-            mrpLay = static_cast<SwLayoutFrame*>(mrpLay->Lower());
+        rpLay = rpPage->FindBodyCont();
+        while (rpLay->Lower())
+            rpLay = static_cast<SwLayoutFrame*>(rpLay->Lower());
         return true;
     }
     return false;
@@ -885,7 +891,7 @@ bool SwLayHelper::CheckInsert( SwNodeOffset nNodeIndex )
             }
 
             SwPageFrame* pLastPage = mrpPage;
-            if( CheckInsertPage() )
+            if (CheckInsertPage(mrpPage, mrpLay, mrpFrame, mbBreakAfter, 
mnMaxParaPerPage < mnParagraphCnt))
             {
                 CheckFlyCache_( pLastPage );
                 if( mrpPrv && mrpPrv->IsTextFrame() && 
!mrpPrv->isFrameAreaSizeValid() )
diff --git a/sw/source/core/layout/layhelp.hxx 
b/sw/source/core/layout/layhelp.hxx
index 02ff3ca4f327..1ac325cfac82 100644
--- a/sw/source/core/layout/layhelp.hxx
+++ b/sw/source/core/layout/layhelp.hxx
@@ -129,7 +129,8 @@ public:
     sal_uLong CalcPageCount();
     bool CheckInsert( SwNodeOffset nNodeIndex );
 
-    bool CheckInsertPage();
+    static bool CheckInsertPage(SwPageFrame *& rpPage, SwLayoutFrame *& rpLay,
+        SwFrame *& rpFrame, bool & rIsBreakAfter, bool const isForceBreak);
 
     /// Look for fresh text frames at this (new) page and set them to the right
     /// position, if they are in the fly cache.
diff --git a/sw/source/core/layout/sectfrm.cxx 
b/sw/source/core/layout/sectfrm.cxx
index 0e96e542a04e..2bab18a2888e 100644
--- a/sw/source/core/layout/sectfrm.cxx
+++ b/sw/source/core/layout/sectfrm.cxx
@@ -39,6 +39,7 @@
 #include <colfrm.hxx>
 #include <tabfrm.hxx>
 #include <ftnfrm.hxx>
+#include "layhelp.hxx"
 #include <layouter.hxx>
 #include <dbg_lay.hxx>
 #include <viewopt.hxx>
@@ -2745,6 +2746,65 @@ void SwSectionFrame::SwClientNotify(const SwModify& 
rMod, const SfxHint& rHint)
             pLowerFrame->InvalidateAll();
             pLowerFrame->InvalidateObjs(false);
         }
+        // Check if any page-breaks have been unhidden, create the new pages.
+        // Call IsHiddenNow() because a parent section could still hide.
+        if (!IsFollow() && IsInDocBody() && !IsInTab() && !IsHiddenNow())
+        {
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+            SwViewShell *const pViewShell(getRootFrame()->GetCurrShell());
+            // no notification if SwViewShell is in construction
+            if (pViewShell && !pViewShell->IsInConstructor()
+                && pViewShell->GetLayout()
+                && pViewShell->GetLayout()->IsAnyShellAccessible())
+            {
+                auto pNext = FindNextCnt(true);
+                auto pPrev = FindPrevCnt();
+                pViewShell->InvalidateAccessibleParaFlowRelation(
+                    pNext ? pNext->DynCastTextFrame() : nullptr,
+                    pPrev ? pPrev->DynCastTextFrame() : nullptr );
+            }
+#endif
+            SwSectionFrame * pFollow{this};
+            SwPageFrame * pPage{FindPageFrame()};
+            SwLayoutFrame * pLay{nullptr};
+            bool isBreakAfter{false};
+            SwFrame * pFirstOnPage{pPage->FindFirstBodyContent()};
+            while (pFirstOnPage->GetUpper()->IsInTab())
+            {
+                pFirstOnPage = pFirstOnPage->GetUpper();
+            }
+            assert(pFirstOnPage->IsContentFrame() || 
pFirstOnPage->IsTabFrame());
+            for (SwFrame* pLowerFrame = Lower(); pLowerFrame; pLowerFrame = 
pLowerFrame->GetNext())
+            {
+                if (pLowerFrame == pFirstOnPage)
+                {
+                    continue;
+                }
+                assert(pLowerFrame->IsContentFrame() || 
pLowerFrame->IsTabFrame());
+                if (SwLayHelper::CheckInsertPage(pPage, pLay, pLowerFrame, 
isBreakAfter, false))
+                {
+                    if (pLowerFrame == Lower())
+                    {   // move the whole section
+                        assert(pFollow == this);
+                        MoveSubTree(pLay, nullptr);
+                    }
+                    else
+                    {
+                        if (GetNext())
+                        {
+                            assert(GetNext()->IsFlowFrame());
+                            
SwFlowFrame::CastFlowFrame(GetNext())->MoveSubTree(pLay, nullptr);
+                        }
+                        pFollow = new SwSectionFrame(*pFollow, false);
+                        SimpleFormat();
+                        pFollow->InsertBehind(pLay, nullptr);
+                        pFollow->Init();
+                        
SwFlowFrame::CastFlowFrame(pLowerFrame)->MoveSubTree(pFollow, nullptr);
+                    }
+                }
+            }
+            CheckPageDescs(FindPageFrame());
+        }
     }
     else
         SwFrame::SwClientNotify(rMod, rHint);

Reply via email to