/**************************************************************
 *
 * 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;
}
