2747 lines
102 KiB
C++
2747 lines
102 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <config_wasm_strip.h>
|
|
|
|
#include <comphelper/lok.hxx>
|
|
#include <ndole.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <svl/itemiter.hxx>
|
|
#include <fmtfsize.hxx>
|
|
#include <fmthdft.hxx>
|
|
#include <fmtclds.hxx>
|
|
#include <fmtpdsc.hxx>
|
|
#include <fmtornt.hxx>
|
|
#include <fmtsrnd.hxx>
|
|
#include <ftninfo.hxx>
|
|
#include <frmtool.hxx>
|
|
#include <tgrditem.hxx>
|
|
#include <viewopt.hxx>
|
|
#include <docsh.hxx>
|
|
#include <wrtsh.hxx>
|
|
#include <view.hxx>
|
|
#include <edtwin.hxx>
|
|
#include <frameformats.hxx>
|
|
|
|
#include <viewimp.hxx>
|
|
#include <pagefrm.hxx>
|
|
#include <rootfrm.hxx>
|
|
#include <IDocumentDrawModelAccess.hxx>
|
|
#include <IDocumentSettingAccess.hxx>
|
|
#include <IDocumentFieldsAccess.hxx>
|
|
#include <dcontact.hxx>
|
|
#include <hints.hxx>
|
|
#include <FrameControlsManager.hxx>
|
|
|
|
#include <ftnidx.hxx>
|
|
#include <bodyfrm.hxx>
|
|
#include <ftnfrm.hxx>
|
|
#include <tabfrm.hxx>
|
|
#include <txtfrm.hxx>
|
|
#include <notxtfrm.hxx>
|
|
#include <sectfrm.hxx>
|
|
#include <layact.hxx>
|
|
#include <flyfrms.hxx>
|
|
#include <htmltbl.hxx>
|
|
#include <pagedesc.hxx>
|
|
#include <editeng/frmdiritem.hxx>
|
|
#include <sortedobjs.hxx>
|
|
#include <calbck.hxx>
|
|
#include <txtfly.hxx>
|
|
#include <frmatr.hxx>
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
SwBodyFrame::SwBodyFrame( SwFrameFormat *pFormat, SwFrame* pSib ):
|
|
SwLayoutFrame( pFormat, pSib )
|
|
{
|
|
mnFrameType = SwFrameType::Body;
|
|
}
|
|
|
|
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.
|
|
|
|
if ( !isFrameAreaSizeValid() )
|
|
{
|
|
SwTwips nHeight = GetUpper()->getFramePrintArea().Height();
|
|
SwTwips nWidth = GetUpper()->getFramePrintArea().Width();
|
|
const SwFrame *pFrame = GetUpper()->Lower();
|
|
do
|
|
{
|
|
if ( pFrame != this )
|
|
{
|
|
if( pFrame->IsVertical() )
|
|
nWidth -= pFrame->getFrameArea().Width();
|
|
else
|
|
nHeight -= pFrame->getFrameArea().Height();
|
|
}
|
|
pFrame = pFrame->GetNext();
|
|
} while ( pFrame );
|
|
|
|
if ( nHeight < 0 )
|
|
{
|
|
nHeight = 0;
|
|
}
|
|
|
|
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
|
|
aFrm.Height( nHeight );
|
|
|
|
if( IsVertical() && !IsVertLR() && nWidth != aFrm.Width() )
|
|
{
|
|
aFrm.Pos().setX(aFrm.Pos().getX() + aFrm.Width() - nWidth);
|
|
}
|
|
|
|
aFrm.Width( nWidth );
|
|
}
|
|
|
|
bool bNoGrid = true;
|
|
if( GetUpper()->IsPageFrame() && static_cast<SwPageFrame*>(GetUpper())->HasGrid() )
|
|
{
|
|
SwTextGridItem const*const pGrid(
|
|
GetGridItem(static_cast<SwPageFrame*>(GetUpper())));
|
|
if( pGrid )
|
|
{
|
|
bNoGrid = false;
|
|
tools::Long nSum = pGrid->GetBaseHeight() + pGrid->GetRubyHeight();
|
|
SwRectFnSet aRectFnSet(this);
|
|
tools::Long nSize = aRectFnSet.GetWidth(getFrameArea());
|
|
tools::Long nBorder = 0;
|
|
if( GRID_LINES_CHARS == pGrid->GetGridType() )
|
|
{
|
|
//for textgrid refactor
|
|
SwDoc *pDoc = GetFormat()->GetDoc();
|
|
nBorder = nSize % (GetGridWidth(*pGrid, *pDoc));
|
|
nSize -= nBorder;
|
|
nBorder /= 2;
|
|
}
|
|
|
|
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
|
|
aRectFnSet.SetPosX( aPrt, nBorder );
|
|
aRectFnSet.SetWidth( aPrt, nSize );
|
|
|
|
// 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:
|
|
const bool bAdjust = static_cast<SwPageFrame*>(GetUpper())->GetFormat()->GetDoc()->
|
|
GetFootnoteIdxs().empty();
|
|
|
|
aRectFnSet.SetPosY( aPrt, bAdjust ? nBorder : 0 );
|
|
aRectFnSet.SetHeight( aPrt, nSize );
|
|
}
|
|
}
|
|
|
|
if( bNoGrid )
|
|
{
|
|
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
|
|
aPrt.Pos().setX(0);
|
|
aPrt.Pos().setY(0);
|
|
aPrt.Height( getFrameArea().Height() );
|
|
aPrt.Width( getFrameArea().Width() );
|
|
}
|
|
|
|
setFrameAreaSizeValid(true);
|
|
setFramePrintAreaValid(true);
|
|
}
|
|
|
|
void SwBodyFrame::dumpAsXml(xmlTextWriterPtr writer) const
|
|
{
|
|
(void)xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("body"));
|
|
dumpAsXmlAttributes(writer);
|
|
|
|
SwLayoutFrame::dumpAsXml(writer);
|
|
|
|
(void)xmlTextWriterEndElement(writer);
|
|
}
|
|
|
|
SwPageFrame::SwPageFrame( SwFrameFormat *pFormat, SwFrame* pSib, SwPageDesc *pPgDsc ) :
|
|
SwFootnoteBossFrame( pFormat, pSib ),
|
|
m_pDesc( pPgDsc ),
|
|
m_nPhyPageNum( 0 )
|
|
{
|
|
SetDerivedVert( false );
|
|
SetDerivedR2L( false );
|
|
if( m_pDesc )
|
|
{
|
|
m_bHasGrid = true;
|
|
SwTextGridItem const*const pGrid(GetGridItem(this));
|
|
if( !pGrid )
|
|
m_bHasGrid = false;
|
|
}
|
|
else
|
|
m_bHasGrid = false;
|
|
SetMaxFootnoteHeight( pPgDsc->GetFootnoteInfo().GetHeight() ?
|
|
pPgDsc->GetFootnoteInfo().GetHeight() : LONG_MAX );
|
|
mnFrameType = SwFrameType::Page;
|
|
m_bInvalidLayout = m_bInvalidContent = m_bInvalidSpelling = m_bInvalidSmartTags = m_bInvalidAutoCmplWrds = m_bInvalidWordCount = true;
|
|
m_bInvalidFlyLayout = m_bInvalidFlyContent = m_bInvalidFlyInCnt = m_bFootnotePage = m_bEndNotePage = false;
|
|
|
|
SwViewShell *pSh = getRootFrame()->GetCurrShell();
|
|
const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
|
|
vcl::RenderContext* pRenderContext = pSh ? pSh->GetOut() : nullptr;
|
|
|
|
{
|
|
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
|
|
|
|
if ( bBrowseMode )
|
|
{
|
|
aFrm.Height( 0 );
|
|
tools::Long nWidth = pSh->VisArea().Width();
|
|
|
|
if ( !nWidth )
|
|
{
|
|
nWidth = 5000; // changes anyway
|
|
}
|
|
|
|
aFrm.Width ( nWidth );
|
|
}
|
|
else
|
|
{
|
|
aFrm.SSize( pFormat->GetFrameSize().GetSize() );
|
|
}
|
|
}
|
|
|
|
// create and insert body area if it is not a blank page
|
|
SwDoc* pDoc(pFormat->GetDoc());
|
|
m_bEmptyPage = (pFormat == pDoc->GetEmptyPageFormat());
|
|
|
|
if(m_bEmptyPage)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Calc(pRenderContext); // so that the PrtArea is correct
|
|
SwBodyFrame *pBodyFrame = new SwBodyFrame( pDoc->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
|
|
SwDoc *pDoc = GetFormat() ? GetFormat()->GetDoc() : nullptr;
|
|
if( pDoc && !pDoc->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.
|
|
const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT);
|
|
SwRect aRetoucheRect;
|
|
SwPageFrame::GetBorderAndShadowBoundRect( getFrameArea(), pSh, pSh->GetOut(), aRetoucheRect, IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar );
|
|
pSh->AddPaintRect( aRetoucheRect );
|
|
}
|
|
}
|
|
|
|
SwFootnoteBossFrame::DestroyImpl();
|
|
}
|
|
|
|
SwPageFrame::~SwPageFrame()
|
|
{
|
|
}
|
|
|
|
void SwPageFrame::CheckGrid( bool bInvalidate )
|
|
{
|
|
bool bOld = m_bHasGrid;
|
|
m_bHasGrid = true;
|
|
SwTextGridItem const*const pGrid(GetGridItem(this));
|
|
m_bHasGrid = nullptr != pGrid;
|
|
if( !(bInvalidate || bOld != m_bHasGrid) )
|
|
return;
|
|
|
|
SwLayoutFrame* pBody = FindBodyCont();
|
|
if( pBody )
|
|
{
|
|
pBody->InvalidatePrt();
|
|
SwContentFrame* pFrame = pBody->ContainsContent();
|
|
while( pBody->IsAnLower( pFrame ) )
|
|
{
|
|
static_cast<SwTextFrame*>(pFrame)->Prepare();
|
|
pFrame = pFrame->GetNextContentFrame();
|
|
}
|
|
}
|
|
SetCompletePaint();
|
|
}
|
|
|
|
void SwPageFrame::CheckDirection( bool bVert )
|
|
{
|
|
SvxFrameDirection nDir = GetFormat()->GetFormatAttr( RES_FRAMEDIR ).GetValue();
|
|
if( bVert )
|
|
{
|
|
if( SvxFrameDirection::Horizontal_LR_TB == nDir || SvxFrameDirection::Horizontal_RL_TB == nDir )
|
|
{
|
|
mbVertLR = false;
|
|
mbVertical = false;
|
|
}
|
|
else
|
|
{
|
|
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
|
|
if( pSh && pSh->GetViewOptions()->getBrowseMode() )
|
|
{
|
|
mbVertLR = false;
|
|
mbVertical = false;
|
|
}
|
|
else
|
|
{
|
|
mbVertical = true;
|
|
|
|
if(SvxFrameDirection::Vertical_RL_TB == nDir)
|
|
mbVertLR = false;
|
|
else if(SvxFrameDirection::Vertical_LR_TB==nDir)
|
|
mbVertLR = true;
|
|
}
|
|
}
|
|
|
|
mbInvalidVert = false;
|
|
}
|
|
else
|
|
{
|
|
if( SvxFrameDirection::Horizontal_RL_TB == nDir )
|
|
mbRightToLeft = true;
|
|
else
|
|
mbRightToLeft = false;
|
|
mbInvalidR2L = false;
|
|
}
|
|
}
|
|
|
|
/// create specific Flys for this page and format generic content
|
|
static void lcl_FormatLay( SwLayoutFrame *pLay )
|
|
{
|
|
vcl::RenderContext* pRenderContext = pLay->getRootFrame()->GetCurrShell()->GetOut();
|
|
// format all LayoutFrames - no tables, Flys etc.
|
|
|
|
SwFrame *pTmp = pLay->Lower();
|
|
// first the low-level ones
|
|
while ( pTmp )
|
|
{
|
|
const SwFrameType nTypes = SwFrameType::Root | SwFrameType::Page | SwFrameType::Column
|
|
| SwFrameType::Header | SwFrameType::Footer | SwFrameType::FtnCont
|
|
| SwFrameType::Ftn | SwFrameType::Body;
|
|
if ( pTmp->GetType() & nTypes )
|
|
::lcl_FormatLay( static_cast<SwLayoutFrame*>(pTmp) );
|
|
pTmp = pTmp->GetNext();
|
|
}
|
|
pLay->Calc(pRenderContext);
|
|
}
|
|
|
|
/// Create Flys or register draw objects
|
|
static void lcl_MakeObjs(const sw::FrameFormats<sw::SpzFrameFormat*>& rSpzs, SwPageFrame* pPage)
|
|
{
|
|
// formats are in the special table of the document
|
|
size_t i = 0;
|
|
while (i < rSpzs.size())
|
|
{
|
|
auto pSpz = rSpzs[i];
|
|
const SwFormatAnchor &rAnch = pSpz->GetAnchor();
|
|
if ( rAnch.GetPageNum() == pPage->GetPhyPageNum() )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
void SwPageFrame::PreparePage( bool bFootnote )
|
|
{
|
|
SetFootnotePage( bFootnote );
|
|
|
|
// #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 *pDoc = GetFormat()->GetDoc();
|
|
|
|
if ( GetPrev() && static_cast<SwPageFrame*>(GetPrev())->IsEmptyPage() )
|
|
lcl_MakeObjs( *pDoc->GetSpzFrameFormats(), static_cast<SwPageFrame*>(GetPrev()) );
|
|
lcl_MakeObjs( *pDoc->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);
|
|
}
|
|
else if (rHint.GetId() == SfxHintId::SwAutoFormatUsedHint)
|
|
{
|
|
// a page frame exists, so use this one
|
|
static_cast<const sw::AutoFormatUsedHint&>(rHint).SetUsed();
|
|
return;
|
|
}
|
|
else if (rHint.GetId() == SfxHintId::SwLegacyModify || rHint.GetId() == SfxHintId::SwFormatChange)
|
|
{
|
|
if(auto pSh = getRootFrame()->GetCurrShell())
|
|
pSh->SetFirstVisPageInvalid();
|
|
|
|
SwPageFrameInvFlags eInvFlags = SwPageFrameInvFlags::NONE;
|
|
if (rHint.GetId() == SfxHintId::SwLegacyModify)
|
|
{
|
|
auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
|
|
if(pLegacy->m_pNew && RES_ATTRSET_CHG == pLegacy->m_pNew->Which())
|
|
{
|
|
auto& rOldSetChg = *static_cast<const SwAttrSetChg*>(pLegacy->m_pOld);
|
|
auto& rNewSetChg = *static_cast<const SwAttrSetChg*>(pLegacy->m_pNew);
|
|
SfxItemIter aOIter(*rOldSetChg.GetChgSet());
|
|
SfxItemIter aNIter(*rNewSetChg.GetChgSet());
|
|
const SfxPoolItem* pOItem = aOIter.GetCurItem();
|
|
const SfxPoolItem* pNItem = aNIter.GetCurItem();
|
|
SwAttrSetChg aOldSet(rOldSetChg);
|
|
SwAttrSetChg aNewSet(rNewSetChg);
|
|
do
|
|
{
|
|
UpdateAttr_(pOItem, pNItem, eInvFlags, &aOldSet, &aNewSet);
|
|
pOItem = aOIter.NextItem();
|
|
pNItem = aNIter.NextItem();
|
|
} while(pNItem);
|
|
if(aOldSet.Count() || aNewSet.Count())
|
|
SwLayoutFrame::SwClientNotify(rModify, sw::LegacyModifyHint(&aOldSet, &aNewSet));
|
|
}
|
|
else
|
|
UpdateAttr_(pLegacy->m_pOld, pLegacy->m_pNew, eInvFlags);
|
|
}
|
|
else // rHint.GetId() == SfxHintId::SwFormatChange
|
|
{
|
|
auto pChangeHint = static_cast<const SwFormatChangeHint*>(&rHint);
|
|
UpdateAttrForFormatChange(pChangeHint->m_pOldFormat, pChangeHint->m_pNewFormat, eInvFlags);
|
|
}
|
|
|
|
if (eInvFlags == SwPageFrameInvFlags::NONE)
|
|
return;
|
|
|
|
InvalidatePage( this );
|
|
if(eInvFlags & SwPageFrameInvFlags::InvalidatePrt)
|
|
InvalidatePrt_();
|
|
if(eInvFlags & SwPageFrameInvFlags::SetCompletePaint)
|
|
SetCompletePaint();
|
|
if(eInvFlags & SwPageFrameInvFlags::InvalidateNextPos && GetNext() )
|
|
GetNext()->InvalidatePos();
|
|
if(eInvFlags & SwPageFrameInvFlags::PrepareHeader)
|
|
PrepareHeader();
|
|
if(eInvFlags & SwPageFrameInvFlags::PrepareFooter)
|
|
PrepareFooter();
|
|
if(eInvFlags & SwPageFrameInvFlags::CheckGrid)
|
|
CheckGrid(bool(eInvFlags & SwPageFrameInvFlags::InvalidateGrid));
|
|
} else
|
|
SwFrame::SwClientNotify(rModify, rHint);
|
|
}
|
|
|
|
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();
|
|
}
|
|
else if (pNew)
|
|
{
|
|
if ( GetUpper() )
|
|
{
|
|
static_cast<SwRootFrame*>(GetUpper())->CheckViewLayout( nullptr, nullptr );
|
|
}
|
|
}
|
|
// cleanup Window
|
|
if( pSh && pSh->GetWin() && aOldPageFrameRect.HasArea() )
|
|
{
|
|
// #i9719# - consider border and shadow of
|
|
// page frame for determine 'old' rectangle - it's used for invalidating.
|
|
const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT);
|
|
SwRect aOldRectWithBorderAndShadow;
|
|
SwPageFrame::GetBorderAndShadowBoundRect( aOldPageFrameRect, pSh, pSh->GetOut(), aOldRectWithBorderAndShadow,
|
|
IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar );
|
|
pSh->InvalidateWindows( aOldRectWithBorderAndShadow );
|
|
}
|
|
rInvFlags |= SwPageFrameInvFlags::InvalidatePrt | SwPageFrameInvFlags::SetCompletePaint;
|
|
if ( aOldPageFrameRect.Height() != getFrameArea().Height() )
|
|
rInvFlags |= SwPageFrameInvFlags::InvalidateNextPos;
|
|
}
|
|
break;
|
|
|
|
case RES_COL:
|
|
assert(pOld && pNew); //COL Missing Format
|
|
if (pOld && pNew)
|
|
{
|
|
SwLayoutFrame *pB = FindBodyCont();
|
|
assert(pB); //page without body
|
|
pB->ChgColumns( *static_cast<const SwFormatCol*>(pOld), *static_cast<const SwFormatCol*>(pNew) );
|
|
rInvFlags |= SwPageFrameInvFlags::SetCompletePaint | SwPageFrameInvFlags::CheckGrid;
|
|
}
|
|
break;
|
|
|
|
case RES_HEADER:
|
|
rInvFlags |= SwPageFrameInvFlags::PrepareHeader;
|
|
break;
|
|
|
|
case RES_FOOTER:
|
|
rInvFlags |= SwPageFrameInvFlags::PrepareFooter;
|
|
break;
|
|
case RES_TEXTGRID:
|
|
rInvFlags |= SwPageFrameInvFlags::CheckGrid | SwPageFrameInvFlags::InvalidateGrid;
|
|
break;
|
|
case RES_FRAMEDIR :
|
|
CheckDirChange();
|
|
break;
|
|
|
|
default:
|
|
bClear = false;
|
|
}
|
|
if ( !bClear )
|
|
return;
|
|
|
|
if ( pOldSet || pNewSet )
|
|
{
|
|
if ( pOldSet )
|
|
pOldSet->ClearItem( nWhich );
|
|
if ( pNewSet )
|
|
pNewSet->ClearItem( nWhich );
|
|
}
|
|
else
|
|
{
|
|
SwModify aMod;
|
|
SwLayoutFrame::SwClientNotify(aMod, sw::LegacyModifyHint(pOld, pNew));
|
|
}
|
|
}
|
|
|
|
void SwPageFrame::UpdateAttrForFormatChange( SwFormat* pOldFormat, SwFormat* pNewFormat,
|
|
SwPageFrameInvFlags &rInvFlags )
|
|
{
|
|
// state of m_bEmptyPage needs to be determined newly
|
|
const bool 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;
|
|
}
|
|
|
|
// 2. header and footer:
|
|
const SwFormatHeader &rOldH = pOldFormat->GetHeader();
|
|
const SwFormatHeader &rNewH = pNewFormat->GetHeader();
|
|
if( rOldH != rNewH )
|
|
rInvFlags |= SwPageFrameInvFlags::PrepareHeader;
|
|
|
|
const SwFormatFooter &rOldF = pOldFormat->GetFooter();
|
|
const SwFormatFooter &rNewF = pNewFormat->GetFooter();
|
|
if( rOldF != rNewF )
|
|
rInvFlags |= SwPageFrameInvFlags::PrepareFooter;
|
|
CheckDirChange();
|
|
|
|
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();
|
|
}
|
|
else if (pNewFormat)
|
|
{
|
|
const SwFormatFrameSize &rSz = pNewFormat->GetFrameSize();
|
|
|
|
{
|
|
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
|
|
aFrm.Height( std::max( rSz.GetHeight(), tools::Long(MINLAY) ) );
|
|
aFrm.Width ( std::max( rSz.GetWidth(), tools::Long(MINLAY) ) );
|
|
}
|
|
|
|
if ( GetUpper() )
|
|
{
|
|
static_cast<SwRootFrame*>(GetUpper())->CheckViewLayout( nullptr, nullptr );
|
|
}
|
|
}
|
|
// cleanup Window
|
|
if( pSh && pSh->GetWin() && aOldPageFrameRect.HasArea() )
|
|
{
|
|
// #i9719# - consider border and shadow of
|
|
// page frame for determine 'old' rectangle - it's used for invalidating.
|
|
const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT);
|
|
SwRect aOldRectWithBorderAndShadow;
|
|
SwPageFrame::GetBorderAndShadowBoundRect( aOldPageFrameRect, pSh, pSh->GetOut(), aOldRectWithBorderAndShadow,
|
|
IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar );
|
|
pSh->InvalidateWindows( aOldRectWithBorderAndShadow );
|
|
}
|
|
rInvFlags |= SwPageFrameInvFlags::InvalidatePrt | SwPageFrameInvFlags::SetCompletePaint;
|
|
if ( aOldPageFrameRect.Height() != getFrameArea().Height() )
|
|
rInvFlags |= SwPageFrameInvFlags::InvalidateNextPos;
|
|
|
|
SwModify aMod;
|
|
SwLayoutFrame::SwClientNotify(aMod, SwFormatChangeHint(pOldFormat, pNewFormat));
|
|
}
|
|
|
|
void SwPageFrame::SetPageDesc( SwPageDesc *pNew, SwFrameFormat *pFormat )
|
|
{
|
|
m_pDesc = pNew;
|
|
if ( pFormat )
|
|
SetFrameFormat( pFormat );
|
|
}
|
|
|
|
/* 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 *pDoc = GetFormat()->GetDoc();
|
|
if ( IsEndNotePage() )
|
|
return pDoc->GetEndNoteInfo().GetPageDesc( *pDoc );
|
|
else
|
|
return pDoc->GetFootnoteInfo().GetPageDesc( *pDoc );
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
SwContentFrame* pFirstContent = FindFirstBodyContent();
|
|
while (pFirstContent && pFirstContent->IsInSct()
|
|
&& pFirstContent->FindSctFrame()->IsHiddenNow())
|
|
{
|
|
pFirstContent = pFirstContent->GetNextContentFrame();
|
|
}
|
|
SwFrame* pFlow = pFirstContent;
|
|
if ( pFlow && pFlow->IsInTab() )
|
|
pFlow = pFlow->FindTabFrame();
|
|
|
|
//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 );
|
|
|
|
OSL_ENSURE( pRet, "could not find page descriptor." );
|
|
return pRet;
|
|
}
|
|
|
|
// Notify if the RootFrame changes its size
|
|
void AdjustSizeChgNotify( SwRootFrame *pRoot )
|
|
{
|
|
const bool bOld = pRoot->IsSuperfluous();
|
|
pRoot->mbCheckSuperfluous = false;
|
|
if ( pRoot->GetCurrShell() )
|
|
{
|
|
for(SwViewShell& rSh : pRoot->GetCurrShell()->GetRingContainer())
|
|
{
|
|
if( pRoot == rSh.GetLayout() )
|
|
{
|
|
rSh.SizeChgNotify();
|
|
if ( rSh.Imp() )
|
|
rSh.Imp()->NotifySizeChg( pRoot->getFrameArea().SSize() );
|
|
}
|
|
}
|
|
}
|
|
pRoot->mbCheckSuperfluous = bOld;
|
|
}
|
|
|
|
inline void SetLastPage( SwPageFrame *pPage )
|
|
{
|
|
static_cast<SwRootFrame*>(pPage->GetUpper())->mpLastPage = pPage;
|
|
}
|
|
|
|
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 );
|
|
|
|
if( getFrameArea().Width() != pParent->getFramePrintArea().Width() )
|
|
InvalidateSize_();
|
|
|
|
InvalidatePos();
|
|
|
|
SwViewShell *pSh = getRootFrame()->GetCurrShell();
|
|
if ( pSh )
|
|
pSh->SetFirstVisPageInvalid();
|
|
|
|
getRootFrame()->CheckViewLayout( nullptr, nullptr );
|
|
}
|
|
|
|
static void lcl_PrepFlyInCntRegister( SwContentFrame *pFrame )
|
|
{
|
|
pFrame->Prepare( PrepareHint::Register );
|
|
if( !pFrame->GetDrawObjs() )
|
|
return;
|
|
|
|
for(SwAnchoredObject* pAnchoredObj : *pFrame->GetDrawObjs())
|
|
{
|
|
// #i28701#
|
|
if ( auto pFly = dynamic_cast<SwFlyInContentFrame *>( pAnchoredObj ) )
|
|
{
|
|
SwContentFrame *pCnt = pFly->ContainsContent();
|
|
while ( pCnt )
|
|
{
|
|
lcl_PrepFlyInCntRegister( pCnt );
|
|
pCnt = pCnt->GetNextContentFrame();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SwPageFrame::PrepareRegisterChg()
|
|
{
|
|
SwContentFrame *pFrame = FindFirstBodyContent();
|
|
while( pFrame )
|
|
{
|
|
lcl_PrepFlyInCntRegister( pFrame );
|
|
pFrame = pFrame->GetNextContentFrame();
|
|
if( !IsAnLower( pFrame ) )
|
|
break;
|
|
}
|
|
if( !GetSortedObjs() )
|
|
return;
|
|
|
|
for(SwAnchoredObject* pAnchoredObj : *GetSortedObjs())
|
|
{
|
|
// #i28701#
|
|
if ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
|
|
{
|
|
pFrame = pFly->ContainsContent();
|
|
while ( pFrame )
|
|
{
|
|
::lcl_PrepFlyInCntRegister( pFrame );
|
|
pFrame = pFrame->GetNextContentFrame();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace sw {
|
|
|
|
/// 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.
|
|
const SwLayoutFrame* pBody = nullptr;
|
|
if ( bExistEssentialObjs ||
|
|
rPage.FindFootnoteCont() ||
|
|
(nullptr != (pBody = rPage.FindBodyCont()) &&
|
|
( 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:
|
|
( pBody->Lower() && pBody->Lower()->IsTabFrame() ) ) ) )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
} // 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.");
|
|
|
|
SwViewShell *pSh = pStart->getRootFrame()->GetCurrShell();
|
|
SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr;
|
|
|
|
if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() )
|
|
{
|
|
pImp->GetLayAction().SetCheckPageNum( pStart->GetPhyPageNum() );
|
|
SAL_INFO( "sw.pageframe", "CheckPageDescs out fast - via SetCheckPageNum: "
|
|
<< pStart->GetPhyPageNum() << ")" );
|
|
return;
|
|
}
|
|
|
|
// For the update of page numbering fields, nDocPos provides
|
|
// the page position from where invalidation should start.
|
|
SwTwips nDocPos = LONG_MAX;
|
|
|
|
SwRootFrame *pRoot = static_cast<SwRootFrame*>(pStart->GetUpper());
|
|
SwDoc* pDoc = pStart->GetFormat()->GetDoc();
|
|
const bool bFootnotes = !pDoc->GetFootnoteIdxs().empty();
|
|
|
|
SwPageFrame *pPage = pStart;
|
|
if( pPage->GetPrev() && static_cast<SwPageFrame*>(pPage->GetPrev())->IsEmptyPage() )
|
|
pPage = static_cast<SwPageFrame*>(pPage->GetPrev());
|
|
while ( pPage )
|
|
{
|
|
SwPageFrame *pPrevPage = static_cast<SwPageFrame*>(pPage->GetPrev());
|
|
SwPageFrame *pNextPage = static_cast<SwPageFrame*>(pPage->GetNext());
|
|
|
|
SwPageDesc *pDesc = pPage->FindPageDesc();
|
|
/// page is intentionally empty page
|
|
bool bIsEmpty = pPage->IsEmptyPage();
|
|
// false for intentionally empty pages, they need additional check
|
|
bool isPageFrameEmpty(!bIsEmpty && sw::IsPageFrameEmpty(*pPage));
|
|
bool bIsOdd = pPage->OnRightPage();
|
|
bool bWantOdd = pPage->WannaRightPage();
|
|
bool bFirst = pPage->OnFirstPage();
|
|
SwFrameFormat *pFormatWish = bWantOdd
|
|
? pDesc->GetRightFormat(bFirst) : pDesc->GetLeftFormat(bFirst);
|
|
|
|
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;
|
|
}
|
|
else if ( 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 );
|
|
}
|
|
else if ( !bIsEmpty && //3.
|
|
bIsOdd != bWantOdd &&
|
|
( ( !pPrevPage && !bWantOdd ) ||
|
|
( pPrevPage && !pPrevPage->IsEmptyPage() )
|
|
)
|
|
)
|
|
{
|
|
if ( pPrevPage )
|
|
pDesc = pPrevPage->GetPageDesc();
|
|
SwPageFrame *pTmp = new SwPageFrame( pDoc->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!
|
|
}
|
|
else if ( 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_();
|
|
}
|
|
}
|
|
else if ( pFormatWish && pPage->GetFormat() != pFormatWish ) //5.
|
|
{
|
|
pPage->SetFrameFormat( pFormatWish );
|
|
SAL_INFO( "sw.pageframe", "CheckPageDescs phys: " << pPage->GetPhyPageNum()
|
|
<< " c: 5 - set format p: " << pPage << " f: " << pFormatWish );
|
|
}
|
|
else if ( !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);
|
|
const bool 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());
|
|
}
|
|
|
|
pRoot->SetAssertFlyPages();
|
|
SwRootFrame::AssertPageFlys( pStart );
|
|
|
|
if ( bNotifyFields && (!pImp || !pImp->IsUpdateExpFields()) )
|
|
{
|
|
pDoc->getIDocumentFieldsAccess().UpdatePageFields(nDocPos);
|
|
}
|
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
//1. check if two empty pages are behind one another
|
|
bool bEmpty = false;
|
|
SwPageFrame *pPg = pStart;
|
|
while ( pPg )
|
|
{
|
|
if ( pPg->IsEmptyPage() )
|
|
{
|
|
if ( bEmpty )
|
|
{
|
|
OSL_FAIL( "double empty pages." );
|
|
break; // once is enough
|
|
}
|
|
bEmpty = true;
|
|
}
|
|
else
|
|
bEmpty = false;
|
|
|
|
pPg = static_cast<SwPageFrame*>(pPg->GetNext());
|
|
}
|
|
#endif
|
|
SAL_INFO( "sw.pageframe", "CheckPageDescs out)" );
|
|
}
|
|
|
|
namespace
|
|
{
|
|
bool isDeleteForbidden(const SwPageFrame *pDel)
|
|
{
|
|
if (pDel->IsDeleteForbidden())
|
|
return true;
|
|
const SwLayoutFrame* pBody = pDel->FindBodyCont();
|
|
const SwFrame* pBodyContent = pBody ? pBody->Lower() : nullptr;
|
|
return pBodyContent && pBodyContent->IsDeleteForbidden();
|
|
}
|
|
|
|
bool doInsertPage( SwRootFrame *pRoot, SwPageFrame **pRefSibling,
|
|
SwFrameFormat *pFormat, SwPageDesc *pDesc,
|
|
bool bFootnote, SwPageFrame **pRefPage )
|
|
{
|
|
SwPageFrame *pPage = new SwPageFrame(pFormat, pRoot, pDesc);
|
|
SwPageFrame *pSibling = *pRefSibling;
|
|
if ( pRefPage )
|
|
{
|
|
*pRefPage = pPage;
|
|
SAL_INFO( "sw.pageframe", "doInsertPage p: " << pPage
|
|
<< " d: " << pDesc << " f: " << pFormat );
|
|
}
|
|
else
|
|
SAL_INFO( "sw.pageframe", "doInsertPage - insert empty p: "
|
|
<< pPage << " d: " << pDesc );
|
|
pPage->Paste( pRoot, pSibling );
|
|
|
|
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)
|
|
return true;
|
|
if (pSibling->IsFootnotePage())
|
|
return true;
|
|
if (pSibling->FindFirstBodyContent())
|
|
return true;
|
|
|
|
if (!pRefPage || !isDeleteForbidden(pSibling))
|
|
{
|
|
pRoot->RemovePage( pRefSibling, SwRemoveResult::Next ) ;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
SwPageFrame *SwFrame::InsertPage( SwPageFrame *pPrevPage, bool bFootnote )
|
|
{
|
|
SwRootFrame *pRoot = static_cast<SwRootFrame*>(pPrevPage->GetUpper());
|
|
SwPageFrame *pSibling = static_cast<SwPageFrame*>(pPrevPage->GetNext());
|
|
SwPageDesc *pDesc = nullptr;
|
|
|
|
// 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();
|
|
|
|
assert(pDesc && "Missing PageDesc");
|
|
if( !(bWishedRightPage ? pDesc->GetRightFormat() : pDesc->GetLeftFormat()) )
|
|
bWishedRightPage = !bWishedRightPage;
|
|
bool const bWishedFirst = pDesc != pPrevPage->GetPageDesc();
|
|
|
|
SwDoc *pDoc = pPrevPage->GetFormat()->GetDoc();
|
|
bool bCheckPages = false;
|
|
// If there is no FrameFormat for this page, create an empty page.
|
|
if (bWishedRightPage != bNextRightPage)
|
|
{
|
|
if( doInsertPage( pRoot, &pSibling, pDoc->GetEmptyPageFormat(),
|
|
pPrevPage->GetPageDesc(), bFootnote, nullptr ) )
|
|
bCheckPages = true;
|
|
}
|
|
SwFrameFormat *const pFormat( bWishedRightPage
|
|
? pDesc->GetRightFormat(bWishedFirst)
|
|
: pDesc->GetLeftFormat(bWishedFirst) );
|
|
assert(pFormat);
|
|
SwPageFrame *pPage = nullptr;
|
|
if( doInsertPage( pRoot, &pSibling, pFormat, pDesc, bFootnote, &pPage ) )
|
|
bCheckPages = true;
|
|
|
|
if ( pSibling )
|
|
{
|
|
if ( bCheckPages )
|
|
{
|
|
CheckPageDescs( pSibling, false );
|
|
SwViewShell *pSh = getRootFrame()->GetCurrShell();
|
|
SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr;
|
|
if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() )
|
|
{
|
|
const sal_uInt16 nNum = pImp->GetLayAction().GetCheckPageNum();
|
|
if ( nNum == pPrevPage->GetPhyPageNum() + 1 )
|
|
{
|
|
pImp->GetLayAction().SetCheckPageNumDirect(
|
|
pSibling->GetPhyPageNum() );
|
|
SAL_INFO( "sw.pageframe", "InsertPage - SetCheckPageNumDirect: "
|
|
<< pSibling->GetPhyPageNum() );
|
|
}
|
|
return pPage;
|
|
}
|
|
}
|
|
else
|
|
SwRootFrame::AssertPageFlys( pSibling );
|
|
}
|
|
|
|
// 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() )
|
|
{
|
|
pDoc->getIDocumentFieldsAccess().UpdatePageFields(pPrevPage->getFrameArea().Top());
|
|
}
|
|
return pPage;
|
|
}
|
|
|
|
sw::sidebarwindows::SidebarPosition SwPageFrame::SidebarPosition() const
|
|
{
|
|
SwViewShell *pSh = getRootFrame()->GetCurrShell();
|
|
if( !pSh || pSh->GetViewOptions()->getBrowseMode() )
|
|
{
|
|
return sw::sidebarwindows::SidebarPosition::RIGHT;
|
|
}
|
|
else
|
|
{
|
|
const bool bLTR = getRootFrame()->IsLeftToRightViewLayout();
|
|
const bool bBookMode = pSh->GetViewOptions()->IsViewLayoutBookMode();
|
|
const bool bRightSidebar = bLTR ? (!bBookMode || OnRightPage()) : (bBookMode && !OnRightPage());
|
|
|
|
return bRightSidebar
|
|
? sw::sidebarwindows::SidebarPosition::RIGHT
|
|
: sw::sidebarwindows::SidebarPosition::LEFT;
|
|
}
|
|
}
|
|
|
|
SwTwips SwRootFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool)
|
|
{
|
|
if ( !bTst )
|
|
{
|
|
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
|
|
aFrm.AddHeight(nDist );
|
|
}
|
|
reason = SwResizeLimitReason::Unspecified;
|
|
return nDist;
|
|
}
|
|
|
|
SwTwips SwRootFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool )
|
|
{
|
|
OSL_ENSURE( nDist >= 0, "nDist < 0." );
|
|
OSL_ENSURE( nDist <= getFrameArea().Height(), "nDist greater than current size." );
|
|
|
|
if ( !bTst )
|
|
{
|
|
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
|
|
aFrm.AddHeight( -nDist );
|
|
}
|
|
|
|
return nDist;
|
|
}
|
|
|
|
void SwRootFrame::RemovePage( SwPageFrame **pDelRef, SwRemoveResult eResult )
|
|
{
|
|
SwPageFrame *pDel = *pDelRef;
|
|
(*pDelRef) = static_cast<SwPageFrame*>(
|
|
eResult == SwRemoveResult::Next ? pDel->GetNext() : pDel->GetPrev() );
|
|
if ( !GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
|
|
RemoveFootnotes( pDel, true );
|
|
pDel->Cut();
|
|
SwFrame::DestroyFrame( pDel );
|
|
}
|
|
|
|
/// 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;
|
|
|
|
SwPageFrame *pPage = GetLastPage();
|
|
tools::Long nDocPos = LONG_MAX;
|
|
|
|
// 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;
|
|
}
|
|
|
|
if ( pPage )
|
|
{
|
|
SAL_INFO( "sw.pageframe", "RemoveSuperfluous - DestroyFrm p: " << pPage );
|
|
RemovePage( &pPage, SwRemoveResult::Prev );
|
|
nDocPos = pPage ? pPage->getFrameArea().Top() : 0;
|
|
}
|
|
} while ( pPage );
|
|
|
|
SwViewShell *pSh = getRootFrame()->GetCurrShell();
|
|
if ( nDocPos != LONG_MAX &&
|
|
(!pSh || !pSh->Imp()->IsUpdateExpFields()) )
|
|
{
|
|
GetFormat()->GetDoc()->getIDocumentFieldsAccess().UpdatePageFields(nDocPos);
|
|
}
|
|
}
|
|
|
|
/// 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;
|
|
|
|
SwDoc *pDoc = GetFormat()->GetDoc();
|
|
const sw::SpzFrameFormats* pSpzs = pDoc->GetSpzFrameFormats();
|
|
|
|
// 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());
|
|
|
|
for(auto pSpz: *pSpzs )
|
|
{
|
|
const SwFormatAnchor &rAnch = pSpz->GetAnchor();
|
|
if(!rAnch.GetAnchorNode())
|
|
{
|
|
const sal_uInt16 nPageNum(rAnch.GetPageNum());
|
|
|
|
// calc MaxPage (as before)
|
|
nMaxPg = std::max(nMaxPg, nPageNum);
|
|
|
|
// 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 (!(bWishedRightPage ? pDesc->GetRightFormat() : pDesc->GetLeftFormat()))
|
|
{
|
|
bWishedRightPage = !bWishedRightPage;
|
|
}
|
|
|
|
bool const bWishedFirst(pDesc != pPrevPage->GetPageDesc());
|
|
SwFrameFormat* pFormat(bWishedRightPage ? pDesc->GetRightFormat(bWishedFirst) : pDesc->GetLeftFormat(bWishedFirst));
|
|
|
|
// set SwFrameFormat, this will trigger SwPageFrame::UpdateAttr_ and re-evaluate
|
|
// m_bEmptyPage, too
|
|
pPage->SetFrameFormat(pFormat);
|
|
|
|
if(nullptr == pFirstRevivedEmptyPage)
|
|
{
|
|
// remember first (lowest) SwPageFrame which needed correction
|
|
pFirstRevivedEmptyPage = pPage;
|
|
}
|
|
}
|
|
|
|
// original while-condition II
|
|
if(nullptr == pPage->GetNext())
|
|
{
|
|
break;
|
|
}
|
|
|
|
// original while-condition III
|
|
if(static_cast< SwPageFrame* >(pPage->GetNext())->IsFootnotePage())
|
|
{
|
|
break;
|
|
}
|
|
|
|
pPrevPage = pPage;
|
|
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
|
|
}
|
|
|
|
assert(pPage);
|
|
|
|
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 ( !pDoc->GetFootnoteIdxs().empty() )
|
|
{
|
|
pPage = static_cast<SwPageFrame*>(Lower());
|
|
while ( pPage && !pPage->IsFootnotePage() )
|
|
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
|
|
|
|
if ( pPage )
|
|
{
|
|
SwPageDesc *pTmpDesc = pPage->FindPageDesc();
|
|
bool isRightPage = pPage->OnRightPage();
|
|
if ( pPage->GetFormat() !=
|
|
(isRightPage ? pTmpDesc->GetRightFormat() : pTmpDesc->GetLeftFormat()) )
|
|
RemoveFootnotes( pPage, false, true );
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 );
|
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
pPage = static_cast<SwPageFrame*>(Lower());
|
|
while ( pPage->GetNext() &&
|
|
!static_cast<SwPageFrame*>(pPage->GetNext())->IsFootnotePage() )
|
|
{
|
|
SAL_INFO( "sw.pageframe", "AssertFlyPages p: " << pPage << " d: " << pPage->GetPageDesc()
|
|
<< " f: " << pPage->GetFormat() << " virt: " << pPage->GetVirtPageNum()
|
|
<< " phys: " << pPage->GetPhyPageNum() << " empty: " << pPage->IsEmptyPage() );
|
|
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
|
|
}
|
|
SAL_INFO( "sw.pageframe", "AssertFlyPages p: " << pPage << " d: " << pPage->GetPageDesc()
|
|
<< " f: " << pPage->GetFormat() << " virt: " << pPage->GetVirtPageNum()
|
|
<< " phys: " << pPage->GetPhyPageNum() << " empty: " << pPage->IsEmptyPage() );
|
|
#endif
|
|
}
|
|
|
|
/// Ensure that after the given page all page-bound objects are located on the correct page
|
|
void SwRootFrame::AssertPageFlys( SwPageFrame *pPage )
|
|
{
|
|
SAL_INFO( "sw.pageframe", "(AssertPageFlys in" );
|
|
while ( pPage )
|
|
{
|
|
if (pPage->GetSortedObjs())
|
|
{
|
|
size_t i = 0;
|
|
while ( pPage->GetSortedObjs() && i< pPage->GetSortedObjs()->size() )
|
|
{
|
|
// #i28701#
|
|
SwFrameFormat* pFormat = (*pPage->GetSortedObjs())[i]->GetFrameFormat();
|
|
const SwFormatAnchor &rAnch = pFormat->GetAnchor();
|
|
const sal_uInt16 nPg = rAnch.GetPageNum();
|
|
if ((rAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE) &&
|
|
nPg != pPage->GetPhyPageNum() )
|
|
{
|
|
SAL_INFO( "sw.pageframe", nPg << " " << pPage->GetPhyPageNum() );
|
|
// If on the wrong page, check if previous page is empty
|
|
if( nPg && !(pPage->GetPhyPageNum()-1 == nPg &&
|
|
static_cast<SwPageFrame*>(pPage->GetPrev())->IsEmptyPage()) )
|
|
{
|
|
// It can move by itself. Just send a modify to its anchor attribute.
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
const size_t nCnt = pPage->GetSortedObjs()->size();
|
|
pFormat->CallSwClientNotify(sw::LegacyModifyHint(nullptr, &rAnch));
|
|
OSL_ENSURE( !pPage->GetSortedObjs() ||
|
|
nCnt != pPage->GetSortedObjs()->size(),
|
|
"Object couldn't be reattached!" );
|
|
#else
|
|
pFormat->CallSwClientNotify(sw::LegacyModifyHint(nullptr, &rAnch));
|
|
#endif
|
|
// Do not increment index, in this case
|
|
continue;
|
|
}
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
|
|
}
|
|
SAL_INFO( "sw.pageframe", "AssertPageFlys out)" );
|
|
}
|
|
|
|
Size SwRootFrame::ChgSize( const Size& aNewSize )
|
|
{
|
|
{
|
|
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
|
|
aFrm.SSize(aNewSize);
|
|
}
|
|
|
|
InvalidatePrt_();
|
|
mbFixSize = false;
|
|
return getFrameArea().SSize();
|
|
}
|
|
|
|
void SwRootFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
|
|
{
|
|
if ( !isFrameAreaPositionValid() )
|
|
{
|
|
setFrameAreaPositionValid(true);
|
|
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
|
|
aFrm.Pos().setX(DOCUMENTBORDER);
|
|
aFrm.Pos().setY(DOCUMENTBORDER);
|
|
}
|
|
|
|
if ( !isFramePrintAreaValid() )
|
|
{
|
|
setFramePrintAreaValid(true);
|
|
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
|
|
aPrt.Pos().setX(0);
|
|
aPrt.Pos().setY(0);
|
|
aPrt.SSize( getFrameArea().SSize() );
|
|
}
|
|
|
|
if ( !isFrameAreaSizeValid() )
|
|
{
|
|
// SSize is set by the pages (Cut/Paste).
|
|
setFrameAreaSizeValid(true);
|
|
}
|
|
}
|
|
|
|
void SwRootFrame::ImplInvalidateBrowseWidth()
|
|
{
|
|
mbBrowseWidthValid = false;
|
|
SwFrame *pPg = Lower();
|
|
while ( pPg )
|
|
{
|
|
pPg->InvalidateSize();
|
|
pPg = pPg->GetNext();
|
|
}
|
|
}
|
|
|
|
void SwRootFrame::ImplCalcBrowseWidth()
|
|
{
|
|
OSL_ENSURE( GetCurrShell() && GetCurrShell()->GetViewOptions()->getBrowseMode(),
|
|
"CalcBrowseWidth and not in BrowseView" );
|
|
|
|
// The (minimal) with is determined from borders, tables and paint objects.
|
|
// It is calculated based on the attributes. Thus, it is not relevant how wide they are
|
|
// currently but only how wide they want to be.
|
|
// Frames and paint objects inside other objects (frames, tables) do not count.
|
|
// Borders and columns are not taken into account.
|
|
|
|
SwFrame *pFrame = ContainsContent();
|
|
while ( pFrame && !pFrame->IsInDocBody() )
|
|
pFrame = static_cast<SwContentFrame*>(pFrame)->GetNextContentFrame();
|
|
if ( !pFrame )
|
|
return;
|
|
|
|
mbBrowseWidthValid = true;
|
|
SwViewShell *pSh = getRootFrame()->GetCurrShell();
|
|
mnBrowseWidth = (!comphelper::LibreOfficeKit::isActive() && pSh)? MINLAY + 2 * pSh->GetOut()-> PixelToLogic( pSh->GetBrowseBorder() ).Width(): MIN_BROWSE_WIDTH;
|
|
|
|
do
|
|
{
|
|
if ( pFrame->IsInTab() )
|
|
pFrame = pFrame->FindTabFrame();
|
|
|
|
if ( pFrame->IsTabFrame() &&
|
|
!static_cast<SwLayoutFrame*>(pFrame)->GetFormat()->GetFrameSize().GetWidthPercent() )
|
|
{
|
|
SwBorderAttrAccess aAccess( SwFrame::GetCache(), pFrame );
|
|
const SwBorderAttrs &rAttrs = *aAccess.Get();
|
|
const SwFormatHoriOrient &rHori = rAttrs.GetAttrSet().GetHoriOrient();
|
|
tools::Long nWidth = rAttrs.GetSize().Width();
|
|
if ( nWidth < std::numeric_limits<tools::Long>::max()-2000 && //-2k, because it changes while trying to resize!
|
|
text::HoriOrientation::FULL != rHori.GetHoriOrient() )
|
|
{
|
|
const SwHTMLTableLayout *pLayoutInfo =
|
|
static_cast<const SwTabFrame *>(pFrame)->GetTable()
|
|
->GetHTMLTableLayout();
|
|
if ( pLayoutInfo )
|
|
nWidth = std::min( nWidth, pLayoutInfo->GetBrowseWidthMin() );
|
|
|
|
switch ( rHori.GetHoriOrient() )
|
|
{
|
|
case text::HoriOrientation::NONE:
|
|
// OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
|
|
nWidth += rAttrs.CalcLeft( pFrame ) + rAttrs.CalcRight( pFrame );
|
|
break;
|
|
case text::HoriOrientation::LEFT_AND_WIDTH:
|
|
nWidth += rAttrs.CalcLeft( pFrame );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
mnBrowseWidth = std::max( mnBrowseWidth, nWidth );
|
|
}
|
|
}
|
|
else if ( pFrame->GetDrawObjs() )
|
|
{
|
|
for ( size_t i = 0; i < pFrame->GetDrawObjs()->size(); ++i )
|
|
{
|
|
// #i28701#
|
|
SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i];
|
|
const SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
|
|
const bool bFly = pAnchoredObj->DynCastFlyFrame() != nullptr;
|
|
if ((bFly && (FAR_AWAY == pAnchoredObj->GetObjRect().Width()))
|
|
|| pFormat->GetFrameSize().GetWidthPercent())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
tools::Long nWidth = 0;
|
|
switch ( pFormat->GetAnchor().GetAnchorId() )
|
|
{
|
|
case RndStdIds::FLY_AS_CHAR:
|
|
nWidth = bFly ? pFormat->GetFrameSize().GetWidth() :
|
|
pAnchoredObj->GetObjRect().Width();
|
|
break;
|
|
case RndStdIds::FLY_AT_PARA:
|
|
{
|
|
// #i33170#
|
|
// Reactivated old code because
|
|
// nWidth = pAnchoredObj->GetObjRect().Right()
|
|
// gives wrong results for objects that are still
|
|
// at position FAR_AWAY.
|
|
if ( bFly )
|
|
{
|
|
nWidth = pFormat->GetFrameSize().GetWidth();
|
|
const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
|
|
switch ( rHori.GetHoriOrient() )
|
|
{
|
|
case text::HoriOrientation::NONE:
|
|
nWidth += rHori.GetPos();
|
|
break;
|
|
case text::HoriOrientation::INSIDE:
|
|
case text::HoriOrientation::LEFT:
|
|
if ( text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() )
|
|
nWidth += pFrame->getFramePrintArea().Left();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
// Paint objects to not have attributes and
|
|
// are defined by their current size
|
|
nWidth = pAnchoredObj->GetObjRect().Right() -
|
|
pAnchoredObj->GetDrawObj()->GetAnchorPos().X();
|
|
}
|
|
break;
|
|
default: /* do nothing */;
|
|
}
|
|
mnBrowseWidth = std::max( mnBrowseWidth, nWidth );
|
|
}
|
|
}
|
|
pFrame = pFrame->FindNextCnt();
|
|
} while ( pFrame );
|
|
}
|
|
|
|
void SwRootFrame::StartAllAction()
|
|
{
|
|
if ( GetCurrShell() )
|
|
for(SwViewShell& rSh : GetCurrShell()->GetRingContainer())
|
|
{
|
|
if ( auto pCursorShell = dynamic_cast<SwCursorShell*>( &rSh) )
|
|
pCursorShell->StartAction();
|
|
else
|
|
rSh.StartAction();
|
|
}
|
|
}
|
|
|
|
void SwRootFrame::EndAllAction()
|
|
{
|
|
if ( !GetCurrShell() )
|
|
return;
|
|
|
|
for(SwViewShell& rSh : GetCurrShell()->GetRingContainer())
|
|
{
|
|
if ( auto pCursorShell = dynamic_cast<SwCursorShell*>( &rSh) )
|
|
{
|
|
pCursorShell->EndAction();
|
|
pCursorShell->CallChgLnk();
|
|
if ( auto pFEShell = dynamic_cast<SwFEShell*>( &rSh) )
|
|
pFEShell->SetChainMarker();
|
|
}
|
|
else
|
|
rSh.EndAction();
|
|
}
|
|
}
|
|
|
|
void SwRootFrame::UnoRemoveAllActions()
|
|
{
|
|
if ( !GetCurrShell() )
|
|
return;
|
|
|
|
for(SwViewShell& rSh : GetCurrShell()->GetRingContainer())
|
|
{
|
|
// #i84729#
|
|
// No end action, if <SwViewShell> instance is currently in its end action.
|
|
// Recursive calls to <::EndAction()> are not allowed.
|
|
if ( !rSh.IsInEndAction() )
|
|
{
|
|
OSL_ENSURE(!rSh.GetRestoreActions(), "Restore action count is already set!");
|
|
bool bCursor = dynamic_cast<const SwCursorShell*>( &rSh) != nullptr;
|
|
bool bFE = dynamic_cast<const SwFEShell*>( &rSh) != nullptr;
|
|
sal_uInt16 nRestore = 0;
|
|
while( rSh.ActionCount() )
|
|
{
|
|
if( bCursor )
|
|
{
|
|
static_cast<SwCursorShell*>(&rSh)->EndAction();
|
|
static_cast<SwCursorShell*>(&rSh)->CallChgLnk();
|
|
if ( bFE )
|
|
static_cast<SwFEShell*>(&rSh)->SetChainMarker();
|
|
}
|
|
else
|
|
rSh.EndAction();
|
|
nRestore++;
|
|
}
|
|
rSh.SetRestoreActions(nRestore);
|
|
}
|
|
rSh.LockView(true);
|
|
}
|
|
}
|
|
|
|
void SwRootFrame::UnoRestoreAllActions()
|
|
{
|
|
if ( !GetCurrShell() )
|
|
return;
|
|
|
|
for(SwViewShell& rSh : GetCurrShell()->GetRingContainer())
|
|
{
|
|
sal_uInt16 nActions = rSh.GetRestoreActions();
|
|
while( nActions-- )
|
|
{
|
|
if ( auto pCursorShell = dynamic_cast<SwCursorShell*>( &rSh) )
|
|
pCursorShell->StartAction();
|
|
else
|
|
rSh.StartAction();
|
|
}
|
|
rSh.SetRestoreActions(0);
|
|
rSh.LockView(false);
|
|
}
|
|
}
|
|
|
|
// Helper functions for SwRootFrame::CheckViewLayout
|
|
static void lcl_MoveAllLowers( SwFrame* pFrame, const Point& rOffset );
|
|
|
|
static void lcl_MoveAllLowerObjs( SwFrame* pFrame, const Point& rOffset )
|
|
{
|
|
const bool bPage = pFrame->IsPageFrame();
|
|
const SwSortedObjs* pSortedObj = bPage
|
|
? static_cast<SwPageFrame*>(pFrame)->GetSortedObjs()
|
|
: pFrame->GetDrawObjs();
|
|
if (pSortedObj == nullptr)
|
|
return;
|
|
|
|
// note: pSortedObj elements may be removed and inserted from
|
|
// MoveObjectIfActive(), invalidating iterators
|
|
// DO NOT CONVERT THIS TO A C++11 FOR LOOP, IT DID NOT WORK THE LAST 2 TIMES
|
|
for (size_t i = 0; i < pSortedObj->size(); ++i)
|
|
{
|
|
SwAnchoredObject *const pAnchoredObj = (*pSortedObj)[i];
|
|
const SwFrameFormat* pObjFormat = pAnchoredObj->GetFrameFormat();
|
|
const SwFormatAnchor& rAnchor = pObjFormat->GetAnchor();
|
|
|
|
// all except from the as character anchored objects are moved
|
|
// when processing the page frame:
|
|
if ( !bPage && (rAnchor.GetAnchorId() != RndStdIds::FLY_AS_CHAR) )
|
|
continue;
|
|
|
|
SwObjPositioningInProgress aPosInProgress( *pAnchoredObj );
|
|
|
|
if ( auto pFlyFrame = pAnchoredObj->DynCastFlyFrame() )
|
|
{
|
|
lcl_MoveAllLowers( pFlyFrame, rOffset );
|
|
// tdf#138785 update position specific to as-char flys
|
|
if (pFlyFrame->IsFlyInContentFrame())
|
|
{
|
|
static_cast<SwFlyInContentFrame*>(pFlyFrame)->AddRefOfst(rOffset);
|
|
}
|
|
pFlyFrame->NotifyDrawObj();
|
|
// --> let the active embedded object be moved
|
|
SwFrame* pLower = pFlyFrame->Lower();
|
|
if ( pLower && pLower->IsNoTextFrame() )
|
|
{
|
|
SwRootFrame* pRoot = pLower->getRootFrame();
|
|
SwViewShell *pSh = pRoot ? pRoot->GetCurrShell() : nullptr;
|
|
if ( pSh )
|
|
{
|
|
SwNoTextFrame *const pContentFrame = static_cast<SwNoTextFrame*>(pLower);
|
|
SwOLENode* pNode = pContentFrame->GetNode()->GetOLENode();
|
|
if ( pNode )
|
|
{
|
|
svt::EmbeddedObjectRef& xObj = pNode->GetOLEObj().GetObject();
|
|
if ( xObj.is() )
|
|
{
|
|
for(SwViewShell& rSh : pSh->GetRingContainer())
|
|
{
|
|
SwFEShell* pFEShell = dynamic_cast< SwFEShell* >( &rSh );
|
|
if ( pFEShell )
|
|
pFEShell->MoveObjectIfActive( xObj, rOffset );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( auto pAnchoredDrawObj = dynamic_cast<SwAnchoredDrawObject *>( pAnchoredObj ) )
|
|
{
|
|
// don't touch objects that are not yet positioned:
|
|
if ( pAnchoredDrawObj->NotYetPositioned() )
|
|
continue;
|
|
|
|
const Point& aCurrAnchorPos = pAnchoredDrawObj->GetDrawObj()->GetAnchorPos();
|
|
const Point aNewAnchorPos( aCurrAnchorPos + rOffset );
|
|
pAnchoredDrawObj->DrawObj()->SetAnchorPos( aNewAnchorPos );
|
|
pAnchoredDrawObj->SetLastObjRect( pAnchoredDrawObj->GetObjRect().SVRect() );
|
|
|
|
// clear contour cache
|
|
if ( pAnchoredDrawObj->GetFrameFormat()->GetSurround().IsContour() )
|
|
ClrContourCache( pAnchoredDrawObj->GetDrawObj() );
|
|
}
|
|
// #i92511#
|
|
// cache for object rectangle inclusive spaces has to be invalidated.
|
|
pAnchoredObj->InvalidateObjRectWithSpaces();
|
|
}
|
|
}
|
|
|
|
static void lcl_MoveAllLowers( SwFrame* pFrame, const Point& rOffset )
|
|
{
|
|
// first move the current frame
|
|
// RotateFlyFrame3: moved to transform_translate instead of
|
|
// direct modification to allow the SwFrame evtl. needed own reactions
|
|
pFrame->transform_translate(rOffset);
|
|
|
|
// Don't forget accessibility:
|
|
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
|
|
if( pFrame->IsAccessibleFrame() )
|
|
{
|
|
SwRootFrame *pRootFrame = pFrame->getRootFrame();
|
|
if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
|
|
pRootFrame->GetCurrShell() )
|
|
{
|
|
const SwRect aFrame( pFrame->getFrameArea() );
|
|
|
|
pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( pFrame, aFrame );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// the move any objects
|
|
lcl_MoveAllLowerObjs( pFrame, rOffset );
|
|
|
|
// finally, for layout frames we have to call this function recursively:
|
|
if (pFrame->IsLayoutFrame())
|
|
{
|
|
SwFrame* pLowerFrame = pFrame->GetLower();
|
|
while ( pLowerFrame )
|
|
{
|
|
lcl_MoveAllLowers( pLowerFrame, rOffset );
|
|
pLowerFrame = pLowerFrame->GetNext();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate how the pages have to be positioned
|
|
void SwRootFrame::CheckViewLayout( const SwViewOption* pViewOpt, const SwRect* pVisArea )
|
|
{
|
|
SwViewShell* pSh = GetCurrShell();
|
|
vcl::RenderContext* pRenderContext = pSh ? pSh->GetOut() : nullptr;
|
|
// #i91432#
|
|
// No calculation of page positions, if only an empty page is present.
|
|
// This situation occurs when <SwRootFrame> instance is in construction
|
|
// and the document contains only left pages.
|
|
if ( Lower()->GetNext() == nullptr &&
|
|
static_cast<SwPageFrame*>(Lower())->IsEmptyPage() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !pVisArea )
|
|
{
|
|
// no early return for bNewPage
|
|
if ( mnViewWidth < 0 )
|
|
mnViewWidth = 0;
|
|
}
|
|
else
|
|
{
|
|
assert(pViewOpt && "CheckViewLayout required ViewOptions");
|
|
|
|
const sal_uInt16 nColumns = pViewOpt->GetViewLayoutColumns();
|
|
const bool bBookMode = pViewOpt->IsViewLayoutBookMode();
|
|
|
|
if ( nColumns == mnColumns && bBookMode == mbBookMode && pVisArea->Width() == mnViewWidth && !mbSidebarChanged )
|
|
return;
|
|
|
|
mnColumns = nColumns;
|
|
mbBookMode = bBookMode;
|
|
mnViewWidth = pVisArea->Width();
|
|
mbSidebarChanged = false;
|
|
}
|
|
|
|
if( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::BROWSE_MODE ) )
|
|
{
|
|
mnColumns = 1;
|
|
mbBookMode = false;
|
|
}
|
|
|
|
Calc(pRenderContext);
|
|
|
|
const bool bOldCallbackActionEnabled = IsCallbackActionEnabled();
|
|
SetCallbackActionEnabled( false );
|
|
|
|
maPageRects.clear();
|
|
|
|
const tools::Long nBorder = getFrameArea().Pos().getX();
|
|
const tools::Long nVisWidth = mnViewWidth - 2 * nBorder;
|
|
const tools::Long nGapBetweenPages = pViewOpt ? pViewOpt->GetGapBetweenPages()
|
|
: (pSh ? pSh->GetViewOptions()->GetGapBetweenPages()
|
|
: SwViewOption::defGapBetweenPages);
|
|
|
|
// check how many pages fit into the first page layout row:
|
|
SwPageFrame* pPageFrame = static_cast<SwPageFrame*>(Lower());
|
|
|
|
// will contain the number of pages per row. 0 means that
|
|
// the page does not fit.
|
|
tools::Long nWidthRemain = nVisWidth;
|
|
|
|
// after one row has been processed, these variables contain
|
|
// the width of the row and the maximum of the page heights
|
|
tools::Long nCurrentRowHeight = 0;
|
|
tools::Long nCurrentRowWidth = 0;
|
|
|
|
// these variables are used to finally set the size of the
|
|
// root frame
|
|
tools::Long nSumRowHeight = 0;
|
|
SwTwips nMinPageLeft = TWIPS_MAX;
|
|
SwTwips nMaxPageRight = 0;
|
|
SwPageFrame* pStartOfRow = pPageFrame;
|
|
sal_uInt16 nNumberOfPagesInRow = mbBookMode ? 1 : 0; // in book view, start with right page
|
|
bool bFirstRow = true;
|
|
|
|
bool bPageChanged = false;
|
|
const bool bRTL = !IsLeftToRightViewLayout();
|
|
const SwTwips nSidebarWidth = SwPageFrame::GetSidebarBorderWidth( pSh );
|
|
|
|
while ( pPageFrame )
|
|
{
|
|
// we consider the current page to be "start of row" if
|
|
// 1. it is the first page in the current row or
|
|
// 2. it is the second page in the row and the first page is an empty page in non-book view:
|
|
const bool bStartOfRow = pPageFrame == pStartOfRow ||
|
|
( pStartOfRow->IsEmptyPage() && pPageFrame == pStartOfRow->GetNext() && !mbBookMode );
|
|
|
|
const bool bEmptyPage = pPageFrame->IsEmptyPage() && !mbBookMode;
|
|
|
|
// no half doc border space for first page in each row and
|
|
tools::Long nPageWidth = 0;
|
|
tools::Long nPageHeight = 0;
|
|
|
|
if ( mbBookMode )
|
|
{
|
|
const SwFrame& rFormatPage = pPageFrame->GetFormatPage();
|
|
|
|
nPageWidth = rFormatPage.getFrameArea().Width() + nSidebarWidth + ((bStartOfRow || 1 == (pPageFrame->GetPhyPageNum()%2)) ? 0 : nGapBetweenPages);
|
|
nPageHeight = rFormatPage.getFrameArea().Height() + nGapBetweenPages;
|
|
}
|
|
else
|
|
{
|
|
if ( !pPageFrame->IsEmptyPage() )
|
|
{
|
|
nPageWidth = pPageFrame->getFrameArea().Width() + nSidebarWidth + (bStartOfRow ? 0 : nGapBetweenPages);
|
|
nPageHeight = pPageFrame->getFrameArea().Height() + nGapBetweenPages;
|
|
}
|
|
}
|
|
|
|
if ( !bEmptyPage )
|
|
++nNumberOfPagesInRow;
|
|
|
|
// finish current row if
|
|
// 1. in dynamic mode the current page does not fit anymore or
|
|
// 2. the current page exceeds the maximum number of columns
|
|
bool bRowFinished = (0 == mnColumns && nWidthRemain < nPageWidth ) ||
|
|
(0 != mnColumns && mnColumns < nNumberOfPagesInRow);
|
|
|
|
// make sure that at least one page goes to the current row:
|
|
if ( !bRowFinished || bStartOfRow )
|
|
{
|
|
// current page is allowed to be in current row
|
|
nWidthRemain = nWidthRemain - nPageWidth;
|
|
|
|
nCurrentRowWidth = nCurrentRowWidth + nPageWidth;
|
|
nCurrentRowHeight = std::max( nCurrentRowHeight, nPageHeight );
|
|
|
|
pPageFrame = static_cast<SwPageFrame*>(pPageFrame->GetNext());
|
|
|
|
if ( !pPageFrame )
|
|
bRowFinished = true;
|
|
}
|
|
|
|
if ( bRowFinished )
|
|
{
|
|
// pPageFrame now points to the first page in the new row or null
|
|
// pStartOfRow points to the first page in the current row
|
|
|
|
// special centering for last row. pretend to fill the last row with virtual copies of the last page before centering:
|
|
if ( !pPageFrame && nWidthRemain > 0 )
|
|
{
|
|
// find last page in current row:
|
|
const SwPageFrame* pLastPageInCurrentRow = pStartOfRow;
|
|
while( pLastPageInCurrentRow->GetNext() )
|
|
pLastPageInCurrentRow = static_cast<const SwPageFrame*>(pLastPageInCurrentRow->GetNext());
|
|
|
|
if ( pLastPageInCurrentRow->IsEmptyPage() )
|
|
pLastPageInCurrentRow = static_cast<const SwPageFrame*>(pLastPageInCurrentRow->GetPrev());
|
|
|
|
// check how many times the last page would still fit into the remaining space:
|
|
sal_uInt16 nNumberOfVirtualPages = 0;
|
|
const sal_uInt16 nMaxNumberOfVirtualPages = mnColumns > 0 ? mnColumns - nNumberOfPagesInRow : USHRT_MAX;
|
|
SwTwips nRemain = nWidthRemain;
|
|
SwTwips nVirtualPagesWidth = 0;
|
|
SwTwips nLastPageWidth = pLastPageInCurrentRow->getFrameArea().Width() + nSidebarWidth;
|
|
|
|
while ( ( mnColumns > 0 || nRemain > 0 ) && nNumberOfVirtualPages < nMaxNumberOfVirtualPages )
|
|
{
|
|
SwTwips nLastPageWidthWithGap = nLastPageWidth;
|
|
if ( !mbBookMode || ( 0 == (nNumberOfVirtualPages + nNumberOfPagesInRow) %2) )
|
|
nLastPageWidthWithGap += nGapBetweenPages;
|
|
|
|
if ( mnColumns > 0 || nLastPageWidthWithGap < nRemain )
|
|
{
|
|
++nNumberOfVirtualPages;
|
|
nVirtualPagesWidth += nLastPageWidthWithGap;
|
|
}
|
|
nRemain = nRemain - nLastPageWidthWithGap;
|
|
}
|
|
|
|
nCurrentRowWidth = nCurrentRowWidth + nVirtualPagesWidth;
|
|
}
|
|
|
|
// first page in book mode is always special:
|
|
if ( bFirstRow && mbBookMode )
|
|
{
|
|
// #i88036#
|
|
nCurrentRowWidth +=
|
|
pStartOfRow->GetFormatPage().getFrameArea().Width() + nSidebarWidth;
|
|
}
|
|
|
|
// center page if possible
|
|
tools::Long nSizeDiff = 0;
|
|
if (nVisWidth > nCurrentRowWidth && !comphelper::LibreOfficeKit::isActive())
|
|
nSizeDiff = ( nVisWidth - nCurrentRowWidth ) / 2;
|
|
|
|
// adjust positions of pages in current row
|
|
tools::Long nX = nSizeDiff;
|
|
|
|
const tools::Long nRowStart = nBorder + nSizeDiff;
|
|
const tools::Long nRowEnd = nRowStart + nCurrentRowWidth;
|
|
|
|
if ( bFirstRow && mbBookMode )
|
|
{
|
|
// #i88036#
|
|
nX += pStartOfRow->GetFormatPage().getFrameArea().Width() + nSidebarWidth;
|
|
}
|
|
|
|
SwPageFrame* pEndOfRow = pPageFrame;
|
|
SwPageFrame* pPageToAdjust = pStartOfRow;
|
|
|
|
do
|
|
{
|
|
const SwPageFrame* pFormatPage = pPageToAdjust;
|
|
if ( mbBookMode )
|
|
pFormatPage = &pPageToAdjust->GetFormatPage();
|
|
|
|
const SwTwips nCurrentPageWidth = pFormatPage->getFrameArea().Width() + (pFormatPage->IsEmptyPage() ? 0 : nSidebarWidth);
|
|
const Point aOldPagePos = pPageToAdjust->getFrameArea().Pos();
|
|
const bool bLeftSidebar = pPageToAdjust->SidebarPosition() == sw::sidebarwindows::SidebarPosition::LEFT;
|
|
const SwTwips nLeftPageAddOffset = bLeftSidebar ?
|
|
nSidebarWidth :
|
|
0;
|
|
|
|
Point aNewPagePos( nBorder + nX, nBorder + nSumRowHeight );
|
|
Point aNewPagePosWithLeftOffset( nBorder + nX + nLeftPageAddOffset, nBorder + nSumRowHeight );
|
|
|
|
// RTL view layout: Calculate mirrored page position
|
|
if ( bRTL )
|
|
{
|
|
const tools::Long nXOffsetInRow = aNewPagePos.getX() - nRowStart;
|
|
aNewPagePos.setX(nRowEnd - nXOffsetInRow - nCurrentPageWidth);
|
|
aNewPagePosWithLeftOffset = aNewPagePos;
|
|
aNewPagePosWithLeftOffset.setX(aNewPagePosWithLeftOffset.getX() + nLeftPageAddOffset);
|
|
}
|
|
|
|
if ( aNewPagePosWithLeftOffset != aOldPagePos )
|
|
{
|
|
lcl_MoveAllLowers( pPageToAdjust, aNewPagePosWithLeftOffset - aOldPagePos );
|
|
pPageToAdjust->SetCompletePaint();
|
|
bPageChanged = true;
|
|
}
|
|
|
|
// calculate area covered by the current page and store to
|
|
// maPageRects. This is used e.g., for cursor setting
|
|
const bool bFirstColumn = pPageToAdjust == pStartOfRow;
|
|
const bool bLastColumn = pPageToAdjust->GetNext() == pEndOfRow;
|
|
const bool bLastRow = !pEndOfRow;
|
|
|
|
nMinPageLeft = std::min( nMinPageLeft, SwTwips(aNewPagePos.getX()) );
|
|
nMaxPageRight = std::max( nMaxPageRight, SwTwips(aNewPagePos.getX() + nCurrentPageWidth));
|
|
|
|
// border of nGapBetweenPages around the current page:
|
|
SwRect aPageRectWithBorders( aNewPagePos.getX() - nGapBetweenPages,
|
|
aNewPagePos.getY(),
|
|
pPageToAdjust->getFrameArea().SSize().Width() + nGapBetweenPages + nSidebarWidth,
|
|
nCurrentRowHeight );
|
|
|
|
static const tools::Long nOuterClickDiff = 1000000;
|
|
|
|
// adjust borders for these special cases:
|
|
if ( (bFirstColumn && !bRTL) || (bLastColumn && bRTL) )
|
|
aPageRectWithBorders.SubLeft( nOuterClickDiff );
|
|
if ( (bLastColumn && !bRTL) || (bFirstColumn && bRTL) )
|
|
aPageRectWithBorders.AddRight( nOuterClickDiff );
|
|
if ( bFirstRow )
|
|
aPageRectWithBorders.SubTop( nOuterClickDiff );
|
|
if ( bLastRow )
|
|
aPageRectWithBorders.AddBottom( nOuterClickDiff );
|
|
|
|
maPageRects.push_back( aPageRectWithBorders );
|
|
|
|
nX = nX + nCurrentPageWidth;
|
|
pPageToAdjust = static_cast<SwPageFrame*>(pPageToAdjust->GetNext());
|
|
|
|
// distance to next page
|
|
if ( pPageToAdjust && pPageToAdjust != pEndOfRow )
|
|
{
|
|
// in book view, we add the x gap before left (even) pages:
|
|
if ( mbBookMode )
|
|
{
|
|
if ( 0 == (pPageToAdjust->GetPhyPageNum()%2) )
|
|
nX = nX + nGapBetweenPages;
|
|
}
|
|
else
|
|
{
|
|
// in non-book view, don't add x gap before
|
|
// 1. the last empty page in a row
|
|
// 2. after an empty page
|
|
const bool bDontAddGap = ( pPageToAdjust->IsEmptyPage() && pPageToAdjust->GetNext() == pEndOfRow ) ||
|
|
( static_cast<SwPageFrame*>(pPageToAdjust->GetPrev())->IsEmptyPage() );
|
|
|
|
if ( !bDontAddGap )
|
|
nX = nX + nGapBetweenPages;
|
|
}
|
|
}
|
|
}
|
|
while (pPageToAdjust && pPageToAdjust != pEndOfRow);
|
|
|
|
// adjust values for root frame size
|
|
nSumRowHeight = nSumRowHeight + nCurrentRowHeight;
|
|
|
|
// start new row:
|
|
nCurrentRowHeight = 0;
|
|
nCurrentRowWidth = 0;
|
|
pStartOfRow = pEndOfRow;
|
|
nWidthRemain = nVisWidth;
|
|
nNumberOfPagesInRow = 0;
|
|
bFirstRow = false;
|
|
} // end row finished
|
|
} // end while
|
|
|
|
// set size of root frame:
|
|
const Size aOldSize( getFrameArea().SSize() );
|
|
const Size aNewSize( nMaxPageRight - nBorder, nSumRowHeight - nGapBetweenPages );
|
|
|
|
if ( bPageChanged || aNewSize != aOldSize )
|
|
{
|
|
ChgSize( aNewSize );
|
|
::AdjustSizeChgNotify( this );
|
|
Calc(pRenderContext);
|
|
|
|
if ( pSh && pSh->GetDoc()->GetDocShell() )
|
|
{
|
|
pSh->SetFirstVisPageInvalid();
|
|
if (bOldCallbackActionEnabled)
|
|
{
|
|
pSh->InvalidateWindows( SwRect( 0, 0, SAL_MAX_INT32, SAL_MAX_INT32 ) );
|
|
pSh->GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
|
|
}
|
|
}
|
|
}
|
|
|
|
maPagesArea.Pos( getFrameArea().Pos() );
|
|
maPagesArea.SSize( aNewSize );
|
|
if ( TWIPS_MAX != nMinPageLeft )
|
|
maPagesArea.Left_( nMinPageLeft );
|
|
|
|
SetCallbackActionEnabled( bOldCallbackActionEnabled );
|
|
}
|
|
|
|
bool SwRootFrame::IsLeftToRightViewLayout() const
|
|
{
|
|
// Layout direction determined by layout direction of the first page.
|
|
// #i88036#
|
|
// Only ask a non-empty page frame for its layout direction
|
|
assert(dynamic_cast<const SwPageFrame *>(Lower()) != nullptr);
|
|
const SwPageFrame& rPage = static_cast<const SwPageFrame&>(*Lower()).GetFormatPage();
|
|
return !rPage.IsRightToLeft() && !rPage.IsVertical();
|
|
}
|
|
|
|
const SwPageFrame& SwPageFrame::GetFormatPage() const
|
|
{
|
|
const SwPageFrame* pRet = this;
|
|
if ( IsEmptyPage() )
|
|
{
|
|
pRet = static_cast<const SwPageFrame*>( OnRightPage() ? GetNext() : GetPrev() );
|
|
// #i88035#
|
|
// Typically a right empty page frame has a next non-empty page frame and
|
|
// a left empty page frame has a previous non-empty page frame.
|
|
// But under certain circumstances this assumption is not true -
|
|
// e.g. during insertion of a left page at the end of the document right
|
|
// after a left page in an intermediate state a right empty page does not
|
|
// have a next page frame.
|
|
if ( pRet == nullptr )
|
|
{
|
|
if ( OnRightPage() )
|
|
{
|
|
pRet = static_cast<const SwPageFrame*>( GetPrev() );
|
|
}
|
|
else
|
|
{
|
|
pRet = static_cast<const SwPageFrame*>( GetNext() );
|
|
}
|
|
}
|
|
assert(pRet &&
|
|
"<SwPageFrame::GetFormatPage()> - inconsistent layout: empty page without previous and next page frame --> crash.");
|
|
}
|
|
return *pRet;
|
|
}
|
|
|
|
bool SwPageFrame::IsOverHeaderFooterArea( const Point& rPt, FrameControlType &rControl ) const
|
|
{
|
|
tools::Long nUpperLimit = 0;
|
|
tools::Long nLowerLimit = 0;
|
|
const SwFrame* pFrame = Lower();
|
|
while ( pFrame )
|
|
{
|
|
if ( pFrame->IsBodyFrame() )
|
|
{
|
|
nUpperLimit = pFrame->getFrameArea().Top();
|
|
nLowerLimit = pFrame->getFrameArea().Bottom();
|
|
}
|
|
else if ( pFrame->IsFootnoteContFrame() )
|
|
nLowerLimit = pFrame->getFrameArea().Bottom();
|
|
|
|
pFrame = pFrame->GetNext();
|
|
}
|
|
|
|
SwRect aHeaderArea( getFrameArea().TopLeft(),
|
|
Size( getFrameArea().Width(), nUpperLimit - getFrameArea().Top() ) );
|
|
|
|
SwViewShell* pViewShell = getRootFrame()->GetCurrShell();
|
|
const bool bHideWhitespaceMode = pViewShell->GetViewOptions()->IsHideWhitespaceMode();
|
|
if ( aHeaderArea.Contains( rPt ) )
|
|
{
|
|
if (!bHideWhitespaceMode || static_cast<const SwFrameFormat*>(GetDep())->GetHeader().IsActive())
|
|
{
|
|
rControl = FrameControlType::Header;
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SwRect aFooterArea( Point( getFrameArea().Left(), nLowerLimit ),
|
|
Size( getFrameArea().Width(), getFrameArea().Bottom() - nLowerLimit ) );
|
|
|
|
if ( aFooterArea.Contains( rPt ) &&
|
|
(!bHideWhitespaceMode || static_cast<const SwFrameFormat*>(GetDep())->GetFooter().IsActive()) )
|
|
{
|
|
rControl = FrameControlType::Footer;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SwPageFrame::CheckPageHeightValidForHideWhitespace(SwTwips nDiff)
|
|
{
|
|
SwViewShell* pShell = getRootFrame()->GetCurrShell();
|
|
if (pShell && pShell->GetViewOptions()->IsWhitespaceHidden())
|
|
{
|
|
// When whitespace is hidden, the page frame has two heights: the
|
|
// nominal (defined by the frame format), and the actual (which is
|
|
// at most the nominal height, but can be smaller in case there is
|
|
// no content for the whole page).
|
|
// The layout size is the actual one, but we want to move the
|
|
// content frame to a new page only in case it doesn't fit the
|
|
// nominal size.
|
|
if (nDiff < 0)
|
|
{
|
|
// Content frame doesn't fit the actual size, check if it fits the nominal one.
|
|
const SwFrameFormat* pPageFormat = static_cast<const SwFrameFormat*>(GetDep());
|
|
const Size& rPageSize = pPageFormat->GetFrameSize().GetSize();
|
|
// Count what would be the max size for the body frame, ignoring top/bottom margin.
|
|
const SvxULSpaceItem& rULSpace = pPageFormat->GetULSpace();
|
|
SwTwips nNominalHeight = rPageSize.getHeight() - rULSpace.GetUpper() - rULSpace.GetLower();
|
|
tools::Long nWhitespace = nNominalHeight - getFrameArea().Height();
|
|
if (nWhitespace > -nDiff)
|
|
{
|
|
// It does: don't move it and invalidate our page frame so
|
|
// that it gets a larger height.
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const SwHeaderFrame* SwPageFrame::GetHeaderFrame() const
|
|
{
|
|
const SwFrame* pLowerFrame = Lower();
|
|
while (pLowerFrame)
|
|
{
|
|
if (pLowerFrame->IsHeaderFrame())
|
|
return dynamic_cast<const SwHeaderFrame*>(pLowerFrame);
|
|
pLowerFrame = pLowerFrame->GetNext();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const SwFooterFrame* SwPageFrame::GetFooterFrame() const
|
|
{
|
|
const SwFrame* pLowerFrame = Lower();
|
|
while (pLowerFrame)
|
|
{
|
|
if (pLowerFrame->IsFooterFrame())
|
|
return dynamic_cast<const SwFooterFrame*>(pLowerFrame);
|
|
pLowerFrame = pLowerFrame->GetNext();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void SwPageFrame::UpdateVirtPageNumInfo(sw::VirtPageNumHint& rHint, const SwFrame* pFrame) const
|
|
{
|
|
assert(!rHint.IsFound());
|
|
if(this == rHint.GetOrigPage() && !pFrame->GetPrev())
|
|
{
|
|
// Should be the one (can temporarily be different, should we be concerned about this possibility?)
|
|
rHint.SetFound();
|
|
rHint.SetInfo(this, pFrame);
|
|
}
|
|
if(GetPhyPageNum() < rHint.GetOrigPage()->GetPhyPageNum() &&
|
|
(!rHint.GetPage() || GetPhyPageNum() > rHint.GetPage()->GetPhyPageNum()))
|
|
{
|
|
// This could be the one.
|
|
rHint.SetInfo(this, pFrame);
|
|
}
|
|
}
|
|
|
|
void SwPageFrame::dumpAsXml(xmlTextWriterPtr writer) const
|
|
{
|
|
(void)xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("page"));
|
|
dumpAsXmlAttributes(writer);
|
|
|
|
(void)xmlTextWriterStartElement(writer, BAD_CAST("page_status"));
|
|
(void)xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidFlyLayout"), BAD_CAST(OString::boolean(!IsInvalidFlyLayout()).getStr()));
|
|
(void)xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidFlyContent"), BAD_CAST(OString::boolean(!IsInvalidFlyContent()).getStr()));
|
|
(void)xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidFlyInCnt"), BAD_CAST(OString::boolean(!IsInvalidFlyInCnt()).getStr()));
|
|
(void)xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidLayout"), BAD_CAST(OString::boolean(!IsInvalidLayout()).getStr()));
|
|
(void)xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidContent"), BAD_CAST(OString::boolean(!IsInvalidContent()).getStr()));
|
|
(void)xmlTextWriterEndElement(writer);
|
|
(void)xmlTextWriterStartElement(writer, BAD_CAST("page_info"));
|
|
(void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("phyNum"), "%d", GetPhyPageNum());
|
|
(void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("virtNum"), "%d", GetVirtPageNum());
|
|
OUString aFormatName = GetPageDesc()->GetName();
|
|
(void)xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("pageDesc"), "%s", BAD_CAST(OUStringToOString(aFormatName, RTL_TEXTENCODING_UTF8).getStr()));
|
|
(void)xmlTextWriterEndElement(writer);
|
|
if (auto const* pObjs = GetSortedObjs())
|
|
{
|
|
(void)xmlTextWriterStartElement(writer, BAD_CAST("sorted_objs"));
|
|
for (SwAnchoredObject const*const pObj : *pObjs)
|
|
{ // just print pointer, full details will be printed on its anchor frame
|
|
// this nonsense is needed because of multiple inheritance
|
|
if (SwFlyFrame const* pFly = pObj->DynCastFlyFrame())
|
|
{
|
|
(void)xmlTextWriterStartElement(writer, BAD_CAST("fly"));
|
|
(void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("ptr"), "%p", pFly);
|
|
}
|
|
else
|
|
{
|
|
(void)xmlTextWriterStartElement(writer, BAD_CAST(pObj->getElementName()));
|
|
(void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("ptr"), "%p", pObj);
|
|
}
|
|
(void)xmlTextWriterEndElement(writer);
|
|
}
|
|
(void)xmlTextWriterEndElement(writer);
|
|
}
|
|
|
|
(void)xmlTextWriterStartElement(writer, BAD_CAST("infos"));
|
|
dumpInfosAsXml(writer);
|
|
(void)xmlTextWriterEndElement(writer);
|
|
const SwSortedObjs* pAnchored = GetDrawObjs();
|
|
if ( pAnchored && pAnchored->size() > 0 )
|
|
{
|
|
(void)xmlTextWriterStartElement( writer, BAD_CAST( "anchored" ) );
|
|
|
|
for (SwAnchoredObject* pObject : *pAnchored)
|
|
{
|
|
pObject->dumpAsXml( writer );
|
|
}
|
|
|
|
(void)xmlTextWriterEndElement( writer );
|
|
}
|
|
dumpChildrenAsXml(writer);
|
|
(void)xmlTextWriterEndElement(writer);
|
|
}
|
|
|
|
SwTextGridItem const* GetGridItem(SwPageFrame const*const pPage)
|
|
{
|
|
if (pPage && pPage->HasGrid())
|
|
{
|
|
SwTextGridItem const& rGridItem(
|
|
pPage->GetPageDesc()->GetMaster().GetTextGrid());
|
|
if (GRID_NONE != rGridItem.GetGridType())
|
|
{
|
|
return &rGridItem;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
sal_uInt16 GetGridWidth(SwTextGridItem const& rG, SwDoc const& rDoc)
|
|
{
|
|
return (rDoc.IsSquaredPageMode()) ? rG.GetBaseHeight() : rG.GetBaseWidth();
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|