diff options
Diffstat (limited to 'sw/source/core/layout/trvlfrm.cxx')
-rw-r--r-- | sw/source/core/layout/trvlfrm.cxx | 2662 |
1 files changed, 2662 insertions, 0 deletions
diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx new file mode 100644 index 000000000000..73f2b4d7fc42 --- /dev/null +++ b/sw/source/core/layout/trvlfrm.cxx @@ -0,0 +1,2662 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: trvlfrm.cxx,v $ + * $Revision: 1.63 $ + * + * 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 <hintids.hxx> +#include <hints.hxx> +#include <tools/bigint.hxx> +#include <svx/protitem.hxx> +#include <vcl/settings.hxx> +#include <vcl/outdev.hxx> +#include <fmtpdsc.hxx> +#include <fmtsrnd.hxx> +#include <pagedesc.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <cntfrm.hxx> +#include <ftnfrm.hxx> +#include <flyfrm.hxx> +#include <tabfrm.hxx> +#include <rowfrm.hxx> +#include <cellfrm.hxx> +#include <txtfrm.hxx> +#include <viewsh.hxx> +#include <viewopt.hxx> +#include <doc.hxx> +#include <viscrs.hxx> +#include <frmfmt.hxx> +#include <swtable.hxx> +#include <dflyobj.hxx> +#include <crstate.hxx> +#include <frmtool.hxx> +#include <ndtxt.hxx> +// OD 2004-05-24 #i28701# +#include <sortedobjs.hxx> + +// FLT_MAX +#include <cfloat> +#include <swselectionlist.hxx> + +//Fuer SwFlyFrm::GetCrsrOfst +class SwCrsrOszControl +{ +public: + // damit schon der Compiler die Klasse initialisieren kann, keinen + // DTOR und member als publics: + const SwFlyFrm *pEntry; + const SwFlyFrm *pStk1; + const SwFlyFrm *pStk2; + +//public: +// SwCrsrOszControl() : pStk1( 0 ), pStk2( 0 ) {}; // ; <- ???? + + BOOL ChkOsz( const SwFlyFrm *pFly ) + { + BOOL bRet = TRUE; + if ( pFly != pStk1 && pFly != pStk2 ) + { + pStk1 = pStk2; + pStk2 = pFly; + bRet = FALSE; + } + return bRet; + } + void Entry( const SwFlyFrm *pFly ) + { + if ( !pEntry ) + pEntry = pStk1 = pFly; + } + void Exit( const SwFlyFrm *pFly ) + { + if ( pFly == pEntry ) + pEntry = pStk1 = pStk2 = 0; + } +}; + +static SwCrsrOszControl aOszCtrl = { 0, 0, 0 }; + +/************************************************************************* +|* +|* SwLayoutFrm::GetCrsrOfst() +|* +|* Beschreibung: Sucht denjenigen CntntFrm, innerhalb dessen +|* PrtArea der Point liegt. +|* Ersterstellung MA 20. Jul. 92 +|* Letzte Aenderung MA 23. May. 95 +|* +|*************************************************************************/ +BOOL SwLayoutFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + BOOL bRet = FALSE; + const SwFrm *pFrm = Lower(); + while ( !bRet && pFrm ) + { + pFrm->Calc(); + + // --> FME 2005-05-13 #i43742# New function: SW_CONTENT_CHECK + const bool bCntntCheck = pFrm->IsTxtFrm() && pCMS && pCMS->bCntntCheck; + const SwRect aPaintRect( bCntntCheck ? + pFrm->UnionFrm() : + pFrm->PaintArea() ); + // <-- + + if ( aPaintRect.IsInside( rPoint ) && + ( bCntntCheck || pFrm->GetCrsrOfst( pPos, rPoint, pCMS ) ) ) + bRet = TRUE; + else + pFrm = pFrm->GetNext(); + if ( pCMS && pCMS->bStop ) + return FALSE; + } + return bRet; +} + +/************************************************************************* +|* +|* SwPageFrm::GetCrsrOfst() +|* +|* Beschreibung: Sucht die Seite, innerhalb der der gesuchte Point +|* liegt. +|* Ersterstellung MA 20. Jul. 92 +|* Letzte Aenderung MA 18. Jul. 96 +|* +|*************************************************************************/ + +BOOL SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + BOOL bRet = FALSE; + Point aPoint( rPoint ); + + // check, if we have to adjust the point + if ( !Frm().IsInside( aPoint ) ) + { + aPoint.X() = Max( aPoint.X(), Frm().Left() ); + aPoint.X() = Min( aPoint.X(), Frm().Right() ); + aPoint.Y() = Max( aPoint.Y(), Frm().Top() ); + aPoint.Y() = Min( aPoint.Y(), Frm().Bottom() ); + } + + //Koennte ein Freifliegender gemeint sein? + //Wenn sein Inhalt geschuetzt werden soll, so ist nix mit Crsr + //hineinsetzen, dadurch sollten alle Aenderungen unmoeglich sein. + if ( GetSortedObjs() ) + { + SwOrderIter aIter( this ); + aIter.Top(); + while ( aIter() ) + { + const SwVirtFlyDrawObj* pObj = + static_cast<const SwVirtFlyDrawObj*>(aIter()); + const SwFlyFrm* pFly = pObj ? pObj->GetFlyFrm() : 0; + if ( pFly && + ( ( pCMS ? pCMS->bSetInReadOnly : FALSE ) || + !pFly->IsProtected() ) && + pFly->GetCrsrOfst( pPos, aPoint, pCMS ) ) + { + bRet = TRUE; + break; + } + + if ( pCMS && pCMS->bStop ) + return FALSE; + aIter.Prev(); + } + } + + if ( !bRet ) + { + //Wenn kein Cntnt unterhalb der Seite 'antwortet', so korrigieren + //wir den StartPoint und fangen nochmal eine Seite vor der + //aktuellen an. Mit Flys ist es dann allerdings vorbei. + if ( SwLayoutFrm::GetCrsrOfst( pPos, aPoint, pCMS ) ) + bRet = TRUE; + else + { + if ( pCMS && (pCMS->bStop || pCMS->bExactOnly) ) + { + ((SwCrsrMoveState*)pCMS)->bStop = TRUE; + return FALSE; + } + const SwCntntFrm *pCnt = GetCntntPos( aPoint, FALSE, FALSE, FALSE, pCMS, FALSE ); + if ( pCMS && pCMS->bStop ) + return FALSE; + + ASSERT( pCnt, "Crsr is gone to a Black hole" ); + if( pCMS && pCMS->pFill && pCnt->IsTxtFrm() ) + bRet = pCnt->GetCrsrOfst( pPos, rPoint, pCMS ); + else + bRet = pCnt->GetCrsrOfst( pPos, aPoint, pCMS ); + + if ( !bRet ) + { + // Set point to pCnt, delete mark + // this may happen, if pCnt is hidden + *pPos = SwPosition( *pCnt->GetNode(), SwIndex( (SwTxtNode*)pCnt->GetNode(), 0 ) ); + bRet = TRUE; + } + } + } + + if ( bRet ) + rPoint = aPoint; + + return bRet; +} + +bool SwLayoutFrm::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const +{ + bool bRet = false; + if( rRect.IsOver(PaintArea()) ) + { + const SwFrm* pFrm = Lower(); + while( pFrm ) + { + pFrm->FillSelection( rList, rRect ); + pFrm = pFrm->GetNext(); + } + } + return bRet; +} + +bool SwPageFrm::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const +{ + bool bRet = false; + if( rRect.IsOver(PaintArea()) ) + { + bRet = SwLayoutFrm::FillSelection( rList, rRect ); + if( GetSortedObjs() ) + { + const SwSortedObjs &rObjs = *GetSortedObjs(); + for ( USHORT i = 0; i < rObjs.Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = rObjs[i]; + if( !pAnchoredObj->ISA(SwFlyFrm) ) + continue; + const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj); + if( pFly->FillSelection( rList, rRect ) ) + bRet = true; + } + } + } + return bRet; +} + +bool SwRootFrm::FillSelection( SwSelectionList& aSelList, const SwRect& rRect) const +{ + const SwFrm *pPage = Lower(); + const long nBottom = rRect.Bottom(); + while( pPage ) + { + if( pPage->Frm().Top() < nBottom ) + { + if( pPage->Frm().Bottom() > rRect.Top() ) + pPage->FillSelection( aSelList, rRect ); + pPage = pPage->GetNext(); + } + else + pPage = 0; + } + return !aSelList.isEmpty(); +} + +/************************************************************************* +|* +|* SwRootFrm::GetCrsrOfst() +|* +|* Beschreibung: Reicht Primaer den Aufruf an die erste Seite weiter. +|* Wenn der 'reingereichte Point veraendert wird, +|* so wird FALSE zurueckgegeben. +|* Ersterstellung MA 01. Jun. 92 +|* Letzte Aenderung MA 30. Nov. 94 +|* +|*************************************************************************/ +BOOL SwRootFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + sal_Bool bOldAction = IsCallbackActionEnabled(); + ((SwRootFrm*)this)->SetCallbackActionEnabled( FALSE ); + ASSERT( (Lower() && Lower()->IsPageFrm()), "Keinen PageFrm gefunden." ); + if( pCMS && pCMS->pFill ) + ((SwCrsrMoveState*)pCMS)->bFillRet = FALSE; + Point aOldPoint = rPoint; + + // PAGES01 + // search for page containing rPoint. The borders around the pages are considerd + const SwPageFrm* pPage = GetPageAtPos( rPoint, 0, true ); + + // --> OD 2008-12-23 #i95626# + // special handling for <rPoint> beyond root frames area + if ( !pPage && + rPoint.X() > Frm().Right() && + rPoint.Y() > Frm().Bottom() ) + { + pPage = dynamic_cast<const SwPageFrm*>(Lower()); + while ( pPage && pPage->GetNext() ) + { + pPage = dynamic_cast<const SwPageFrm*>(pPage->GetNext()); + } + } + // <-- + if ( pPage ) + { + pPage->SwPageFrm::GetCrsrOfst( pPos, rPoint, pCMS ); + } + + ((SwRootFrm*)this)->SetCallbackActionEnabled( bOldAction ); + if( pCMS ) + { + if( pCMS->bStop ) + return FALSE; + if( pCMS->pFill ) + return pCMS->bFillRet; + } + return aOldPoint == rPoint; +} + +/************************************************************************* +|* +|* SwCellFrm::GetCrsrOfst() +|* +|* Beschreibung Wenn es sich um eine Cntnt-tragende Cell handelt wird +|* der Crsr notfalls mit Gewalt in einen der CntntFrms +|* gesetzt. +|* In geschuetzte Zellen gibt es hier keinen Eingang. +|* Ersterstellung MA 04. Jun. 93 +|* Letzte Aenderung MA 23. May. 95 +|* +|*************************************************************************/ +BOOL SwCellFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + // cell frame does not necessarily have a lower (split table cell) + if ( !Lower() ) + return FALSE; + + if ( !(pCMS?pCMS->bSetInReadOnly:FALSE) && + GetFmt()->GetProtect().IsCntntProtected() ) + return FALSE; + + if ( pCMS && pCMS->eState == MV_TBLSEL ) + { + const SwTabFrm *pTab = FindTabFrm(); + if ( pTab->IsFollow() && pTab->IsInHeadline( *this ) ) + { + ((SwCrsrMoveState*)pCMS)->bStop = TRUE; + return FALSE; + } + } + + if ( Lower() ) + { + if ( Lower()->IsLayoutFrm() ) + return SwLayoutFrm::GetCrsrOfst( pPos, rPoint, pCMS ); + else + { + Calc(); + BOOL bRet = FALSE; + + const SwFrm *pFrm = Lower(); + while ( pFrm && !bRet ) + { + pFrm->Calc(); + if ( pFrm->Frm().IsInside( rPoint ) ) + { + bRet = pFrm->GetCrsrOfst( pPos, rPoint, pCMS ); + if ( pCMS && pCMS->bStop ) + return FALSE; + } + pFrm = pFrm->GetNext(); + } + if ( !bRet ) + { + Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL; + const SwCntntFrm *pCnt = GetCntntPos( rPoint, TRUE ); + if( pPoint && pCnt->IsTxtFrm() ) + { + pCnt->GetCrsrOfst( pPos, *pPoint, pCMS ); + rPoint = *pPoint; + } + else + pCnt->GetCrsrOfst( pPos, rPoint, pCMS ); + delete pPoint; + } + return TRUE; + } + } + + return FALSE; +} + +/************************************************************************* +|* +|* SwFlyFrm::GetCrsrOfst() +|* +|* Ersterstellung MA 15. Dec. 92 +|* Letzte Aenderung MA 23. May. 95 +|* +|*************************************************************************/ +//Problem: Wenn zwei Flys genau gleich gross sind und auf derselben +//Position stehen, so liegt jeder innerhalb des anderen. +//Da jeweils geprueft wird, ob der Point nicht zufaellig innerhalb eines +//anderen Flys liegt, der sich vollstaendig innerhalb des aktuellen befindet +//und ggf. ein rekursiver Aufruf erfolgt wuerde o.g. Situation zu einer +//endlosen Rekursion fuehren. +//Mit der Hilfsklasse SwCrsrOszControl unterbinden wir die Rekursion. Das +//GetCrsrOfst entscheidet sich bei einer Rekursion fuer denjenigen der +//am weitesten oben liegt. + +BOOL SwFlyFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + aOszCtrl.Entry( this ); + + //Wenn der Point innerhalb des Fly sitzt wollen wir energisch + //versuchen den Crsr hineinzusetzen. + //Wenn der Point allerdings in einem Flys sitzt, der sich vollstaendig + //innerhalb des aktuellen befindet, so wird fuer diesen das + //GetCrsrOfst gerufen. + Calc(); + BOOL bInside = Frm().IsInside( rPoint ) && Lower(), + bRet = FALSE; + + //Wenn der Frm eine Grafik enthaelt, aber nur Text gewuenscht ist, so + //nimmt er den Crsr grundsaetzlich nicht an. + if ( bInside && pCMS && pCMS->eState == MV_SETONLYTEXT && + (!Lower() || Lower()->IsNoTxtFrm()) ) + bInside = FALSE; + + const SwPageFrm *pPage = FindPageFrm(); + if ( bInside && pPage && pPage->GetSortedObjs() ) + { + SwOrderIter aIter( pPage ); + aIter.Top(); + while ( aIter() && !bRet ) + { + const SwVirtFlyDrawObj* pObj = static_cast<const SwVirtFlyDrawObj*>(aIter()); + const SwFlyFrm* pFly = pObj ? pObj->GetFlyFrm() : 0; + if ( pFly && pFly->Frm().IsInside( rPoint ) && + Frm().IsInside( pFly->Frm() ) ) + { + if ( aOszCtrl.ChkOsz( pFly ) || + TRUE == (bRet = pFly->GetCrsrOfst( pPos, rPoint, pCMS ))) + break; + if ( pCMS && pCMS->bStop ) + return FALSE; + } + aIter.Next(); + } + } + + while ( bInside && !bRet ) + { + const SwFrm *pFrm = Lower(); + while ( pFrm && !bRet ) + { + pFrm->Calc(); + if ( pFrm->Frm().IsInside( rPoint ) ) + { + bRet = pFrm->GetCrsrOfst( pPos, rPoint, pCMS ); + if ( pCMS && pCMS->bStop ) + return FALSE; + } + pFrm = pFrm->GetNext(); + } + if ( !bRet ) + { + Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL; + const SwCntntFrm *pCnt = GetCntntPos( + rPoint, TRUE, FALSE, FALSE, pCMS ); + if ( pCMS && pCMS->bStop ) + return FALSE; + if( pPoint && pCnt->IsTxtFrm() ) + { + pCnt->GetCrsrOfst( pPos, *pPoint, pCMS ); + rPoint = *pPoint; + } + else + pCnt->GetCrsrOfst( pPos, rPoint, pCMS ); + delete pPoint; + bRet = TRUE; + } + } + aOszCtrl.Exit( this ); + return bRet; +} + +/************************************************************************* +|* +|* Beschreibung Layoutabhaengiges Cursortravelling +|* Ersterstellung MA 23. Jul. 92 +|* Letzte Aenderung MA 06. Sep. 93 +|* +|*************************************************************************/ +BOOL SwCntntFrm::LeftMargin(SwPaM *pPam) const +{ + if( pPam->GetNode() != (SwCntntNode*)GetNode() ) + return FALSE; + ((SwCntntNode*)GetNode())-> + MakeStartIndex((SwIndex *) &pPam->GetPoint()->nContent); + return TRUE; +} + +BOOL SwCntntFrm::RightMargin(SwPaM *pPam, BOOL) const +{ + if( pPam->GetNode() != (SwCntntNode*)GetNode() ) + return FALSE; + ((SwCntntNode*)GetNode())-> + MakeEndIndex((SwIndex *) &pPam->GetPoint()->nContent); + return TRUE; +} + +const SwCntntFrm *lcl_GetNxtCnt( const SwCntntFrm* pCnt ) +{ + return pCnt->GetNextCntntFrm(); +} + +const SwCntntFrm *lcl_GetPrvCnt( const SwCntntFrm* pCnt ) +{ + return pCnt->GetPrevCntntFrm(); +} + +typedef const SwCntntFrm *(*GetNxtPrvCnt)( const SwCntntFrm* ); + +//Frame in wiederholter Headline? +BOOL lcl_IsInRepeatedHeadline( const SwFrm *pFrm, + const SwTabFrm** ppTFrm = 0 ) +{ + const SwTabFrm *pTab = pFrm->FindTabFrm(); + if( ppTFrm ) + *ppTFrm = pTab; + return pTab && pTab->IsFollow() && pTab->IsInHeadline( *pFrm ); +} + + +//Ueberspringen geschuetzter Tabellenzellen. Optional auch +//Ueberspringen von wiederholten Headlines. +//MA 26. Jan. 98: Chg auch andere Geschuetzte Bereiche ueberspringen. +// FME: Skip follow flow cells +const SwCntntFrm * MA_FASTCALL lcl_MissProtectedFrames( const SwCntntFrm *pCnt, + GetNxtPrvCnt fnNxtPrv, + BOOL bMissHeadline, + BOOL bInReadOnly, + BOOL bMissFollowFlowLine ) +{ + if ( pCnt && pCnt->IsInTab() ) + { + BOOL bProtect = TRUE; + while ( pCnt && bProtect ) + { + const SwLayoutFrm *pCell = pCnt->GetUpper(); + while ( pCell && !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + if ( !pCell || + ( ( bInReadOnly || !pCell->GetFmt()->GetProtect().IsCntntProtected() ) && + ( !bMissHeadline || !lcl_IsInRepeatedHeadline( pCell ) ) && + ( !bMissFollowFlowLine || !pCell->IsInFollowFlowRow() ) ) && + !pCell->IsCoveredCell() ) + bProtect = FALSE; + else + pCnt = (*fnNxtPrv)( pCnt ); + } + } + else if ( !bInReadOnly ) + while ( pCnt && pCnt->IsProtected() ) + pCnt = (*fnNxtPrv)( pCnt ); + + return pCnt; +} + +BOOL MA_FASTCALL lcl_UpDown( SwPaM *pPam, const SwCntntFrm *pStart, + GetNxtPrvCnt fnNxtPrv, BOOL bInReadOnly ) +{ + ASSERT( pPam->GetNode() == (SwCntntNode*)pStart->GetNode(), + "lcl_UpDown arbeitet nicht fuer andere." ); + + const SwCntntFrm *pCnt = 0; + + //Wenn gerade eine Tabellenselection laeuft muss ein bischen getricktst + //werden: Beim hochlaufen an den Anfang der Zelle gehen, beim runterlaufen + //an das Ende der Zelle gehen. + BOOL bTblSel = false; + if ( pStart->IsInTab() && + pPam->GetNode( TRUE )->StartOfSectionNode() != + pPam->GetNode( FALSE )->StartOfSectionNode() ) + { + bTblSel = true; + const SwLayoutFrm *pCell = pStart->GetUpper(); + while ( !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + + // + // Check, if cell has a Prev/Follow cell: + // + const bool bFwd = ( fnNxtPrv == lcl_GetNxtCnt ); + const SwLayoutFrm* pTmpCell = bFwd ? + ((SwCellFrm*)pCell)->GetFollowCell() : + ((SwCellFrm*)pCell)->GetPreviousCell(); + + const SwCntntFrm* pTmpStart = pStart; + while ( pTmpCell && 0 != ( pTmpStart = pTmpCell->ContainsCntnt() ) ) + { + pCell = pTmpCell; + pTmpCell = bFwd ? + ((SwCellFrm*)pCell)->GetFollowCell() : + ((SwCellFrm*)pCell)->GetPreviousCell(); + } + const SwCntntFrm *pNxt = pCnt = pTmpStart; + + while ( pCell->IsAnLower( pNxt ) ) + { + pCnt = pNxt; + pNxt = (*fnNxtPrv)( pNxt ); + } + } + + pCnt = (*fnNxtPrv)( pCnt ? pCnt : pStart ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel ); + + + const SwTabFrm *pStTab = pStart->FindTabFrm(); + const SwTabFrm *pTable = 0; + const BOOL bTab = pStTab || (pCnt && pCnt->IsInTab()) ? TRUE : FALSE; + BOOL bEnd = bTab ? FALSE : TRUE; + + const SwFrm* pVertRefFrm = pStart; + if ( bTblSel && pStTab ) + pVertRefFrm = pStTab; + SWRECTFN( pVertRefFrm ) + + SwTwips nX = 0; + if ( bTab ) + { + // + // pStart or pCnt is inside a table. nX will be used for travelling: + // + SwRect aRect( pStart->Frm() ); + pStart->GetCharRect( aRect, *pPam->GetPoint() ); + Point aCenter = aRect.Center(); + nX = bVert ? aCenter.Y() : aCenter.X(); + + pTable = pCnt ? pCnt->FindTabFrm() : 0; + if ( !pTable ) + pTable = pStTab; + + if ( pStTab && + !pStTab->GetUpper()->IsInTab() && + !pTable->GetUpper()->IsInTab() ) + { + const SwFrm *pCell = pStart->GetUpper(); + while ( pCell && !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + ASSERT( pCell, "Zelle nicht gefunden." ); + nX = (pCell->Frm().*fnRect->fnGetLeft)() + + (pCell->Frm().*fnRect->fnGetWidth)() / 2; + + //Der Fluss fuehrt von einer Tabelle in die nachste. Der X-Wert + //muss ausgehend von der Mitte der Startzelle um die Verschiebung + //der Tabellen korrigiert werden. + if ( pStTab != pTable ) + { + nX += (pTable->Frm().*fnRect->fnGetLeft)() - + (pStTab->Frm().*fnRect->fnGetLeft)(); + } + } + + // + // Restrict nX to the left and right borders of pTab: + // (is this really necessary?) + // + if ( !pTable->GetUpper()->IsInTab() ) + { + const sal_Bool bRTL = pTable->IsRightToLeft(); + const long nPrtLeft = bRTL ? + (pTable->*fnRect->fnGetPrtRight)() : + (pTable->*fnRect->fnGetPrtLeft)(); + if ( bRTL != nX < nPrtLeft ) + nX = nPrtLeft; + else + { + const long nPrtRight = bRTL ? + (pTable->*fnRect->fnGetPrtLeft)() : + (pTable->*fnRect->fnGetPrtRight)(); + if ( bRTL != nX > nPrtRight ) + nX = nPrtRight; + } + } + } + + do + { + //Wenn ich im DokumentBody bin, so will ich da auch bleiben + if ( pStart->IsInDocBody() ) + { + while ( pCnt && (!pCnt->IsInDocBody() || + (pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow()))) + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel ); + } + } + + //Wenn ich im Fussnotenbereich bin, so versuche ich notfalls den naechsten + //Fussnotenbereich zu erreichen. + else if ( pStart->IsInFtn() ) + { + while ( pCnt && (!pCnt->IsInFtn() || + (pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow()))) + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel ); + } + } + + //In Flys kann es Blind weitergehen solange ein Cntnt + //gefunden wird. + else if ( pStart->IsInFly() ) + { + if ( pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow() ) + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel ); + } + } + + //Andernfalls weigere ich mich einfach den derzeitigen Bereich zu + //verlassen. + else if ( pCnt ) + { + const SwFrm *pUp = pStart->GetUpper(); //Head/Foot + while ( pUp && pUp->GetUpper() && !(pUp->GetType() & 0x0018 ) ) + pUp = pUp->GetUpper(); + BOOL bSame = FALSE; + const SwFrm *pCntUp = pCnt->GetUpper(); + while ( pCntUp && !bSame ) + { if ( pUp == pCntUp ) + bSame = TRUE; + else + pCntUp = pCntUp->GetUpper(); + } + if ( !bSame ) + pCnt = 0; + else if ( pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow() ) // i73332 + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel ); + } + } + + if ( bTab ) + { + if ( !pCnt ) + bEnd = TRUE; + else + { const SwTabFrm *pTab = pCnt->FindTabFrm(); + if( !pTab ) + bEnd = TRUE; + else + { + if ( pTab != pTable ) + { + //Der Fluss fuehrt von einer Tabelle in die nachste. Der + //X-Wert muss um die Verschiebung der Tabellen korrigiert + //werden. + if ( pTable && + !pTab->GetUpper()->IsInTab() && + !pTable->GetUpper()->IsInTab() ) + nX += pTab->Frm().Left() - pTable->Frm().Left(); + pTable = pTab; + } + const SwLayoutFrm *pCell = pTable ? pCnt->GetUpper() : 0; + while ( pCell && !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + + Point aInsideCell; + Point aInsideCnt; + if ( pCell ) + { + long nTmpTop = (pCell->Frm().*fnRect->fnGetTop)(); + if ( bVert ) + { + if ( nTmpTop ) + --nTmpTop; + + aInsideCell = Point( nTmpTop, nX ); + } + else + aInsideCell = Point( nX, nTmpTop ); + } + + long nTmpTop = (pCnt->Frm().*fnRect->fnGetTop)(); + if ( bVert ) + { + if ( nTmpTop ) + --nTmpTop; + + aInsideCnt = Point( nTmpTop, nX ); + } + else + aInsideCnt = Point( nX, nTmpTop ); + + if ( pCell && pCell->Frm().IsInside( aInsideCell ) ) + { + bEnd = TRUE; + //Jetzt noch schnell den richtigen Cntnt in der Zelle + //greifen. + if ( !pCnt->Frm().IsInside( aInsideCnt ) ) + { + pCnt = pCell->ContainsCntnt(); + if ( fnNxtPrv == lcl_GetPrvCnt ) + while ( pCell->IsAnLower(pCnt->GetNextCntntFrm()) ) + pCnt = pCnt->GetNextCntntFrm(); + } + } + else if ( pCnt->Frm().IsInside( aInsideCnt ) ) + bEnd = TRUE; + } + } + if ( !bEnd ) + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel ); + } + } + + } while ( !bEnd || + (pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow())); + + if( pCnt ) + { // setze den Point auf den Content-Node + SwCntntNode *pCNd = (SwCntntNode*)pCnt->GetNode(); + pPam->GetPoint()->nNode = *pCNd; + if ( fnNxtPrv == lcl_GetPrvCnt ) + pCNd->MakeEndIndex( (SwIndex*)&pPam->GetPoint()->nContent ); + else + pCNd->MakeStartIndex( (SwIndex*)&pPam->GetPoint()->nContent ); + return TRUE; + } + return FALSE; +} + +BOOL SwCntntFrm::UnitUp( SwPaM* pPam, const SwTwips, BOOL bInReadOnly ) const +{ + return ::lcl_UpDown( pPam, this, lcl_GetPrvCnt, bInReadOnly ); +} + +BOOL SwCntntFrm::UnitDown( SwPaM* pPam, const SwTwips, BOOL bInReadOnly ) const +{ + return ::lcl_UpDown( pPam, this, lcl_GetNxtCnt, bInReadOnly ); +} + +/************************************************************************* +|* +|* SwRootFrm::GetCurrPage() +|* +|* Beschreibung: Liefert die Nummer der aktuellen Seite. +|* Wenn die Methode einen PaM bekommt, so ist die aktuelle Seite +|* diejenige in der der PaM sitzt. Anderfalls ist die aktuelle +|* Seite die erste Seite innerhalb der VisibleArea. +|* Es wird nur auf den vorhandenen Seiten gearbeitet! +|* Ersterstellung MA 20. May. 92 +|* Letzte Aenderung MA 09. Oct. 97 +|* +|*************************************************************************/ +USHORT SwRootFrm::GetCurrPage( const SwPaM *pActualCrsr ) const +{ + ASSERT( pActualCrsr, "Welche Seite soll's denn sein?" ); + const SwFrm *pActFrm = GetFmt()->GetDoc()->GetNodes()[pActualCrsr->GetPoint()->nNode]-> + GetCntntNode()->GetFrm( 0, + pActualCrsr->GetPoint(), + FALSE ); + return pActFrm->FindPageFrm()->GetPhyPageNum(); +} + +/************************************************************************* +|* +|* SwRootFrm::SetCurrPage() +|* +|* Beschreibung: Liefert einen PaM der am Anfang der gewuenschten +|* Seite sitzt. +|* Formatiert wird soweit notwendig +|* Liefert Null, wenn die Operation nicht moeglich ist. +|* Der PaM sitzt in der letzten Seite, wenn die Seitenzahl zu gross +|* gewaehlt wurde. +|* Ersterstellung MA 20. May. 92 +|* Letzte Aenderung MA 09. Oct. 97 +|* +|*************************************************************************/ +USHORT SwRootFrm::SetCurrPage( SwCursor* pToSet, USHORT nPageNum ) +{ + ASSERT( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." ); + + SwPageFrm *pPage = (SwPageFrm*)Lower(); + BOOL bEnd =FALSE; + while ( !bEnd && pPage->GetPhyPageNum() != nPageNum ) + { if ( pPage->GetNext() ) + pPage = (SwPageFrm*)pPage->GetNext(); + else + { //Ersten CntntFrm Suchen, und solange Formatieren bis + //eine neue Seite angefangen wird oder bis die CntntFrm's alle + //sind. + const SwCntntFrm *pCntnt = pPage->ContainsCntnt(); + while ( pCntnt && pPage->IsAnLower( pCntnt ) ) + { + pCntnt->Calc(); + pCntnt = pCntnt->GetNextCntntFrm(); + } + //Jetzt ist entweder eine neue Seite da, oder die letzte Seite + //ist gefunden. + if ( pPage->GetNext() ) + pPage = (SwPageFrm*)pPage->GetNext(); + else + bEnd = TRUE; + } + } + //pPage zeigt jetzt auf die 'gewuenschte' Seite. Jetzt muss noch der + //PaM auf den Anfang des ersten CntntFrm im Body-Text erzeugt werden. + //Wenn es sich um eine Fussnotenseite handelt, wird der PaM in die erste + //Fussnote gesetzt. + const SwCntntFrm *pCntnt = pPage->ContainsCntnt(); + if ( pPage->IsFtnPage() ) + while ( pCntnt && !pCntnt->IsInFtn() ) + pCntnt = pCntnt->GetNextCntntFrm(); + else + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + if ( pCntnt ) + { + SwCntntNode* pCNd = (SwCntntNode*)pCntnt->GetNode(); + pToSet->GetPoint()->nNode = *pCNd; + pCNd->MakeStartIndex( (SwIndex*)&pToSet->GetPoint()->nContent ); + pToSet->GetPoint()->nContent = ((SwTxtFrm*)pCntnt)->GetOfst(); + + SwShellCrsr* pSCrsr = dynamic_cast<SwShellCrsr*>(pToSet); + if( pSCrsr ) + { + Point &rPt = pSCrsr->GetPtPos(); + rPt = pCntnt->Frm().Pos(); + rPt += pCntnt->Prt().Pos(); + } + return pPage->GetPhyPageNum(); + } + return 0; +} + +/************************************************************************* +|* +|* SwCntntFrm::StartxxPage(), EndxxPage() +|* +|* Beschreibung Cursor an Anfang/Ende der aktuellen/vorherigen/ +|* naechsten Seite. Alle sechs Methoden rufen GetFrmInPage() mit der +|* entsprechenden Parametrisierung. +|* Zwei Parameter steuern die Richtung: einer bestimmt die Seite, der +|* andere Anfang/Ende. +|* Fuer die Bestimmung der Seite und des Cntnt (Anfang/Ende) werden +|* die im folgenden definierten Funktionen benutzt. +|* Ersterstellung MA 15. Oct. 92 +|* Letzte Aenderung MA 28. Feb. 93 +|* +|*************************************************************************/ +SwCntntFrm *GetFirstSub( const SwLayoutFrm *pLayout ) +{ + return ((SwPageFrm*)pLayout)->FindFirstBodyCntnt(); +} + +SwCntntFrm *GetLastSub( const SwLayoutFrm *pLayout ) +{ + return ((SwPageFrm*)pLayout)->FindLastBodyCntnt(); +} + +SwLayoutFrm *GetNextFrm( const SwLayoutFrm *pFrm ) +{ + SwLayoutFrm *pNext = + (pFrm->GetNext() && pFrm->GetNext()->IsLayoutFrm()) ? + (SwLayoutFrm*)pFrm->GetNext() : 0; + // #i39402# in case of an empty page + if(pNext && !pNext->ContainsCntnt()) + pNext = (pNext->GetNext() && pNext->GetNext()->IsLayoutFrm()) ? + (SwLayoutFrm*)pNext->GetNext() : 0; + return pNext; +} + +SwLayoutFrm *GetThisFrm( const SwLayoutFrm *pFrm ) +{ + return (SwLayoutFrm*)pFrm; +} + +SwLayoutFrm *GetPrevFrm( const SwLayoutFrm *pFrm ) +{ + SwLayoutFrm *pPrev = + (pFrm->GetPrev() && pFrm->GetPrev()->IsLayoutFrm()) ? + (SwLayoutFrm*)pFrm->GetPrev() : 0; + // #i39402# in case of an empty page + if(pPrev && !pPrev->ContainsCntnt()) + pPrev = (pPrev->GetPrev() && pPrev->GetPrev()->IsLayoutFrm()) ? + (SwLayoutFrm*)pPrev->GetPrev() : 0; + return pPrev; +} + +//Jetzt koennen auch die Funktionspointer initalisiert werden; +//sie sind in cshtyp.hxx declariert. +SwPosPage fnPageStart = GetFirstSub; +SwPosPage fnPageEnd = GetLastSub; +SwWhichPage fnPagePrev = GetPrevFrm; +SwWhichPage fnPageCurr = GetThisFrm; +SwWhichPage fnPageNext = GetNextFrm; + +//Liefert den ersten/den letzten Contentframe (gesteuert ueber +//den Parameter fnPosPage) in der +//aktuellen/vorhergehenden/folgenden Seite (gesteuert durch den +//Parameter fnWhichPage). +BOOL GetFrmInPage( const SwCntntFrm *pCnt, SwWhichPage fnWhichPage, + SwPosPage fnPosPage, SwPaM *pPam ) +{ + //Erstmal die gewuenschte Seite besorgen, anfangs die aktuelle, dann + //die die per fnWichPage gewuenscht wurde + const SwLayoutFrm *pLayoutFrm = pCnt->FindPageFrm(); + if ( !pLayoutFrm || (0 == (pLayoutFrm = (*fnWhichPage)(pLayoutFrm))) ) + return FALSE; + + //Jetzt den gewuenschen CntntFrm unterhalb der Seite + if( 0 == (pCnt = (*fnPosPage)(pLayoutFrm)) ) + return FALSE; + else + { + // repeated headlines in tables + if ( pCnt->IsInTab() && fnPosPage == GetFirstSub ) + { + const SwTabFrm* pTab = pCnt->FindTabFrm(); + if ( pTab->IsFollow() ) + { + if ( pTab->IsInHeadline( *pCnt ) ) + { + SwLayoutFrm* pRow = pTab->GetFirstNonHeadlineRow(); + if ( pRow ) + { + // We are in the first line of a follow table + // with repeated headings. + // To actually make a "real" move we take the first content + // of the next row + pCnt = pRow->ContainsCntnt(); + if ( ! pCnt ) + return FALSE; + } + } + } + } + + SwCntntNode *pCNd = (SwCntntNode*)pCnt->GetNode(); + pPam->GetPoint()->nNode = *pCNd; + xub_StrLen nIdx; + if( fnPosPage == GetFirstSub ) + nIdx = ((SwTxtFrm*)pCnt)->GetOfst(); + else + nIdx = pCnt->GetFollow() ? + ((SwTxtFrm*)pCnt)->GetFollow()->GetOfst()-1 : pCNd->Len(); + pPam->GetPoint()->nContent.Assign( pCNd, nIdx ); + return TRUE; + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::GetCntntPos() +|* +|* Beschreibung Es wird der nachstliegende Cntnt zum uebergebenen +|* gesucht. Betrachtet werden die vorhergehende, die +|* aktuelle und die folgende Seite. +|* Wenn kein Inhalt gefunden wird, so wird der Bereich + * erweitert bis einer gefunden wird. +|* Zurueckgegeben wird die 'Semantisch richtige' Position +|* innerhalb der PrtArea des gefundenen CntntFrm +|* Ersterstellung MA 15. Jul. 92 +|* Letzte Aenderung MA 09. Jan. 97 +|* +|*************************************************************************/ +ULONG CalcDiff( const Point &rPt1, const Point &rPt2 ) +{ + //Jetzt die Entfernung zwischen den beiden Punkten berechnen. + //'Delta' X^2 + 'Delta'Y^2 = 'Entfernung'^2 + sal_uInt32 dX = Max( rPt1.X(), rPt2.X() ) - + Min( rPt1.X(), rPt2.X() ), + dY = Max( rPt1.Y(), rPt2.Y() ) - + Min( rPt1.Y(), rPt2.Y() ); + BigInt dX1( dX ), dY1( dY ); + dX1 *= dX1; dY1 *= dY1; + return ::SqRt( dX1 + dY1 ); +} + +// lcl_Inside ueberprueft, ob der Punkt innerhalb des Seitenteils liegt, in dem +// auch der CntntFrame liegt. Als Seitenteile gelten in diesem Zusammenhang +// Kopfzeile, Seitenbody, Fusszeile und FussnotenContainer. +// Dies dient dazu, dass ein CntntFrm, der im "richtigen" Seitenteil liegt, +// eher akzeptiert wird als ein anderer, der nicht dort liegt, auch wenn +// dessen Abstand zum Punkt geringer ist. + +const SwLayoutFrm* lcl_Inside( const SwCntntFrm *pCnt, Point& rPt ) +{ + const SwLayoutFrm* pUp = pCnt->GetUpper(); + while( pUp ) + { + if( pUp->IsPageBodyFrm() || pUp->IsFooterFrm() || pUp->IsHeaderFrm() ) + { + if( rPt.Y() >= pUp->Frm().Top() && rPt.Y() <= pUp->Frm().Bottom() ) + return pUp; + return NULL; + } + if( pUp->IsFtnContFrm() ) + return pUp->Frm().IsInside( rPt ) ? pUp : NULL; + pUp = pUp->GetUpper(); + } + return NULL; +} + +const SwCntntFrm *SwLayoutFrm::GetCntntPos( Point& rPoint, + const BOOL bDontLeave, + const BOOL bBodyOnly, + const BOOL bCalc, + const SwCrsrMoveState *pCMS, + const BOOL bDefaultExpand ) const +{ + //Ersten CntntFrm ermitteln. + const SwLayoutFrm *pStart = (!bDontLeave && bDefaultExpand && GetPrev()) ? + (SwLayoutFrm*)GetPrev() : this; + const SwCntntFrm *pCntnt = pStart->ContainsCntnt(); + + if ( !pCntnt && (GetPrev() && !bDontLeave) ) + pCntnt = ContainsCntnt(); + + if ( bBodyOnly && pCntnt && !pCntnt->IsInDocBody() ) + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + + const SwCntntFrm *pActual= pCntnt; + const SwLayoutFrm *pInside = NULL; + USHORT nMaxPage = GetPhyPageNum() + (bDefaultExpand ? 1 : 0); + Point aPoint = rPoint; + ULONG nDistance = ULONG_MAX; + + while ( TRUE ) //Sicherheitsschleifchen, damit immer einer gefunden wird. + { + while ( pCntnt && + ((!bDontLeave || IsAnLower( pCntnt )) && + (pCntnt->GetPhyPageNum() <= nMaxPage)) ) + { + if ( ( bCalc || pCntnt->Frm().Width() ) && + ( !bBodyOnly || pCntnt->IsInDocBody() ) ) + { + //Wenn der Cntnt in einem geschuetzen Bereich (Zelle, Ftn, Section) + //liegt, wird der nachste Cntnt der nicht geschuetzt ist gesucht. + const SwCntntFrm *pComp = pCntnt; + pCntnt = ::lcl_MissProtectedFrames( pCntnt, lcl_GetNxtCnt, FALSE, + pCMS ? pCMS->bSetInReadOnly : FALSE, FALSE ); + if ( pComp != pCntnt ) + continue; + + if ( !pCntnt->IsTxtFrm() || !((SwTxtFrm*)pCntnt)->IsHiddenNow() ) + { + if ( bCalc ) + pCntnt->Calc(); + + SwRect aCntFrm( pCntnt->UnionFrm() ); + if ( aCntFrm.IsInside( rPoint ) ) + { + pActual = pCntnt; + aPoint = rPoint; + break; + } + //Die Strecke von rPoint zum dichtesten Punkt von pCntnt wird + //jetzt berechnet. + Point aCntntPoint( rPoint ); + + //Erst die Vertikale Position einstellen + if ( aCntFrm.Top() > aCntntPoint.Y() ) + aCntntPoint.Y() = aCntFrm.Top(); + else if ( aCntFrm.Bottom() < aCntntPoint.Y() ) + aCntntPoint.Y() = aCntFrm.Bottom(); + + //Jetzt die Horizontale Position + if ( aCntFrm.Left() > aCntntPoint.X() ) + aCntntPoint.X() = aCntFrm.Left(); + else if ( aCntFrm.Right() < aCntntPoint.X() ) + aCntntPoint.X() = aCntFrm.Right(); + + // pInside ist ein Seitenbereich, in dem der Punkt liegt, + // sobald pInside!=0 ist, werden nur noch Frames akzeptiert, + // die innerhalb liegen. + if( !pInside || ( pInside->IsAnLower( pCntnt ) && + ( !pCntnt->IsInFtn() || pInside->IsFtnContFrm() ) ) ) + { + const ULONG nDiff = ::CalcDiff( aCntntPoint, rPoint ); + BOOL bBetter = nDiff < nDistance; // Dichter dran + if( !pInside ) + { + pInside = lcl_Inside( pCntnt, rPoint ); + if( pInside ) // Im "richtigen" Seitenteil + bBetter = TRUE; + } + if( bBetter ) + { + aPoint = aCntntPoint; + nDistance = nDiff; + pActual = pCntnt; + } + } + } + } + pCntnt = pCntnt->GetNextCntntFrm(); + if ( bBodyOnly ) + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + } + if ( !pActual ) + { //Wenn noch keiner gefunden wurde muss der Suchbereich erweitert + //werden, irgenwann muessen wir einen Finden! + //MA 09. Jan. 97: Opt fuer viele leere Seiten, wenn wir nur im + //Body suchen, koennen wir den Suchbereich gleich in einem + //Schritt hinreichend erweitern. + if ( bBodyOnly ) + { + while ( !pCntnt && pStart->GetPrev() ) + { + ++nMaxPage; + if( !pStart->GetPrev()->IsLayoutFrm() ) + return 0; + pStart = (SwLayoutFrm*)pStart->GetPrev(); + pCntnt = pStart->IsInDocBody() + ? pStart->ContainsCntnt() + : pStart->FindPageFrm()->FindFirstBodyCntnt(); + } + if ( !pCntnt ) //irgendwann muessen wir mit irgendeinem Anfangen! + { + pCntnt = pStart->FindPageFrm()->GetUpper()->ContainsCntnt(); + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + if ( !pCntnt ) + return 0; //Es gibt noch keine Dokumentinhalt! + } + } + else + { + ++nMaxPage; + if ( pStart->GetPrev() ) + { + if( !pStart->GetPrev()->IsLayoutFrm() ) + return 0; + pStart = (SwLayoutFrm*)pStart->GetPrev(); + pCntnt = pStart->ContainsCntnt(); + } + else //irgendwann muessen wir mit irgendeinem Anfangen! + pCntnt = pStart->FindPageFrm()->GetUpper()->ContainsCntnt(); + } + pActual = pCntnt; + } + else + break; + } + +#ifdef DBG_UTIL + ASSERT( pActual, "Keinen Cntnt gefunden." ); + if ( bBodyOnly ) + ASSERT( pActual->IsInDocBody(), "Cnt nicht im Body." ); +#endif + + //Spezialfall fuer das selektieren von Tabellen, nicht in wiederholte + //TblHedlines. + if ( pActual->IsInTab() && pCMS && pCMS->eState == MV_TBLSEL ) + { + const SwTabFrm *pTab = pActual->FindTabFrm(); + if ( pTab->IsFollow() && pTab->IsInHeadline( *pActual ) ) + { + ((SwCrsrMoveState*)pCMS)->bStop = TRUE; + return 0; + } + } + + //Jetzt noch eine kleine Korrektur beim ersten/letzten + Size aActualSize( pActual->Prt().SSize() ); + if ( aActualSize.Height() > pActual->GetUpper()->Prt().Height() ) + aActualSize.Height() = pActual->GetUpper()->Prt().Height(); + + SWRECTFN( pActual ) + if ( !pActual->GetPrev() && + (*fnRect->fnYDiff)( (pActual->*fnRect->fnGetPrtTop)(), + bVert ? rPoint.X() : rPoint.Y() ) > 0 ) + { + aPoint.Y() = pActual->Frm().Top() + pActual->Prt().Top(); + aPoint.X() = pActual->Frm().Left() + + ( pActual->IsRightToLeft() || bVert ? + pActual->Prt().Right() : + pActual->Prt().Left() ); + } + else if ( !pActual->GetNext() && + (*fnRect->fnYDiff)( (pActual->*fnRect->fnGetPrtBottom)(), + bVert ? rPoint.X() : rPoint.Y() ) < 0 ) + { + aPoint.Y() = pActual->Frm().Top() + pActual->Prt().Bottom(); + aPoint.X() = pActual->Frm().Left() + + ( pActual->IsRightToLeft() || bVert ? + pActual->Prt().Left() : + pActual->Prt().Right() ); + } + + //Und den Point in die PrtArea bringen + if ( bCalc ) + pActual->Calc(); + const SwRect aRect( pActual->Frm().Pos() + pActual->Prt().Pos(), + aActualSize ); + if ( aPoint.Y() < aRect.Top() ) + aPoint.Y() = aRect.Top(); + else if ( aPoint.Y() > aRect.Bottom() ) + aPoint.Y() = aRect.Bottom(); + if ( aPoint.X() < aRect.Left() ) + aPoint.X() = aRect.Left(); + else if ( aPoint.X() > aRect.Right() ) + aPoint.X() = aRect.Right(); + rPoint = aPoint; + return pActual; +} + +/************************************************************************* +|* +|* SwPageFrm::GetCntntPosition() +|* +|* Beschreibung Analog zu SwLayoutFrm::GetCntntPos(). +|* Spezialisiert fuer Felder in Rahmen. +|* +|* Ersterstellung MA 22. Mar. 95 +|* Letzte Aenderung MA 07. Nov. 95 +|* +|*************************************************************************/ +void SwPageFrm::GetCntntPosition( const Point &rPt, SwPosition &rPos ) const +{ + //Ersten CntntFrm ermitteln. + const SwCntntFrm *pCntnt = ContainsCntnt(); + if ( pCntnt ) + { + //Einen weiter zurueck schauen (falls moeglich). + const SwCntntFrm *pTmp = pCntnt->GetPrevCntntFrm(); + while ( pTmp && !pTmp->IsInDocBody() ) + pTmp = pTmp->GetPrevCntntFrm(); + if ( pTmp ) + pCntnt = pTmp; + } + else + pCntnt = GetUpper()->ContainsCntnt(); + + const SwCntntFrm *pAct = pCntnt; + Point aAct = rPt; + ULONG nDist = ULONG_MAX; + + while ( pCntnt ) + { + SwRect aCntFrm( pCntnt->UnionFrm() ); + if ( aCntFrm.IsInside( rPt ) ) + { + //dichter gehts nimmer. + pAct = pCntnt; + break; + } + + //Die Strecke von rPt zum dichtesten Punkt von pCntnt berechnen. + Point aPoint( rPt ); + + //Erst die vertikale Position einstellen + if ( aCntFrm.Top() > rPt.Y() ) + aPoint.Y() = aCntFrm.Top(); + else if ( aCntFrm.Bottom() < rPt.Y() ) + aPoint.Y() = aCntFrm.Bottom(); + + //Jetzt die horizontale Position + if ( aCntFrm.Left() > rPt.X() ) + aPoint.X() = aCntFrm.Left(); + else if ( aCntFrm.Right() < rPt.X() ) + aPoint.X() = aCntFrm.Right(); + + const ULONG nDiff = ::CalcDiff( aPoint, rPt ); + if ( nDiff < nDist ) + { + aAct = aPoint; + nDist = nDiff; + pAct = pCntnt; + } + else if ( aCntFrm.Top() > Frm().Bottom() ) + //Dichter wirds im Sinne der Felder nicht mehr! + break; + + pCntnt = pCntnt->GetNextCntntFrm(); + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + } + + //Und den Point in die PrtArea bringen + const SwRect aRect( pAct->Frm().Pos() + pAct->Prt().Pos(), pAct->Prt().SSize() ); + if ( aAct.Y() < aRect.Top() ) + aAct.Y() = aRect.Top(); + else if ( aAct.Y() > aRect.Bottom() ) + aAct.Y() = aRect.Bottom(); + if ( aAct.X() < aRect.Left() ) + aAct.X() = aRect.Left(); + else if ( aAct.X() > aRect.Right() ) + aAct.X() = aRect.Right(); + + if( !pAct->IsValid() ) + { + // CntntFrm nicht formatiert -> immer auf Node-Anfang + SwCntntNode* pCNd = (SwCntntNode*)pAct->GetNode(); + ASSERT( pCNd, "Wo ist mein CntntNode?" ); + rPos.nNode = *pCNd; + rPos.nContent.Assign( pCNd, 0 ); + } + else + { + SwCrsrMoveState aTmpState( MV_SETONLYTEXT ); + pAct->GetCrsrOfst( &rPos, aAct, &aTmpState ); + } +} + +/************************************************************************* +|* +|* SwRootFrm::GetNextPrevCntntPos() +|* +|* Beschreibung Es wird der naechstliegende Cntnt zum uebergebenen +|* Point gesucht. Es wird nur im BodyText gesucht. +|* Ersterstellung MA 15. Jul. 92 +|* Letzte Aenderung JP 11.10.2001 +|* +|*************************************************************************/ + +// --> OD 2005-05-25 #123110# - helper class to disable creation of an action +// by a callback event - e.g., change event from a drawing object +class DisableCallbackAction +{ + private: + SwRootFrm& mrRootFrm; + BOOL mbOldCallbackActionState; + + public: + DisableCallbackAction( const SwRootFrm& _rRootFrm ) : + mrRootFrm( const_cast<SwRootFrm&>(_rRootFrm) ), + mbOldCallbackActionState( _rRootFrm.IsCallbackActionEnabled() ) + { + mrRootFrm.SetCallbackActionEnabled( FALSE ); + } + + ~DisableCallbackAction() + { + mrRootFrm.SetCallbackActionEnabled( mbOldCallbackActionState ); + } +}; +// <-- + +//!!!!! Es wird nur der vertikal naechstliegende gesucht. +//JP 11.10.2001: only in tables we try to find the right column - Bug 72294 +Point SwRootFrm::GetNextPrevCntntPos( const Point& rPoint, BOOL bNext ) const +{ + // --> OD 2005-05-25 #123110# - disable creation of an action by a callback + // event during processing of this method. Needed because formatting is + // triggered by this method. + DisableCallbackAction aDisableCallbackAction( *this ); + // <-- + //Ersten CntntFrm und seinen Nachfolger im Body-Bereich suchen + //Damit wir uns nicht tot suchen (und vor allem nicht zuviel formatieren) + //gehen wir schon mal von der richtigen Seite aus. + SwLayoutFrm *pPage = (SwLayoutFrm*)Lower(); + if( pPage ) + while( pPage->GetNext() && pPage->Frm().Bottom() < rPoint.Y() ) + pPage = (SwLayoutFrm*)pPage->GetNext(); + + const SwCntntFrm *pCnt = pPage ? pPage->ContainsCntnt() : ContainsCntnt(); + while ( pCnt && !pCnt->IsInDocBody() ) + pCnt = pCnt->GetNextCntntFrm(); + + if ( !pCnt ) + return Point( 0, 0 ); + + pCnt->Calc(); + if( !bNext ) + { + // Solange der Point vor dem ersten CntntFrm liegt und es noch + // vorhergehende Seiten gibt gehe ich jeweils eine Seite nach vorn. + while ( rPoint.Y() < pCnt->Frm().Top() && pPage->GetPrev() ) + { + pPage = (SwLayoutFrm*)pPage->GetPrev(); + pCnt = pPage->ContainsCntnt(); + while ( !pCnt ) + { + pPage = (SwLayoutFrm*)pPage->GetPrev(); + if ( pPage ) + pCnt = pPage->ContainsCntnt(); + else + return ContainsCntnt()->UnionFrm().Pos(); + } + pCnt->Calc(); + } + } + + //Liegt der Point ueber dem ersten CntntFrm? + if ( rPoint.Y() < pCnt->Frm().Top() && !lcl_IsInRepeatedHeadline( pCnt ) ) + return pCnt->UnionFrm().Pos(); + + while ( pCnt ) + { + //Liegt der Point im aktuellen CntntFrm? + SwRect aCntFrm( pCnt->UnionFrm() ); + if ( aCntFrm.IsInside( rPoint ) && !lcl_IsInRepeatedHeadline( pCnt )) + return rPoint; + + //Ist der aktuelle der letzte CntntFrm? || + //Wenn der naechste CntntFrm hinter dem Point liegt, ist der + //aktuelle der gesuchte. + const SwCntntFrm *pNxt = pCnt->GetNextCntntFrm(); + while ( pNxt && !pNxt->IsInDocBody() ) + pNxt = pNxt->GetNextCntntFrm(); + + //Liegt der Point hinter dem letzten CntntFrm? + if ( !pNxt ) + return Point( aCntFrm.Right(), aCntFrm.Bottom() ); + + //Wenn der naechste CntntFrm hinter dem Point liegt ist er der + //gesuchte. + const SwTabFrm* pTFrm; + pNxt->Calc(); + if( pNxt->Frm().Top() > rPoint.Y() && + !lcl_IsInRepeatedHeadline( pCnt, &pTFrm ) && + ( !pTFrm || pNxt->Frm().Left() > rPoint.X() )) + { + if( bNext ) + return pNxt->Frm().Pos(); + return Point( aCntFrm.Right(), aCntFrm.Bottom() ); + } + pCnt = pNxt; + } + return Point( 0, 0 ); +} + +/************************************************************************* +|* +|* SwRootFrm::GetPagePos() +|* +|* Beschreibung: Liefert die absolute Dokumentpositon der gewuenschten +|* Seite. +|* Formatiert wird nur soweit notwendig und nur dann wenn bFormat=TRUE +|* Liefert Null, wenn die Operation nicht moeglich ist. +|* Die Pos ist die der letzten Seite, wenn die Seitenzahl zu gross +|* gewaehlt wurde. +|* Ersterstellung MA 01. Jun. 92 +|* Letzte Aenderung MA 09. Oct. 97 +|* +|*************************************************************************/ +Point SwRootFrm::GetPagePos( USHORT nPageNum ) const +{ + ASSERT( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." ); + + const SwPageFrm *pPage = (const SwPageFrm*)Lower(); + while ( TRUE ) + { + if ( pPage->GetPhyPageNum() >= nPageNum || !pPage->GetNext() ) + break; + pPage = (const SwPageFrm*)pPage->GetNext(); + } + return pPage->Frm().Pos(); +} + +/** get page frame by phyiscal page number + + OD 14.01.2003 #103492# + + @return pointer to the page frame with the given physical page number +*/ +SwPageFrm* SwRootFrm::GetPageByPageNum( sal_uInt16 _nPageNum ) const +{ + const SwPageFrm* pPageFrm = static_cast<const SwPageFrm*>( Lower() ); + while ( pPageFrm && pPageFrm->GetPhyPageNum() < _nPageNum ) + { + pPageFrm = static_cast<const SwPageFrm*>( pPageFrm->GetNext() ); + } + + if ( pPageFrm && pPageFrm->GetPhyPageNum() == _nPageNum ) + { + return const_cast<SwPageFrm*>( pPageFrm ); + } + else + { + return 0; + } +} + +/************************************************************************* +|* +|* SwRootFrm::IsDummyPage(USHORT) +|* +|* Description: Returns TRUE, when the given physical pagenumber does't exist +|* or this page is an empty page. +|*************************************************************************/ +BOOL SwRootFrm::IsDummyPage( USHORT nPageNum ) const +{ + if( !Lower() || !nPageNum || nPageNum > GetPageNum() ) + return TRUE; + + const SwPageFrm *pPage = (const SwPageFrm*)Lower(); + while( pPage && nPageNum < pPage->GetPhyPageNum() ) + pPage = (const SwPageFrm*)pPage->GetNext(); + return pPage ? pPage->IsEmptyPage() : TRUE; +} + + +/************************************************************************* +|* +|* SwFrm::IsProtected() +|* +|* Beschreibung Ist der Frm bzw. die Section in der er steht +|* geschuetzt? +|* Auch Fly in Fly in ... und Fussnoten +|* +|* Ersterstellung MA 28. Jul. 93 +|* Letzte Aenderung MA 06. Nov. 97 +|* +|*************************************************************************/ +BOOL SwFrm::IsProtected() const +{ + if (this->IsCntntFrm() && ((SwCntntFrm*)this)->GetNode()) + { + const SwDoc *pDoc=((SwCntntFrm*)this)->GetNode()->GetDoc(); + bool isFormProtected=pDoc->get(IDocumentSettingAccess::PROTECT_FORM ); + if (isFormProtected) + { + return FALSE; // TODO a hack for now, well deal with it laster, I we return true here we have a "double" locking + } + } + //Der Frm kann in Rahmen, Zellen oder Bereichen geschuetzt sein. + //Geht auch FlyFrms rekursiv hoch. Geht auch von Fussnoten zum Anker. + const SwFrm *pFrm = this; + do + { + if ( pFrm->IsCntntFrm() ) + { + if ( ((SwCntntFrm*)pFrm)->GetNode() && + ((SwCntntFrm*)pFrm)->GetNode()->IsInProtectSect() ) + return TRUE; + } + else + { + if ( ((SwLayoutFrm*)pFrm)->GetFmt() && + ((SwLayoutFrm*)pFrm)->GetFmt()-> + GetProtect().IsCntntProtected() ) + return TRUE; + if ( pFrm->IsCoveredCell() ) + return TRUE; + } + if ( pFrm->IsFlyFrm() ) + { + //Der Schutz des Inhaltes kann bei Verkettung vom Master der Kette + //vorgegeben werden. + if ( ((SwFlyFrm*)pFrm)->GetPrevLink() ) + { + SwFlyFrm *pMaster = (SwFlyFrm*)pFrm; + do + { pMaster = pMaster->GetPrevLink(); + } while ( pMaster->GetPrevLink() ); + if ( pMaster->IsProtected() ) + return TRUE; + } + pFrm = ((SwFlyFrm*)pFrm)->GetAnchorFrm(); + } + else if ( pFrm->IsFtnFrm() ) + pFrm = ((SwFtnFrm*)pFrm)->GetRef(); + else + pFrm = pFrm->GetUpper(); + + } while ( pFrm ); + + return FALSE; +} + +/************************************************************************* +|* +|* SwFrm::GetPhyPageNum() +|* Beschreibung: Liefert die physikalische Seitennummer +|* +|* Ersterstellung OK 06.07.93 08:35 +|* Letzte Aenderung MA 30. Nov. 94 +|* +|*************************************************************************/ +USHORT SwFrm::GetPhyPageNum() const +{ + const SwPageFrm *pPage = FindPageFrm(); + return pPage ? pPage->GetPhyPageNum() : 0; +} + +/*-----------------26.02.01 11:25------------------- + * SwFrm::WannaRightPage() + * decides if the page want to be a rightpage or not. + * If the first content of the page has a page descriptor, + * we take the follow of the page descriptor of the last not empty page. + * If this descriptor allows only right(left) pages and the page + * isn't an empty page then it wanna be such right(left) page. + * If the descriptor allows right and left pages, we look for a number offset + * in the first content. If there is one, odd number results right pages, + * even number results left pages. + * If there is no number offset, we take the physical page number instead, + * but a previous empty page don't count. + * --------------------------------------------------*/ + +BOOL SwFrm::WannaRightPage() const +{ + const SwPageFrm *pPage = FindPageFrm(); + if ( !pPage || !pPage->GetUpper() ) + return TRUE; + + const SwFrm *pFlow = pPage->FindFirstBodyCntnt(); + SwPageDesc *pDesc = 0; + USHORT nPgNum = 0; + if ( pFlow ) + { + if ( pFlow->IsInTab() ) + pFlow = pFlow->FindTabFrm(); + const SwFlowFrm *pTmp = SwFlowFrm::CastFlowFrm( pFlow ); + if ( !pTmp->IsFollow() ) + { + const SwFmtPageDesc& rPgDesc = pFlow->GetAttrSet()->GetPageDesc(); + pDesc = (SwPageDesc*)rPgDesc.GetPageDesc(); + nPgNum = rPgDesc.GetNumOffset(); + } + } + if ( !pDesc ) + { + SwPageFrm *pPrv = (SwPageFrm*)pPage->GetPrev(); + if( pPrv && pPrv->IsEmptyPage() ) + pPrv = (SwPageFrm*)pPrv->GetPrev(); + if( pPrv ) + pDesc = pPrv->GetPageDesc()->GetFollow(); + else + { + const SwDoc* pDoc = pPage->GetFmt()->GetDoc(); + pDesc = (SwPageDesc*)&pDoc->GetPageDesc( 0 ); + } + } + ASSERT( pDesc, "No pagedescriptor" ); + BOOL bOdd; + if( nPgNum ) + bOdd = nPgNum % 2 ? TRUE : FALSE; + else + { + bOdd = pPage->OnRightPage(); + if( pPage->GetPrev() && ((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() ) + bOdd = !bOdd; + } + if( !pPage->IsEmptyPage() ) + { + if( !pDesc->GetRightFmt() ) + bOdd = FALSE; + else if( !pDesc->GetLeftFmt() ) + bOdd = TRUE; + } + return bOdd; +} + +/************************************************************************* +|* +|* SwFrm::GetVirtPageNum() +|* Beschreibung: Liefert die virtuelle Seitennummer mit Offset +|* +|* Ersterstellung OK 06.07.93 08:35 +|* Letzte Aenderung MA 30. Nov. 94 +|* +|*************************************************************************/ +USHORT SwFrm::GetVirtPageNum() const +{ + const SwPageFrm *pPage = FindPageFrm(); + if ( !pPage || !pPage->GetUpper() ) + return 0; + + USHORT nPhyPage = pPage->GetPhyPageNum(); + if ( !((SwRootFrm*)pPage->GetUpper())->IsVirtPageNum() ) + return nPhyPage; + + //Den am naechsten stehenden Absatz mit virtueller Seitennummer suchen. + //Da das rueckwaertsuchen insgesamt sehr viel Zeit verschlingt suchen + //wir jetzt gezielt ueber die Abhaengigkeiten. + //von den PageDescs bekommen wir die Attribute, von den Attributen + //wiederum bekommen wir die Absaetze. + const SwPageFrm *pVirtPage = 0; + const SwFrm *pFrm = 0; + const SfxItemPool &rPool = pPage->GetFmt()->GetDoc()->GetAttrPool(); + const SfxPoolItem* pItem; + USHORT nMaxItems = rPool.GetItemCount( RES_PAGEDESC ); + for( USHORT n = 0; n < nMaxItems; ++n ) + { + if( 0 == (pItem = rPool.GetItem( RES_PAGEDESC, n ) )) + continue; + + const SwFmtPageDesc *pDesc = (SwFmtPageDesc*)pItem; + if ( pDesc->GetNumOffset() && pDesc->GetDefinedIn() ) + { + const SwModify *pMod = pDesc->GetDefinedIn(); + SwVirtPageNumInfo aInfo( pPage ); + pMod->GetInfo( aInfo ); + if ( aInfo.GetPage() ) + { + if( !pVirtPage || ( pVirtPage && aInfo.GetPage()-> + GetPhyPageNum() > pVirtPage->GetPhyPageNum() ) ) + { + pVirtPage = aInfo.GetPage(); + pFrm = aInfo.GetFrm(); + } + } + } + } + if ( pFrm ) + return nPhyPage - pFrm->GetPhyPageNum() + + pFrm->GetAttrSet()->GetPageDesc().GetNumOffset(); + return nPhyPage; +} + +/************************************************************************* +|* +|* SwRootFrm::MakeTblCrsrs() +|* +|* Ersterstellung MA 14. May. 93 +|* Letzte Aenderung MA 02. Feb. 94 +|* +|*************************************************************************/ +//Ermitteln und einstellen derjenigen Zellen die von der Selektion +//eingeschlossen sind. + +bool SwRootFrm::MakeTblCrsrs( SwTableCursor& rTblCrsr ) +{ + //Union-Rects und Tabellen (Follows) der Selektion besorgen. + ASSERT( rTblCrsr.GetCntntNode() && rTblCrsr.GetCntntNode( FALSE ), + "Tabselection nicht auf Cnt." ); + + bool bRet = false; + + // For new table models there's no need to ask the layout.. + if( rTblCrsr.NewTableSelection() ) + return true; + + Point aPtPt, aMkPt; + { + SwShellCrsr* pShCrsr = dynamic_cast<SwShellCrsr*>(&rTblCrsr); + + if( pShCrsr ) + { + aPtPt = pShCrsr->GetPtPos(); + aMkPt = pShCrsr->GetMkPos(); + } + } + + // --> FME 2008-01-14 #151012# Made code robust here: + const SwCntntNode* pTmpStartNode = rTblCrsr.GetCntntNode(); + const SwCntntNode* pTmpEndNode = rTblCrsr.GetCntntNode(FALSE); + + const SwFrm* pTmpStartFrm = pTmpStartNode ? pTmpStartNode->GetFrm( &aPtPt, 0, FALSE ) : 0; + const SwFrm* pTmpEndFrm = pTmpEndNode ? pTmpEndNode->GetFrm( &aMkPt, 0, FALSE ) : 0; + + const SwLayoutFrm* pStart = pTmpStartFrm ? pTmpStartFrm->GetUpper() : 0; + const SwLayoutFrm* pEnd = pTmpEndFrm ? pTmpEndFrm->GetUpper() : 0; + + ASSERT( pStart && pEnd, "MakeTblCrsrs: Good to have the code robust here!" ) + // <-- + + /* #109590# Only change table boxes if the frames are + valid. Needed because otherwise the table cursor after moving + table cells by dnd resulted in an empty tables cursor. */ + if ( pStart && pEnd && pStart->IsValid() && pEnd->IsValid()) + { + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd ); + + SwSelBoxes aNew; + + const BOOL bReadOnlyAvailable = rTblCrsr.IsReadOnlyAvailable(); + + for ( USHORT i = 0; i < aUnions.Count(); ++i ) + { + SwSelUnion *pUnion = aUnions[i]; + const SwTabFrm *pTable = pUnion->GetTable(); + + // Skip any repeated headlines in the follow: + SwLayoutFrm* pRow = pTable->IsFollow() ? + pTable->GetFirstNonHeadlineRow() : + (SwLayoutFrm*)pTable->Lower(); + + while ( pRow ) + { + if ( pRow->Frm().IsOver( pUnion->GetUnion() ) ) + { + const SwLayoutFrm *pCell = pRow->FirstCell(); + + while ( pCell && pRow->IsAnLower( pCell ) ) + { + ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); + if( IsFrmInTblSel( pUnion->GetUnion(), pCell ) && + (bReadOnlyAvailable || + !pCell->GetFmt()->GetProtect().IsCntntProtected())) + { + SwTableBox* pInsBox = (SwTableBox*) + ((SwCellFrm*)pCell)->GetTabBox(); + aNew.Insert( pInsBox ); + } + if ( pCell->GetNext() ) + { + pCell = (const SwLayoutFrm*)pCell->GetNext(); + if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) + pCell = pCell->FirstCell(); + } + else + { + const SwLayoutFrm* pLastCell = pCell; + do + { + pCell = pCell->GetNextLayoutLeaf(); + } while ( pCell && pLastCell->IsAnLower( pCell ) ); + // Fuer (spaltige) Bereiche... + if( pCell && pCell->IsInTab() ) + { + while( !pCell->IsCellFrm() ) + { + pCell = pCell->GetUpper(); + ASSERT( pCell, "Where's my cell?" ); + } + } + } + } + } + pRow = (SwLayoutFrm*)pRow->GetNext(); + } + } + + rTblCrsr.ActualizeSelection( aNew ); + bRet = true; + } + + return bRet; +} + + +/************************************************************************* +|* +|* SwRootFrm::CalcFrmRects +|* +|* Ersterstellung MA 24. Aug. 92 +|* Letzte Aenderung MA 24. Aug. 93 +|* +|*************************************************************************/ + +/* + * nun koennen folgende Situationen auftreten: + * 1. Start und Ende liegen in einer Bildschirm - Zeile und im + * gleichen Node + * -> aus Start und End ein Rectangle, dann Ok + * 2. Start und Ende liegen in einem Frame (dadurch im gleichen Node!) + * -> Start nach rechts, End nach links erweitern, + * und bei mehr als 2 Bildschirm - Zeilen, das dazwischen + * liegende berechnen + * 3. Start und Ende liegen in verschiedenen Frames + * -> Start nach rechts erweitern, bis Frame-Ende Rect berechnen + * Ende nach links erweitern, bis Frame-Start Rect berechnen + * und bei mehr als 2 Frames von allen dazwischen liegenden + * Frames die PrtArea dazu. + * 4. Wenn es sich um eine Tabellenselektion handelt wird fuer jeden + * PaM im Ring der CellFrm besorgt, dessen PrtArea wird zu den + * Rechtecken addiert. + * + * Grosser Umbau wg. der FlyFrm; denn diese muessen ausgespart werden. + * Ausnahmen: - Der Fly in dem die Selektion stattfindet (wenn sie in einem Fly + * stattfindet). + * - Die Flys, die vom Text unterlaufen werden. + * Arbeitsweise: Zuerst wird eine SwRegion mit der Root initialisiert. + * Aus der Region werden die zu invertierenden Bereiche + * ausgestantzt. Die Region wird Komprimiert und letztlich + * invertiert. Damit liegen dann die zu invertierenden + * Rechtecke vor. + * Am Ende werden die Flys aus der Region ausgestanzt. + */ + +inline void Sub( SwRegionRects& rRegion, const SwRect& rRect ) +{ + if( rRect.Width() > 1 && rRect.Height() > 1 && + rRect.IsOver( rRegion.GetOrigin() )) + rRegion -= rRect; +} + +void SwRootFrm::CalcFrmRects( SwShellCrsr &rCrsr, BOOL bIsTblMode ) +{ + const SwNodes &rNds = GetFmt()->GetDoc()->GetNodes(); + SwPosition *pStartPos = rCrsr.Start(), + *pEndPos = rCrsr.GetPoint() == pStartPos ? + rCrsr.GetMark() : rCrsr.GetPoint(); + + ViewShell *pSh = GetShell(); + +// --> FME 2004-06-08 #i12836# enhanced pdf + SwRegionRects aRegion( pSh && !pSh->GetViewOptions()->IsPDFExport() ? + pSh->VisArea() : + Frm() ); +// <-- + if( !pStartPos->nNode.GetNode().IsCntntNode() || + !pStartPos->nNode.GetNode().GetCntntNode()->GetFrm() || + ( pStartPos->nNode != pEndPos->nNode && + ( !pEndPos->nNode.GetNode().IsCntntNode() || + !pEndPos->nNode.GetNode().GetCntntNode()->GetFrm() ) ) ) + { + /* For SelectAll we will need something like this later on... + const SwFrm* pPageFrm = GetLower(); + while( pPageFrm ) + { + SwRect aTmp( pPageFrm->Prt() ); + aTmp.Pos() += pPageFrm->Frm().Pos(); + Sub( aRegion, aTmp ); + pPageFrm = pPageFrm->GetNext(); + } + aRegion.Invert(); + rCrsr.Remove( 0, rCrsr.Count() ); + rCrsr.Insert( &aRegion, 0 ); + */ + return; + } + + //Erstmal die CntntFrms zum Start und End besorgen, die brauch ich auf + //jedenfall. + const SwCntntFrm *pStartFrm = rNds[ pStartPos->nNode ]-> + GetCntntNode()->GetFrm( &rCrsr.GetSttPos(), pStartPos ); + + const SwCntntFrm *pEndFrm = rNds[ pEndPos->nNode ]-> + GetCntntNode()->GetFrm( &rCrsr.GetEndPos(), pEndPos ); + + ASSERT( (pStartFrm && pEndFrm), "Keine CntntFrms gefunden." ); + + //Damit die FlyFrms, in denen selektierte Frames stecken, nicht + //abgezogen werden + SwSortedObjs aSortObjs; + if ( pStartFrm->IsInFly() ) + { + const SwAnchoredObject* pObj = pStartFrm->FindFlyFrm(); + aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj)) ); + const SwAnchoredObject* pObj2 = pEndFrm->FindFlyFrm(); + aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj2)) ); + } + + //Fall 4: Tabellenselection + if( bIsTblMode ) + { + const SwFrm *pCell = pStartFrm->GetUpper(); + while ( !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + SwRect aTmp( pCell->Prt() ); + aTmp.Pos() += pCell->Frm().Pos(); + aRegion.ChangeOrigin( aTmp ); + aRegion.Remove( 0, aRegion.Count() ); + aRegion.Insert( aTmp, 0 ); + } + else + { + // falls eine nicht erlaubte Selection besteht, dann korrigiere das + // nicht erlaubt ist Header/Footer/TableHeadline ueber 2 Seiten + do { // middle check loop + const SwLayoutFrm* pSttLFrm = pStartFrm->GetUpper(); + const USHORT cHdFtTblHd = FRM_HEADER | FRM_FOOTER | FRM_TAB; + while( pSttLFrm && + ! (cHdFtTblHd & pSttLFrm->GetType() )) + pSttLFrm = pSttLFrm->GetUpper(); + if( !pSttLFrm ) + break; + const SwLayoutFrm* pEndLFrm = pEndFrm->GetUpper(); + while( pEndLFrm && + ! (cHdFtTblHd & pEndLFrm->GetType() )) + pEndLFrm = pEndLFrm->GetUpper(); + if( !pEndLFrm ) + break; + + ASSERT( pEndLFrm->GetType() == pSttLFrm->GetType(), + "Selection ueber unterschiedliche Inhalte" ); + switch( pSttLFrm->GetType() ) + { + case FRM_HEADER: + case FRM_FOOTER: + // auf unterschiedlichen Seiten ?? + // dann immer auf die Start-Seite + if( pEndLFrm->FindPageFrm() != pSttLFrm->FindPageFrm() ) + { + // End- auf den Start-CntntFrame setzen + if( pStartPos == rCrsr.GetPoint() ) + pEndFrm = pStartFrm; + else + pStartFrm = pEndFrm; + } + break; + case FRM_TAB: + // auf unterschiedlichen Seiten ?? + // existiert + // dann teste auf Tabelle-Headline + { + const SwTabFrm* pTabFrm = (SwTabFrm*)pSttLFrm; + if( ( pTabFrm->GetFollow() || + ((SwTabFrm*)pEndLFrm)->GetFollow() ) && + pTabFrm->GetTable()->GetRowsToRepeat() > 0 && + pTabFrm->GetLower() != ((SwTabFrm*)pEndLFrm)->GetLower() && + ( lcl_IsInRepeatedHeadline( pStartFrm ) || + lcl_IsInRepeatedHeadline( pEndFrm ) ) ) + { + // End- auf den Start-CntntFrame setzen + if( pStartPos == rCrsr.GetPoint() ) + pEndFrm = pStartFrm; + else + pStartFrm = pEndFrm; + } + } + break; + } + } while( FALSE ); + + SwCrsrMoveState aTmpState( MV_NONE ); + aTmpState.b2Lines = sal_True; + aTmpState.bNoScroll = sal_True; + aTmpState.nCursorBidiLevel = pStartFrm->IsRightToLeft() ? 1 : 0; + + //CntntRects zu Start- und EndFrms. + SwRect aStRect, aEndRect; + pStartFrm->GetCharRect( aStRect, *pStartPos, &aTmpState ); + Sw2LinesPos *pSt2Pos = aTmpState.p2Lines; + aTmpState.p2Lines = NULL; + aTmpState.nCursorBidiLevel = pEndFrm->IsRightToLeft() ? 1 : 0; + + pEndFrm->GetCharRect ( aEndRect, *pEndPos, &aTmpState ); + Sw2LinesPos *pEnd2Pos = aTmpState.p2Lines; + + SwRect aStFrm ( pStartFrm->UnionFrm( sal_True ) ); + aStFrm.Intersection( pStartFrm->PaintArea() ); + SwRect aEndFrm( pStartFrm == pEndFrm ? aStFrm : + pEndFrm->UnionFrm( sal_True ) ); + if( pStartFrm != pEndFrm ) + aEndFrm.Intersection( pEndFrm->PaintArea() ); + SWRECTFN( pStartFrm ) + const BOOL bR2L = pStartFrm->IsRightToLeft(); + const BOOL bEndR2L = pEndFrm->IsRightToLeft(); + + // If there's no doubleline portion involved or start and end are both + // in the same doubleline portion, all works fine, but otherwise + // we need the following... + if( pSt2Pos != pEnd2Pos && ( !pSt2Pos || !pEnd2Pos || + pSt2Pos->aPortion != pEnd2Pos->aPortion ) ) + { + // If we have a start(end) position inside a doubleline portion + // the surrounded part of the doubleline portion is subtracted + // from the region and the aStRect(aEndRect) is set to the + // end(start) of the doubleline portion. + if( pSt2Pos ) + { + SwRect aTmp( aStRect ); + + // BiDi-Portions are swimming against the current. + const sal_Bool bPorR2L = ( MT_BIDI == pSt2Pos->nMultiType ) ? + ! bR2L : + bR2L; + + if( MT_BIDI == pSt2Pos->nMultiType && + (pSt2Pos->aPortion2.*fnRect->fnGetWidth)() ) + { + // nested bidi portion + long nRightAbs = (pSt2Pos->aPortion.*fnRect->fnGetRight)(); + nRightAbs -= (pSt2Pos->aPortion2.*fnRect->fnGetLeft)(); + long nLeftAbs = nRightAbs - (pSt2Pos->aPortion2.*fnRect->fnGetWidth)(); + + (aTmp.*fnRect->fnSetRight)( nRightAbs ); + + if ( ! pEnd2Pos || pEnd2Pos->aPortion != pSt2Pos->aPortion ) + { + SwRect aTmp2( pSt2Pos->aPortion ); + (aTmp2.*fnRect->fnSetRight)( nLeftAbs ); + aTmp2.Intersection( aEndFrm ); + Sub( aRegion, aTmp2 ); + } + } + else + { + if( bPorR2L ) + (aTmp.*fnRect->fnSetLeft)( + (pSt2Pos->aPortion.*fnRect->fnGetLeft)() ); + else + (aTmp.*fnRect->fnSetRight)( + (pSt2Pos->aPortion.*fnRect->fnGetRight)() ); + } + + if( MT_ROT_90 == pSt2Pos->nMultiType || + (pSt2Pos->aPortion.*fnRect->fnGetTop)() == + (aTmp.*fnRect->fnGetTop)() ) + { + (aTmp.*fnRect->fnSetTop)( + (pSt2Pos->aLine.*fnRect->fnGetTop)() ); + } + + aTmp.Intersection( aStFrm ); + Sub( aRegion, aTmp ); + + SwTwips nTmp = (pSt2Pos->aLine.*fnRect->fnGetBottom)(); + if( MT_ROT_90 != pSt2Pos->nMultiType && + (aStRect.*fnRect->fnBottomDist)( nTmp ) > 0 ) + { + (aTmp.*fnRect->fnSetTop)( (aTmp.*fnRect->fnGetBottom)() ); + (aTmp.*fnRect->fnSetBottom)( nTmp ); + if( (aStRect.*fnRect->fnBottomDist)( + (pSt2Pos->aPortion.*fnRect->fnGetBottom)() ) > 0 ) + { + if( bPorR2L ) + (aTmp.*fnRect->fnSetRight)( + (pSt2Pos->aPortion.*fnRect->fnGetRight)() ); + else + (aTmp.*fnRect->fnSetLeft)( + (pSt2Pos->aPortion.*fnRect->fnGetLeft)() ); + } + aTmp.Intersection( aStFrm ); + Sub( aRegion, aTmp ); + } + + aStRect = pSt2Pos->aLine; + (aStRect.*fnRect->fnSetLeft)( bR2L ? + (pSt2Pos->aPortion.*fnRect->fnGetLeft)() : + (pSt2Pos->aPortion.*fnRect->fnGetRight)() ); + (aStRect.*fnRect->fnSetWidth)( 1 ); + } + + if( pEnd2Pos ) + { + SWRECTFNX( pEndFrm ) + SwRect aTmp( aEndRect ); + + // BiDi-Portions are swimming against the current. + const sal_Bool bPorR2L = ( MT_BIDI == pEnd2Pos->nMultiType ) ? + ! bEndR2L : + bEndR2L; + + if( MT_BIDI == pEnd2Pos->nMultiType && + (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)() ) + { + // nested bidi portion + long nRightAbs = (pEnd2Pos->aPortion.*fnRectX->fnGetRight)(); + nRightAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetLeft)(); + long nLeftAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)(); + + (aTmp.*fnRectX->fnSetLeft)( nLeftAbs ); + + if ( ! pSt2Pos || pSt2Pos->aPortion != pEnd2Pos->aPortion ) + { + SwRect aTmp2( pEnd2Pos->aPortion ); + (aTmp2.*fnRectX->fnSetLeft)( nRightAbs ); + aTmp2.Intersection( aEndFrm ); + Sub( aRegion, aTmp2 ); + } + } + else + { + if ( bPorR2L ) + (aTmp.*fnRectX->fnSetRight)( + (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() ); + else + (aTmp.*fnRectX->fnSetLeft)( + (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() ); + } + + if( MT_ROT_90 == pEnd2Pos->nMultiType || + (pEnd2Pos->aPortion.*fnRectX->fnGetBottom)() == + (aEndRect.*fnRectX->fnGetBottom)() ) + { + (aTmp.*fnRectX->fnSetBottom)( + (pEnd2Pos->aLine.*fnRectX->fnGetBottom)() ); + } + + aTmp.Intersection( aEndFrm ); + Sub( aRegion, aTmp ); + + // The next statement means neither ruby nor rotate(90): + if( !( MT_RUBY & pEnd2Pos->nMultiType ) ) + { + SwTwips nTmp = (pEnd2Pos->aLine.*fnRectX->fnGetTop)(); + if( (aEndRect.*fnRectX->fnGetTop)() != nTmp ) + { + (aTmp.*fnRectX->fnSetBottom)( + (aTmp.*fnRectX->fnGetTop)() ); + (aTmp.*fnRectX->fnSetTop)( nTmp ); + if( (aEndRect.*fnRectX->fnGetTop)() != + (pEnd2Pos->aPortion.*fnRectX->fnGetTop)() ) + if( bPorR2L ) + (aTmp.*fnRectX->fnSetLeft)( + (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() ); + else + (aTmp.*fnRectX->fnSetRight)( + (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() ); + aTmp.Intersection( aEndFrm ); + Sub( aRegion, aTmp ); + } + } + + aEndRect = pEnd2Pos->aLine; + (aEndRect.*fnRectX->fnSetLeft)( bEndR2L ? + (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() : + (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() ); + (aEndRect.*fnRectX->fnSetWidth)( 1 ); + } + } + else if( pSt2Pos && pEnd2Pos && + MT_BIDI == pSt2Pos->nMultiType && + MT_BIDI == pEnd2Pos->nMultiType && + pSt2Pos->aPortion == pEnd2Pos->aPortion && + pSt2Pos->aPortion2 != pEnd2Pos->aPortion2 ) + { + // This is the ugly special case, where the selection starts and + // ends in the same bidi portion but one start or end is inside a + // nested bidi portion. + + if ( (pSt2Pos->aPortion2.*fnRect->fnGetWidth)() ) + { + SwRect aTmp( aStRect ); + long nRightAbs = (pSt2Pos->aPortion.*fnRect->fnGetRight)(); + nRightAbs -= (pSt2Pos->aPortion2.*fnRect->fnGetLeft)(); + long nLeftAbs = nRightAbs - (pSt2Pos->aPortion2.*fnRect->fnGetWidth)(); + + (aTmp.*fnRect->fnSetRight)( nRightAbs ); + aTmp.Intersection( aStFrm ); + Sub( aRegion, aTmp ); + + aStRect = pSt2Pos->aLine; + (aStRect.*fnRect->fnSetLeft)( bR2L ? nRightAbs : nLeftAbs ); + (aStRect.*fnRect->fnSetWidth)( 1 ); + } + + SWRECTFNX( pEndFrm ) + if ( (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)() ) + { + SwRect aTmp( aEndRect ); + long nRightAbs = (pEnd2Pos->aPortion.*fnRectX->fnGetRight)(); + nRightAbs -= (pEnd2Pos->aPortion2.*fnRectX->fnGetLeft)(); + long nLeftAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)(); + + (aTmp.*fnRectX->fnSetLeft)( nLeftAbs ); + aTmp.Intersection( aEndFrm ); + Sub( aRegion, aTmp ); + + aEndRect = pEnd2Pos->aLine; + (aEndRect.*fnRectX->fnSetLeft)( bEndR2L ? nLeftAbs : nRightAbs ); + (aEndRect.*fnRectX->fnSetWidth)( 1 ); + } + } + + // The charrect may be outside the paintarea (for cursortravelling) + // but the selection has to be restricted to the paintarea + if( aStRect.Left() < aStFrm.Left() ) + aStRect.Left( aStFrm.Left() ); + else if( aStRect.Left() > aStFrm.Right() ) + aStRect.Left( aStFrm.Right() ); + SwTwips nTmp = aStRect.Right(); + if( nTmp < aStFrm.Left() ) + aStRect.Right( aStFrm.Left() ); + else if( nTmp > aStFrm.Right() ) + aStRect.Right( aStFrm.Right() ); + if( aEndRect.Left() < aEndFrm.Left() ) + aEndRect.Left( aEndFrm.Left() ); + else if( aEndRect.Left() > aEndFrm.Right() ) + aEndRect.Left( aEndFrm.Right() ); + nTmp = aEndRect.Right(); + if( nTmp < aEndFrm.Left() ) + aEndRect.Right( aEndFrm.Left() ); + else if( nTmp > aEndFrm.Right() ) + aEndRect.Right( aEndFrm.Right() ); + + if( pStartFrm == pEndFrm ) + { + sal_Bool bSameRotatedOrBidi = pSt2Pos && pEnd2Pos && + ( MT_BIDI & pSt2Pos->nMultiType ) && + pSt2Pos->aPortion == pEnd2Pos->aPortion; + //case 1: (Same frame and same row) + if( bSameRotatedOrBidi || + (aStRect.*fnRect->fnGetTop)() == (aEndRect.*fnRect->fnGetTop)() ) + { + Point aTmpSt( aStRect.Pos() ); + Point aTmpEnd( aEndRect.Right(), aEndRect.Bottom() ); + if( bSameRotatedOrBidi || bR2L ) + { + if( aTmpSt.Y() > aTmpEnd.Y() ) + { + long nTmpY = aTmpEnd.Y(); + aTmpEnd.Y() = aTmpSt.Y(); + aTmpSt.Y() = nTmpY; + } + if( aTmpSt.X() > aTmpEnd.X() ) + { + long nTmpX = aTmpEnd.X(); + aTmpEnd.X() = aTmpSt.X(); + aTmpSt.X() = nTmpX; + } + } + + SwRect aTmp = SwRect( aTmpSt, aTmpEnd ); + // Bug 34888: falls Inhalt selektiert ist, der keinen Platz + // einnimmt (z.B. PostIts,RefMarks, TOXMarks), + // dann mindestens die Breite des Crsr setzen. + if( 1 == (aTmp.*fnRect->fnGetWidth)() && + pStartPos->nContent.GetIndex() != + pEndPos->nContent.GetIndex() ) + { + OutputDevice* pOut = pSh->GetOut(); + long nCrsrWidth = pOut->GetSettings().GetStyleSettings(). + GetCursorSize(); + (aTmp.*fnRect->fnSetWidth)( pOut->PixelToLogic( + Size( nCrsrWidth, 0 ) ).Width() ); + } + aTmp.Intersection( aStFrm ); + Sub( aRegion, aTmp ); + } + //case 2: (Same frame, but not the same line) + else + { + SwTwips lLeft, lRight; + if( pSt2Pos && pEnd2Pos && pSt2Pos->aPortion == pEnd2Pos->aPortion ) + { + lLeft = (pSt2Pos->aPortion.*fnRect->fnGetLeft)(); + lRight = (pSt2Pos->aPortion.*fnRect->fnGetRight)(); + } + else + { + lLeft = (pStartFrm->Frm().*fnRect->fnGetLeft)() + + (pStartFrm->Prt().*fnRect->fnGetLeft)(); + lRight = (pStartFrm->Frm().*fnRect->fnGetLeft)() + + (pStartFrm->Prt().*fnRect->fnGetRight)(); + } + if( lLeft < (aStFrm.*fnRect->fnGetLeft)() ) + lLeft = (aStFrm.*fnRect->fnGetLeft)(); + if( lRight > (aStFrm.*fnRect->fnGetRight)() ) + lRight = (aStFrm.*fnRect->fnGetRight)(); + SwRect aSubRect( aStRect ); + //First line + if( bR2L ) + (aSubRect.*fnRect->fnSetLeft)( lLeft ); + else + (aSubRect.*fnRect->fnSetRight)( lRight ); + Sub( aRegion, aSubRect ); + + //If there's at least a twips between start- and endline, + //so the whole area between will be added. + SwTwips aTmpBottom = (aStRect.*fnRect->fnGetBottom)(); + SwTwips aTmpTop = (aEndRect.*fnRect->fnGetTop)(); + if( aTmpBottom != aTmpTop ) + { + (aSubRect.*fnRect->fnSetLeft)( lLeft ); + (aSubRect.*fnRect->fnSetRight)( lRight ); + (aSubRect.*fnRect->fnSetTop)( aTmpBottom ); + (aSubRect.*fnRect->fnSetBottom)( aTmpTop ); + Sub( aRegion, aSubRect ); + } + //and the last line + aSubRect = aEndRect; + if( bR2L ) + (aSubRect.*fnRect->fnSetRight)( lRight ); + else + (aSubRect.*fnRect->fnSetLeft)( lLeft ); + Sub( aRegion, aSubRect ); + } + } + //case 3: (Different frames, maybe with ohther frames between + else + { + //The startframe first... + SwRect aSubRect( aStRect ); + if( bR2L ) + (aSubRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)()); + else + (aSubRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)()); + Sub( aRegion, aSubRect ); + SwTwips nTmpTwips = (aStRect.*fnRect->fnGetBottom)(); + if( (aStFrm.*fnRect->fnGetBottom)() != nTmpTwips ) + { + aSubRect = aStFrm; + (aSubRect.*fnRect->fnSetTop)( nTmpTwips ); + Sub( aRegion, aSubRect ); + } + + //Now the frames between, if there are any + BOOL bBody = pStartFrm->IsInDocBody(); + const SwTableBox* pCellBox = pStartFrm->GetUpper()->IsCellFrm() ? + ((SwCellFrm*)pStartFrm->GetUpper())->GetTabBox() : 0; + const SwCntntFrm *pCntnt = pStartFrm->GetNextCntntFrm(); + SwRect aPrvRect; + + // --> OD 2006-01-24 #123908# - introduce robust code: + // The stacktrace issue reveals that <pCntnt> could be NULL. + // One root cause found by AMA - see #130650# + ASSERT( pCntnt, + "<SwRootFrm::CalcFrmRects(..)> - no content frame. This is a serious defect -> please inform OD" ); + while ( pCntnt && pCntnt != pEndFrm ) + // <-- + { + if ( pCntnt->IsInFly() ) + { + const SwAnchoredObject* pObj = pCntnt->FindFlyFrm(); + aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj)) ); + } + + // Consider only frames which have the same IsInDocBody value like pStartFrm + // If pStartFrm is inside a SwCellFrm, consider only frames which are inside the + // same cell frame (or its follow cell) + const SwTableBox* pTmpCellBox = pCntnt->GetUpper()->IsCellFrm() ? + ((SwCellFrm*)pCntnt->GetUpper())->GetTabBox() : 0; + if ( bBody == pCntnt->IsInDocBody() && + ( !pCellBox || pCellBox == pTmpCellBox ) ) + { + SwRect aCRect( pCntnt->UnionFrm( sal_True ) ); + aCRect.Intersection( pCntnt->PaintArea() ); + if( aCRect.IsOver( aRegion.GetOrigin() )) + { + SwRect aTmp( aPrvRect ); + aTmp.Union( aCRect ); + if ( (aPrvRect.Height() * aPrvRect.Width() + + aCRect.Height() * aCRect.Width()) == + (aTmp.Height() * aTmp.Width()) ) + { + aPrvRect.Union( aCRect ); + } + else + { + if ( aPrvRect.HasArea() ) + Sub( aRegion, aPrvRect ); + aPrvRect = aCRect; + } + } + } + pCntnt = pCntnt->GetNextCntntFrm(); + // --> OD 2006-01-24 #123908# + ASSERT( pCntnt, + "<SwRootFrm::CalcFrmRects(..)> - no content frame. This is a serious defect -> please inform OD" ); + // <-- + } + if ( aPrvRect.HasArea() ) + Sub( aRegion, aPrvRect ); + + //At least the endframe... + bVert = pEndFrm->IsVertical(); + bRev = pEndFrm->IsReverse(); + fnRect = bVert ? ( bRev ? fnRectVL2R : fnRectVert ) : + ( bRev ? fnRectB2T : fnRectHori ); + nTmpTwips = (aEndRect.*fnRect->fnGetTop)(); + if( (aEndFrm.*fnRect->fnGetTop)() != nTmpTwips ) + { + aSubRect = aEndFrm; + (aSubRect.*fnRect->fnSetBottom)( nTmpTwips ); + Sub( aRegion, aSubRect ); + } + aSubRect = aEndRect; + if( bEndR2L ) + (aSubRect.*fnRect->fnSetRight)((aEndFrm.*fnRect->fnGetRight)()); + else + (aSubRect.*fnRect->fnSetLeft)( (aEndFrm.*fnRect->fnGetLeft)() ); + Sub( aRegion, aSubRect ); + } + +// aRegion.Compress( FALSE ); + aRegion.Invert(); + delete pSt2Pos; + delete pEnd2Pos; + } + + //Flys mit Durchlauf ausstanzen. Nicht ausgestanzt werden Flys: + //- die Lower des StartFrm/EndFrm sind (FlyInCnt und alle Flys die wiederum + // darin sitzen) + //- in der Z-Order ueber denjenigen Flys stehen in denen sich der StartFrm + // befindet. + const SwPageFrm *pPage = pStartFrm->FindPageFrm(); + const SwPageFrm *pEndPage = pEndFrm->FindPageFrm(); + + while ( pPage ) + { + if ( pPage->GetSortedObjs() ) + { + const SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + for ( USHORT i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( !pAnchoredObj->ISA(SwFlyFrm) ) + continue; + const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj); + const SwVirtFlyDrawObj* pObj = pFly->GetVirtDrawObj(); + const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround(); + if ( !pFly->IsAnLower( pStartFrm ) && + (rSur.GetSurround() != SURROUND_THROUGHT && + !rSur.IsContour()) ) + { + if ( aSortObjs.Contains( *pAnchoredObj ) ) + continue; + + BOOL bSub = TRUE; + const UINT32 nPos = pObj->GetOrdNum(); + for ( USHORT k = 0; bSub && k < aSortObjs.Count(); ++k ) + { + ASSERT( aSortObjs[k]->ISA(SwFlyFrm), + "<SwRootFrm::CalcFrmRects(..)> - object in <aSortObjs> of unexcepted type" ); + const SwFlyFrm* pTmp = static_cast<SwFlyFrm*>(aSortObjs[k]); + do + { if ( nPos < pTmp->GetVirtDrawObj()->GetOrdNumDirect() ) + bSub = FALSE; + else + pTmp = pTmp->GetAnchorFrm()->FindFlyFrm(); + } while ( bSub && pTmp ); + } + if ( bSub ) + Sub( aRegion, pFly->Frm() ); + } + } + } + if ( pPage == pEndPage ) + break; + else + pPage = (SwPageFrm*)pPage->GetNext(); + } + + //Weil's besser aussieht noch die DropCaps ausschliessen. + SwRect aDropRect; + if ( pStartFrm->IsTxtFrm() ) + { + if ( ((SwTxtFrm*)pStartFrm)->GetDropRect( aDropRect ) ) + Sub( aRegion, aDropRect ); + } + if ( pEndFrm != pStartFrm && pEndFrm->IsTxtFrm() ) + { + if ( ((SwTxtFrm*)pEndFrm)->GetDropRect( aDropRect ) ) + Sub( aRegion, aDropRect ); + } + + rCrsr.Remove( 0, rCrsr.Count() ); + rCrsr.Insert( &aRegion, 0 ); +} + + |