diff options
Diffstat (limited to 'sw/source/core/layout/pagechg.cxx')
-rw-r--r-- | sw/source/core/layout/pagechg.cxx | 2496 |
1 files changed, 2496 insertions, 0 deletions
diff --git a/sw/source/core/layout/pagechg.cxx b/sw/source/core/layout/pagechg.cxx new file mode 100644 index 000000000000..b45f1bcb2ceb --- /dev/null +++ b/sw/source/core/layout/pagechg.cxx @@ -0,0 +1,2496 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 <ftninfo.hxx> +#include <tgrditem.hxx> +#include <viewopt.hxx> +#include <docsh.hxx> + +#include "viewimp.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 +// OD 2004-05-24 #i28701# +#include <sortedobjs.hxx> + +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; + + +/************************************************************************* +|* +|* SwBodyFrm::SwBodyFrm() +|* +|* Ersterstellung MA ?? +|* Letzte Aenderung MA 01. Aug. 93 +|* +|*************************************************************************/ +SwBodyFrm::SwBodyFrm( SwFrmFmt *pFmt ): + SwLayoutFrm( pFmt ) +{ + 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 ); + if( IsVertical() && !IsReverse() && nWidth != Frm().Width() ) + Frm().Pos().X() += Frm().Width() - nWidth; + Frm().Width( nWidth ); + } + + BOOL bNoGrid = TRUE; + if( GetUpper()->IsPageFrm() && ((SwPageFrm*)GetUpper())->HasGrid() ) + { + GETGRID( ((SwPageFrm*)GetUpper()) ) + if( pGrid ) + { + bNoGrid = 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 = TRUE; +} + +/************************************************************************* +|* +|* SwPageFrm::SwPageFrm(), ~SwPageFrm() +|* +|* Ersterstellung MA 20. Oct. 92 +|* Letzte Aenderung MA 08. Dec. 97 +|* +|*************************************************************************/ +SwPageFrm::SwPageFrm( SwFrmFmt *pFmt, SwPageDesc *pPgDsc ) : + SwFtnBossFrm( pFmt ), + pSortedObjs( 0 ), + pDesc( pPgDsc ), + nPhyPageNum( 0 ), + // OD 2004-05-17 #i28701# + mbLayoutInProgress( false ) +{ + SetDerivedVert( FALSE ); + SetDerivedR2L( FALSE ); + if( pDesc ) + { + bHasGrid = TRUE; + GETGRID( this ) + if( !pGrid ) + bHasGrid = FALSE; + } + else + bHasGrid = FALSE; + SetMaxFtnHeight( pPgDsc->GetFtnInfo().GetHeight() ? + pPgDsc->GetFtnInfo().GetHeight() : LONG_MAX ), + nType = FRMC_PAGE; + bInvalidLayout = bInvalidCntnt = bInvalidSpelling = bInvalidSmartTags = bInvalidAutoCmplWrds = bInvalidWordCount = TRUE; + bInvalidFlyLayout = bInvalidFlyCntnt = bInvalidFlyInCnt = bFtnPage = bEndNotePage = FALSE; + + const bool bBrowseMode = pFmt->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE); + if ( bBrowseMode ) + { + Frm().Height( 0 ); + ViewShell *pSh = GetShell(); + long nWidth = pSh ? pSh->VisArea().Width():0; + 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 ( FALSE == (bEmptyPage = pFmt == pDoc->GetEmptyPageFmt()) ) + { + bEmptyPage = FALSE; + Calc(); //Damit die PrtArea stimmt. + SwBodyFrm *pBodyFrm = new SwBodyFrm( pDoc->GetDfltFrmFmt() ); + 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 ( USHORT 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 = GetShell(); + 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( BOOL bInvalidate ) +{ + BOOL bOld = bHasGrid; + bHasGrid = 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( BOOL bVert ) +{ + UINT16 nDir = + ((SvxFrameDirectionItem&)GetFmt()->GetFmtAttr( RES_FRAMEDIR )).GetValue(); + if( bVert ) + { + if( FRMDIR_HORI_LEFT_TOP == nDir || FRMDIR_HORI_RIGHT_TOP == nDir || + GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ) + bVertical = 0; + else + bVertical = 1; +/* + if( pDesc && pDesc->GetName().GetChar(0)=='x') + bReverse = 1; + else + */ + 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 ( USHORT 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? + BOOL bSdrObj = RES_DRAWFRMFMT == pFmt->Which(); + pSdrObj = 0; + if ( bSdrObj && 0 == (pSdrObj = pFmt->FindSdrObject()) ) + { + ASSERT( 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 + { + SwClientIter aIter( *pFmt ); + SwClient *pTmp = aIter.First( TYPE(SwFrm) ); + SwFlyFrm *pFly; + if ( pTmp ) + { + pFly = (SwFlyFrm*)pTmp; + if( pFly->GetAnchorFrm() ) + pFly->AnchorFrm()->RemoveFly( pFly ); + } + else + pFly = new SwFlyLayFrm( (SwFlyFrmFmt*)pFmt, pPg ); + pPg->AppendFly( pFly ); + ::RegistFlys( pPg, pFly ); + } + } + } +} + +void SwPageFrm::PreparePage( 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( SfxPoolItem * pOld, SfxPoolItem * pNew ) +{ + ViewShell *pSh = GetShell(); + if ( pSh ) + pSh->SetFirstVisPageInvalid(); + BYTE 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( 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( SfxPoolItem *pOld, SfxPoolItem *pNew, + BYTE &rInvFlags, + SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) +{ + BOOL bClear = TRUE; + const USHORT 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() ); + if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ) + { + bValidSize = 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. + ViewShell *pSh; + if ( 0 != (pSh = GetShell()) && 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, FALSE, TRUE ); + break; + case RES_FRAMEDIR : + CheckDirChange(); + break; + + default: + bClear = 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 +BOOL SwPageFrm::GetInfo( SfxPoolItem & rInfo ) const +{ + if( RES_AUTOFMT_DOCNODE == rInfo.Which() ) + { + // es gibt einen PageFrm also wird er benutzt + return FALSE; + } + return 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. + if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ) + { + 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 BOOL bOld = pRoot->IsSuperfluous(); + pRoot->bCheckSuperfluous = FALSE; + ViewShell *pSh = pRoot->GetCurrShell(); + if ( pSh ) + { + pSh->Imp()->NotifySizeChg( pRoot->Frm().SSize() );//Einmal fuer das Drawing. + do + { + pSh->SizeChgNotify(); //Einmal fuer jede Sicht. + 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 = GetShell(); + 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() && + (USHORT)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(); + + // PAGES01 + if ( GetUpper() ) + static_cast<SwRootFrm*>(GetUpper())->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( USHORT 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( USHORT 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, BOOL bNotifyFields ) +{ + ASSERT( pStart, "Keine Startpage." ); + + ViewShell *pSh = pStart->GetShell(); + 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 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(); + BOOL bCheckEmpty = pPage->IsEmptyPage(); + BOOL bActOdd = pPage->OnRightPage(); + 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(),pDesc); + pTmp->Paste( pRoot, pPage ); + pTmp->PreparePage( 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( 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? + BOOL bEmpty = FALSE; + SwPageFrm *pPg = pStart; + while ( pPg ) + { + if ( pPg->IsEmptyPage() ) + { + if ( bEmpty ) + { + ASSERT( FALSE, "Doppelte Leerseiten." ); + break; //Einmal reicht. + } + bEmpty = TRUE; + } + else + bEmpty = 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, 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? + BOOL bNextOdd = !pPrevPage->OnRightPage(); + 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 ? TRUE : FALSE; + //Die Gelegenheit nutzen wir um das Flag an der Root zu pflegen. + pRoot->SetVirtPageNum( 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; + BOOL bCheckPages = 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, 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, TRUE ); + pDel->Cut(); + delete pDel; + } + else + bCheckPages = TRUE; + } + pFmt = bWishedOdd ? pDesc->GetRightFmt() : pDesc->GetLeftFmt(); + ASSERT( pFmt, "Descriptor without format." ); + SwPageFrm *pPage = new SwPageFrm( pFmt, 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, TRUE ); + pDel->Cut(); + delete pDel; + } + else + bCheckPages = TRUE; + + if ( pSibling ) + { + if ( bCheckPages ) + { + CheckPageDescs( pSibling, FALSE ); + ViewShell *pSh = GetShell(); + SwViewImp *pImp = pSh ? pSh->Imp() : 0; + if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() ) + { + const USHORT 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 = GetShell(); + if ( !pSh || !pSh->Imp()->IsUpdateExpFlds() ) + { + SwDocPosUpdate aMsgHnt( pPrevPage->Frm().Top() ); + pDoc->UpdatePageFlds( &aMsgHnt ); + } + return pPage; +} + +sw::sidebarwindows::SidebarPosition SwPageFrm::SidebarPosition() const +{ + if ( !GetShell() || + GetShell()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ) + { + // --> OD 2010-06-03 #i111964# - provide default sidebar position + return sw::sidebarwindows::SIDEBAR_RIGHT; + // <-- + } + else + { + const bool bLTR = GetUpper() ? static_cast<const SwRootFrm*>(GetUpper())->IsLeftToRightViewLayout() : true; + const bool bBookMode = GetShell()->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, BOOL bTst, 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, BOOL bTst, 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 = 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 ( USHORT 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, TRUE ); + pEmpty->Cut(); + delete pEmpty; + nDocPos = pPage ? pPage->Frm().Top() : 0; + } + } while ( pPage ); + + ViewShell *pSh = GetShell(); + 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 = FALSE; + + SwDoc *pDoc = GetFmt()->GetDoc(); + const SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts(); + + //Auf welche Seite will der 'letzte' Fly? + USHORT nMaxPg = 0; + USHORT 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. + BOOL bOdd = pPage->GetPhyPageNum() % 2 ? TRUE : 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(), pDesc ); + pPage->Paste( this, pSibling ); + pPage->PreparePage( FALSE ); + bOdd = bOdd ? FALSE : TRUE; + ++i; + } + pPage = new + SwPageFrm( (bOdd ? pDesc->GetRightFmt() : + pDesc->GetLeftFmt()), pDesc ); + pPage->Paste( this, pSibling ); + pPage->PreparePage( FALSE ); + bOdd = bOdd ? FALSE : 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, FALSE, 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() && USHORT(i) < pPage->GetSortedObjs()->Count(); + ++i) + { + // --> OD 2004-06-29 #i28701# + SwFrmFmt& rFmt = (*pPage->GetSortedObjs())[i]->GetFrmFmt(); + const SwFmtAnchor &rAnch = rFmt.GetAnchor(); + const USHORT 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.SwModify::Modify( 0, (SwFmtAnchor*)&rAnch ); +#else + const sal_uInt32 nCnt = pPage->GetSortedObjs()->Count(); + rFmt.SwModify::Modify( 0, (SwFmtAnchor*)&rAnch ); + ASSERT( !pPage->GetSortedObjs() || + nCnt != pPage->GetSortedObjs()->Count(), + "Kann das Obj nicht umhaengen." ); +#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 = FALSE; + return Frm().SSize(); +} + +/************************************************************************* +|* +|* SwRootFrm::MakeAll() +|* +|* Ersterstellung MA 17. Nov. 92 +|* Letzte Aenderung MA 19. Apr. 93 +|* +|*************************************************************************/ +void SwRootFrm::MakeAll() +{ + if ( !bValidPos ) + { bValidPos = TRUE; + aFrm.Pos().X() = aFrm.Pos().Y() = DOCUMENTBORDER; + } + if ( !bValidPrtArea ) + { bValidPrtArea = TRUE; + aPrt.Pos().X() = aPrt.Pos().Y() = 0; + aPrt.SSize( aFrm.SSize() ); + } + if ( !bValidSize ) + //SSize wird von den Seiten (Cut/Paste) eingestellt. + bValidSize = TRUE; +} + +/************************************************************************* +|* +|* SwRootFrm::ImplInvalidateBrowseWidth() +|* +|* Ersterstellung MA 08. Jun. 96 +|* Letzte Aenderung MA 08. Jun. 96 +|* +|*************************************************************************/ +void SwRootFrm::ImplInvalidateBrowseWidth() +{ + bBrowseWidthValid = 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( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE), + "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 = TRUE; + ViewShell *pSh = GetShell(); + 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 ( USHORT i = 0; i < pFrm->GetDrawObjs()->Count(); ++i ) + { + // --> OD 2004-06-29 #i28701# + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; + const SwFrmFmt& rFmt = pAnchoredObj->GetFrmFmt(); + const 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( BOOL bVirDev ) +{ + ViewShell *pSh = GetCurrShell(); + if ( pSh ) + do + { + const 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!"); + BOOL bCrsr = pSh->ISA( SwCrsrShell ); + BOOL bFE = pSh->ISA( SwFEShell ); + USHORT 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(TRUE); + pSh = (ViewShell*)pSh->GetNext(); + + } while ( pSh != GetCurrShell() ); +} + +void SwRootFrm::UnoRestoreAllActions() +{ + ViewShell *pSh = GetCurrShell(); + if ( pSh ) + do + { + USHORT nActions = pSh->GetRestoreActions(); + while( nActions-- ) + { + if ( pSh->ISA( SwCrsrShell ) ) + ((SwCrsrShell*)pSh)->StartAction(); + else + pSh->StartAction(); + } + pSh->SetRestoreActions(0); + pSh->LockView(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 ( USHORT 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()); + ViewShell *pSh = pFlyFrm->Lower()->GetShell(); + 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() ); + } + // --> 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->FindRootFrm(); + 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 USHORT 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 BOOL bOldCallbackActionEnabled = IsCallbackActionEnabled(); + SetCallbackActionEnabled( 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; + USHORT 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( GetShell() ); + + 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: + USHORT nNumberOfVirtualPages = 0; + const USHORT 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 = GetShell(); + + 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( USHORT 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; +} + |