blob: daf25238c0b60ac0664c1474f7504a9fd864f453 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <com/sun/star/embed/EmbedStates.hpp>
#include <ndole.hxx>
#include <docary.hxx>
#include <svl/itemiter.hxx>
#include <fmtfsize.hxx>
#include <fmthdft.hxx>
#include <fmtclds.hxx>
#include <fmtanchr.hxx>
#include <fmtpdsc.hxx>
#include <fmtfordr.hxx>
#include <fmtfld.hxx>
#include <fmtornt.hxx>
#include <fmtsrnd.hxx>
#include <ftninfo.hxx>
#include <tgrditem.hxx>
#include <viewopt.hxx>
#include <docsh.hxx>
#include "viewimp.hxx"
#include "viewopt.hxx"
#include "pagefrm.hxx"
#include "rootfrm.hxx"
#include "cntfrm.hxx"
#include "flyfrm.hxx"
#include "doc.hxx"
#include "fesh.hxx"
#include "dview.hxx"
#include "dflyobj.hxx"
#include "dcontact.hxx"
#include "frmtool.hxx"
#include "fldbas.hxx"
#include "hints.hxx"
#include "errhdl.hxx"
#include "swtable.hxx"
#include "ftnidx.hxx"
#include "bodyfrm.hxx"
#include "ftnfrm.hxx"
#include "tabfrm.hxx"
#include "txtfrm.hxx"
#include "layact.hxx"
#include "flyfrms.hxx"
#include "htmltbl.hxx"
#include "pagedesc.hxx"
#include "poolfmt.hxx"
#include <editeng/frmdiritem.hxx>
#include <swfntcch.hxx> // SwFontAccess
#include <sortedobjs.hxx>
#include <switerator.hxx>
#include <vcl/svapp.hxx>
using namespace ::com::sun::star;
/*************************************************************************
|*
|* SwBodyFrm::SwBodyFrm()
|*
|* Ersterstellung MA ??
|* Letzte Aenderung MA 01. Aug. 93
|*
|*************************************************************************/
SwBodyFrm::SwBodyFrm( SwFrmFmt *pFmt, SwFrm* pSib ):
SwLayoutFrm( pFmt, pSib )
{
nType = FRMC_BODY;
}
/*************************************************************************
|*
|* SwBodyFrm::Format()
|*
|* Ersterstellung MA 30. May. 94
|* Letzte Aenderung MA 20. Jan. 99
|*
|*************************************************************************/
void SwBodyFrm::Format( const SwBorderAttrs * )
{
//Formatieren des Body ist zu einfach, deshalb bekommt er ein eigenes
//Format; Umrandungen und dergl. sind hier nicht zu beruecksichtigen.
//Breite ist die der PrtArea des Uppers, Hoehe ist die Hoehe der PrtArea
//des Uppers abzueglich der Nachbarn (Wird eigentlich eingestellt aber
//Vorsicht ist die Mutter der Robustheit).
//Die PrtArea ist stets so gross wie der Frm itself.
if ( !bValidSize )
{
SwTwips nHeight = GetUpper()->Prt().Height();
SwTwips nWidth = GetUpper()->Prt().Width();
const SwFrm *pFrm = GetUpper()->Lower();
do
{
if ( pFrm != this )
{
if( pFrm->IsVertical() )
nWidth -= pFrm->Frm().Width();
else
nHeight -= pFrm->Frm().Height();
}
pFrm = pFrm->GetNext();
} while ( pFrm );
if ( nHeight < 0 )
nHeight = 0;
Frm().Height( nHeight );
//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
if( IsVertical() && !IsVertLR() && !IsReverse() && nWidth != Frm().Width() )
Frm().Pos().X() += Frm().Width() - nWidth;
Frm().Width( nWidth );
}
sal_Bool bNoGrid = sal_True;
if( GetUpper()->IsPageFrm() && ((SwPageFrm*)GetUpper())->HasGrid() )
{
GETGRID( ((SwPageFrm*)GetUpper()) )
if( pGrid )
{
bNoGrid = sal_False;
long nSum = pGrid->GetBaseHeight() + pGrid->GetRubyHeight();
SWRECTFN( this )
long nSize = (Frm().*fnRect->fnGetWidth)();
long nBorder = 0;
if( GRID_LINES_CHARS == pGrid->GetGridType() )
{
//for textgrid refactor
SwDoc *pDoc = GetFmt()->GetDoc();
nBorder = nSize % (GETGRIDWIDTH(pGrid, pDoc));
nSize -= nBorder;
nBorder /= 2;
}
(Prt().*fnRect->fnSetPosX)( nBorder );
(Prt().*fnRect->fnSetWidth)( nSize );
// Height of body frame:
nBorder = (Frm().*fnRect->fnGetHeight)();
// Number of possible lines in area of body frame:
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 = 0 == ((SwPageFrm*)GetUpper())->GetFmt()->GetDoc()->
GetFtnIdxs().Count();
(Prt().*fnRect->fnSetPosY)( bAdjust ? nBorder : 0 );
(Prt().*fnRect->fnSetHeight)( nSize );
}
}
if( bNoGrid )
{
Prt().Pos().X() = Prt().Pos().Y() = 0;
Prt().Height( Frm().Height() );
Prt().Width( Frm().Width() );
}
bValidSize = bValidPrtArea = sal_True;
}
/*************************************************************************
|*
|* SwPageFrm::SwPageFrm(), ~SwPageFrm()
|*
|* Ersterstellung MA 20. Oct. 92
|* Letzte Aenderung MA 08. Dec. 97
|*
|*************************************************************************/
SwPageFrm::SwPageFrm( SwFrmFmt *pFmt, SwFrm* pSib, SwPageDesc *pPgDsc ) :
SwFtnBossFrm( pFmt, pSib ),
pSortedObjs( 0 ),
pDesc( pPgDsc ),
nPhyPageNum( 0 ),
// OD 2004-05-17 #i28701#
mbLayoutInProgress( false )
{
SetDerivedVert( sal_False );
SetDerivedR2L( sal_False );
if( pDesc )
{
bHasGrid = sal_True;
GETGRID( this )
if( !pGrid )
bHasGrid = sal_False;
}
else
bHasGrid = sal_False;
SetMaxFtnHeight( pPgDsc->GetFtnInfo().GetHeight() ?
pPgDsc->GetFtnInfo().GetHeight() : LONG_MAX ),
nType = FRMC_PAGE;
bInvalidLayout = bInvalidCntnt = bInvalidSpelling = bInvalidSmartTags = bInvalidAutoCmplWrds = bInvalidWordCount = sal_True;
bInvalidFlyLayout = bInvalidFlyCntnt = bInvalidFlyInCnt = bFtnPage = bEndNotePage = sal_False;
ViewShell *pSh = getRootFrm()->GetCurrShell();
const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
if ( bBrowseMode )
{
Frm().Height( 0 );
long nWidth = pSh->VisArea().Width();
if ( !nWidth )
nWidth = 5000L; //aendert sich sowieso
Frm().Width ( nWidth );
}
else
Frm().SSize( pFmt->GetFrmSize().GetSize() );
//Body-Bereich erzeugen und einsetzen, aber nur wenn ich nicht gerade
//eine Leerseite bin.
SwDoc *pDoc = pFmt->GetDoc();
if ( sal_False == (bEmptyPage = pFmt == pDoc->GetEmptyPageFmt()) )
{
bEmptyPage = sal_False;
Calc(); //Damit die PrtArea stimmt.
SwBodyFrm *pBodyFrm = new SwBodyFrm( pDoc->GetDfltFrmFmt(), this );
pBodyFrm->ChgSize( Prt().SSize() );
pBodyFrm->Paste( this );
pBodyFrm->Calc(); //Damit die Spalten korrekt
//eingesetzt werden koennen.
pBodyFrm->InvalidatePos();
if ( bBrowseMode )
_InvalidateSize(); //Alles nur gelogen
//Header/Footer einsetzen, nur rufen wenn aktiv.
if ( pFmt->GetHeader().IsActive() )
PrepareHeader();
if ( pFmt->GetFooter().IsActive() )
PrepareFooter();
const SwFmtCol &rCol = pFmt->GetCol();
if ( rCol.GetNumCols() > 1 )
{
const SwFmtCol aOld; //ChgColumns() verlaesst sich darauf, dass ein
//Old-Wert hereingereicht wird.
pBodyFrm->ChgColumns( aOld, rCol );
}
}
}
SwPageFrm::~SwPageFrm()
{
//FlyContainer entleeren, delete der Flys uebernimmt der Anchor
//(Basisklasse SwFrm)
if ( pSortedObjs )
{
//Objekte koennen (warum auch immer) auch an Seiten verankert sein,
//die vor Ihren Ankern stehen. Dann wuerde auf bereits freigegebenen
//Speicher zugegriffen.
for ( sal_uInt16 i = 0; i < pSortedObjs->Count(); ++i )
{
SwAnchoredObject* pAnchoredObj = (*pSortedObjs)[i];
pAnchoredObj->SetPageFrm( 0L );
}
delete pSortedObjs;
pSortedObjs = 0; //Auf 0 setzen, sonst rauchts beim Abmdelden von Flys!
}
//Damit der Zugriff auf zerstoerte Seiten verhindert werden kann.
if ( !IsEmptyPage() ) //#59184# sollte fuer Leerseiten unnoetig sein.
{
SwDoc *pDoc = GetFmt()->GetDoc();
if( pDoc && !pDoc->IsInDtor() )
{
ViewShell *pSh = getRootFrm()->GetCurrShell();
if ( pSh )
{
SwViewImp *pImp = pSh->Imp();
pImp->SetFirstVisPageInvalid();
if ( pImp->IsAction() )
pImp->GetLayAction().SetAgain();
// OD 12.02.2003 #i9719#, #105645# - retouche area of page
// including border and shadow area.
const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SIDEBAR_RIGHT);
SwRect aRetoucheRect;
SwPageFrm::GetBorderAndShadowBoundRect( Frm(), pSh, aRetoucheRect, bRightSidebar );
pSh->AddPaintRect( aRetoucheRect );
}
}
}
}
void SwPageFrm::CheckGrid( sal_Bool bInvalidate )
{
sal_Bool bOld = bHasGrid;
bHasGrid = sal_True;
GETGRID( this )
bHasGrid = 0 != pGrid;
if( bInvalidate || bOld != bHasGrid )
{
SwLayoutFrm* pBody = FindBodyCont();
if( pBody )
{
pBody->InvalidatePrt();
SwCntntFrm* pFrm = pBody->ContainsCntnt();
while( pBody->IsAnLower( pFrm ) )
{
((SwTxtFrm*)pFrm)->Prepare( PREP_CLEAR );
pFrm = pFrm->GetNextCntntFrm();
}
}
SetCompletePaint();
}
}
void SwPageFrm::CheckDirection( sal_Bool bVert )
{
sal_uInt16 nDir =
((SvxFrameDirectionItem&)GetFmt()->GetFmtAttr( RES_FRAMEDIR )).GetValue();
if( bVert )
{
if( FRMDIR_HORI_LEFT_TOP == nDir || FRMDIR_HORI_RIGHT_TOP == nDir )
{
//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
bVertLR = 0;
bVertical = 0;
}
else
{
const ViewShell *pSh = getRootFrm()->GetCurrShell();
if( pSh && pSh->GetViewOptions()->getBrowseMode() )
{
//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
bVertLR = 0;
bVertical = 0;
}
else
{
bVertical = 1;
//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
if(FRMDIR_VERT_TOP_RIGHT == nDir)
bVertLR = 0;
else if(FRMDIR_VERT_TOP_LEFT==nDir)
bVertLR = 1;
}
}
bReverse = 0;
bInvalidVert = 0;
}
else
{
if( FRMDIR_HORI_RIGHT_TOP == nDir )
bRightToLeft = 1;
else
bRightToLeft = 0;
bInvalidR2L = 0;
}
}
/*************************************************************************
|*
|* SwPageFrm::PreparePage()
|*
|* Beschreibung Erzeugt die Spezifischen Flys zur Seite und formatiert
|* generischen Cntnt
|* Ersterstellung MA 20. Oct. 92
|* Letzte Aenderung MA 09. Nov. 95
|*
|*************************************************************************/
void MA_FASTCALL lcl_FormatLay( SwLayoutFrm *pLay )
{
//Alle LayoutFrms - nicht aber Tables, Flys o.ae. - formatieren.
SwFrm *pTmp = pLay->Lower();
//Erst die untergeordneten
while ( pTmp )
{
if ( pTmp->GetType() & 0x00FF )
::lcl_FormatLay( (SwLayoutFrm*)pTmp );
pTmp = pTmp->GetNext();
}
pLay->Calc();
}
void MA_FASTCALL lcl_MakeObjs( const SwSpzFrmFmts &rTbl, SwPageFrm *pPage )
{
//Anlegen bzw. registrieren von Flys und Drawobjekten.
//Die Formate stehen in der SpzTbl (vom Dokument).
//Flys werden angelegt, DrawObjekte werden bei der Seite angemeldet.
for ( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
{
SdrObject *pSdrObj;
SwFrmFmt *pFmt = rTbl[i];
const SwFmtAnchor &rAnch = pFmt->GetAnchor();
if ( rAnch.GetPageNum() == pPage->GetPhyPageNum() )
{
if( rAnch.GetCntntAnchor() )
{
if (FLY_AT_PAGE == rAnch.GetAnchorId())
{
SwFmtAnchor aAnch( rAnch );
aAnch.SetAnchor( 0 );
pFmt->SetFmtAttr( aAnch );
}
else
continue;
}
//Wird ein Rahmen oder ein SdrObject beschrieben?
sal_Bool bSdrObj = RES_DRAWFRMFMT == pFmt->Which();
pSdrObj = 0;
if ( bSdrObj && 0 == (pSdrObj = pFmt->FindSdrObject()) )
{
ASSERT( sal_False, "DrawObject not found." );
pFmt->GetDoc()->DelFrmFmt( pFmt );
--i;
continue;
}
//Das Objekt kann noch an einer anderen Seite verankert sein.
//Z.B. beim Einfuegen einer neuen Seite aufgrund eines
//Pagedescriptor-Wechsels. Das Objekt muss dann umgehaengt
//werden.
//Fuer bestimmte Faelle ist das Objekt bereits an der richtigen
//Seite verankert. Das wird hier automatisch erledigt und braucht
//- wenngleich performater machbar - nicht extra codiert werden.
SwPageFrm *pPg = pPage->IsEmptyPage() ? (SwPageFrm*)pPage->GetNext() : pPage;
if ( bSdrObj )
{
// OD 23.06.2003 #108784# - consider 'virtual' drawing objects
SwDrawContact *pContact =
static_cast<SwDrawContact*>(::GetUserCall(pSdrObj));
if ( pSdrObj->ISA(SwDrawVirtObj) )
{
SwDrawVirtObj* pDrawVirtObj = static_cast<SwDrawVirtObj*>(pSdrObj);
if ( pContact )
{
pDrawVirtObj->RemoveFromWriterLayout();
pDrawVirtObj->RemoveFromDrawingPage();
pPg->AppendDrawObj( *(pContact->GetAnchoredObj( pDrawVirtObj )) );
}
}
else
{
if ( pContact->GetAnchorFrm() )
pContact->DisconnectFromLayout( false );
pPg->AppendDrawObj( *(pContact->GetAnchoredObj( pSdrObj )) );
}
}
else
{
SwIterator<SwFlyFrm,SwFmt> aIter( *pFmt );
SwFlyFrm *pFly = aIter.First();
if ( pFly)
{
if( pFly->GetAnchorFrm() )
pFly->AnchorFrm()->RemoveFly( pFly );
}
else
pFly = new SwFlyLayFrm( (SwFlyFrmFmt*)pFmt, pPg, pPg );
pPg->AppendFly( pFly );
::RegistFlys( pPg, pFly );
}
}
}
}
void SwPageFrm::PreparePage( sal_Bool bFtn )
{
SetFtnPage( bFtn );
// --> OD 2008-01-30 #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 <SwPageFrm> instance.
// Thus, first calling <::RegistFlys(..)>, then call <::lcl_FormatLay(..)>
::RegistFlys( this, this );
if ( Lower() )
{
::lcl_FormatLay( this );
}
// <--
//Flys und DrawObjekte die noch am Dokument bereitstehen.
//Fussnotenseiten tragen keine Seitengebundenen Flys!
//Es kann Flys und Objekte geben, die auf Leerseiten (Seitennummernmaessig)
//stehen wollen, diese werden jedoch von den Leerseiten ignoriert;
//sie werden von den Folgeseiten aufgenommen.
if ( !bFtn && !IsEmptyPage() )
{
SwDoc *pDoc = GetFmt()->GetDoc();
if ( GetPrev() && ((SwPageFrm*)GetPrev())->IsEmptyPage() )
lcl_MakeObjs( *pDoc->GetSpzFrmFmts(), (SwPageFrm*)GetPrev() );
lcl_MakeObjs( *pDoc->GetSpzFrmFmts(), this );
//Kopf-/Fusszeilen) formatieren.
SwLayoutFrm *pLow = (SwLayoutFrm*)Lower();
while ( pLow )
{
if ( pLow->GetType() & (FRMTYPE_HEADER|FRMTYPE_FOOTER) )
{
SwCntntFrm *pCntnt = pLow->ContainsCntnt();
while ( pCntnt && pLow->IsAnLower( pCntnt ) )
{
pCntnt->OptCalc(); //Nicht die Vorgaenger
pCntnt = pCntnt->GetNextCntntFrm();
}
}
pLow = (SwLayoutFrm*)pLow->GetNext();
}
}
}
/*************************************************************************
|*
|* SwPageFrm::Modify()
|*
|* Ersterstellung MA 20. Oct. 92
|* Letzte Aenderung MA 03. Mar. 96
|*
|*************************************************************************/
void SwPageFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
{
ViewShell *pSh = getRootFrm()->GetCurrShell();
if ( pSh )
pSh->SetFirstVisPageInvalid();
sal_uInt8 nInvFlags = 0;
if( pNew && RES_ATTRSET_CHG == pNew->Which() )
{
SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() );
SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() );
SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld );
SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew );
while( sal_True )
{
_UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(),
(SfxPoolItem*)aNIter.GetCurItem(), nInvFlags,
&aOldSet, &aNewSet );
if( aNIter.IsAtEnd() )
break;
aNIter.NextItem();
aOIter.NextItem();
}
if ( aOldSet.Count() || aNewSet.Count() )
SwLayoutFrm::Modify( &aOldSet, &aNewSet );
}
else
_UpdateAttr( pOld, pNew, nInvFlags );
if ( nInvFlags != 0 )
{
InvalidatePage( this );
if ( nInvFlags & 0x01 )
_InvalidatePrt();
if ( nInvFlags & 0x02 )
SetCompletePaint();
if ( nInvFlags & 0x04 && GetNext() )
GetNext()->InvalidatePos();
if ( nInvFlags & 0x08 )
PrepareHeader();
if ( nInvFlags & 0x10 )
PrepareFooter();
if ( nInvFlags & 0x20 )
CheckGrid( nInvFlags & 0x40 );
}
}
void SwPageFrm::_UpdateAttr( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
sal_uInt8 &rInvFlags,
SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
{
sal_Bool bClear = sal_True;
const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
switch( nWhich )
{
case RES_FMT_CHG:
{
//Wenn sich das FrmFmt aendert kann hier einiges passieren.
//Abgesehen von den Grossenverhaeltnissen sind noch andere
//Dinge betroffen.
//1. Spaltigkeit.
ASSERT( pOld && pNew, "FMT_CHG Missing Format." );
const SwFmt* pOldFmt = ((SwFmtChg*)pOld)->pChangedFmt;
const SwFmt* pNewFmt = ((SwFmtChg*)pNew)->pChangedFmt;
ASSERT( pOldFmt && pNewFmt, "FMT_CHG Missing Format." );
const SwFmtCol &rOldCol = pOldFmt->GetCol();
const SwFmtCol &rNewCol = pNewFmt->GetCol();
if( rOldCol != rNewCol )
{
SwLayoutFrm *pB = FindBodyCont();
ASSERT( pB, "Seite ohne Body." );
pB->ChgColumns( rOldCol, rNewCol );
rInvFlags |= 0x20;
}
//2. Kopf- und Fusszeilen.
const SwFmtHeader &rOldH = pOldFmt->GetHeader();
const SwFmtHeader &rNewH = pNewFmt->GetHeader();
if( rOldH != rNewH )
rInvFlags |= 0x08;
const SwFmtFooter &rOldF = pOldFmt->GetFooter();
const SwFmtFooter &rNewF = pNewFmt->GetFooter();
if( rOldF != rNewF )
rInvFlags |= 0x10;
CheckDirChange();
}
/* kein break hier */
case RES_FRM_SIZE:
{
const SwRect aOldPageFrmRect( Frm() );
ViewShell *pSh = getRootFrm()->GetCurrShell();
if( pSh && pSh->GetViewOptions()->getBrowseMode() )
{
bValidSize = sal_False;
// OD 28.10.2002 #97265# - Don't call <SwPageFrm::MakeAll()>
// Calculation of the page is not necessary, because its size is
// is invalidated here and further invalidation is done in the
// calling method <SwPageFrm::Modify(..)> and probably by calling
// <SwLayoutFrm::Modify(..)> at the end.
// It can also causes inconsistences, because the lowers are
// adjusted, but not calculated, and a <SwPageFrm::MakeAll()> of
// a next page is called. This is performed on the switch to the
// online layout.
//MakeAll();
}
else
{
const SwFmtFrmSize &rSz = nWhich == RES_FMT_CHG ?
((SwFmtChg*)pNew)->pChangedFmt->GetFrmSize() :
(const SwFmtFrmSize&)*pNew;
Frm().Height( Max( rSz.GetHeight(), long(MINLAY) ) );
Frm().Width ( Max( rSz.GetWidth(), long(MINLAY) ) );
// PAGES01
if ( GetUpper() )
static_cast<SwRootFrm*>(GetUpper())->CheckViewLayout( 0, 0 );
}
//Window aufraeumen.
if( pSh && pSh->GetWin() && aOldPageFrmRect.HasArea() )
{
// OD 12.02.2003 #i9719#, #105645# - consider border and shadow of
// page frame for determine 'old' rectangle - it's used for invalidating.
const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SIDEBAR_RIGHT);
SwRect aOldRectWithBorderAndShadow;
SwPageFrm::GetBorderAndShadowBoundRect( aOldPageFrmRect, pSh, aOldRectWithBorderAndShadow, bRightSidebar );
pSh->InvalidateWindows( aOldRectWithBorderAndShadow );
}
rInvFlags |= 0x03;
if ( aOldPageFrmRect.Height() != Frm().Height() )
rInvFlags |= 0x04;
}
break;
case RES_COL:
{
SwLayoutFrm *pB = FindBodyCont();
ASSERT( pB, "Seite ohne Body." );
pB->ChgColumns( *(const SwFmtCol*)pOld, *(const SwFmtCol*)pNew );
rInvFlags |= 0x22;
}
break;
case RES_HEADER:
rInvFlags |= 0x08;
break;
case RES_FOOTER:
rInvFlags |= 0x10;
break;
case RES_TEXTGRID:
rInvFlags |= 0x60;
break;
case RES_PAGEDESC_FTNINFO:
//Die derzeit einzig sichere Methode:
((SwRootFrm*)GetUpper())->SetSuperfluous();
SetMaxFtnHeight( pDesc->GetFtnInfo().GetHeight() );
if ( !GetMaxFtnHeight() )
SetMaxFtnHeight( LONG_MAX );
SetColMaxFtnHeight();
//Hier wird die Seite ggf. zerstoert!
((SwRootFrm*)GetUpper())->RemoveFtns( 0, sal_False, sal_True );
break;
case RES_FRAMEDIR :
CheckDirChange();
break;
default:
bClear = sal_False;
}
if ( bClear )
{
if ( pOldSet || pNewSet )
{
if ( pOldSet )
pOldSet->ClearItem( nWhich );
if ( pNewSet )
pNewSet->ClearItem( nWhich );
}
else
SwLayoutFrm::Modify( pOld, pNew );
}
}
/*************************************************************************
|*
|* SwPageFrm::GetInfo()
|*
|* Beschreibung erfragt Informationen
|* Ersterstellung JP 31.03.94
|* Letzte Aenderung JP 31.03.94
|*
*************************************************************************/
// erfrage vom Modify Informationen
sal_Bool SwPageFrm::GetInfo( SfxPoolItem & rInfo ) const
{
if( RES_AUTOFMT_DOCNODE == rInfo.Which() )
{
// es gibt einen PageFrm also wird er benutzt
return sal_False;
}
return sal_True; // weiter suchen
}
/*************************************************************************
|*
|* SwPageFrm::SetPageDesc()
|*
|* Ersterstellung MA 02. Nov. 94
|* Letzte Aenderung MA 02. Nov. 94
|*
|*************************************************************************/
void SwPageFrm::SetPageDesc( SwPageDesc *pNew, SwFrmFmt *pFmt )
{
pDesc = pNew;
if ( pFmt )
SetFrmFmt( pFmt );
}
/*************************************************************************
|*
|* SwPageFrm::FindPageDesc()
|*
|* Beschreibung Der richtige PageDesc wird bestimmt:
|* 0. Vom Dokument bei Fussnotenseiten und Endnotenseiten
|* 1. vom ersten BodyCntnt unterhalb der Seite.
|* 2. vom PageDesc der vorstehenden Seite.
|* 3. bei Leerseiten vom PageDesc der vorigen Seite.
|* 3.1 vom PageDesc der folgenden Seite wenn es keinen Vorgaenger gibt.
|* 4. es ist der Default-PageDesc sonst.
|* 5. Im BrowseMode ist der Pagedesc immer der vom ersten Absatz im
|* Dokument oder Standard (der 0-te) wenn der erste Absatz keinen
|* wuenscht.
|* (6. Im HTML-Mode ist der Pagedesc immer die HTML-Seitenvorlage.)
|* Ersterstellung MA 15. Feb. 93
|* Letzte Aenderung MA 17. Jun. 99
|*
|*************************************************************************/
SwPageDesc *SwPageFrm::FindPageDesc()
{
//0.
if ( IsFtnPage() )
{
SwDoc *pDoc = GetFmt()->GetDoc();
if ( IsEndNotePage() )
return pDoc->GetEndNoteInfo().GetPageDesc( *pDoc );
else
return pDoc->GetFtnInfo().GetPageDesc( *pDoc );
}
//6.
//if ( GetFmt()->GetDoc()->IsHTMLMode() )
// return GetFmt()->GetDoc()->GetPageDescFromPool( RES_POOLPAGE_HTML );
SwPageDesc *pRet = 0;
//5.
const ViewShell *pSh = getRootFrm()->GetCurrShell();
if( pSh && pSh->GetViewOptions()->getBrowseMode() )
{
SwCntntFrm *pFrm = GetUpper()->ContainsCntnt();
while ( !pFrm->IsInDocBody() )
pFrm = pFrm->GetNextCntntFrm();
SwFrm *pFlow = pFrm;
if ( pFlow->IsInTab() )
pFlow = pFlow->FindTabFrm();
pRet = (SwPageDesc*)pFlow->GetAttrSet()->GetPageDesc().GetPageDesc();
if ( !pRet )
pRet = &GetFmt()->GetDoc()->_GetPageDesc( 0 );
return pRet;
}
SwFrm *pFlow = FindFirstBodyCntnt();
if ( pFlow && pFlow->IsInTab() )
pFlow = pFlow->FindTabFrm();
//1.
if ( pFlow )
{
SwFlowFrm *pTmp = SwFlowFrm::CastFlowFrm( pFlow );
if ( !pTmp->IsFollow() )
pRet = (SwPageDesc*)pFlow->GetAttrSet()->GetPageDesc().GetPageDesc();
}
//3. und 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() ? ((SwPageFrm*)GetPrev())->GetPageDesc() :
GetNext() ? ((SwPageFrm*)GetNext())->GetPageDesc() : 0;
//2.
if ( !pRet )
pRet = GetPrev() ?
((SwPageFrm*)GetPrev())->GetPageDesc()->GetFollow() : 0;
//4.
if ( !pRet )
pRet = (SwPageDesc*)&(const_cast<const SwDoc *>(GetFmt()->GetDoc())
->GetPageDesc( 0 ));
ASSERT( pRet, "Kein Descriptor gefunden." );
return pRet;
}
//Wenn der RootFrm seine Groesse aendert muss benachrichtigt werden.
void AdjustSizeChgNotify( SwRootFrm *pRoot )
{
const sal_Bool bOld = pRoot->IsSuperfluous();
pRoot->bCheckSuperfluous = sal_False;
ViewShell *pSh = pRoot->GetCurrShell();
if ( pSh )
{
do
{
if( pRoot == pSh->GetLayout() )
{
pSh->SizeChgNotify();
pSh->Imp()->NotifySizeChg( pRoot->Frm().SSize() );
}
pSh = (ViewShell*)pSh->GetNext();
} while ( pSh != pRoot->GetCurrShell() );
}
pRoot->bCheckSuperfluous = bOld;
}
inline void SetLastPage( SwPageFrm *pPage )
{
((SwRootFrm*)pPage->GetUpper())->pLastPage = pPage;
}
/*************************************************************************
|*
|* SwPageFrm::Cut()
|*
|* Ersterstellung MA 23. Feb. 94
|* Letzte Aenderung MA 22. Jun. 95
|*
|*************************************************************************/
void SwPageFrm::Cut()
{
// PAGES01
//AdjustRootSize( CHG_CUTPAGE, 0 );
ViewShell *pSh = getRootFrm()->GetCurrShell();
if ( !IsEmptyPage() )
{
if ( GetNext() )
GetNext()->InvalidatePos();
//Flys deren Anker auf anderen Seiten stehen umhaengen.
//DrawObjecte spielen hier keine Rolle.
if ( GetSortedObjs() )
{
for ( int i = 0; GetSortedObjs() &&
(sal_uInt16)i < GetSortedObjs()->Count(); ++i )
{
// --> OD 2004-06-29 #i28701#
SwAnchoredObject* pAnchoredObj = (*GetSortedObjs())[i];
if ( pAnchoredObj->ISA(SwFlyAtCntFrm) )
{
SwFlyFrm* pFly = static_cast<SwFlyAtCntFrm*>(pAnchoredObj);
SwPageFrm *pAnchPage = pFly->GetAnchorFrm() ?
pFly->AnchorFrm()->FindPageFrm() : 0;
if ( pAnchPage && (pAnchPage != this) )
{
MoveFly( pFly, pAnchPage );
--i;
pFly->InvalidateSize();
pFly->_InvalidatePos();
}
}
// <--
}
}
//Window aufraeumen
if ( pSh && pSh->GetWin() )
pSh->InvalidateWindows( Frm() );
}
// die Seitennummer der Root runterzaehlen.
((SwRootFrm*)GetUpper())->DecrPhyPageNums();
SwPageFrm *pPg = (SwPageFrm*)GetNext();
if ( pPg )
{
while ( pPg )
{
pPg->DecrPhyPageNum(); //inline --nPhyPageNum
pPg = (SwPageFrm*)pPg->GetNext();
}
}
else
::SetLastPage( (SwPageFrm*)GetPrev() );
SwFrm* pRootFrm = GetUpper();
// Alle Verbindungen kappen.
Remove();
// PAGES01
if ( pRootFrm )
static_cast<SwRootFrm*>(pRootFrm)->CheckViewLayout( 0, 0 );
}
/*************************************************************************
|*
|* SwPageFrm::Paste()
|*
|* Ersterstellung MA 23. Feb. 94
|* Letzte Aenderung MA 07. Dec. 94
|*
|*************************************************************************/
void SwPageFrm::Paste( SwFrm* pParent, SwFrm* pSibling )
{
ASSERT( pParent->IsRootFrm(), "Parent ist keine Root." );
ASSERT( pParent, "Kein Parent fuer Paste." );
ASSERT( pParent != this, "Bin selbst der Parent." );
ASSERT( pSibling != this, "Bin mein eigener Nachbar." );
ASSERT( !GetPrev() && !GetNext() && !GetUpper(),
"Bin noch irgendwo angemeldet." );
//In den Baum einhaengen.
InsertBefore( (SwLayoutFrm*)pParent, pSibling );
// die Seitennummer am Root hochzaehlen.
((SwRootFrm*)GetUpper())->IncrPhyPageNums();
if( GetPrev() )
SetPhyPageNum( ((SwPageFrm*)GetPrev())->GetPhyPageNum() + 1 );
else
SetPhyPageNum( 1 );
SwPageFrm *pPg = (SwPageFrm*)GetNext();
if ( pPg )
{
while ( pPg )
{
pPg->IncrPhyPageNum(); //inline ++nPhyPageNum
pPg->_InvalidatePos();
pPg->InvalidateLayout();
pPg = (SwPageFrm*)pPg->GetNext();
}
}
else
::SetLastPage( this );
if( Frm().Width() != pParent->Prt().Width() )
_InvalidateSize();
InvalidatePos();
ViewShell *pSh = getRootFrm()->GetCurrShell();
if ( pSh )
pSh->SetFirstVisPageInvalid();
// PAGES01
getRootFrm()->CheckViewLayout( 0, 0 );
}
/*************************************************************************
|*
|* SwPageFrm::PrepareRegisterChg()
|*
|* Ersterstellung AMA 22. Jul. 96
|* Letzte Aenderung AMA 22. Jul. 96
|*
|*************************************************************************/
void lcl_PrepFlyInCntRegister( SwCntntFrm *pFrm )
{
pFrm->Prepare( PREP_REGISTER );
if( pFrm->GetDrawObjs() )
{
for( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i )
{
// --> OD 2004-06-29 #i28701#
SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i];
if ( pAnchoredObj->ISA(SwFlyInCntFrm) )
{
SwFlyFrm* pFly = static_cast<SwFlyInCntFrm*>(pAnchoredObj);
SwCntntFrm *pCnt = pFly->ContainsCntnt();
while ( pCnt )
{
lcl_PrepFlyInCntRegister( pCnt );
pCnt = pCnt->GetNextCntntFrm();
}
}
// <--
}
}
}
void SwPageFrm::PrepareRegisterChg()
{
SwCntntFrm *pFrm = FindFirstBodyCntnt();
while( pFrm )
{
lcl_PrepFlyInCntRegister( pFrm );
pFrm = pFrm->GetNextCntntFrm();
if( !IsAnLower( pFrm ) )
break;
}
if( GetSortedObjs() )
{
for( sal_uInt16 i = 0; i < GetSortedObjs()->Count(); ++i )
{
// --> OD 2004-06-29 #i28701#
SwAnchoredObject* pAnchoredObj = (*GetSortedObjs())[i];
if ( pAnchoredObj->ISA(SwFlyFrm) )
{
SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
pFrm = pFly->ContainsCntnt();
while ( pFrm )
{
::lcl_PrepFlyInCntRegister( pFrm );
pFrm = pFrm->GetNextCntntFrm();
}
}
}
}
}
/*************************************************************************
|*
|* SwFrm::CheckPageDescs()
|*
|* Beschreibung Prueft alle Seiten ab der uebergebenen, daraufhin,
|* ob sie das richtige FrmFmt verwenden. Wenn 'falsche' Seiten
|* aufgespuehrt werden, so wird versucht die Situation moeglichst
|* einfache zu bereinigen.
|*
|* Ersterstellung MA 10. Feb. 93
|* Letzte Aenderung MA 18. Apr. 96
|*
|*************************************************************************/
void SwFrm::CheckPageDescs( SwPageFrm *pStart, sal_Bool bNotifyFields )
{
ASSERT( pStart, "Keine Startpage." );
ViewShell *pSh = pStart->getRootFrm()->GetCurrShell();
SwViewImp *pImp = pSh ? pSh->Imp() : 0;
if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() )
{
pImp->GetLayAction().SetCheckPageNum( pStart->GetPhyPageNum() );
return;
}
//Fuer das Aktualisieren der Seitennummern-Felder gibt nDocPos
//die Seitenposition an, _ab_ der invalidiert werden soll.
SwTwips nDocPos = LONG_MAX;
SwRootFrm *pRoot = (SwRootFrm*)pStart->GetUpper();
SwDoc* pDoc = pStart->GetFmt()->GetDoc();
const sal_Bool bFtns = 0 != pDoc->GetFtnIdxs().Count();
SwPageFrm *pPage = pStart;
if( pPage->GetPrev() && ((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() )
pPage = (SwPageFrm*)pPage->GetPrev();
while ( pPage )
{
//gewuenschten PageDesc und FrmFmt festellen.
SwPageDesc *pDesc = pPage->FindPageDesc();
sal_Bool bCheckEmpty = pPage->IsEmptyPage();
sal_Bool bActOdd = pPage->OnRightPage();
sal_Bool bOdd = pPage->WannaRightPage();
SwFrmFmt *pFmtWish = bOdd ? pDesc->GetRightFmt()
: pDesc->GetLeftFmt();
if ( bActOdd != bOdd ||
pDesc != pPage->GetPageDesc() || //falscher Desc
( pFmtWish != pPage->GetFmt() && //falsches Format und
( !pPage->IsEmptyPage() || pFmtWish ) //nicht Leerseite
)
)
{
//Wenn wir schon ein Seite veraendern muessen kann das eine
//Weile dauern, deshalb hier den WaitCrsr pruefen.
if( pImp )
pImp->CheckWaitCrsr();
//Ab hier muessen die Felder invalidiert werden!
if ( nDocPos == LONG_MAX )
nDocPos = pPage->GetPrev() ?
pPage->GetPrev()->Frm().Top() : pPage->Frm().Top();
//Faelle:
//1. Wir haben eine EmptyPage und wollen eine "Normalseite".
// ->EmptyPage wegwerfen und weiter mit der naechsten.
//2. Wir haben eine EmptyPage und wollen eine EmptyPage mit
// anderem Descriptor.
// ->Descriptor austauschen.
//3. Wir haben eine "Normalseite" und wollen eine EmptyPage.
// ->Emptypage einfuegen, nicht aber wenn die Vorseite
// bereits eine EmptyPage ist -> 6.
//4. Wir haben eine "Normalseite" und wollen eine "Normalseite"
// mit anderem Descriptor
// ->Descriptor und Format austauschen
//5. Wir haben eine "Normalseite" und wollen eine "Normalseite"
// mit anderem Format
// ->Format austauschen.
//6. Wir haben kein Wunschformat erhalten, also nehmen wir das
// 'andere' Format (rechts/links) des PageDesc.
if ( pPage->IsEmptyPage() && ( pFmtWish || //1.
( !bOdd && !pPage->GetPrev() ) ) )
{
SwPageFrm *pTmp = (SwPageFrm*)pPage->GetNext();
pPage->Cut();
delete pPage;
if ( pStart == pPage )
pStart = pTmp;
pPage = pTmp;
continue;
}
else if ( pPage->IsEmptyPage() && !pFmtWish && //2.
pDesc != pPage->GetPageDesc() )
{
pPage->SetPageDesc( pDesc, 0 );
}
else if ( !pPage->IsEmptyPage() && //3.
bActOdd != bOdd &&
( ( !pPage->GetPrev() && !bOdd ) ||
( pPage->GetPrev() &&
!((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() )
)
)
{
if ( pPage->GetPrev() )
pDesc = ((SwPageFrm*)pPage->GetPrev())->GetPageDesc();
SwPageFrm *pTmp = new SwPageFrm( pDoc->GetEmptyPageFmt(),pRoot,pDesc);
pTmp->Paste( pRoot, pPage );
pTmp->PreparePage( sal_False );
pPage = pTmp;
}
else if ( pPage->GetPageDesc() != pDesc ) //4.
{
SwPageDesc *pOld = pPage->GetPageDesc();
pPage->SetPageDesc( pDesc, pFmtWish );
if ( bFtns )
{
//Wenn sich bestimmte Werte der FtnInfo veraendert haben
//muss etwas passieren. Wir versuchen den Schaden zu
//begrenzen.
//Wenn die Seiten keinen FtnCont hat, ist zwar theoretisches
//ein Problem denkbar, aber das ignorieren wir mit aller Kraft.
//Bei Aenderungen hoffen wir mal, dass eine Invalidierung
//ausreicht, denn alles andere wuerde viel Kraft kosten.
SwFtnContFrm *pCont = pPage->FindFtnCont();
if ( pCont && !(pOld->GetFtnInfo() == pDesc->GetFtnInfo()) )
pCont->_InvalidateAll();
}
}
else if ( pFmtWish && pPage->GetFmt() != pFmtWish ) //5.
{
pPage->SetFrmFmt( pFmtWish );
}
else if ( !pFmtWish ) //6.
{
//Format mit verdrehter Logic besorgen.
pFmtWish = bOdd ? pDesc->GetLeftFmt() : pDesc->GetRightFmt();
if ( pPage->GetFmt() != pFmtWish )
pPage->SetFrmFmt( pFmtWish );
}
#ifdef DBG_UTIL
else
{
ASSERT( sal_False, "CheckPageDescs, missing solution" );
}
#endif
}
if ( bCheckEmpty )
{
//Es kann noch sein, dass die Leerseite schlicht ueberflussig ist.
//Obiger Algorithmus kann dies leider nicht feststellen.
//Eigentlich muesste die Leerseite einfach praeventiv entfernt
//werden; sie wuerde ja ggf. wieder eingefuegt.
//Die EmptyPage ist genau dann ueberfluessig, wenn die Folgeseite
//auch ohne sie auskommt. Dazu muessen wir uns die Verhaeltnisse
//genauer ansehen. Wir bestimmen den PageDesc und die virtuelle
//Seitennummer manuell.
SwPageFrm *pPg = (SwPageFrm*)pPage->GetNext();
if( !pPg || pPage->OnRightPage() == pPg->WannaRightPage() )
{
//Die Folgeseite hat kein Problem ein FrmFmt zu finden oder keinen
//Nachfolger, also ist die Leerseite ueberfluessig.
SwPageFrm *pTmp = (SwPageFrm*)pPage->GetNext();
pPage->Cut();
delete pPage;
if ( pStart == pPage )
pStart = pTmp;
pPage = pTmp;
continue;
}
}
pPage = (SwPageFrm*)pPage->GetNext();
}
pRoot->SetAssertFlyPages();
pRoot->AssertPageFlys( pStart );
if ( bNotifyFields && (!pImp || !pImp->IsUpdateExpFlds()) )
{
SwDocPosUpdate aMsgHnt( nDocPos );
pDoc->UpdatePageFlds( &aMsgHnt );
}
#ifdef DBG_UTIL
//Ein paar Pruefungen muessen schon erlaubt sein.
//1. Keine zwei EmptyPages hintereinander.
//2. Alle PageDescs richtig?
sal_Bool bEmpty = sal_False;
SwPageFrm *pPg = pStart;
while ( pPg )
{
if ( pPg->IsEmptyPage() )
{
if ( bEmpty )
{
ASSERT( sal_False, "Doppelte Leerseiten." );
break; //Einmal reicht.
}
bEmpty = sal_True;
}
else
bEmpty = sal_False;
//MA 21. Jun. 95: Kann zu testzwecken 'rein, ist aber bei zyklen durchaus
//moeglich: Ein paar Seiten, auf der ersten 'erste Seite' anwenden,
//rechte als folge der ersten, linke als folge der rechten, rechte als
//folge der linken.
// ASSERT( pPg->GetPageDesc() == pPg->FindPageDesc(),
// "Seite mit falschem Descriptor." );
pPg = (SwPageFrm*)pPg->GetNext();
}
#endif
}
/*************************************************************************
|*
|* SwFrm::InsertPage()
|*
|* Beschreibung
|* Ersterstellung MA 10. Feb. 93
|* Letzte Aenderung MA 27. Jul. 93
|*
|*************************************************************************/
SwPageFrm *SwFrm::InsertPage( SwPageFrm *pPrevPage, sal_Bool bFtn )
{
SwRootFrm *pRoot = (SwRootFrm*)pPrevPage->GetUpper();
SwPageFrm *pSibling = (SwPageFrm*)pRoot->GetLower();
SwPageDesc *pDesc = pSibling->GetPageDesc();
pSibling = (SwPageFrm*)pPrevPage->GetNext();
//Rechte (ungerade) oder linke (gerade) Seite einfuegen?
sal_Bool bNextOdd = !pPrevPage->OnRightPage();
sal_Bool bWishedOdd = bNextOdd;
//Welcher PageDesc gilt?
//Bei CntntFrm der aus dem Format wenn einer angegeben ist,
//der Follow vom bereits in der PrevPage gueltigen sonst.
pDesc = 0;
if ( IsFlowFrm() && !SwFlowFrm::CastFlowFrm( this )->IsFollow() )
{ SwFmtPageDesc &rDesc = (SwFmtPageDesc&)GetAttrSet()->GetPageDesc();
pDesc = rDesc.GetPageDesc();
if ( rDesc.GetNumOffset() )
{
bWishedOdd = rDesc.GetNumOffset() % 2 ? sal_True : sal_False;
//Die Gelegenheit nutzen wir um das Flag an der Root zu pflegen.
pRoot->SetVirtPageNum( sal_True );
}
}
if ( !pDesc )
pDesc = pPrevPage->GetPageDesc()->GetFollow();
ASSERT( pDesc, "Missing PageDesc" );
if( !(bWishedOdd ? pDesc->GetRightFmt() : pDesc->GetLeftFmt()) )
bWishedOdd = !bWishedOdd;
SwDoc *pDoc = pPrevPage->GetFmt()->GetDoc();
SwFrmFmt *pFmt;
sal_Bool bCheckPages = sal_False;
//Wenn ich kein FrmFmt fuer die Seite gefunden habe, muss ich eben eine
//Leerseite einfuegen.
if( bWishedOdd != bNextOdd )
{ pFmt = pDoc->GetEmptyPageFmt();
SwPageDesc *pTmpDesc = pPrevPage->GetPageDesc();
SwPageFrm *pPage = new SwPageFrm( pFmt, pRoot, pTmpDesc );
pPage->Paste( pRoot, pSibling );
pPage->PreparePage( bFtn );
//Wenn der Sibling keinen Bodytext enthaelt kann ich ihn vernichten
//Es sei denn, es ist eine Fussnotenseite
if ( pSibling && !pSibling->IsFtnPage() &&
!pSibling->FindFirstBodyCntnt() )
{
SwPageFrm *pDel = pSibling;
pSibling = (SwPageFrm*)pSibling->GetNext();
if ( pDoc->GetFtnIdxs().Count() )
pRoot->RemoveFtns( pDel, sal_True );
pDel->Cut();
delete pDel;
}
else
bCheckPages = sal_True;
}
pFmt = bWishedOdd ? pDesc->GetRightFmt() : pDesc->GetLeftFmt();
ASSERT( pFmt, "Descriptor without format." );
SwPageFrm *pPage = new SwPageFrm( pFmt, pRoot, pDesc );
pPage->Paste( pRoot, pSibling );
pPage->PreparePage( bFtn );
//Wenn der Sibling keinen Bodytext enthaelt kann ich ihn vernichten
//Es sei denn es ist eine Fussnotenseite.
if ( pSibling && !pSibling->IsFtnPage() &&
!pSibling->FindFirstBodyCntnt() )
{
SwPageFrm *pDel = pSibling;
pSibling = (SwPageFrm*)pSibling->GetNext();
if ( pDoc->GetFtnIdxs().Count() )
pRoot->RemoveFtns( pDel, sal_True );
pDel->Cut();
delete pDel;
}
else
bCheckPages = sal_True;
if ( pSibling )
{
if ( bCheckPages )
{
CheckPageDescs( pSibling, sal_False );
ViewShell *pSh = getRootFrm()->GetCurrShell();
SwViewImp *pImp = pSh ? pSh->Imp() : 0;
if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() )
{
const sal_uInt16 nNum = pImp->GetLayAction().GetCheckPageNum();
if ( nNum == pPrevPage->GetPhyPageNum() + 1 )
pImp->GetLayAction().SetCheckPageNumDirect(
pSibling->GetPhyPageNum() );
return pPage;
}
}
else
pRoot->AssertPageFlys( pSibling );
}
//Fuer das Aktualisieren der Seitennummern-Felder gibt nDocPos
//die Seitenposition an, _ab_ der invalidiert werden soll.
ViewShell *pSh = getRootFrm()->GetCurrShell();
if ( !pSh || !pSh->Imp()->IsUpdateExpFlds() )
{
SwDocPosUpdate aMsgHnt( pPrevPage->Frm().Top() );
pDoc->UpdatePageFlds( &aMsgHnt );
}
return pPage;
}
sw::sidebarwindows::SidebarPosition SwPageFrm::SidebarPosition() const
{
ViewShell *pSh = getRootFrm()->GetCurrShell();
if( !pSh || pSh->GetViewOptions()->getBrowseMode() )
{
return sw::sidebarwindows::SIDEBAR_RIGHT;
}
else
{
const bool bLTR = getRootFrm()->IsLeftToRightViewLayout();
const bool bBookMode = pSh->GetViewOptions()->IsViewLayoutBookMode();
const bool bRightSidebar = bLTR ? (!bBookMode || OnRightPage()) : (bBookMode && !OnRightPage());
return bRightSidebar
? sw::sidebarwindows::SIDEBAR_RIGHT
: sw::sidebarwindows::SIDEBAR_LEFT;
}
}
/*************************************************************************
|*
|* SwRootFrm::GrowFrm()
|*
|* Ersterstellung MA 30. Jul. 92
|* Letzte Aenderung MA 05. May. 94
|*
|*************************************************************************/
SwTwips SwRootFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool )
{
if ( !bTst )
Frm().SSize().Height() += nDist;
return nDist;
}
/*************************************************************************
|*
|* SwRootFrm::ShrinkFrm()
|*
|* Ersterstellung MA 30. Jul. 92
|* Letzte Aenderung MA 05. May. 94
|*
|*************************************************************************/
SwTwips SwRootFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool )
{
ASSERT( nDist >= 0, "nDist < 0." );
ASSERT( nDist <= Frm().Height(), "nDist > als aktuelle Groesse." );
if ( !bTst )
Frm().SSize().Height() -= nDist;
return nDist;
}
/*************************************************************************
|*
|* SwRootFrm::RemoveSuperfluous()
|*
|* Beschreibung: Entfernung von ueberfluessigen Seiten.
|* Arbeitet nur wenn das Flag bCheckSuperfluous gesetzt ist.
|* Definition: Eine Seite ist genau dann leer, wenn der
|* Body-Textbereich keinen CntntFrm enthaelt, aber nicht, wenn noch
|* mindestens ein Fly an der Seite klebt.
|* Die Seite ist auch dann nicht leer, wenn sie noch eine
|* Fussnote enthaelt.
|* Es muss zweimal angesetzt werden um leeren Seiten aufzuspueren:
|* - einmal fuer die Endnotenseiten.
|* - und einmal fuer die Seiten des Bodytextes.
|*
|* Ersterstellung MA 20. May. 92
|* Letzte Aenderung MA 10. Jan. 95
|*
|*************************************************************************/
void SwRootFrm::RemoveSuperfluous()
{
if ( !IsSuperfluous() )
return;
bCheckSuperfluous = sal_False;
SwPageFrm *pPage = GetLastPage();
long nDocPos = LONG_MAX;
//Jetzt wird fuer die jeweils letzte Seite geprueft ob sie leer ist
//bei der ersten nicht leeren Seite wird die Schleife beendet.
do
{
bool bExistEssentialObjs = ( 0 != pPage->GetSortedObjs() );
if ( bExistEssentialObjs )
{
//Nur weil die Seite Flys hat sind wir noch lange nicht fertig,
//denn wenn alle Flys an generischem Inhalt haengen, so ist sie
//trotzdem ueberfluessig (Ueberpruefung auf DocBody sollte reichen).
// OD 19.06.2003 #108784# - consider that drawing objects in
// header/footer are supported now.
bool bOnlySuperfluosObjs = true;
SwSortedObjs &rObjs = *pPage->GetSortedObjs();
for ( sal_uInt16 i = 0; bOnlySuperfluosObjs && i < rObjs.Count(); ++i )
{
// --> OD 2004-06-29 #i28701#
SwAnchoredObject* pAnchoredObj = rObjs[i];
// OD 2004-01-19 #110582# - do not consider hidden objects
if ( pPage->GetFmt()->GetDoc()->IsVisibleLayerId(
pAnchoredObj->GetDrawObj()->GetLayer() ) &&
!pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() )
{
bOnlySuperfluosObjs = false;
}
// <--
}
bExistEssentialObjs = !bOnlySuperfluosObjs;
}
// OD 19.06.2003 #108784# - optimization: check first, if essential objects
// exists.
const SwLayoutFrm* pBody = 0;
if ( bExistEssentialObjs ||
pPage->FindFtnCont() ||
( 0 != ( pBody = pPage->FindBodyCont() ) &&
( pBody->ContainsCntnt() ||
// --> FME 2005-05-18 #i47580#
// Do not delete page if there's an empty tabframe
// left. I think it might be correct to use ContainsAny()
// instead of ContainsCntnt() 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()->IsTabFrm() ) ) ) )
// <--
{
if ( pPage->IsFtnPage() )
{
while ( pPage->IsFtnPage() )
{
pPage = (SwPageFrm*)pPage->GetPrev();
ASSERT( pPage, "Nur noch Endnotenseiten uebrig." );
}
continue;
}
else
pPage = 0;
}
if ( pPage )
{
SwPageFrm *pEmpty = pPage;
pPage = (SwPageFrm*)pPage->GetPrev();
if ( GetFmt()->GetDoc()->GetFtnIdxs().Count() )
RemoveFtns( pEmpty, sal_True );
pEmpty->Cut();
delete pEmpty;
nDocPos = pPage ? pPage->Frm().Top() : 0;
}
} while ( pPage );
ViewShell *pSh = getRootFrm()->GetCurrShell();
if ( nDocPos != LONG_MAX &&
(!pSh || !pSh->Imp()->IsUpdateExpFlds()) )
{
SwDocPosUpdate aMsgHnt( nDocPos );
GetFmt()->GetDoc()->UpdatePageFlds( &aMsgHnt );
}
}
/*************************************************************************
|*
|* SwRootFrm::AssertFlyPages()
|*
|* Beschreibung Stellt sicher, dass genuegend Seiten vorhanden
|* sind, damit alle Seitengebundenen Rahmen und DrawObject
|* untergebracht sind.
|*
|* Ersterstellung MA 27. Jul. 93
|* Letzte Aenderung MA 24. Apr. 97
|*
|*************************************************************************/
void SwRootFrm::AssertFlyPages()
{
if ( !IsAssertFlyPages() )
return;
bAssertFlyPages = sal_False;
SwDoc *pDoc = GetFmt()->GetDoc();
const SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts();
//Auf welche Seite will der 'letzte' Fly?
sal_uInt16 nMaxPg = 0;
sal_uInt16 i;
for ( i = 0; i < pTbl->Count(); ++i )
{
const SwFmtAnchor &rAnch = (*pTbl)[i]->GetAnchor();
if ( !rAnch.GetCntntAnchor() && nMaxPg < rAnch.GetPageNum() )
nMaxPg = rAnch.GetPageNum();
}
//Wieviele Seiten haben wir derzeit?
SwPageFrm *pPage = (SwPageFrm*)Lower();
while ( pPage && pPage->GetNext() &&
!((SwPageFrm*)pPage->GetNext())->IsFtnPage() )
{
pPage = (SwPageFrm*)pPage->GetNext();
}
if ( nMaxPg > pPage->GetPhyPageNum() )
{
//Die Seiten werden ausgehend von der letzten Seite konsequent
//nach den Regeln der PageDescs weitergefuehrt.
sal_Bool bOdd = pPage->GetPhyPageNum() % 2 ? sal_True : sal_False;
SwPageDesc *pDesc = pPage->GetPageDesc();
SwFrm *pSibling = pPage->GetNext();
for ( i = pPage->GetPhyPageNum(); i < nMaxPg; ++i )
{
if ( !(bOdd ? pDesc->GetRightFmt() : pDesc->GetLeftFmt()) )
{
//Leerseite einfuegen, die Flys werden aber erst von
//der naechsten Seite aufgenommen!
pPage = new SwPageFrm( pDoc->GetEmptyPageFmt(), this, pDesc );
pPage->Paste( this, pSibling );
pPage->PreparePage( sal_False );
bOdd = bOdd ? sal_False : sal_True;
++i;
}
pPage = new
SwPageFrm( (bOdd ? pDesc->GetRightFmt() :
pDesc->GetLeftFmt()), this, pDesc );
pPage->Paste( this, pSibling );
pPage->PreparePage( sal_False );
bOdd = bOdd ? sal_False : sal_True;
pDesc = pDesc->GetFollow();
}
//Jetzt koennen die Endnotenseiten natuerlich wieder krumm sein;
//in diesem Fall werden sie vernichtet.
if ( pDoc->GetFtnIdxs().Count() )
{
pPage = (SwPageFrm*)Lower();
while ( pPage && !pPage->IsFtnPage() )
pPage = (SwPageFrm*)pPage->GetNext();
if ( pPage )
{
SwPageDesc *pTmpDesc = pPage->FindPageDesc();
bOdd = pPage->OnRightPage();
if ( pPage->GetFmt() !=
(bOdd ? pTmpDesc->GetRightFmt() : pTmpDesc->GetLeftFmt()) )
RemoveFtns( pPage, sal_False, sal_True );
}
}
}
}
/*************************************************************************
|*
|* SwRootFrm::AssertPageFlys()
|*
|* Beschreibung Stellt sicher, dass ab der uebergebenen Seite
|* auf allen Seiten die Seitengebunden Objecte auf der richtigen
|* Seite (Seitennummer stehen).
|*
|* Ersterstellung MA 02. Nov. 94
|* Letzte Aenderung MA 10. Aug. 95
|*
|*************************************************************************/
void SwRootFrm::AssertPageFlys( SwPageFrm *pPage )
{
while ( pPage )
{
if ( pPage->GetSortedObjs() )
{
pPage->GetSortedObjs();
for ( int i = 0;
pPage->GetSortedObjs() && sal_uInt16(i) < pPage->GetSortedObjs()->Count();
++i)
{
// --> OD 2004-06-29 #i28701#
SwFrmFmt& rFmt = (*pPage->GetSortedObjs())[i]->GetFrmFmt();
const SwFmtAnchor &rAnch = rFmt.GetAnchor();
const sal_uInt16 nPg = rAnch.GetPageNum();
if ((rAnch.GetAnchorId() == FLY_AT_PAGE) &&
nPg != pPage->GetPhyPageNum() )
{
//Das er auf der falschen Seite steht muss noch nichts
//heissen, wenn er eigentlich auf der Vorseite
//stehen will und diese eine EmptyPage ist.
if( nPg && !(pPage->GetPhyPageNum()-1 == nPg &&
((SwPageFrm*)pPage->GetPrev())->IsEmptyPage()) )
{
//Umhaengen kann er sich selbst, indem wir ihm
//einfach ein Modify mit seinem AnkerAttr schicken.
#ifndef DBG_UTIL
rFmt.NotifyClients( 0, (SwFmtAnchor*)&rAnch );
#else
const sal_uInt32 nCnt = pPage->GetSortedObjs()->Count();
rFmt.NotifyClients( 0, (SwFmtAnchor*)&rAnch );
ASSERT( !pPage->GetSortedObjs() ||
nCnt != pPage->GetSortedObjs()->Count(),
"Object couldn't be reattached!" );
#endif
--i;
}
}
}
}
pPage = (SwPageFrm*)pPage->GetNext();
}
}
/*************************************************************************
|*
|* SwRootFrm::ChgSize()
|*
|* Ersterstellung MA 24. Jul. 92
|* Letzte Aenderung MA 13. Aug. 93
|*
|*************************************************************************/
Size SwRootFrm::ChgSize( const Size& aNewSize )
{
Frm().SSize() = aNewSize;
_InvalidatePrt();
bFixSize = sal_False;
return Frm().SSize();
}
/*************************************************************************
|*
|* SwRootFrm::MakeAll()
|*
|* Ersterstellung MA 17. Nov. 92
|* Letzte Aenderung MA 19. Apr. 93
|*
|*************************************************************************/
void SwRootFrm::MakeAll()
{
if ( !bValidPos )
{ bValidPos = sal_True;
aFrm.Pos().X() = aFrm.Pos().Y() = DOCUMENTBORDER;
}
if ( !bValidPrtArea )
{ bValidPrtArea = sal_True;
aPrt.Pos().X() = aPrt.Pos().Y() = 0;
aPrt.SSize( aFrm.SSize() );
}
if ( !bValidSize )
//SSize wird von den Seiten (Cut/Paste) eingestellt.
bValidSize = sal_True;
}
/*************************************************************************
|*
|* SwRootFrm::ImplInvalidateBrowseWidth()
|*
|* Ersterstellung MA 08. Jun. 96
|* Letzte Aenderung MA 08. Jun. 96
|*
|*************************************************************************/
void SwRootFrm::ImplInvalidateBrowseWidth()
{
bBrowseWidthValid = sal_False;
SwFrm *pPg = Lower();
while ( pPg )
{
pPg->InvalidateSize();
pPg = pPg->GetNext();
}
}
/*************************************************************************
|*
|* SwRootFrm::ImplCalcBrowseWidth()
|*
|* Ersterstellung MA 07. Jun. 96
|* Letzte Aenderung MA 13. Jun. 96
|*
|*************************************************************************/
void SwRootFrm::ImplCalcBrowseWidth()
{
ASSERT( GetCurrShell() && GetCurrShell()->GetViewOptions()->getBrowseMode(),
"CalcBrowseWidth and not in BrowseView" )
//Die (minimale) Breite wird von Rahmen, Tabellen und Zeichenobjekten
//bestimmt. Die Breite wird nicht anhand ihrer aktuellen Groessen bestimmt,
//sondern anhand der Attribute. Es interessiert also nicht wie breit sie
//sind, sondern wie breit sie sein wollen.
//Rahmen und Zeichenobjekte innerhalb ander Objekte (Rahmen, Tabellen)
//Zaehlen nicht.
//Seitenraender und Spalten werden hier nicht beruecksichtigt.
SwFrm *pFrm = ContainsCntnt();
while ( pFrm && !pFrm->IsInDocBody() )
pFrm = ((SwCntntFrm*)pFrm)->GetNextCntntFrm();
if ( !pFrm )
return;
bBrowseWidthValid = sal_True;
ViewShell *pSh = getRootFrm()->GetCurrShell();
nBrowseWidth = pSh
? MINLAY + 2 * pSh->GetOut()->
PixelToLogic( pSh->GetBrowseBorder() ).Width()
: 5000;
do
{
if ( pFrm->IsInTab() )
pFrm = pFrm->FindTabFrm();
if ( pFrm->IsTabFrm() &&
!((SwLayoutFrm*)pFrm)->GetFmt()->GetFrmSize().GetWidthPercent() )
{
SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
const SwBorderAttrs &rAttrs = *aAccess.Get();
const SwFmtHoriOrient &rHori = rAttrs.GetAttrSet().GetHoriOrient();
long nWidth = rAttrs.GetSize().Width();
if ( nWidth < USHRT_MAX-2000 && //-2000, weil bei Randeinstellung per
//Zuppeln das USHRT_MAX verlorengeht!
text::HoriOrientation::FULL != rHori.GetHoriOrient() )
{
const SwHTMLTableLayout *pLayoutInfo =
((const SwTabFrm *)pFrm)->GetTable()
->GetHTMLTableLayout();
if ( pLayoutInfo )
nWidth = 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( pFrm ) + rAttrs.CalcRight( pFrm );
break;
case text::HoriOrientation::LEFT_AND_WIDTH:
nWidth += rAttrs.CalcLeft( pFrm );
break;
default:
break;
}
nBrowseWidth = Max( nBrowseWidth, nWidth );
}
}
else if ( pFrm->GetDrawObjs() )
{
for ( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i )
{
// --> OD 2004-06-29 #i28701#
SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i];
const SwFrmFmt& rFmt = pAnchoredObj->GetFrmFmt();
const sal_Bool bFly = pAnchoredObj->ISA(SwFlyFrm);
if ((bFly && (WEIT_WECH == pAnchoredObj->GetObjRect().Width()))
|| rFmt.GetFrmSize().GetWidthPercent())
{
continue;
}
long nWidth = 0;
switch ( rFmt.GetAnchor().GetAnchorId() )
{
case FLY_AS_CHAR:
nWidth = bFly ? rFmt.GetFrmSize().GetWidth() :
pAnchoredObj->GetObjRect().Width();
break;
case FLY_AT_PARA:
{
// --> FME 2004-09-13 #i33170#
// Reactivated old code because
// nWidth = pAnchoredObj->GetObjRect().Right()
// gives wrong results for objects that are still
// at position WEIT_WECH.
if ( bFly )
{
nWidth = rFmt.GetFrmSize().GetWidth();
const SwFmtHoriOrient &rHori = rFmt.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 += pFrm->Prt().Left();
break;
default:
break;
}
}
else
//Fuer Zeichenobjekte ist die Auswahl sehr klein,
//weil sie keine Attribute haben, also durch ihre
//aktuelle Groesse bestimmt werden.
nWidth = pAnchoredObj->GetObjRect().Right() -
pAnchoredObj->GetDrawObj()->GetAnchorPos().X();
// <--
}
break;
default: /* do nothing */;
}
nBrowseWidth = Max( nBrowseWidth, nWidth );
}
}
pFrm = pFrm->FindNextCnt();
} while ( pFrm );
}
/*************************************************************************
|*
|* SwRootFrm::StartAllAction()
|*
|* Ersterstellung MA 08. Mar. 98
|* Letzte Aenderung MA 08. Mar. 98
|*
|*************************************************************************/
void SwRootFrm::StartAllAction()
{
ViewShell *pSh = GetCurrShell();
if ( pSh )
do
{ if ( pSh->ISA( SwCrsrShell ) )
((SwCrsrShell*)pSh)->StartAction();
else
pSh->StartAction();
pSh = (ViewShell*)pSh->GetNext();
} while ( pSh != GetCurrShell() );
}
void SwRootFrm::EndAllAction( sal_Bool bVirDev )
{
ViewShell *pSh = GetCurrShell();
if ( pSh )
do
{
const sal_Bool bOldEndActionByVirDev = pSh->IsEndActionByVirDev();
pSh->SetEndActionByVirDev( bVirDev );
if ( pSh->ISA( SwCrsrShell ) )
{
((SwCrsrShell*)pSh)->EndAction();
((SwCrsrShell*)pSh)->CallChgLnk();
if ( pSh->ISA( SwFEShell ) )
((SwFEShell*)pSh)->SetChainMarker();
}
else
pSh->EndAction();
pSh->SetEndActionByVirDev( bOldEndActionByVirDev );
pSh = (ViewShell*)pSh->GetNext();
} while ( pSh != GetCurrShell() );
}
void SwRootFrm::UnoRemoveAllActions()
{
ViewShell *pSh = GetCurrShell();
if ( pSh )
do
{
// --> OD 2008-05-16 #i84729#
// No end action, if <ViewShell> instance is currently in its end action.
// Recursives calls to <::EndAction()> are not allowed.
if ( !pSh->IsInEndAction() )
{
DBG_ASSERT(!pSh->GetRestoreActions(), "Restore action count is already set!");
sal_Bool bCrsr = pSh->ISA( SwCrsrShell );
sal_Bool bFE = pSh->ISA( SwFEShell );
sal_uInt16 nRestore = 0;
while( pSh->ActionCount() )
{
if( bCrsr )
{
((SwCrsrShell*)pSh)->EndAction();
((SwCrsrShell*)pSh)->CallChgLnk();
if ( bFE )
((SwFEShell*)pSh)->SetChainMarker();
}
else
pSh->EndAction();
nRestore++;
}
pSh->SetRestoreActions(nRestore);
}
// <--
pSh->LockView(sal_True);
pSh = (ViewShell*)pSh->GetNext();
} while ( pSh != GetCurrShell() );
}
void SwRootFrm::UnoRestoreAllActions()
{
ViewShell *pSh = GetCurrShell();
if ( pSh )
do
{
sal_uInt16 nActions = pSh->GetRestoreActions();
while( nActions-- )
{
if ( pSh->ISA( SwCrsrShell ) )
((SwCrsrShell*)pSh)->StartAction();
else
pSh->StartAction();
}
pSh->SetRestoreActions(0);
pSh->LockView(sal_False);
pSh = (ViewShell*)pSh->GetNext();
} while ( pSh != GetCurrShell() );
}
// PAGES01: Helper functions for SwRootFrm::CheckViewLayout
void lcl_MoveAllLowers( SwFrm* pFrm, const Point& rOffset );
void lcl_MoveAllLowerObjs( SwFrm* pFrm, const Point& rOffset )
{
SwSortedObjs* pSortedObj = 0;
const bool bPage = pFrm->IsPageFrm();
if ( bPage )
pSortedObj = static_cast<SwPageFrm*>(pFrm)->GetSortedObjs();
else
pSortedObj = pFrm->GetDrawObjs();
for ( sal_uInt16 i = 0; pSortedObj && i < pSortedObj->Count(); ++i)
{
SwAnchoredObject* pAnchoredObj = (*pSortedObj)[i];
const SwFrmFmt& rObjFmt = pAnchoredObj->GetFrmFmt();
const SwFmtAnchor& rAnchor = rObjFmt.GetAnchor();
// all except from the as character anchored objects are moved
// when processing the page frame:
const bool bAsChar = (rAnchor.GetAnchorId() == FLY_AS_CHAR);
if ( !bPage && !bAsChar )
continue;
SwObjPositioningInProgress aPosInProgress( *pAnchoredObj );
if ( pAnchoredObj->ISA(SwFlyFrm) )
{
SwFlyFrm* pFlyFrm( static_cast<SwFlyFrm*>(pAnchoredObj) );
lcl_MoveAllLowers( pFlyFrm, rOffset );
pFlyFrm->NotifyDrawObj();
// --> let the active embedded object be moved
if ( pFlyFrm->Lower() )
{
if ( pFlyFrm->Lower()->IsNoTxtFrm() )
{
SwCntntFrm* pCntntFrm = static_cast<SwCntntFrm*>(pFlyFrm->Lower());
SwRootFrm* pRoot = pFlyFrm->Lower()->getRootFrm();
ViewShell *pSh = pRoot ? pRoot->GetCurrShell() : 0;
if ( pSh )
{
SwOLENode* pNode = pCntntFrm->GetNode()->GetOLENode();
if ( pNode )
{
svt::EmbeddedObjectRef& xObj = pNode->GetOLEObj().GetObject();
if ( xObj.is() )
{
ViewShell* pTmp = pSh;
do
{
SwFEShell* pFEShell = dynamic_cast< SwFEShell* >( pTmp );
if ( pFEShell )
pFEShell->MoveObjectIfActive( xObj, rOffset );
pTmp = static_cast<ViewShell*>( pTmp->GetNext() );
} while( pTmp != pSh );
}
}
}
}
}
// <--
}
else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) )
{
SwAnchoredDrawObject* pAnchoredDrawObj( static_cast<SwAnchoredDrawObject*>(pAnchoredObj) );
// don't touch objects that are not yet positioned:
const bool bNotYetPositioned = pAnchoredDrawObj->NotYetPositioned();
if ( bNotYetPositioned )
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 contour wrapping is enabled #i100684#
if ( pAnchoredDrawObj->GetFrmFmt().GetSurround().IsContour() )
ClrContourCache( pAnchoredDrawObj->GetDrawObj() );
}
// --> OD 2009-08-20 #i92511#
// cache for object rectangle inclusive spaces has to be invalidated.
pAnchoredObj->InvalidateObjRectWithSpaces();
// <--
}
}
void lcl_MoveAllLowers( SwFrm* pFrm, const Point& rOffset )
{
const SwRect aFrm( pFrm->Frm() );
// first move the current frame
pFrm->Frm().Pos() += rOffset;
// Don't forget accessibility:
if( pFrm->IsAccessibleFrm() )
{
SwRootFrm *pRootFrm = pFrm->getRootFrm();
if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
pRootFrm->GetCurrShell() )
{
pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pFrm, aFrm );
}
}
// the move any objects
lcl_MoveAllLowerObjs( pFrm, rOffset );
// finally, for layout frames we have to call this function recursively:
if ( pFrm->ISA(SwLayoutFrm) )
{
SwFrm* pLowerFrm = pFrm->GetLower();
while ( pLowerFrm )
{
lcl_MoveAllLowers( pLowerFrm, rOffset );
pLowerFrm = pLowerFrm->GetNext();
}
}
}
// PAGES01: Calculate how the pages have to be positioned
void SwRootFrm::CheckViewLayout( const SwViewOption* pViewOpt, const SwRect* pVisArea )
{
// --> OD 2008-07-07 #i91432#
// No calculation of page positions, if only an empty page is present.
// This situation occurs when <SwRootFrm> instance is in construction
// and the document contains only left pages.
if ( Lower()->GetNext() == 0 &&
static_cast<SwPageFrm*>(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( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE ) )
{
mnColumns = 1;
mbBookMode = false;
}
Calc();
const sal_Bool bOldCallbackActionEnabled = IsCallbackActionEnabled();
SetCallbackActionEnabled( sal_False );
maPageRects.clear();
const long nBorder = Frm().Pos().X();
const long nVisWidth = mnViewWidth - 2 * nBorder;
const long nGapBetweenPages = GAPBETWEENPAGES;
// check how many pages fit into the first page layout row:
SwPageFrm* pPageFrm = static_cast<SwPageFrm*>(Lower());
// will contain the number of pages per row. 0 means that
// the page does not fit.
long nWidthRemain = nVisWidth;
// after one row has been processed, these variables contain
// the width of the row and the maxium of the page heights
long nCurrentRowHeight = 0;
long nCurrentRowWidth = 0;
// these variables are used to finally set the size of the
// root frame
long nSumRowHeight = 0;
SwTwips nMinPageLeft = TWIPS_MAX;
SwTwips nMaxPageRight = 0;
SwPageFrm* pStartOfRow = pPageFrm;
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 = SwPageFrm::GetSidebarBorderWidth( GetCurrShell() );
while ( pPageFrm )
{
// 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 = pPageFrm == pStartOfRow ||
( pStartOfRow->IsEmptyPage() && pPageFrm == pStartOfRow->GetNext() && !mbBookMode );
const bool bEmptyPage = pPageFrm->IsEmptyPage() && !mbBookMode;
// no half doc border space for first page in each row and
long nPageWidth = 0;
long nPageHeight = 0;
if ( mbBookMode )
{
const SwFrm& rFormatPage = pPageFrm->GetFormatPage();
nPageWidth = rFormatPage.Frm().Width() + nSidebarWidth + ((bStartOfRow || 1 == (pPageFrm->GetPhyPageNum()%2)) ? 0 : nGapBetweenPages);
nPageHeight = rFormatPage.Frm().Height() + nGapBetweenPages;
}
else
{
SwRect aPageFrm;
if ( !pPageFrm->IsEmptyPage() )
{
nPageWidth = pPageFrm->Frm().Width() + nSidebarWidth + (bStartOfRow ? 0 : nGapBetweenPages);
nPageHeight = pPageFrm->Frm().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 = Max( nCurrentRowHeight, nPageHeight );
pPageFrm = static_cast<SwPageFrm*>(pPageFrm->GetNext());
if ( !pPageFrm )
bRowFinished = true;
}
if ( bRowFinished )
{
// pPageFrm 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 ( !pPageFrm && nWidthRemain > 0 )
{
// find last page in current row:
const SwPageFrm* pLastPageInCurrentRow = pStartOfRow;
while( pLastPageInCurrentRow->GetNext() )
pLastPageInCurrentRow = static_cast<const SwPageFrm*>(pLastPageInCurrentRow->GetNext());
if ( pLastPageInCurrentRow->IsEmptyPage() )
pLastPageInCurrentRow = static_cast<const SwPageFrm*>(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->Frm().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 )
{
// --> OD 2008-04-08 #i88036#
// nCurrentRowWidth += pStartOfRow->Frm().Width() + nSidebarWidth;
nCurrentRowWidth +=
pStartOfRow->GetFormatPage().Frm().Width() + nSidebarWidth;
// <--
}
// center page if possible
const long nSizeDiff = nVisWidth > nCurrentRowWidth ?
( nVisWidth - nCurrentRowWidth ) / 2 :
0;
// adjust positions of pages in current row
long nX = nSizeDiff;
const long nRowStart = nBorder + nSizeDiff;
const long nRowEnd = nRowStart + nCurrentRowWidth;
if ( bFirstRow && mbBookMode )
{
// --> OD 2008-04-08 #i88036#
// nX += pStartOfRow->Frm().Width() + nSidebarWidth;
nX += pStartOfRow->GetFormatPage().Frm().Width() + nSidebarWidth;
// <--
}
SwPageFrm* pEndOfRow = pPageFrm;
SwPageFrm* pPageToAdjust = pStartOfRow;
do
{
const SwPageFrm* pFormatPage = pPageToAdjust;
if ( mbBookMode )
pFormatPage = &pPageToAdjust->GetFormatPage();
const SwTwips nCurrentPageWidth = pFormatPage->Frm().Width() + (pFormatPage->IsEmptyPage() ? 0 : nSidebarWidth);
const Point aOldPagePos = pPageToAdjust->Frm().Pos();
const bool bLeftSidebar = pPageToAdjust->SidebarPosition() == sw::sidebarwindows::SIDEBAR_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 long nXOffsetInRow = aNewPagePos.X() - nRowStart;
aNewPagePos.X() = nRowEnd - nXOffsetInRow - nCurrentPageWidth;
aNewPagePosWithLeftOffset = aNewPagePos;
aNewPagePosWithLeftOffset.X() += 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 = Min( nMinPageLeft, aNewPagePos.X() );
nMaxPageRight = Max( nMaxPageRight, aNewPagePos.X() + nCurrentPageWidth);
// border of nGapBetweenPages around the current page:
SwRect aPageRectWithBorders( aNewPagePos.X() - nGapBetweenPages,
aNewPagePos.Y(),
pPageToAdjust->Frm().SSize().Width() + nGapBetweenPages + nSidebarWidth,
nCurrentRowHeight );
static const 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<SwPageFrm*>(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, dont 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<SwPageFrm*>(pPageToAdjust->GetPrev())->IsEmptyPage() );
if ( !bDontAddGap )
nX = nX + nGapBetweenPages;
}
}
}
while ( 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( Frm().SSize() );
const Size aNewSize( nMaxPageRight - nBorder, nSumRowHeight - nGapBetweenPages );
if ( bPageChanged || aNewSize != aOldSize )
{
ChgSize( aNewSize );
::AdjustSizeChgNotify( this );
Calc();
ViewShell* pSh = GetCurrShell();
if ( pSh && pSh->GetDoc()->GetDocShell() )
{
pSh->SetFirstVisPageInvalid();
if (bOldCallbackActionEnabled)
{
pSh->InvalidateWindows( SwRect( 0, 0, LONG_MAX, LONG_MAX ) );
pSh->GetDoc()->GetDocShell()->Broadcast(SfxSimpleHint(SFX_HINT_DOCCHANGED));
}
}
}
maPagesArea.Pos( Frm().Pos() );
maPagesArea.SSize( aNewSize );
if ( TWIPS_MAX != nMinPageLeft )
maPagesArea._Left( nMinPageLeft );
SetCallbackActionEnabled( bOldCallbackActionEnabled );
}
bool SwRootFrm::IsLeftToRightViewLayout() const
{
// Layout direction determined by layout direction of the first page.
// --> OD 2008-04-08 #i88036#
// Only ask a non-empty page frame for its layout direction
// const SwPageFrm* pPage = dynamic_cast<const SwPageFrm*>(Lower());
// return !pPage->IsRightToLeft() && !pPage->IsVertical();
const SwPageFrm& rPage =
dynamic_cast<const SwPageFrm*>(Lower())->GetFormatPage();
return !rPage.IsRightToLeft() && !rPage.IsVertical();
// <--
}
/*const SwRect SwRootFrm::GetExtendedPageArea( sal_uInt16 nPageNumber ) const
{
SwRect aRet;
ASSERT( nPageNumber < maPageRects.size(), "No extended page area available" )
if ( nPageNumber < maPageRects.size() )
aRet = maPageRects[ nPageNumber ];
return aRet;
}*/
const SwPageFrm& SwPageFrm::GetFormatPage() const
{
const SwPageFrm* pRet = this;
if ( IsEmptyPage() )
{
pRet = static_cast<const SwPageFrm*>( OnRightPage() ? GetNext() : GetPrev() );
// --> OD 2008-04-08 #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 cirsumstances 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 == 0 )
{
if ( OnRightPage() )
{
pRet = static_cast<const SwPageFrm*>( GetPrev() );
}
else
{
pRet = static_cast<const SwPageFrm*>( GetNext() );
}
}
ASSERT( pRet,
"<SwPageFrm::GetFormatPage()> - inconsistent layout: empty page without previous and next page frame --> crash." );
// <--
}
return *pRet;
}