| /************************************************************** |
| * |
| * 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 <hintids.hxx> |
| #include <hints.hxx> |
| #include <tools/bigint.hxx> |
| #include <editeng/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 ) {}; // ; <- ???? |
| |
| sal_Bool ChkOsz( const SwFlyFrm *pFly ) |
| { |
| sal_Bool bRet = sal_True; |
| if ( pFly != pStk1 && pFly != pStk2 ) |
| { |
| pStk1 = pStk2; |
| pStk2 = pFly; |
| bRet = sal_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 |
| |* |
| |*************************************************************************/ |
| sal_Bool SwLayoutFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, |
| SwCrsrMoveState* pCMS ) const |
| { |
| sal_Bool bRet = sal_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 = sal_True; |
| else |
| pFrm = pFrm->GetNext(); |
| if ( pCMS && pCMS->bStop ) |
| return sal_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 |
| |* |
| |*************************************************************************/ |
| |
| sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, |
| SwCrsrMoveState* pCMS ) const |
| { |
| sal_Bool bRet = sal_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 : sal_False ) || |
| !pFly->IsProtected() ) && |
| pFly->GetCrsrOfst( pPos, aPoint, pCMS ) ) |
| { |
| bRet = sal_True; |
| break; |
| } |
| |
| if ( pCMS && pCMS->bStop ) |
| return sal_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 = sal_True; |
| else |
| { |
| if ( pCMS && (pCMS->bStop || pCMS->bExactOnly) ) |
| { |
| ((SwCrsrMoveState*)pCMS)->bStop = sal_True; |
| return sal_False; |
| } |
| const SwCntntFrm *pCnt = GetCntntPos( aPoint, sal_False, sal_False, sal_False, pCMS, sal_False ); |
| if ( pCMS && pCMS->bStop ) |
| return sal_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 = sal_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 ( sal_uInt16 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 sal_False zurueckgegeben. |
| |* Ersterstellung MA 01. Jun. 92 |
| |* Letzte Aenderung MA 30. Nov. 94 |
| |* |
| |*************************************************************************/ |
| sal_Bool SwRootFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, |
| SwCrsrMoveState* pCMS ) const |
| { |
| sal_Bool bOldAction = IsCallbackActionEnabled(); |
| ((SwRootFrm*)this)->SetCallbackActionEnabled( sal_False ); |
| ASSERT( (Lower() && Lower()->IsPageFrm()), "Keinen PageFrm gefunden." ); |
| if( pCMS && pCMS->pFill ) |
| ((SwCrsrMoveState*)pCMS)->bFillRet = sal_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 sal_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 |
| |* |
| |*************************************************************************/ |
| sal_Bool SwCellFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, |
| SwCrsrMoveState* pCMS ) const |
| { |
| // cell frame does not necessarily have a lower (split table cell) |
| if ( !Lower() ) |
| return sal_False; |
| |
| if ( !(pCMS?pCMS->bSetInReadOnly:sal_False) && |
| GetFmt()->GetProtect().IsCntntProtected() ) |
| return sal_False; |
| |
| if ( pCMS && pCMS->eState == MV_TBLSEL ) |
| { |
| const SwTabFrm *pTab = FindTabFrm(); |
| if ( pTab->IsFollow() && pTab->IsInHeadline( *this ) ) |
| { |
| ((SwCrsrMoveState*)pCMS)->bStop = sal_True; |
| return sal_False; |
| } |
| } |
| |
| if ( Lower() ) |
| { |
| if ( Lower()->IsLayoutFrm() ) |
| return SwLayoutFrm::GetCrsrOfst( pPos, rPoint, pCMS ); |
| else |
| { |
| Calc(); |
| sal_Bool bRet = sal_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 sal_False; |
| } |
| pFrm = pFrm->GetNext(); |
| } |
| if ( !bRet ) |
| { |
| Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL; |
| const SwCntntFrm *pCnt = GetCntntPos( rPoint, sal_True ); |
| if( pPoint && pCnt->IsTxtFrm() ) |
| { |
| pCnt->GetCrsrOfst( pPos, *pPoint, pCMS ); |
| rPoint = *pPoint; |
| } |
| else |
| pCnt->GetCrsrOfst( pPos, rPoint, pCMS ); |
| delete pPoint; |
| } |
| return sal_True; |
| } |
| } |
| |
| return sal_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. |
| |
| sal_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(); |
| sal_Bool bInside = Frm().IsInside( rPoint ) && Lower(), |
| bRet = sal_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 = sal_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 ) || |
| sal_True == (bRet = pFly->GetCrsrOfst( pPos, rPoint, pCMS ))) |
| break; |
| if ( pCMS && pCMS->bStop ) |
| return sal_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 sal_False; |
| } |
| pFrm = pFrm->GetNext(); |
| } |
| if ( !bRet ) |
| { |
| Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL; |
| const SwCntntFrm *pCnt = GetCntntPos( |
| rPoint, sal_True, sal_False, sal_False, pCMS ); |
| if ( pCMS && pCMS->bStop ) |
| return sal_False; |
| if( pPoint && pCnt->IsTxtFrm() ) |
| { |
| pCnt->GetCrsrOfst( pPos, *pPoint, pCMS ); |
| rPoint = *pPoint; |
| } |
| else |
| pCnt->GetCrsrOfst( pPos, rPoint, pCMS ); |
| delete pPoint; |
| bRet = sal_True; |
| } |
| } |
| aOszCtrl.Exit( this ); |
| return bRet; |
| } |
| |
| /************************************************************************* |
| |* |
| |* Beschreibung Layoutabhaengiges Cursortravelling |
| |* Ersterstellung MA 23. Jul. 92 |
| |* Letzte Aenderung MA 06. Sep. 93 |
| |* |
| |*************************************************************************/ |
| sal_Bool SwCntntFrm::LeftMargin(SwPaM *pPam) const |
| { |
| if( pPam->GetNode() != (SwCntntNode*)GetNode() ) |
| return sal_False; |
| ((SwCntntNode*)GetNode())-> |
| MakeStartIndex((SwIndex *) &pPam->GetPoint()->nContent); |
| return sal_True; |
| } |
| |
| sal_Bool SwCntntFrm::RightMargin(SwPaM *pPam, sal_Bool) const |
| { |
| if( pPam->GetNode() != (SwCntntNode*)GetNode() ) |
| return sal_False; |
| ((SwCntntNode*)GetNode())-> |
| MakeEndIndex((SwIndex *) &pPam->GetPoint()->nContent); |
| return sal_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? |
| sal_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, |
| sal_Bool bMissHeadline, |
| sal_Bool bInReadOnly, |
| sal_Bool bMissFollowFlowLine ) |
| { |
| if ( pCnt && pCnt->IsInTab() ) |
| { |
| sal_Bool bProtect = sal_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 = sal_False; |
| else |
| pCnt = (*fnNxtPrv)( pCnt ); |
| } |
| } |
| else if ( !bInReadOnly ) |
| while ( pCnt && pCnt->IsProtected() ) |
| pCnt = (*fnNxtPrv)( pCnt ); |
| |
| return pCnt; |
| } |
| |
| sal_Bool MA_FASTCALL lcl_UpDown( SwPaM *pPam, const SwCntntFrm *pStart, |
| GetNxtPrvCnt fnNxtPrv, sal_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. |
| sal_Bool bTblSel = false; |
| if ( pStart->IsInTab() && |
| pPam->GetNode( sal_True )->StartOfSectionNode() != |
| pPam->GetNode( sal_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, sal_True, bInReadOnly, bTblSel ); |
| |
| |
| const SwTabFrm *pStTab = pStart->FindTabFrm(); |
| const SwTabFrm *pTable = 0; |
| const sal_Bool bTab = pStTab || (pCnt && pCnt->IsInTab()) ? sal_True : sal_False; |
| sal_Bool bEnd = bTab ? sal_False : sal_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, sal_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, sal_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, sal_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(); |
| sal_Bool bSame = sal_False; |
| const SwFrm *pCntUp = pCnt->GetUpper(); |
| while ( pCntUp && !bSame ) |
| { if ( pUp == pCntUp ) |
| bSame = sal_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, sal_True, bInReadOnly, bTblSel ); |
| } |
| } |
| |
| if ( bTab ) |
| { |
| if ( !pCnt ) |
| bEnd = sal_True; |
| else |
| { const SwTabFrm *pTab = pCnt->FindTabFrm(); |
| if( !pTab ) |
| bEnd = sal_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 = sal_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 = sal_True; |
| } |
| } |
| if ( !bEnd ) |
| { |
| pCnt = (*fnNxtPrv)( pCnt ); |
| pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_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 sal_True; |
| } |
| return sal_False; |
| } |
| |
| sal_Bool SwCntntFrm::UnitUp( SwPaM* pPam, const SwTwips, sal_Bool bInReadOnly ) const |
| { |
| return ::lcl_UpDown( pPam, this, lcl_GetPrvCnt, bInReadOnly ); |
| } |
| |
| sal_Bool SwCntntFrm::UnitDown( SwPaM* pPam, const SwTwips, sal_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 |
| |* |
| |*************************************************************************/ |
| sal_uInt16 SwRootFrm::GetCurrPage( const SwPaM *pActualCrsr ) const |
| { |
| ASSERT( pActualCrsr, "Welche Seite soll's denn sein?" ); |
| SwFrm const*const pActFrm = pActualCrsr->GetPoint()->nNode.GetNode(). |
| GetCntntNode()->getLayoutFrm( this, 0, |
| pActualCrsr->GetPoint(), |
| sal_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 |
| |* |
| |*************************************************************************/ |
| sal_uInt16 SwRootFrm::SetCurrPage( SwCursor* pToSet, sal_uInt16 nPageNum ) |
| { |
| ASSERT( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." ); |
| |
| SwPageFrm *pPage = (SwPageFrm*)Lower(); |
| sal_Bool bEnd =sal_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 = sal_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). |
| sal_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 sal_False; |
| |
| //Jetzt den gewuenschen CntntFrm unterhalb der Seite |
| if( 0 == (pCnt = (*fnPosPage)(pLayoutFrm)) ) |
| return sal_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 sal_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 sal_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 |
| |* |
| |*************************************************************************/ |
| sal_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 sal_Bool bDontLeave, |
| const sal_Bool bBodyOnly, |
| const sal_Bool bCalc, |
| const SwCrsrMoveState *pCMS, |
| const sal_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; |
| sal_uInt16 nMaxPage = GetPhyPageNum() + (bDefaultExpand ? 1 : 0); |
| Point aPoint = rPoint; |
| sal_uLong nDistance = ULONG_MAX; |
| |
| while ( sal_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, sal_False, |
| pCMS ? pCMS->bSetInReadOnly : sal_False, sal_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 sal_uLong nDiff = ::CalcDiff( aCntntPoint, rPoint ); |
| sal_Bool bBetter = nDiff < nDistance; // Dichter dran |
| if( !pInside ) |
| { |
| pInside = lcl_Inside( pCntnt, rPoint ); |
| if( pInside ) // Im "richtigen" Seitenteil |
| bBetter = sal_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 = sal_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; |
| sal_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 sal_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; |
| sal_Bool mbOldCallbackActionState; |
| |
| public: |
| DisableCallbackAction( const SwRootFrm& _rRootFrm ) : |
| mrRootFrm( const_cast<SwRootFrm&>(_rRootFrm) ), |
| mbOldCallbackActionState( _rRootFrm.IsCallbackActionEnabled() ) |
| { |
| mrRootFrm.SetCallbackActionEnabled( sal_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, sal_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=sal_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( sal_uInt16 nPageNum ) const |
| { |
| ASSERT( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." ); |
| |
| const SwPageFrm *pPage = (const SwPageFrm*)Lower(); |
| while ( sal_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(sal_uInt16) |
| |* |
| |* Description: Returns sal_True, when the given physical pagenumber does't exist |
| |* or this page is an empty page. |
| |*************************************************************************/ |
| sal_Bool SwRootFrm::IsDummyPage( sal_uInt16 nPageNum ) const |
| { |
| if( !Lower() || !nPageNum || nPageNum > GetPageNum() ) |
| return sal_True; |
| |
| const SwPageFrm *pPage = (const SwPageFrm*)Lower(); |
| while( pPage && nPageNum < pPage->GetPhyPageNum() ) |
| pPage = (const SwPageFrm*)pPage->GetNext(); |
| return pPage ? pPage->IsEmptyPage() : sal_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 |
| |* |
| |*************************************************************************/ |
| sal_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 sal_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 sal_True; |
| } |
| else |
| { |
| if ( ((SwLayoutFrm*)pFrm)->GetFmt() && |
| ((SwLayoutFrm*)pFrm)->GetFmt()-> |
| GetProtect().IsCntntProtected() ) |
| return sal_True; |
| if ( pFrm->IsCoveredCell() ) |
| return sal_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 sal_True; |
| } |
| pFrm = ((SwFlyFrm*)pFrm)->GetAnchorFrm(); |
| } |
| else if ( pFrm->IsFtnFrm() ) |
| pFrm = ((SwFtnFrm*)pFrm)->GetRef(); |
| else |
| pFrm = pFrm->GetUpper(); |
| |
| } while ( pFrm ); |
| |
| return sal_False; |
| } |
| |
| /************************************************************************* |
| |* |
| |* SwFrm::GetPhyPageNum() |
| |* Beschreibung: Liefert die physikalische Seitennummer |
| |* |
| |* Ersterstellung OK 06.07.93 08:35 |
| |* Letzte Aenderung MA 30. Nov. 94 |
| |* |
| |*************************************************************************/ |
| sal_uInt16 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. |
| * --------------------------------------------------*/ |
| |
| sal_Bool SwFrm::WannaRightPage() const |
| { |
| const SwPageFrm *pPage = FindPageFrm(); |
| if ( !pPage || !pPage->GetUpper() ) |
| return sal_True; |
| |
| const SwFrm *pFlow = pPage->FindFirstBodyCntnt(); |
| SwPageDesc *pDesc = 0; |
| sal_uInt16 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" ); |
| sal_Bool bOdd; |
| if( nPgNum ) |
| bOdd = nPgNum % 2 ? sal_True : sal_False; |
| else |
| { |
| bOdd = pPage->OnRightPage(); |
| if( pPage->GetPrev() && ((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() ) |
| bOdd = !bOdd; |
| } |
| if( !pPage->IsEmptyPage() ) |
| { |
| if( !pDesc->GetRightFmt() ) |
| bOdd = sal_False; |
| else if( !pDesc->GetLeftFmt() ) |
| bOdd = sal_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 |
| |* |
| |*************************************************************************/ |
| sal_uInt16 SwFrm::GetVirtPageNum() const |
| { |
| const SwPageFrm *pPage = FindPageFrm(); |
| if ( !pPage || !pPage->GetUpper() ) |
| return 0; |
| |
| sal_uInt16 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; |
| sal_uInt32 nMaxItems = rPool.GetItemCount2( RES_PAGEDESC ); |
| for( sal_uInt32 n = 0; n < nMaxItems; ++n ) |
| { |
| if( 0 == (pItem = rPool.GetItem2( 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( sal_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(sal_False); |
| |
| const SwFrm* pTmpStartFrm = pTmpStartNode ? pTmpStartNode->getLayoutFrm( this, &aPtPt, 0, sal_False ) : 0; |
| const SwFrm* pTmpEndFrm = pTmpEndNode ? pTmpEndNode->getLayoutFrm( this, &aMkPt, 0, sal_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 sal_Bool bReadOnlyAvailable = rTblCrsr.IsReadOnlyAvailable(); |
| |
| for ( sal_uInt16 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. |
| * |
| * 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 ) |
| { |
| SwPosition *pStartPos = rCrsr.Start(), |
| *pEndPos = rCrsr.GetPoint() == pStartPos ? rCrsr.GetMark() : rCrsr.GetPoint(); |
| |
| ViewShell *pSh = GetCurrShell(); |
| |
| SwRegionRects aRegion( pSh && !pSh->GetViewOptions()->IsPDFExport() ? |
| pSh->VisArea() : |
| Frm() ); |
| if( !pStartPos->nNode.GetNode().IsCntntNode() || |
| !pStartPos->nNode.GetNode().GetCntntNode()->getLayoutFrm(this) || |
| ( pStartPos->nNode != pEndPos->nNode && |
| ( !pEndPos->nNode.GetNode().IsCntntNode() || |
| !pEndPos->nNode.GetNode().GetCntntNode()->getLayoutFrm(this) ) ) ) |
| { |
| return; |
| } |
| |
| //Erstmal die CntntFrms zum Start und End besorgen, die brauch ich auf |
| //jedenfall. |
| SwCntntFrm const* pStartFrm = pStartPos->nNode.GetNode(). |
| GetCntntNode()->getLayoutFrm( this, &rCrsr.GetSttPos(), pStartPos ); |
| |
| SwCntntFrm const* pEndFrm = pEndPos->nNode.GetNode(). |
| GetCntntNode()->getLayoutFrm( this, &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(); |
| ASSERT( pObj2 != NULL, "SwRootFrm::CalcFrmRects(..) - FlyFrame missing - looks like an invalid selection" ); |
| if ( pObj2 != NULL && pObj2 != pObj ) |
| { |
| aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj2)) ); |
| } |
| } |
| |
| // 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 sal_uInt16 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 ( sal_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 sal_Bool bR2L = pStartFrm->IsRightToLeft(); |
| const sal_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 |
| sal_Bool bBody = pStartFrm->IsInDocBody(); |
| const SwTableBox* pCellBox = pStartFrm->GetUpper()->IsCellFrm() ? |
| ( (SwCellFrm*) pStartFrm->GetUpper() )->GetTabBox() : |
| 0; |
| const SwCntntFrm *pCntnt = pStartFrm->GetNextCntntFrm(); |
| SwRect aPrvRect; |
| |
| 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(); |
| 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(); |
| //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin |
| fnRect = bVert ? ( bRev ? fnRectVL2R : ( pEndFrm->IsVertLR() ? fnRectVertL2R : 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.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 ( sal_uInt16 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; |
| |
| sal_Bool bSub = sal_True; |
| const sal_uInt32 nPos = pObj->GetOrdNum(); |
| for ( sal_uInt16 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 = sal_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 ); |
| } |
| |
| |