sw/qa/extras/layout/data/hidden-sections-with-pagestyles.odt |binary sw/qa/extras/layout/layout3.cxx | 90 +++++++++++ sw/source/core/layout/laycache.cxx | 66 ++++---- sw/source/core/layout/layhelp.hxx | 3 sw/source/core/layout/sectfrm.cxx | 82 ++++++++++ 5 files changed, 210 insertions(+), 31 deletions(-)
New commits: commit 806b94a73949e714e9cedb4533616f27c15ef9f1 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Thu Aug 29 13:27:03 2024 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Tue Sep 3 18:22:41 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. Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172609 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit a97e245ba11598050e1800fde9ace796d20e9df2) sw: fix iterating columned sections in SwSectionFrame::SwClientNotify() This was asserting in JunitTest_sw_unoapi_3 on libreoffice-24-2 branch but strangely enough not on master. (regression from commit a97e245ba11598050e1800fde9ace796d20e9df2) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172740 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> (cherry picked from commit 5f0f69ba9b7d083cf7c0169be6e9c916008787bb) Change-Id: Id6560d8706abf92fba259a5d534d6cd5067c8e6a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172666 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> 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 7672dc40b28e..1f34ae2a2069 100644 --- a/sw/qa/extras/layout/layout3.cxx +++ b/sw/qa/extras/layout/layout3.cxx @@ -1652,6 +1652,96 @@ 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"); + discardDumpedLayout(); + } + + // 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"); + discardDumpedLayout(); + } + + // 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"); + discardDumpedLayout(); + } +} + 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 25cd970d9720..34a666e5b6af 100644 --- a/sw/source/core/layout/laycache.cxx +++ b/sw/source/core/layout/laycache.cxx @@ -633,20 +633,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 || @@ -657,47 +662,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; @@ -883,7 +889,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 8202fda6033d..9c0deb20abce 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> @@ -2735,6 +2736,87 @@ 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()); + SwColumnFrame * pColumn{Lower()->IsColumnFrame() + ? static_cast<SwColumnFrame*>(Lower()) : nullptr}; + auto IterateLower = [&pColumn](SwFrame *const pLowerFrame) -> SwFrame* + { + if (pLowerFrame->GetNext()) + { + return pLowerFrame->GetNext(); + } + if (pColumn) + { + pColumn = static_cast<SwColumnFrame*>(pColumn->GetNext()); + if (pColumn) + { + return static_cast<SwLayoutFrame*>(pColumn->Lower())->Lower(); + } + } + return nullptr; + }; + for (SwFrame* pLowerFrame = pColumn + ? static_cast<SwLayoutFrame*>(pColumn->Lower())->Lower() + : Lower(); + pLowerFrame; + pLowerFrame = IterateLower(pLowerFrame)) + { + 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);