/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
void SwBodyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs * )
{ // Formatting of the body is too simple, thus, it gets its own format method. // Borders etc. are not taken into account here. // Width is taken from the PrtArea of the Upper. Height is the height of the // PrtArea of the Upper minus any neighbors (for robustness). // The PrtArea has always the size of the frame.
// Height of body frame:
nBorder = aRectFnSet.GetHeight(getFrameArea());
// Number of possible lines in area of body frame:
tools::Long nNumberOfLines = nBorder / nSum; if( nNumberOfLines > pGrid->GetLines() )
nNumberOfLines = pGrid->GetLines();
// Space required for nNumberOfLines lines:
nSize = nNumberOfLines * nSum;
nBorder -= nSize;
nBorder /= 2;
// #i21774# Footnotes and centering the grid does not work together: constbool bAdjust = static_cast<SwPageFrame*>(GetUpper())->GetFormat()->GetDoc().
GetFootnoteIdxs().empty();
// create and insert body area if it is not a blank page
SwDoc& rDoc(pFormat->GetDoc());
m_bEmptyPage = (pFormat == rDoc.GetEmptyPageFormat());
if(m_bEmptyPage)
{ return;
}
Calc(pRenderContext); // so that the PrtArea is correct
SwBodyFrame *pBodyFrame = new SwBodyFrame( rDoc.GetDfltFrameFormat(), this );
pBodyFrame->ChgSize( getFramePrintArea().SSize() );
pBodyFrame->Paste( this );
pBodyFrame->Calc(pRenderContext); // so that the columns can be inserted correctly
pBodyFrame->InvalidatePos();
if ( bBrowseMode )
InvalidateSize_();
// insert header/footer,, but only if active. if ( pFormat->GetHeader().IsActive() )
PrepareHeader(); if ( pFormat->GetFooter().IsActive() )
PrepareFooter();
const SwFormatCol &rCol = pFormat->GetCol(); if ( rCol.GetNumCols() > 1 )
{ const SwFormatCol aOld; //ChgColumns() needs an old value
pBodyFrame->ChgColumns( aOld, rCol );
}
}
void SwPageFrame::DestroyImpl()
{ // Cleanup the header-footer controls in all SwEditWins
SwViewShell* pSh = getRootFrame()->GetCurrShell(); if (pSh)
{ for (SwViewShell& rSh : pSh->GetRingContainer())
{
SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( &rSh ); if ( pWrtSh )
{
SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
rEditWin.GetFrameControlsManager( ).RemoveControls( this );
}
}
}
// empty FlyContainer, deletion of the Flys is done by the anchor (in base class SwFrame) if (m_pSortedObjs)
{ // Objects can be anchored at pages that are before their anchors (why ever...). // In such cases, we would access already freed memory. for (SwAnchoredObject* pAnchoredObj : *m_pSortedObjs)
{
pAnchoredObj->SetPageFrame( nullptr );
}
m_pSortedObjs.reset(); // reset to zero to prevent problems when detaching the Flys
}
// prevent access to destroyed pages if( GetFormat() && !GetFormat()->GetDoc().IsInDtor() )
{ if ( pSh )
{
SwViewShellImp *pImp = pSh->Imp();
pImp->SetFirstVisPageInvalid(); if ( pImp->IsAction() )
pImp->GetLayAction().SetAgain(true); // #i9719# - retouche area of page // including border and shadow area. constbool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT);
SwRect aRetoucheRect;
SwPageFrame::GetBorderAndShadowBoundRect( getFrameArea(), pSh, pSh->GetOut(), aRetoucheRect, IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar );
pSh->AddPaintRect( aRetoucheRect );
}
}
/// create specific Flys for this page and format generic content staticvoid lcl_FormatLay( SwLayoutFrame *pLay )
{
vcl::RenderContext* pRenderContext = pLay->getRootFrame()->GetCurrShell()->GetOut(); // format all LayoutFrames - no tables, Flys etc.
/// Create Flys or register draw objects staticvoid lcl_MakeObjs(const sw::FrameFormats<sw::SpzFrameFormat*>& rSpzs, SwPageFrame* pPage)
{ // formats are in the special table of the document const sal_uInt16 nPhyPageNum = pPage->GetPhyPageNum();
size_t i = 0; const size_t nSpzsCnt = rSpzs.size(); while (i < nSpzsCnt)
{ auto pSpz = rSpzs[i]; const SwFormatAnchor &rAnch = pSpz->GetAnchor(); if ( rAnch.GetPageNum() == nPhyPageNum )
{ if( rAnch.GetAnchorNode() )
{ if (RndStdIds::FLY_AT_PAGE == rAnch.GetAnchorId())
{
SwFormatAnchor aAnch( rAnch );
aAnch.SetAnchor( nullptr );
pSpz->SetFormatAttr( aAnch );
} else
{
++i; continue;
}
}
// is it a border or a SdrObject? bool bSdrObj = RES_DRAWFRMFMT == pSpz->Which();
SdrObject *pSdrObj = nullptr; if ( bSdrObj && nullptr == (pSdrObj = pSpz->FindSdrObject()) )
{
OSL_FAIL( "DrawObject not found." );
pSpz->GetDoc().DelFrameFormat( pSpz ); continue;
} // The object might be anchored to another page, e.g. when inserting // a new page due to a page descriptor change. In such cases, the // object needs to be moved. // In some cases the object is already anchored to the correct page. // This will be handled here and does not need to be coded extra.
SwPageFrame *pPg = pPage->IsEmptyPage() ? static_cast<SwPageFrame*>(pPage->GetNext()) : pPage; if ( bSdrObj )
{ // OD 23.06.2003 #108784# - consider 'virtual' drawing objects if (SwDrawContact *pContact = static_cast<SwDrawContact*>(::GetUserCall(pSdrObj)))
{ if ( auto pDrawVirtObj = dynamic_cast<SwDrawVirtObj *>( pSdrObj ) )
{
pDrawVirtObj->RemoveFromWriterLayout();
pDrawVirtObj->RemoveFromDrawingPage();
pPg->AppendDrawObj( *(pContact->GetAnchoredObj( pDrawVirtObj )) );
} else
{ if ( pContact->GetAnchorFrame() )
pContact->DisconnectFromLayout( false );
pPg->AppendDrawObj( *(pContact->GetAnchoredObj( pSdrObj )) );
}
}
} else
{
SwIterator<SwFlyFrame,SwFormat> aIter( *pSpz );
SwFlyFrame *pFly = aIter.First(); if ( pFly)
{ if( pFly->GetAnchorFrame() )
pFly->AnchorFrame()->RemoveFly( pFly );
} else
pFly = new SwFlyLayFrame( static_cast<SwFlyFrameFormat*>(pSpz), pPg, pPg );
pPg->AppendFly( pFly );
::RegistFlys( pPg, pFly );
}
}
++i;
}
}
// #i82258# // Due to made change on OOo 2.0 code line, method <::lcl_FormatLay(..)> has // the side effect, that the content of page header and footer are formatted. // For this formatting it is needed that the anchored objects are registered // at the <SwPageFrame> instance. // Thus, first calling <::RegistFlys(..)>, then call <::lcl_FormatLay(..)>
::RegistFlys( this, this );
if ( Lower() )
{
::lcl_FormatLay( this );
}
// Flys and draw objects that are still attached to the document. // Footnote pages do not have page-bound Flys! // There might be Flys or draw objects that want to be placed on // empty pages, however, the empty pages ignore that and the following // pages take care of them. if ( !bFootnote && !IsEmptyPage() )
{
SwDoc& rDoc = GetFormat()->GetDoc();
if ( GetPrev() && static_cast<SwPageFrame*>(GetPrev())->IsEmptyPage() )
lcl_MakeObjs( *rDoc.GetSpzFrameFormats(), static_cast<SwPageFrame*>(GetPrev()) );
lcl_MakeObjs( *rDoc.GetSpzFrameFormats(), this );
}
}
void SwPageFrame::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
{ if(rHint.GetId() == SfxHintId::SwPageFootnote)
{ // currently the savest way: static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
SetMaxFootnoteHeight(m_pDesc->GetFootnoteInfo().GetHeight()); if(!GetMaxFootnoteHeight())
SetMaxFootnoteHeight(LONG_MAX);
SetColMaxFootnoteHeight(); // here, the page might be destroyed: static_cast<SwRootFrame*>(GetUpper())->RemoveFootnotes(nullptr, false, true);
} elseif (rHint.GetId() == SfxHintId::SwAutoFormatUsedHint)
{ // a page frame exists, so use this one static_cast<const sw::AutoFormatUsedHint&>(rHint).SetUsed(); return;
} elseif (rHint.GetId() == SfxHintId::SwLegacyModify || rHint.GetId() == SfxHintId::SwFormatChange
|| rHint.GetId() == SfxHintId::SwAttrSetChange)
{ if(auto pSh = getRootFrame()->GetCurrShell())
pSh->SetFirstVisPageInvalid();
void SwPageFrame::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
SwPageFrameInvFlags &rInvFlags,
SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
{ bool bClear = true; const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; switch( nWhich )
{ case RES_FRM_SIZE:
{ const SwRect aOldPageFrameRect( getFrameArea() );
SwViewShell *pSh = getRootFrame()->GetCurrShell(); if( pSh && pSh->GetViewOptions()->getBrowseMode() )
{
setFrameAreaSizeValid(false); // OD 28.10.2002 #97265# - Don't call <SwPageFrame::MakeAll()> // Calculation of the page is not necessary, because its size is // invalidated here and further invalidation is done in the // calling method <SwPageFrame::Modify(..)> and probably by calling // <SwLayoutFrame::SwClientNotify(..)> at the end. // It can also causes inconsistences, because the lowers are // adjusted, but not calculated, and a <SwPageFrame::MakeAll()> of // a next page is called. This is performed on the switch to the // online layout. //MakeAll();
} elseif (pNew)
{ const SwFormatFrameSize &rSz = static_cast<const SwFormatFrameSize&>(*pNew);
void SwPageFrame::UpdateAttrForFormatChange( SwFormat* pOldFormat, SwFormat* pNewFormat,
SwPageFrameInvFlags &rInvFlags )
{ // state of m_bEmptyPage needs to be determined newly constbool bNewState(GetFormat() == GetFormat()->GetDoc().GetEmptyPageFormat());
if(m_bEmptyPage != bNewState)
{ // copy new state
m_bEmptyPage = bNewState;
if(nullptr == GetLower())
{ // if we were an empty page before there is not yet a BodyArea in the // form of a SwBodyFrame, see constructor
SwViewShell* pSh(getRootFrame()->GetCurrShell());
vcl::RenderContext* pRenderContext(pSh ? pSh->GetOut() : nullptr);
Calc(pRenderContext); // so that the PrtArea is correct
SwBodyFrame* pBodyFrame = new SwBodyFrame(GetFormat(), this);
pBodyFrame->ChgSize(getFramePrintArea().SSize());
pBodyFrame->Paste(this);
pBodyFrame->InvalidatePos();
}
}
// If the frame format is changed, several things might also change: // 1. columns:
assert(pOldFormat && pNewFormat); //FMT_CHG Missing Format const SwFormatCol &rOldCol = pOldFormat->GetCol(); const SwFormatCol &rNewCol = pNewFormat->GetCol(); if( rOldCol != rNewCol )
{
SwLayoutFrame *pB = FindBodyCont();
assert(pB && "Page without Body.");
pB->ChgColumns( rOldCol, rNewCol );
rInvFlags |= SwPageFrameInvFlags::CheckGrid;
}
const SwRect aOldPageFrameRect( getFrameArea() );
SwViewShell *pSh = getRootFrame()->GetCurrShell(); if( pSh && pSh->GetViewOptions()->getBrowseMode() )
{
setFrameAreaSizeValid(false); // OD 28.10.2002 #97265# - Don't call <SwPageFrame::MakeAll()> // Calculation of the page is not necessary, because its size is // invalidated here and further invalidation is done in the // calling method <SwPageFrame::Modify(..)> and probably by calling // <SwLayoutFrame::SwClientNotify(..)> at the end. // It can also causes inconsistences, because the lowers are // adjusted, but not calculated, and a <SwPageFrame::MakeAll()> of // a next page is called. This is performed on the switch to the // online layout. //MakeAll();
} elseif (pNewFormat)
{ const SwFormatFrameSize &rSz = pNewFormat->GetFrameSize();
/* determine the right PageDesc: * 0. from the document for footnote and endnote pages * 1. from the first BodyContent below a page * 2. from PageDesc of the predecessor page * 3. from PageDesc of the previous page if blank page * 3.1 from PageDesc of the next page if no predecessor exists * 4. default PageDesc * 5. In BrowseMode use the first paragraph or default PageDesc.
*/
SwPageDesc *SwPageFrame::FindPageDesc()
{ // 0. if ( IsFootnotePage() )
{
SwDoc& rDoc = GetFormat()->GetDoc(); if ( IsEndNotePage() ) return rDoc.GetEndNoteInfo().GetPageDesc( rDoc ); else return rDoc.GetFootnoteInfo().GetPageDesc( rDoc );
}
SwPageDesc *pRet = nullptr;
//5. const SwViewShell *pSh = getRootFrame()->GetCurrShell(); if( pSh && pSh->GetViewOptions()->getBrowseMode() )
{
SwContentFrame *pFrame = GetUpper()->ContainsContent(); while (pFrame && !pFrame->IsInDocBody())
pFrame = pFrame->GetNextContentFrame(); if (pFrame)
{
SwFrame *pFlow = pFrame; if ( pFlow->IsInTab() )
pFlow = pFlow->FindTabFrame();
pRet = const_cast<SwPageDesc*>(pFlow->GetPageDescItem().GetPageDesc());
} if ( !pRet )
pRet = &GetFormat()->GetDoc().GetPageDesc( 0 ); return pRet;
}
//1. if ( pFlow )
{
SwFlowFrame *pTmp = SwFlowFrame::CastFlowFrame( pFlow ); if ( !pTmp->IsFollow() )
pRet = const_cast<SwPageDesc*>(pFlow->GetPageDescItem().GetPageDesc());
}
//3. and 3.1 if ( !pRet && IsEmptyPage() ) // FME 2008-03-03 #i81544# lijian/fme: an empty page should have // the same page description as its prev, just like after construction // of the empty page.
pRet = GetPrev() ? static_cast<SwPageFrame*>(GetPrev())->GetPageDesc() :
GetNext() ? static_cast<SwPageFrame*>(GetNext())->GetPageDesc() : nullptr;
//2. if ( !pRet )
pRet = GetPrev() ? static_cast<SwPageFrame*>(GetPrev())->GetPageDesc()->GetFollow() : nullptr;
//4. if ( !pRet )
pRet = &GetFormat()->GetDoc().GetPageDesc( 0 );
void SwPageFrame::Cut()
{
SwViewShell *pSh = getRootFrame()->GetCurrShell(); if ( !IsEmptyPage() )
{ if ( GetNext() )
GetNext()->InvalidatePos();
// move Flys whose anchor is on a different page (draw objects are not relevant here) if ( GetSortedObjs() )
{
size_t i = 0; while ( GetSortedObjs() && i < GetSortedObjs()->size() )
{ // #i28701#
SwAnchoredObject* pAnchoredObj = (*GetSortedObjs())[i];
if ( auto pFly = dynamic_cast<SwFlyAtContentFrame *>( pAnchoredObj ) )
{
SwPageFrame *pAnchPage = pFly->GetAnchorFrame() ?
pFly->AnchorFrame()->FindPageFrame() : nullptr; if ( pAnchPage && (pAnchPage != this) )
{
MoveFly( pFly, pAnchPage );
pFly->InvalidateSize();
pFly->InvalidatePos_(); // Do not increment index, in this case continue;
}
}
++i;
}
} // cleanup Window if ( pSh && pSh->GetWin() )
pSh->InvalidateWindows( getFrameArea() );
}
// decrease the root's page number static_cast<SwRootFrame*>(GetUpper())->DecrPhyPageNums();
SwPageFrame *pPg = static_cast<SwPageFrame*>(GetNext()); if ( pPg )
{ while ( pPg )
{
--pPg->m_nPhyPageNum;
pPg = static_cast<SwPageFrame*>(pPg->GetNext());
}
} else
::SetLastPage( static_cast<SwPageFrame*>(GetPrev()) );
SwFrame* pRootFrame = GetUpper();
// cut all connections
RemoveFromLayout();
if ( pRootFrame ) static_cast<SwRootFrame*>(pRootFrame)->CheckViewLayout( nullptr, nullptr );
}
void SwPageFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
{
OSL_ENSURE( pParent->IsRootFrame(), "Parent is no Root." );
assert(pParent && "No parent for Paste().");
OSL_ENSURE( pParent != this, "I'm my own parent." );
OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(), "I am still registered somewhere." );
// insert into tree structure
InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
// increase the root's page number static_cast<SwRootFrame*>(GetUpper())->IncrPhyPageNums(); if( GetPrev() )
SetPhyPageNum( static_cast<SwPageFrame*>(GetPrev())->GetPhyPageNum() + 1 ); else
SetPhyPageNum( 1 );
SwPageFrame *pPg = static_cast<SwPageFrame*>(GetNext()); if ( pPg )
{ while ( pPg )
{
++pPg->m_nPhyPageNum;
pPg->InvalidatePos_();
pPg->InvalidateLayout();
pPg = static_cast<SwPageFrame*>(pPg->GetNext());
}
} else
::SetLastPage( this );
/// check if there's content on the page that requires it to exist bool IsPageFrameEmpty(SwPageFrame const& rPage)
{ bool bExistEssentialObjs = (nullptr != rPage.GetSortedObjs()); if (bExistEssentialObjs)
{ // Only because the page has Flys does not mean that it is needed. If all Flys are // attached to generic content it is also superfluous (checking DocBody should be enough) // OD 19.06.2003 - consider that drawing objects in // header/footer are supported now. bool bOnlySuperfluousObjs = true;
SwSortedObjs const& rObjs = *rPage.GetSortedObjs(); for (size_t i = 0; bOnlySuperfluousObjs && i < rObjs.size(); ++i)
{ // #i28701#
SwAnchoredObject* pAnchoredObj = rObjs[i]; // do not consider hidden objects if ( rPage.GetFormat()->GetDoc().getIDocumentDrawModelAccess().IsVisibleLayerId(
pAnchoredObj->GetDrawObj()->GetLayer() ) &&
!pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader() )
{
bOnlySuperfluousObjs = false;
}
}
bExistEssentialObjs = !bOnlySuperfluousObjs;
}
// optimization: check first if essential objects exist. if (bExistEssentialObjs) returnfalse; elseif (rPage.FindFootnoteCont()) returnfalse; else
{ if (const SwLayoutFrame* pBody = rPage.FindBodyCont())
{ const SwFrame* pLower = pBody->Lower(); if ( pBody->ContainsContent() || // check for section frames that are being formatted on the stack
rPage.ContainsDeleteForbiddenLayFrame() || // #i47580# // Do not delete page if there's an empty tabframe // left. I think it might be correct to use ContainsAny() // instead of ContainsContent() to cover the empty-table-case, // but I'm not fully sure, since ContainsAny() also returns // SectionFrames. Therefore I prefer to do it the safe way:
( pLower && pLower->IsTabFrame() ) ) returnfalse;
}
}
returntrue;
}
} // namespace sw
//FIXME: provide missing documentation /** Check all pages (starting from the given one) if they use the appropriate frame format. * * If "wrong" pages are found, try to fix this as simple as possible. * * Also delete pages that don't have content on them. * * @param pStart the page from where to start searching * @param bNotifyFields * @param ppPrev
*/ void SwFrame::CheckPageDescs( SwPageFrame *pStart, bool bNotifyFields, SwPageFrame** ppPrev )
{
SAL_INFO( "sw.pageframe", "(CheckPageDescs in phy: " << pStart->GetPhyPageNum() );
assert(pStart && "no starting page.");
if ( bIsOdd != bWantOdd ||
pDesc != pPage->GetPageDesc() || // wrong Desc
( pFormatWish != pPage->GetFormat() && // wrong format and
( !bIsEmpty || pFormatWish ) // not blank /empty
)
)
{ // Updating a page might take a while, so check the WaitCursor if( pImp )
pImp->CheckWaitCursor();
// invalidate the field, starting from here if ( nDocPos == LONG_MAX )
nDocPos = pPrevPage ? pPrevPage->getFrameArea().Top() : pPage->getFrameArea().Top();
// Cases: // 1. Empty page should be "normal" page -> remove empty page and take next one // 2. Empty page should have different descriptor -> change // 3. Normal page should be empty -> insert empty page if previous page // is not empty, otherwise see (6). // 4. Normal page should have different descriptor -> change // 5. Normal page should have different format -> change // 6. No "wish" format provided -> take the "other" format (left/right) of the PageDesc
if ( bIsEmpty && ( pFormatWish || //1.
( !bWantOdd && !pPrevPage ) ) )
{ // Check all cases for the next page, so we don't oscillate empty pages // Skip case 1 and 2, as we require a non-empty next page to save the empty page // Case 3 is the one we actually want to predict and skip // We can skip the empty check of case 3, as we just work on an existing next page bool bNextWantOdd;
SwPageDesc *pNextDesc; if ( pNextPage && !pNextPage->IsEmptyPage() && //3.
pNextPage->OnRightPage() == (bNextWantOdd = pNextPage->WannaRightPage()) &&
pNextPage->GetPageDesc() == (pNextDesc = pNextPage->FindPageDesc()) ) //4.
{ bool bNextFirst = pNextPage->OnFirstPage();
SwFrameFormat *pNextFormatWish = bNextWantOdd ? //5.
pNextDesc->GetRightFormat(bNextFirst) : pNextDesc->GetLeftFormat(bNextFirst); if ( !pNextFormatWish ) // 6.
pNextFormatWish = bNextWantOdd ? pNextDesc->GetLeftFormat() : pNextDesc->GetRightFormat(); if ( pNextFormatWish && pNextPage->GetFormat() == pNextFormatWish )
{
SAL_INFO( "sw.pageframe", "CheckPageDescs phys: " << pPage->GetPhyPageNum()
<< " c: 1+3 - skip next page of p: " << pPage ); if (pPrevPage && pPage->GetPageDesc() != pPrevPage->GetPageDesc())
pPage->SetPageDesc( pPrevPage->GetPageDesc(), nullptr ); // We can skip the next page, as all checks were already done!
pPage = static_cast<SwPageFrame*>(pNextPage->GetNext()); continue;
}
}
pPage->Cut(); bool bUpdatePrev = false; if (ppPrev && *ppPrev == pPage)
bUpdatePrev = true;
SAL_INFO( "sw.pageframe", "CheckPageDescs phys: " << pPage->GetPhyPageNum()
<< " c: 1 - destroy p: " << pPage );
SwFrame::DestroyFrame(pPage); if ( pStart == pPage )
pStart = pNextPage;
pPage = pNextPage; if (bUpdatePrev)
*ppPrev = pNextPage; continue;
} elseif ( bIsEmpty && !pFormatWish && //2.
pDesc != pPage->GetPageDesc() )
{
SAL_INFO( "sw.pageframe", "CheckPageDescs phys: " << pPage->GetPhyPageNum()
<< " c: 2 - set desc p: " << pPage << " d: " << pDesc );
pPage->SetPageDesc( pDesc, nullptr );
} elseif ( !bIsEmpty && //3.
bIsOdd != bWantOdd &&
( ( !pPrevPage && !bWantOdd ) ||
( pPrevPage && !pPrevPage->IsEmptyPage() )
)
)
{ if ( pPrevPage )
pDesc = pPrevPage->GetPageDesc();
SwPageFrame *pTmp = new SwPageFrame( rDoc.GetEmptyPageFormat(), pRoot, pDesc );
SAL_INFO( "sw.pageframe", "CheckPageDescs phys: " << pPage->GetPhyPageNum()
<< " c: 3 - insert empty p: " << pTmp << " d: " << pDesc );
pTmp->Paste( pRoot, pPage );
pTmp->PreparePage( false );
pPage = pTmp;
isPageFrameEmpty = false; // don't delete it right away!
} elseif ( pPage->GetPageDesc() != pDesc ) //4.
{
SwPageDesc *pOld = pPage->GetPageDesc();
pPage->SetPageDesc( pDesc, pFormatWish );
SAL_INFO( "sw.pageframe", "CheckPageDescs phys: " << pPage->GetPhyPageNum()
<< " c: 4 - set desc + format p: " << pPage
<< " d: " << pDesc << " f: " << pFormatWish ); if ( bFootnotes )
{ // If specific values of the FootnoteInfo are changed, something has to happen. // We try to limit the damage... // If the page has no FootnoteCont it might be problematic. // Let's hope that invalidation is enough.
SwFootnoteContFrame *pCont = pPage->FindFootnoteCont(); if ( pCont && !(pOld->GetFootnoteInfo() == pDesc->GetFootnoteInfo()) )
pCont->InvalidateAll_();
}
} elseif ( pFormatWish && pPage->GetFormat() != pFormatWish ) //5.
{
pPage->SetFrameFormat( pFormatWish );
SAL_INFO( "sw.pageframe", "CheckPageDescs phys: " << pPage->GetPhyPageNum()
<< " c: 5 - set format p: " << pPage << " f: " << pFormatWish );
} elseif ( !pFormatWish ) //6.
{ // get format with inverted logic
pFormatWish = bWantOdd ? pDesc->GetLeftFormat() : pDesc->GetRightFormat(); if ( pFormatWish && pPage->GetFormat() != pFormatWish )
{
pPage->SetFrameFormat( pFormatWish );
SAL_INFO( "sw.pageframe", "CheckPageDescs phys: " << pPage->GetPhyPageNum()
<< " c: 6 - set format p: " << pPage << " f: " << pFormatWish );
}
} #if OSL_DEBUG_LEVEL > 0 else
{
OSL_FAIL( "CheckPageDescs, missing solution" );
} #endif
}
assert(!bIsEmpty || !isPageFrameEmpty); constbool bWantRemovePage = bIsEmpty || isPageFrameEmpty; if (bWantRemovePage && !pPage->IsDeleteForbidden())
{ // It also might be that an empty page is not needed at all. // However, the algorithm above cannot determine that. It is not needed if the following // page can live without it. Do obtain that information, we need to dig deeper...
SwPageFrame *pPg = static_cast<SwPageFrame*>(pPage->GetNext()); if (isPageFrameEmpty || !pPg || pPage->OnRightPage() == pPg->WannaRightPage())
{ // The following page can find a FrameFormat or has no successor -> empty page not needed
SwPageFrame *pTmp = static_cast<SwPageFrame*>(pPage->GetNext()); if (isPageFrameEmpty && pPage->GetPrev())
{ // check previous *again* vs. its new next! see "ooo321_stylepagenumber.odt"
pTmp = static_cast<SwPageFrame*>(pPage->GetPrev());
}
pPage->Cut(); bool bUpdatePrev = false; if (ppPrev && *ppPrev == pPage)
bUpdatePrev = true;
SwFrame::DestroyFrame(pPage);
SAL_INFO( "sw.pageframe", "CheckPageDescs - handle bIsEmpty - destroy p: " << pPage ); if ( pStart == pPage )
pStart = pTmp;
pPage = pTmp; if (bUpdatePrev)
*ppPrev = pTmp; continue;
}
}
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
}
SwViewShell* pViewShell = pRoot->GetCurrShell(); if (pViewShell && pViewShell->GetViewOptions()->IsHideWhitespaceMode())
{ // Hide-whitespace mode does not shrink the last page, so resize the page that used to // be the last one. if (SwFrame* pPrevPage = pPage->GetPrev())
{
pPrevPage->InvalidateSize();
}
}
pPage->PreparePage( bFootnote ); // If the sibling has no body text, destroy it as long as it is no footnote page. if (!pSibling) returntrue; if (pSibling->IsFootnotePage()) returntrue; if (pSibling->FindFirstBodyContent()) returntrue;
// insert right (odd) or left (even) page? bool bNextRightPage = !pPrevPage->OnRightPage(); bool bWishedRightPage = bNextRightPage;
// Which PageDesc is relevant? // For ContentFrame take the one from format if provided, // otherwise from the Follow of the PrevPage if ( IsFlowFrame() && !SwFlowFrame::CastFlowFrame( this )->IsFollow() )
{
SwFormatPageDesc &rDesc = const_cast<SwFormatPageDesc&>(GetPageDescItem());
pDesc = rDesc.GetPageDesc(); if ( rDesc.GetNumOffset() )
{
::std::optional<sal_uInt16> oNumOffset = rDesc.GetNumOffset();
bWishedRightPage = sw::IsRightPageByNumber(*pRoot, *oNumOffset); // use the opportunity to set the flag at root
pRoot->SetVirtPageNum( true );
}
} if ( !pDesc )
pDesc = pPrevPage->GetPageDesc()->GetFollow();
// For the update of page numbering fields, nDocPos provides // the page position from where invalidation should start.
SwViewShell *pSh = getRootFrame()->GetCurrShell(); if ( !pSh || !pSh->Imp()->IsUpdateExpFields() )
{
rDoc.getIDocumentFieldsAccess().UpdatePageFields(pPrevPage->getFrameArea().Top());
} return pPage;
}
/// remove pages that are not needed at all void SwRootFrame::RemoveSuperfluous()
{ // A page is empty if the body text area has no ContentFrame, but not if there // is at least one Fly or one footnote attached to the page. Two runs are // needed: one for endnote pages and one for the pages of the body text.
if ( !IsSuperfluous() ) return;
mbCheckSuperfluous = false;
// Check the corresponding last page if it is empty and stop loop at the last non-empty page. do
{ if (!sw::IsPageFrameEmpty(*pPage))
{ if ( pPage->IsFootnotePage() )
{ while ( pPage->IsFootnotePage() )
{
pPage = static_cast<SwPageFrame*>(pPage->GetPrev());
assert(pPage && "only endnote pages remain.");
} continue;
} else
pPage = nullptr;
}
/// Ensures that enough pages exist, so that all page bound frames and draw objects can be placed void SwRootFrame::AssertFlyPages()
{ if ( !IsAssertFlyPages() ) return;
mbAssertFlyPages = false;
// what page targets the "last" Fly? // note the needed pages in a set
sal_uInt16 nMaxPg(0);
o3tl::sorted_vector< sal_uInt16 > neededPages;
neededPages.reserve(pSpzs->size());
// note as needed page
neededPages.insert(nPageNum);
}
}
// How many pages exist at the moment? // And are there EmptyPages that are needed?
SwPageFrame* pPage(static_cast<SwPageFrame*>(Lower()));
SwPageFrame* pPrevPage(nullptr);
SwPageFrame* pFirstRevivedEmptyPage(nullptr);
while(pPage) // moved two while-conditions to break-statements (see below)
{ const sal_uInt16 nPageNum(pPage->GetPhyPageNum());
if(pPage->IsEmptyPage() &&
nullptr != pPrevPage &&
neededPages.find(nPageNum) != neededPages.end())
{ // This is an empty page, but it *is* needed since a SwFrame // is anchored at it directly. Initially these SwFrames are // not fully initialized. Need to change the format of this SwFrame // and let the ::Notify mechanism newly evaluate // m_bEmptyPage (see SwPageFrame::UpdateAttr_). Code is taken and // adapted from ::InsertPage (used below), this needs previous page bool bWishedRightPage(!pPrevPage->OnRightPage());
SwPageDesc* pDesc(pPrevPage->GetPageDesc()->GetFollow());
assert(pDesc && "Missing PageDesc");
if ( nMaxPg > pPage->GetPhyPageNum() )
{ for ( sal_uInt16 i = pPage->GetPhyPageNum(); i < nMaxPg; ++i )
pPage = InsertPage( pPage, false );
// If the endnote pages are now corrupt, destroy them. if ( !rDoc.GetFootnoteIdxs().empty() )
{
pPage = static_cast<SwPageFrame*>(Lower()); while ( pPage && !pPage->IsFootnotePage() )
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
// if we corrected SwFrameFormat and changed one (or more) m_bEmptyPage // flags, we need to correct evtl. currently wrong positioned SwFrame(s) // which did think until now that these Page(s) are empty. // After trying to correct myself I found SwRootFrame::AssertPageFlys // directly below that already does that, so use it. if(nullptr != pFirstRevivedEmptyPage)
{
AssertPageFlys(pFirstRevivedEmptyPage);
}
//Remove masters that haven't been replaced yet from the list.
RemoveMasterObjs( mpDrawPage );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.