Update ooo320-m1
[ooovba.git] / sw / source / core / layout / trvlfrm.cxx
blob0e7256351aec8796a3d7b2fcde680b42467fabfd
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: trvlfrm.cxx,v $
10 * $Revision: 1.63 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <hints.hxx>
37 #include <tools/bigint.hxx>
38 #include <svx/protitem.hxx>
39 #include <vcl/settings.hxx>
40 #include <vcl/outdev.hxx>
41 #include <fmtpdsc.hxx>
42 #include <fmtsrnd.hxx>
43 #include <pagedesc.hxx>
44 #include <pagefrm.hxx>
45 #include <rootfrm.hxx>
46 #include <cntfrm.hxx>
47 #include <ftnfrm.hxx>
48 #include <flyfrm.hxx>
49 #include <tabfrm.hxx>
50 #include <rowfrm.hxx>
51 #include <cellfrm.hxx>
52 #include <txtfrm.hxx>
53 #include <viewsh.hxx>
54 #include <viewopt.hxx>
55 #include <doc.hxx>
56 #include <viscrs.hxx>
57 #include <frmfmt.hxx>
58 #include <swtable.hxx>
59 #include <dflyobj.hxx>
60 #include <crstate.hxx>
61 #include <frmtool.hxx>
62 #include <ndtxt.hxx>
63 // OD 2004-05-24 #i28701#
64 #include <sortedobjs.hxx>
66 // FLT_MAX
67 #include <cfloat>
68 #include <swselectionlist.hxx>
70 //Fuer SwFlyFrm::GetCrsrOfst
71 class SwCrsrOszControl
73 public:
74 // damit schon der Compiler die Klasse initialisieren kann, keinen
75 // DTOR und member als publics:
76 const SwFlyFrm *pEntry;
77 const SwFlyFrm *pStk1;
78 const SwFlyFrm *pStk2;
80 //public:
81 // SwCrsrOszControl() : pStk1( 0 ), pStk2( 0 ) {}; // ; <- ????
83 BOOL ChkOsz( const SwFlyFrm *pFly )
85 BOOL bRet = TRUE;
86 if ( pFly != pStk1 && pFly != pStk2 )
88 pStk1 = pStk2;
89 pStk2 = pFly;
90 bRet = FALSE;
92 return bRet;
94 void Entry( const SwFlyFrm *pFly )
96 if ( !pEntry )
97 pEntry = pStk1 = pFly;
99 void Exit( const SwFlyFrm *pFly )
101 if ( pFly == pEntry )
102 pEntry = pStk1 = pStk2 = 0;
106 static SwCrsrOszControl aOszCtrl = { 0, 0, 0 };
108 /*************************************************************************
110 |* SwLayoutFrm::GetCrsrOfst()
112 |* Beschreibung: Sucht denjenigen CntntFrm, innerhalb dessen
113 |* PrtArea der Point liegt.
114 |* Ersterstellung MA 20. Jul. 92
115 |* Letzte Aenderung MA 23. May. 95
117 |*************************************************************************/
118 BOOL SwLayoutFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
119 SwCrsrMoveState* pCMS ) const
121 BOOL bRet = FALSE;
122 const SwFrm *pFrm = Lower();
123 while ( !bRet && pFrm )
125 pFrm->Calc();
127 // --> FME 2005-05-13 #i43742# New function: SW_CONTENT_CHECK
128 const bool bCntntCheck = pFrm->IsTxtFrm() && pCMS && pCMS->bCntntCheck;
129 const SwRect aPaintRect( bCntntCheck ?
130 pFrm->UnionFrm() :
131 pFrm->PaintArea() );
132 // <--
134 if ( aPaintRect.IsInside( rPoint ) &&
135 ( bCntntCheck || pFrm->GetCrsrOfst( pPos, rPoint, pCMS ) ) )
136 bRet = TRUE;
137 else
138 pFrm = pFrm->GetNext();
139 if ( pCMS && pCMS->bStop )
140 return FALSE;
142 return bRet;
145 /*************************************************************************
147 |* SwPageFrm::GetCrsrOfst()
149 |* Beschreibung: Sucht die Seite, innerhalb der der gesuchte Point
150 |* liegt.
151 |* Ersterstellung MA 20. Jul. 92
152 |* Letzte Aenderung MA 18. Jul. 96
154 |*************************************************************************/
156 BOOL SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
157 SwCrsrMoveState* pCMS ) const
159 BOOL bRet = FALSE;
160 Point aPoint( rPoint );
162 // check, if we have to adjust the point
163 if ( !Frm().IsInside( aPoint ) )
165 aPoint.X() = Max( aPoint.X(), Frm().Left() );
166 aPoint.X() = Min( aPoint.X(), Frm().Right() );
167 aPoint.Y() = Max( aPoint.Y(), Frm().Top() );
168 aPoint.Y() = Min( aPoint.Y(), Frm().Bottom() );
171 //Koennte ein Freifliegender gemeint sein?
172 //Wenn sein Inhalt geschuetzt werden soll, so ist nix mit Crsr
173 //hineinsetzen, dadurch sollten alle Aenderungen unmoeglich sein.
174 if ( GetSortedObjs() )
176 SwOrderIter aIter( this );
177 aIter.Top();
178 while ( aIter() )
180 const SwVirtFlyDrawObj* pObj =
181 static_cast<const SwVirtFlyDrawObj*>(aIter());
182 const SwFlyFrm* pFly = pObj ? pObj->GetFlyFrm() : 0;
183 if ( pFly &&
184 ( ( pCMS ? pCMS->bSetInReadOnly : FALSE ) ||
185 !pFly->IsProtected() ) &&
186 pFly->GetCrsrOfst( pPos, aPoint, pCMS ) )
188 bRet = TRUE;
189 break;
192 if ( pCMS && pCMS->bStop )
193 return FALSE;
194 aIter.Prev();
198 if ( !bRet )
200 //Wenn kein Cntnt unterhalb der Seite 'antwortet', so korrigieren
201 //wir den StartPoint und fangen nochmal eine Seite vor der
202 //aktuellen an. Mit Flys ist es dann allerdings vorbei.
203 if ( SwLayoutFrm::GetCrsrOfst( pPos, aPoint, pCMS ) )
204 bRet = TRUE;
205 else
207 if ( pCMS && (pCMS->bStop || pCMS->bExactOnly) )
209 ((SwCrsrMoveState*)pCMS)->bStop = TRUE;
210 return FALSE;
212 const SwCntntFrm *pCnt = GetCntntPos( aPoint, FALSE, FALSE, FALSE, pCMS, FALSE );
213 if ( pCMS && pCMS->bStop )
214 return FALSE;
216 ASSERT( pCnt, "Crsr is gone to a Black hole" );
217 if( pCMS && pCMS->pFill && pCnt->IsTxtFrm() )
218 bRet = pCnt->GetCrsrOfst( pPos, rPoint, pCMS );
219 else
220 bRet = pCnt->GetCrsrOfst( pPos, aPoint, pCMS );
222 if ( !bRet )
224 // Set point to pCnt, delete mark
225 // this may happen, if pCnt is hidden
226 *pPos = SwPosition( *pCnt->GetNode(), SwIndex( (SwTxtNode*)pCnt->GetNode(), 0 ) );
227 bRet = TRUE;
232 if ( bRet )
233 rPoint = aPoint;
235 return bRet;
238 bool SwLayoutFrm::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const
240 bool bRet = false;
241 if( rRect.IsOver(PaintArea()) )
243 const SwFrm* pFrm = Lower();
244 while( pFrm )
246 pFrm->FillSelection( rList, rRect );
247 pFrm = pFrm->GetNext();
250 return bRet;
253 bool SwPageFrm::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const
255 bool bRet = false;
256 if( rRect.IsOver(PaintArea()) )
258 bRet = SwLayoutFrm::FillSelection( rList, rRect );
259 if( GetSortedObjs() )
261 const SwSortedObjs &rObjs = *GetSortedObjs();
262 for ( USHORT i = 0; i < rObjs.Count(); ++i )
264 const SwAnchoredObject* pAnchoredObj = rObjs[i];
265 if( !pAnchoredObj->ISA(SwFlyFrm) )
266 continue;
267 const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj);
268 if( pFly->FillSelection( rList, rRect ) )
269 bRet = true;
273 return bRet;
276 bool SwRootFrm::FillSelection( SwSelectionList& aSelList, const SwRect& rRect) const
278 const SwFrm *pPage = Lower();
279 const long nBottom = rRect.Bottom();
280 while( pPage )
282 if( pPage->Frm().Top() < nBottom )
284 if( pPage->Frm().Bottom() > rRect.Top() )
285 pPage->FillSelection( aSelList, rRect );
286 pPage = pPage->GetNext();
288 else
289 pPage = 0;
291 return !aSelList.isEmpty();
294 /*************************************************************************
296 |* SwRootFrm::GetCrsrOfst()
298 |* Beschreibung: Reicht Primaer den Aufruf an die erste Seite weiter.
299 |* Wenn der 'reingereichte Point veraendert wird,
300 |* so wird FALSE zurueckgegeben.
301 |* Ersterstellung MA 01. Jun. 92
302 |* Letzte Aenderung MA 30. Nov. 94
304 |*************************************************************************/
305 BOOL SwRootFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
306 SwCrsrMoveState* pCMS ) const
308 sal_Bool bOldAction = IsCallbackActionEnabled();
309 ((SwRootFrm*)this)->SetCallbackActionEnabled( FALSE );
310 ASSERT( (Lower() && Lower()->IsPageFrm()), "Keinen PageFrm gefunden." );
311 if( pCMS && pCMS->pFill )
312 ((SwCrsrMoveState*)pCMS)->bFillRet = FALSE;
313 Point aOldPoint = rPoint;
315 // PAGES01
316 // search for page containing rPoint. The borders around the pages are considerd
317 const SwPageFrm* pPage = GetPageAtPos( rPoint, 0, true );
319 // --> OD 2008-12-23 #i95626#
320 // special handling for <rPoint> beyond root frames area
321 if ( !pPage &&
322 rPoint.X() > Frm().Right() &&
323 rPoint.Y() > Frm().Bottom() )
325 pPage = dynamic_cast<const SwPageFrm*>(Lower());
326 while ( pPage && pPage->GetNext() )
328 pPage = dynamic_cast<const SwPageFrm*>(pPage->GetNext());
331 // <--
332 if ( pPage )
334 pPage->SwPageFrm::GetCrsrOfst( pPos, rPoint, pCMS );
337 ((SwRootFrm*)this)->SetCallbackActionEnabled( bOldAction );
338 if( pCMS )
340 if( pCMS->bStop )
341 return FALSE;
342 if( pCMS->pFill )
343 return pCMS->bFillRet;
345 return aOldPoint == rPoint;
348 /*************************************************************************
350 |* SwCellFrm::GetCrsrOfst()
352 |* Beschreibung Wenn es sich um eine Cntnt-tragende Cell handelt wird
353 |* der Crsr notfalls mit Gewalt in einen der CntntFrms
354 |* gesetzt.
355 |* In geschuetzte Zellen gibt es hier keinen Eingang.
356 |* Ersterstellung MA 04. Jun. 93
357 |* Letzte Aenderung MA 23. May. 95
359 |*************************************************************************/
360 BOOL SwCellFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
361 SwCrsrMoveState* pCMS ) const
363 // cell frame does not necessarily have a lower (split table cell)
364 if ( !Lower() )
365 return FALSE;
367 if ( !(pCMS?pCMS->bSetInReadOnly:FALSE) &&
368 GetFmt()->GetProtect().IsCntntProtected() )
369 return FALSE;
371 if ( pCMS && pCMS->eState == MV_TBLSEL )
373 const SwTabFrm *pTab = FindTabFrm();
374 if ( pTab->IsFollow() && pTab->IsInHeadline( *this ) )
376 ((SwCrsrMoveState*)pCMS)->bStop = TRUE;
377 return FALSE;
381 if ( Lower() )
383 if ( Lower()->IsLayoutFrm() )
384 return SwLayoutFrm::GetCrsrOfst( pPos, rPoint, pCMS );
385 else
387 Calc();
388 BOOL bRet = FALSE;
390 const SwFrm *pFrm = Lower();
391 while ( pFrm && !bRet )
393 pFrm->Calc();
394 if ( pFrm->Frm().IsInside( rPoint ) )
396 bRet = pFrm->GetCrsrOfst( pPos, rPoint, pCMS );
397 if ( pCMS && pCMS->bStop )
398 return FALSE;
400 pFrm = pFrm->GetNext();
402 if ( !bRet )
404 Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL;
405 const SwCntntFrm *pCnt = GetCntntPos( rPoint, TRUE );
406 if( pPoint && pCnt->IsTxtFrm() )
408 pCnt->GetCrsrOfst( pPos, *pPoint, pCMS );
409 rPoint = *pPoint;
411 else
412 pCnt->GetCrsrOfst( pPos, rPoint, pCMS );
413 delete pPoint;
415 return TRUE;
419 return FALSE;
422 /*************************************************************************
424 |* SwFlyFrm::GetCrsrOfst()
426 |* Ersterstellung MA 15. Dec. 92
427 |* Letzte Aenderung MA 23. May. 95
429 |*************************************************************************/
430 //Problem: Wenn zwei Flys genau gleich gross sind und auf derselben
431 //Position stehen, so liegt jeder innerhalb des anderen.
432 //Da jeweils geprueft wird, ob der Point nicht zufaellig innerhalb eines
433 //anderen Flys liegt, der sich vollstaendig innerhalb des aktuellen befindet
434 //und ggf. ein rekursiver Aufruf erfolgt wuerde o.g. Situation zu einer
435 //endlosen Rekursion fuehren.
436 //Mit der Hilfsklasse SwCrsrOszControl unterbinden wir die Rekursion. Das
437 //GetCrsrOfst entscheidet sich bei einer Rekursion fuer denjenigen der
438 //am weitesten oben liegt.
440 BOOL SwFlyFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
441 SwCrsrMoveState* pCMS ) const
443 aOszCtrl.Entry( this );
445 //Wenn der Point innerhalb des Fly sitzt wollen wir energisch
446 //versuchen den Crsr hineinzusetzen.
447 //Wenn der Point allerdings in einem Flys sitzt, der sich vollstaendig
448 //innerhalb des aktuellen befindet, so wird fuer diesen das
449 //GetCrsrOfst gerufen.
450 Calc();
451 BOOL bInside = Frm().IsInside( rPoint ) && Lower(),
452 bRet = FALSE;
454 //Wenn der Frm eine Grafik enthaelt, aber nur Text gewuenscht ist, so
455 //nimmt er den Crsr grundsaetzlich nicht an.
456 if ( bInside && pCMS && pCMS->eState == MV_SETONLYTEXT &&
457 (!Lower() || Lower()->IsNoTxtFrm()) )
458 bInside = FALSE;
460 const SwPageFrm *pPage = FindPageFrm();
461 if ( bInside && pPage && pPage->GetSortedObjs() )
463 SwOrderIter aIter( pPage );
464 aIter.Top();
465 while ( aIter() && !bRet )
467 const SwVirtFlyDrawObj* pObj = static_cast<const SwVirtFlyDrawObj*>(aIter());
468 const SwFlyFrm* pFly = pObj ? pObj->GetFlyFrm() : 0;
469 if ( pFly && pFly->Frm().IsInside( rPoint ) &&
470 Frm().IsInside( pFly->Frm() ) )
472 if ( aOszCtrl.ChkOsz( pFly ) ||
473 TRUE == (bRet = pFly->GetCrsrOfst( pPos, rPoint, pCMS )))
474 break;
475 if ( pCMS && pCMS->bStop )
476 return FALSE;
478 aIter.Next();
482 while ( bInside && !bRet )
484 const SwFrm *pFrm = Lower();
485 while ( pFrm && !bRet )
487 pFrm->Calc();
488 if ( pFrm->Frm().IsInside( rPoint ) )
490 bRet = pFrm->GetCrsrOfst( pPos, rPoint, pCMS );
491 if ( pCMS && pCMS->bStop )
492 return FALSE;
494 pFrm = pFrm->GetNext();
496 if ( !bRet )
498 Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL;
499 const SwCntntFrm *pCnt = GetCntntPos(
500 rPoint, TRUE, FALSE, FALSE, pCMS );
501 if ( pCMS && pCMS->bStop )
502 return FALSE;
503 if( pPoint && pCnt->IsTxtFrm() )
505 pCnt->GetCrsrOfst( pPos, *pPoint, pCMS );
506 rPoint = *pPoint;
508 else
509 pCnt->GetCrsrOfst( pPos, rPoint, pCMS );
510 delete pPoint;
511 bRet = TRUE;
514 aOszCtrl.Exit( this );
515 return bRet;
518 /*************************************************************************
520 |* Beschreibung Layoutabhaengiges Cursortravelling
521 |* Ersterstellung MA 23. Jul. 92
522 |* Letzte Aenderung MA 06. Sep. 93
524 |*************************************************************************/
525 BOOL SwCntntFrm::LeftMargin(SwPaM *pPam) const
527 if( pPam->GetNode() != (SwCntntNode*)GetNode() )
528 return FALSE;
529 ((SwCntntNode*)GetNode())->
530 MakeStartIndex((SwIndex *) &pPam->GetPoint()->nContent);
531 return TRUE;
534 BOOL SwCntntFrm::RightMargin(SwPaM *pPam, BOOL) const
536 if( pPam->GetNode() != (SwCntntNode*)GetNode() )
537 return FALSE;
538 ((SwCntntNode*)GetNode())->
539 MakeEndIndex((SwIndex *) &pPam->GetPoint()->nContent);
540 return TRUE;
543 const SwCntntFrm *lcl_GetNxtCnt( const SwCntntFrm* pCnt )
545 return pCnt->GetNextCntntFrm();
548 const SwCntntFrm *lcl_GetPrvCnt( const SwCntntFrm* pCnt )
550 return pCnt->GetPrevCntntFrm();
553 typedef const SwCntntFrm *(*GetNxtPrvCnt)( const SwCntntFrm* );
555 //Frame in wiederholter Headline?
556 BOOL lcl_IsInRepeatedHeadline( const SwFrm *pFrm,
557 const SwTabFrm** ppTFrm = 0 )
559 const SwTabFrm *pTab = pFrm->FindTabFrm();
560 if( ppTFrm )
561 *ppTFrm = pTab;
562 return pTab && pTab->IsFollow() && pTab->IsInHeadline( *pFrm );
566 //Ueberspringen geschuetzter Tabellenzellen. Optional auch
567 //Ueberspringen von wiederholten Headlines.
568 //MA 26. Jan. 98: Chg auch andere Geschuetzte Bereiche ueberspringen.
569 // FME: Skip follow flow cells
570 const SwCntntFrm * MA_FASTCALL lcl_MissProtectedFrames( const SwCntntFrm *pCnt,
571 GetNxtPrvCnt fnNxtPrv,
572 BOOL bMissHeadline,
573 BOOL bInReadOnly,
574 BOOL bMissFollowFlowLine )
576 if ( pCnt && pCnt->IsInTab() )
578 BOOL bProtect = TRUE;
579 while ( pCnt && bProtect )
581 const SwLayoutFrm *pCell = pCnt->GetUpper();
582 while ( pCell && !pCell->IsCellFrm() )
583 pCell = pCell->GetUpper();
584 if ( !pCell ||
585 ( ( bInReadOnly || !pCell->GetFmt()->GetProtect().IsCntntProtected() ) &&
586 ( !bMissHeadline || !lcl_IsInRepeatedHeadline( pCell ) ) &&
587 ( !bMissFollowFlowLine || !pCell->IsInFollowFlowRow() ) ) &&
588 !pCell->IsCoveredCell() )
589 bProtect = FALSE;
590 else
591 pCnt = (*fnNxtPrv)( pCnt );
594 else if ( !bInReadOnly )
595 while ( pCnt && pCnt->IsProtected() )
596 pCnt = (*fnNxtPrv)( pCnt );
598 return pCnt;
601 BOOL MA_FASTCALL lcl_UpDown( SwPaM *pPam, const SwCntntFrm *pStart,
602 GetNxtPrvCnt fnNxtPrv, BOOL bInReadOnly )
604 ASSERT( pPam->GetNode() == (SwCntntNode*)pStart->GetNode(),
605 "lcl_UpDown arbeitet nicht fuer andere." );
607 const SwCntntFrm *pCnt = 0;
609 //Wenn gerade eine Tabellenselection laeuft muss ein bischen getricktst
610 //werden: Beim hochlaufen an den Anfang der Zelle gehen, beim runterlaufen
611 //an das Ende der Zelle gehen.
612 BOOL bTblSel = false;
613 if ( pStart->IsInTab() &&
614 pPam->GetNode( TRUE )->StartOfSectionNode() !=
615 pPam->GetNode( FALSE )->StartOfSectionNode() )
617 bTblSel = true;
618 const SwLayoutFrm *pCell = pStart->GetUpper();
619 while ( !pCell->IsCellFrm() )
620 pCell = pCell->GetUpper();
623 // Check, if cell has a Prev/Follow cell:
625 const bool bFwd = ( fnNxtPrv == lcl_GetNxtCnt );
626 const SwLayoutFrm* pTmpCell = bFwd ?
627 ((SwCellFrm*)pCell)->GetFollowCell() :
628 ((SwCellFrm*)pCell)->GetPreviousCell();
630 const SwCntntFrm* pTmpStart = pStart;
631 while ( pTmpCell && 0 != ( pTmpStart = pTmpCell->ContainsCntnt() ) )
633 pCell = pTmpCell;
634 pTmpCell = bFwd ?
635 ((SwCellFrm*)pCell)->GetFollowCell() :
636 ((SwCellFrm*)pCell)->GetPreviousCell();
638 const SwCntntFrm *pNxt = pCnt = pTmpStart;
640 while ( pCell->IsAnLower( pNxt ) )
642 pCnt = pNxt;
643 pNxt = (*fnNxtPrv)( pNxt );
647 pCnt = (*fnNxtPrv)( pCnt ? pCnt : pStart );
648 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel );
651 const SwTabFrm *pStTab = pStart->FindTabFrm();
652 const SwTabFrm *pTable = 0;
653 const BOOL bTab = pStTab || (pCnt && pCnt->IsInTab()) ? TRUE : FALSE;
654 BOOL bEnd = bTab ? FALSE : TRUE;
656 const SwFrm* pVertRefFrm = pStart;
657 if ( bTblSel && pStTab )
658 pVertRefFrm = pStTab;
659 SWRECTFN( pVertRefFrm )
661 SwTwips nX = 0;
662 if ( bTab )
665 // pStart or pCnt is inside a table. nX will be used for travelling:
667 SwRect aRect( pStart->Frm() );
668 pStart->GetCharRect( aRect, *pPam->GetPoint() );
669 Point aCenter = aRect.Center();
670 nX = bVert ? aCenter.Y() : aCenter.X();
672 pTable = pCnt ? pCnt->FindTabFrm() : 0;
673 if ( !pTable )
674 pTable = pStTab;
676 if ( pStTab &&
677 !pStTab->GetUpper()->IsInTab() &&
678 !pTable->GetUpper()->IsInTab() )
680 const SwFrm *pCell = pStart->GetUpper();
681 while ( pCell && !pCell->IsCellFrm() )
682 pCell = pCell->GetUpper();
683 ASSERT( pCell, "Zelle nicht gefunden." );
684 nX = (pCell->Frm().*fnRect->fnGetLeft)() +
685 (pCell->Frm().*fnRect->fnGetWidth)() / 2;
687 //Der Fluss fuehrt von einer Tabelle in die nachste. Der X-Wert
688 //muss ausgehend von der Mitte der Startzelle um die Verschiebung
689 //der Tabellen korrigiert werden.
690 if ( pStTab != pTable )
692 nX += (pTable->Frm().*fnRect->fnGetLeft)() -
693 (pStTab->Frm().*fnRect->fnGetLeft)();
698 // Restrict nX to the left and right borders of pTab:
699 // (is this really necessary?)
701 if ( !pTable->GetUpper()->IsInTab() )
703 const sal_Bool bRTL = pTable->IsRightToLeft();
704 const long nPrtLeft = bRTL ?
705 (pTable->*fnRect->fnGetPrtRight)() :
706 (pTable->*fnRect->fnGetPrtLeft)();
707 if ( bRTL != nX < nPrtLeft )
708 nX = nPrtLeft;
709 else
711 const long nPrtRight = bRTL ?
712 (pTable->*fnRect->fnGetPrtLeft)() :
713 (pTable->*fnRect->fnGetPrtRight)();
714 if ( bRTL != nX > nPrtRight )
715 nX = nPrtRight;
722 //Wenn ich im DokumentBody bin, so will ich da auch bleiben
723 if ( pStart->IsInDocBody() )
725 while ( pCnt && (!pCnt->IsInDocBody() ||
726 (pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow())))
728 pCnt = (*fnNxtPrv)( pCnt );
729 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel );
733 //Wenn ich im Fussnotenbereich bin, so versuche ich notfalls den naechsten
734 //Fussnotenbereich zu erreichen.
735 else if ( pStart->IsInFtn() )
737 while ( pCnt && (!pCnt->IsInFtn() ||
738 (pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow())))
740 pCnt = (*fnNxtPrv)( pCnt );
741 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel );
745 //In Flys kann es Blind weitergehen solange ein Cntnt
746 //gefunden wird.
747 else if ( pStart->IsInFly() )
749 if ( pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow() )
751 pCnt = (*fnNxtPrv)( pCnt );
752 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel );
756 //Andernfalls weigere ich mich einfach den derzeitigen Bereich zu
757 //verlassen.
758 else if ( pCnt )
760 const SwFrm *pUp = pStart->GetUpper(); //Head/Foot
761 while ( pUp && pUp->GetUpper() && !(pUp->GetType() & 0x0018 ) )
762 pUp = pUp->GetUpper();
763 BOOL bSame = FALSE;
764 const SwFrm *pCntUp = pCnt->GetUpper();
765 while ( pCntUp && !bSame )
766 { if ( pUp == pCntUp )
767 bSame = TRUE;
768 else
769 pCntUp = pCntUp->GetUpper();
771 if ( !bSame )
772 pCnt = 0;
773 else if ( pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow() ) // i73332
775 pCnt = (*fnNxtPrv)( pCnt );
776 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel );
780 if ( bTab )
782 if ( !pCnt )
783 bEnd = TRUE;
784 else
785 { const SwTabFrm *pTab = pCnt->FindTabFrm();
786 if( !pTab )
787 bEnd = TRUE;
788 else
790 if ( pTab != pTable )
792 //Der Fluss fuehrt von einer Tabelle in die nachste. Der
793 //X-Wert muss um die Verschiebung der Tabellen korrigiert
794 //werden.
795 if ( pTable &&
796 !pTab->GetUpper()->IsInTab() &&
797 !pTable->GetUpper()->IsInTab() )
798 nX += pTab->Frm().Left() - pTable->Frm().Left();
799 pTable = pTab;
801 const SwLayoutFrm *pCell = pTable ? pCnt->GetUpper() : 0;
802 while ( pCell && !pCell->IsCellFrm() )
803 pCell = pCell->GetUpper();
805 Point aInsideCell;
806 Point aInsideCnt;
807 if ( pCell )
809 long nTmpTop = (pCell->Frm().*fnRect->fnGetTop)();
810 if ( bVert )
812 if ( nTmpTop )
813 --nTmpTop;
815 aInsideCell = Point( nTmpTop, nX );
817 else
818 aInsideCell = Point( nX, nTmpTop );
821 long nTmpTop = (pCnt->Frm().*fnRect->fnGetTop)();
822 if ( bVert )
824 if ( nTmpTop )
825 --nTmpTop;
827 aInsideCnt = Point( nTmpTop, nX );
829 else
830 aInsideCnt = Point( nX, nTmpTop );
832 if ( pCell && pCell->Frm().IsInside( aInsideCell ) )
834 bEnd = TRUE;
835 //Jetzt noch schnell den richtigen Cntnt in der Zelle
836 //greifen.
837 if ( !pCnt->Frm().IsInside( aInsideCnt ) )
839 pCnt = pCell->ContainsCntnt();
840 if ( fnNxtPrv == lcl_GetPrvCnt )
841 while ( pCell->IsAnLower(pCnt->GetNextCntntFrm()) )
842 pCnt = pCnt->GetNextCntntFrm();
845 else if ( pCnt->Frm().IsInside( aInsideCnt ) )
846 bEnd = TRUE;
849 if ( !bEnd )
851 pCnt = (*fnNxtPrv)( pCnt );
852 pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, TRUE, bInReadOnly, bTblSel );
856 } while ( !bEnd ||
857 (pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow()));
859 if( pCnt )
860 { // setze den Point auf den Content-Node
861 SwCntntNode *pCNd = (SwCntntNode*)pCnt->GetNode();
862 pPam->GetPoint()->nNode = *pCNd;
863 if ( fnNxtPrv == lcl_GetPrvCnt )
864 pCNd->MakeEndIndex( (SwIndex*)&pPam->GetPoint()->nContent );
865 else
866 pCNd->MakeStartIndex( (SwIndex*)&pPam->GetPoint()->nContent );
867 return TRUE;
869 return FALSE;
872 BOOL SwCntntFrm::UnitUp( SwPaM* pPam, const SwTwips, BOOL bInReadOnly ) const
874 return ::lcl_UpDown( pPam, this, lcl_GetPrvCnt, bInReadOnly );
877 BOOL SwCntntFrm::UnitDown( SwPaM* pPam, const SwTwips, BOOL bInReadOnly ) const
879 return ::lcl_UpDown( pPam, this, lcl_GetNxtCnt, bInReadOnly );
882 /*************************************************************************
884 |* SwRootFrm::GetCurrPage()
886 |* Beschreibung: Liefert die Nummer der aktuellen Seite.
887 |* Wenn die Methode einen PaM bekommt, so ist die aktuelle Seite
888 |* diejenige in der der PaM sitzt. Anderfalls ist die aktuelle
889 |* Seite die erste Seite innerhalb der VisibleArea.
890 |* Es wird nur auf den vorhandenen Seiten gearbeitet!
891 |* Ersterstellung MA 20. May. 92
892 |* Letzte Aenderung MA 09. Oct. 97
894 |*************************************************************************/
895 USHORT SwRootFrm::GetCurrPage( const SwPaM *pActualCrsr ) const
897 ASSERT( pActualCrsr, "Welche Seite soll's denn sein?" );
898 const SwFrm *pActFrm = GetFmt()->GetDoc()->GetNodes()[pActualCrsr->GetPoint()->nNode]->
899 GetCntntNode()->GetFrm( 0,
900 pActualCrsr->GetPoint(),
901 FALSE );
902 return pActFrm->FindPageFrm()->GetPhyPageNum();
905 /*************************************************************************
907 |* SwRootFrm::SetCurrPage()
909 |* Beschreibung: Liefert einen PaM der am Anfang der gewuenschten
910 |* Seite sitzt.
911 |* Formatiert wird soweit notwendig
912 |* Liefert Null, wenn die Operation nicht moeglich ist.
913 |* Der PaM sitzt in der letzten Seite, wenn die Seitenzahl zu gross
914 |* gewaehlt wurde.
915 |* Ersterstellung MA 20. May. 92
916 |* Letzte Aenderung MA 09. Oct. 97
918 |*************************************************************************/
919 USHORT SwRootFrm::SetCurrPage( SwCursor* pToSet, USHORT nPageNum )
921 ASSERT( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." );
923 SwPageFrm *pPage = (SwPageFrm*)Lower();
924 BOOL bEnd =FALSE;
925 while ( !bEnd && pPage->GetPhyPageNum() != nPageNum )
926 { if ( pPage->GetNext() )
927 pPage = (SwPageFrm*)pPage->GetNext();
928 else
929 { //Ersten CntntFrm Suchen, und solange Formatieren bis
930 //eine neue Seite angefangen wird oder bis die CntntFrm's alle
931 //sind.
932 const SwCntntFrm *pCntnt = pPage->ContainsCntnt();
933 while ( pCntnt && pPage->IsAnLower( pCntnt ) )
935 pCntnt->Calc();
936 pCntnt = pCntnt->GetNextCntntFrm();
938 //Jetzt ist entweder eine neue Seite da, oder die letzte Seite
939 //ist gefunden.
940 if ( pPage->GetNext() )
941 pPage = (SwPageFrm*)pPage->GetNext();
942 else
943 bEnd = TRUE;
946 //pPage zeigt jetzt auf die 'gewuenschte' Seite. Jetzt muss noch der
947 //PaM auf den Anfang des ersten CntntFrm im Body-Text erzeugt werden.
948 //Wenn es sich um eine Fussnotenseite handelt, wird der PaM in die erste
949 //Fussnote gesetzt.
950 const SwCntntFrm *pCntnt = pPage->ContainsCntnt();
951 if ( pPage->IsFtnPage() )
952 while ( pCntnt && !pCntnt->IsInFtn() )
953 pCntnt = pCntnt->GetNextCntntFrm();
954 else
955 while ( pCntnt && !pCntnt->IsInDocBody() )
956 pCntnt = pCntnt->GetNextCntntFrm();
957 if ( pCntnt )
959 SwCntntNode* pCNd = (SwCntntNode*)pCntnt->GetNode();
960 pToSet->GetPoint()->nNode = *pCNd;
961 pCNd->MakeStartIndex( (SwIndex*)&pToSet->GetPoint()->nContent );
962 pToSet->GetPoint()->nContent = ((SwTxtFrm*)pCntnt)->GetOfst();
964 SwShellCrsr* pSCrsr = dynamic_cast<SwShellCrsr*>(pToSet);
965 if( pSCrsr )
967 Point &rPt = pSCrsr->GetPtPos();
968 rPt = pCntnt->Frm().Pos();
969 rPt += pCntnt->Prt().Pos();
971 return pPage->GetPhyPageNum();
973 return 0;
976 /*************************************************************************
978 |* SwCntntFrm::StartxxPage(), EndxxPage()
980 |* Beschreibung Cursor an Anfang/Ende der aktuellen/vorherigen/
981 |* naechsten Seite. Alle sechs Methoden rufen GetFrmInPage() mit der
982 |* entsprechenden Parametrisierung.
983 |* Zwei Parameter steuern die Richtung: einer bestimmt die Seite, der
984 |* andere Anfang/Ende.
985 |* Fuer die Bestimmung der Seite und des Cntnt (Anfang/Ende) werden
986 |* die im folgenden definierten Funktionen benutzt.
987 |* Ersterstellung MA 15. Oct. 92
988 |* Letzte Aenderung MA 28. Feb. 93
990 |*************************************************************************/
991 SwCntntFrm *GetFirstSub( const SwLayoutFrm *pLayout )
993 return ((SwPageFrm*)pLayout)->FindFirstBodyCntnt();
996 SwCntntFrm *GetLastSub( const SwLayoutFrm *pLayout )
998 return ((SwPageFrm*)pLayout)->FindLastBodyCntnt();
1001 SwLayoutFrm *GetNextFrm( const SwLayoutFrm *pFrm )
1003 SwLayoutFrm *pNext =
1004 (pFrm->GetNext() && pFrm->GetNext()->IsLayoutFrm()) ?
1005 (SwLayoutFrm*)pFrm->GetNext() : 0;
1006 // #i39402# in case of an empty page
1007 if(pNext && !pNext->ContainsCntnt())
1008 pNext = (pNext->GetNext() && pNext->GetNext()->IsLayoutFrm()) ?
1009 (SwLayoutFrm*)pNext->GetNext() : 0;
1010 return pNext;
1013 SwLayoutFrm *GetThisFrm( const SwLayoutFrm *pFrm )
1015 return (SwLayoutFrm*)pFrm;
1018 SwLayoutFrm *GetPrevFrm( const SwLayoutFrm *pFrm )
1020 SwLayoutFrm *pPrev =
1021 (pFrm->GetPrev() && pFrm->GetPrev()->IsLayoutFrm()) ?
1022 (SwLayoutFrm*)pFrm->GetPrev() : 0;
1023 // #i39402# in case of an empty page
1024 if(pPrev && !pPrev->ContainsCntnt())
1025 pPrev = (pPrev->GetPrev() && pPrev->GetPrev()->IsLayoutFrm()) ?
1026 (SwLayoutFrm*)pPrev->GetPrev() : 0;
1027 return pPrev;
1030 //Jetzt koennen auch die Funktionspointer initalisiert werden;
1031 //sie sind in cshtyp.hxx declariert.
1032 SwPosPage fnPageStart = GetFirstSub;
1033 SwPosPage fnPageEnd = GetLastSub;
1034 SwWhichPage fnPagePrev = GetPrevFrm;
1035 SwWhichPage fnPageCurr = GetThisFrm;
1036 SwWhichPage fnPageNext = GetNextFrm;
1038 //Liefert den ersten/den letzten Contentframe (gesteuert ueber
1039 //den Parameter fnPosPage) in der
1040 //aktuellen/vorhergehenden/folgenden Seite (gesteuert durch den
1041 //Parameter fnWhichPage).
1042 BOOL GetFrmInPage( const SwCntntFrm *pCnt, SwWhichPage fnWhichPage,
1043 SwPosPage fnPosPage, SwPaM *pPam )
1045 //Erstmal die gewuenschte Seite besorgen, anfangs die aktuelle, dann
1046 //die die per fnWichPage gewuenscht wurde
1047 const SwLayoutFrm *pLayoutFrm = pCnt->FindPageFrm();
1048 if ( !pLayoutFrm || (0 == (pLayoutFrm = (*fnWhichPage)(pLayoutFrm))) )
1049 return FALSE;
1051 //Jetzt den gewuenschen CntntFrm unterhalb der Seite
1052 if( 0 == (pCnt = (*fnPosPage)(pLayoutFrm)) )
1053 return FALSE;
1054 else
1056 // repeated headlines in tables
1057 if ( pCnt->IsInTab() && fnPosPage == GetFirstSub )
1059 const SwTabFrm* pTab = pCnt->FindTabFrm();
1060 if ( pTab->IsFollow() )
1062 if ( pTab->IsInHeadline( *pCnt ) )
1064 SwLayoutFrm* pRow = pTab->GetFirstNonHeadlineRow();
1065 if ( pRow )
1067 // We are in the first line of a follow table
1068 // with repeated headings.
1069 // To actually make a "real" move we take the first content
1070 // of the next row
1071 pCnt = pRow->ContainsCntnt();
1072 if ( ! pCnt )
1073 return FALSE;
1079 SwCntntNode *pCNd = (SwCntntNode*)pCnt->GetNode();
1080 pPam->GetPoint()->nNode = *pCNd;
1081 xub_StrLen nIdx;
1082 if( fnPosPage == GetFirstSub )
1083 nIdx = ((SwTxtFrm*)pCnt)->GetOfst();
1084 else
1085 nIdx = pCnt->GetFollow() ?
1086 ((SwTxtFrm*)pCnt)->GetFollow()->GetOfst()-1 : pCNd->Len();
1087 pPam->GetPoint()->nContent.Assign( pCNd, nIdx );
1088 return TRUE;
1092 /*************************************************************************
1094 |* SwLayoutFrm::GetCntntPos()
1096 |* Beschreibung Es wird der nachstliegende Cntnt zum uebergebenen
1097 |* gesucht. Betrachtet werden die vorhergehende, die
1098 |* aktuelle und die folgende Seite.
1099 |* Wenn kein Inhalt gefunden wird, so wird der Bereich
1100 * erweitert bis einer gefunden wird.
1101 |* Zurueckgegeben wird die 'Semantisch richtige' Position
1102 |* innerhalb der PrtArea des gefundenen CntntFrm
1103 |* Ersterstellung MA 15. Jul. 92
1104 |* Letzte Aenderung MA 09. Jan. 97
1106 |*************************************************************************/
1107 ULONG CalcDiff( const Point &rPt1, const Point &rPt2 )
1109 //Jetzt die Entfernung zwischen den beiden Punkten berechnen.
1110 //'Delta' X^2 + 'Delta'Y^2 = 'Entfernung'^2
1111 sal_uInt32 dX = Max( rPt1.X(), rPt2.X() ) -
1112 Min( rPt1.X(), rPt2.X() ),
1113 dY = Max( rPt1.Y(), rPt2.Y() ) -
1114 Min( rPt1.Y(), rPt2.Y() );
1115 BigInt dX1( dX ), dY1( dY );
1116 dX1 *= dX1; dY1 *= dY1;
1117 return ::SqRt( dX1 + dY1 );
1120 // lcl_Inside ueberprueft, ob der Punkt innerhalb des Seitenteils liegt, in dem
1121 // auch der CntntFrame liegt. Als Seitenteile gelten in diesem Zusammenhang
1122 // Kopfzeile, Seitenbody, Fusszeile und FussnotenContainer.
1123 // Dies dient dazu, dass ein CntntFrm, der im "richtigen" Seitenteil liegt,
1124 // eher akzeptiert wird als ein anderer, der nicht dort liegt, auch wenn
1125 // dessen Abstand zum Punkt geringer ist.
1127 const SwLayoutFrm* lcl_Inside( const SwCntntFrm *pCnt, Point& rPt )
1129 const SwLayoutFrm* pUp = pCnt->GetUpper();
1130 while( pUp )
1132 if( pUp->IsPageBodyFrm() || pUp->IsFooterFrm() || pUp->IsHeaderFrm() )
1134 if( rPt.Y() >= pUp->Frm().Top() && rPt.Y() <= pUp->Frm().Bottom() )
1135 return pUp;
1136 return NULL;
1138 if( pUp->IsFtnContFrm() )
1139 return pUp->Frm().IsInside( rPt ) ? pUp : NULL;
1140 pUp = pUp->GetUpper();
1142 return NULL;
1145 const SwCntntFrm *SwLayoutFrm::GetCntntPos( Point& rPoint,
1146 const BOOL bDontLeave,
1147 const BOOL bBodyOnly,
1148 const BOOL bCalc,
1149 const SwCrsrMoveState *pCMS,
1150 const BOOL bDefaultExpand ) const
1152 //Ersten CntntFrm ermitteln.
1153 const SwLayoutFrm *pStart = (!bDontLeave && bDefaultExpand && GetPrev()) ?
1154 (SwLayoutFrm*)GetPrev() : this;
1155 const SwCntntFrm *pCntnt = pStart->ContainsCntnt();
1157 if ( !pCntnt && (GetPrev() && !bDontLeave) )
1158 pCntnt = ContainsCntnt();
1160 if ( bBodyOnly && pCntnt && !pCntnt->IsInDocBody() )
1161 while ( pCntnt && !pCntnt->IsInDocBody() )
1162 pCntnt = pCntnt->GetNextCntntFrm();
1164 const SwCntntFrm *pActual= pCntnt;
1165 const SwLayoutFrm *pInside = NULL;
1166 USHORT nMaxPage = GetPhyPageNum() + (bDefaultExpand ? 1 : 0);
1167 Point aPoint = rPoint;
1168 ULONG nDistance = ULONG_MAX;
1170 while ( TRUE ) //Sicherheitsschleifchen, damit immer einer gefunden wird.
1172 while ( pCntnt &&
1173 ((!bDontLeave || IsAnLower( pCntnt )) &&
1174 (pCntnt->GetPhyPageNum() <= nMaxPage)) )
1176 if ( ( bCalc || pCntnt->Frm().Width() ) &&
1177 ( !bBodyOnly || pCntnt->IsInDocBody() ) )
1179 //Wenn der Cntnt in einem geschuetzen Bereich (Zelle, Ftn, Section)
1180 //liegt, wird der nachste Cntnt der nicht geschuetzt ist gesucht.
1181 const SwCntntFrm *pComp = pCntnt;
1182 pCntnt = ::lcl_MissProtectedFrames( pCntnt, lcl_GetNxtCnt, FALSE,
1183 pCMS ? pCMS->bSetInReadOnly : FALSE, FALSE );
1184 if ( pComp != pCntnt )
1185 continue;
1187 if ( !pCntnt->IsTxtFrm() || !((SwTxtFrm*)pCntnt)->IsHiddenNow() )
1189 if ( bCalc )
1190 pCntnt->Calc();
1192 SwRect aCntFrm( pCntnt->UnionFrm() );
1193 if ( aCntFrm.IsInside( rPoint ) )
1195 pActual = pCntnt;
1196 aPoint = rPoint;
1197 break;
1199 //Die Strecke von rPoint zum dichtesten Punkt von pCntnt wird
1200 //jetzt berechnet.
1201 Point aCntntPoint( rPoint );
1203 //Erst die Vertikale Position einstellen
1204 if ( aCntFrm.Top() > aCntntPoint.Y() )
1205 aCntntPoint.Y() = aCntFrm.Top();
1206 else if ( aCntFrm.Bottom() < aCntntPoint.Y() )
1207 aCntntPoint.Y() = aCntFrm.Bottom();
1209 //Jetzt die Horizontale Position
1210 if ( aCntFrm.Left() > aCntntPoint.X() )
1211 aCntntPoint.X() = aCntFrm.Left();
1212 else if ( aCntFrm.Right() < aCntntPoint.X() )
1213 aCntntPoint.X() = aCntFrm.Right();
1215 // pInside ist ein Seitenbereich, in dem der Punkt liegt,
1216 // sobald pInside!=0 ist, werden nur noch Frames akzeptiert,
1217 // die innerhalb liegen.
1218 if( !pInside || ( pInside->IsAnLower( pCntnt ) &&
1219 ( !pCntnt->IsInFtn() || pInside->IsFtnContFrm() ) ) )
1221 const ULONG nDiff = ::CalcDiff( aCntntPoint, rPoint );
1222 BOOL bBetter = nDiff < nDistance; // Dichter dran
1223 if( !pInside )
1225 pInside = lcl_Inside( pCntnt, rPoint );
1226 if( pInside ) // Im "richtigen" Seitenteil
1227 bBetter = TRUE;
1229 if( bBetter )
1231 aPoint = aCntntPoint;
1232 nDistance = nDiff;
1233 pActual = pCntnt;
1238 pCntnt = pCntnt->GetNextCntntFrm();
1239 if ( bBodyOnly )
1240 while ( pCntnt && !pCntnt->IsInDocBody() )
1241 pCntnt = pCntnt->GetNextCntntFrm();
1243 if ( !pActual )
1244 { //Wenn noch keiner gefunden wurde muss der Suchbereich erweitert
1245 //werden, irgenwann muessen wir einen Finden!
1246 //MA 09. Jan. 97: Opt fuer viele leere Seiten, wenn wir nur im
1247 //Body suchen, koennen wir den Suchbereich gleich in einem
1248 //Schritt hinreichend erweitern.
1249 if ( bBodyOnly )
1251 while ( !pCntnt && pStart->GetPrev() )
1253 ++nMaxPage;
1254 if( !pStart->GetPrev()->IsLayoutFrm() )
1255 return 0;
1256 pStart = (SwLayoutFrm*)pStart->GetPrev();
1257 pCntnt = pStart->IsInDocBody()
1258 ? pStart->ContainsCntnt()
1259 : pStart->FindPageFrm()->FindFirstBodyCntnt();
1261 if ( !pCntnt ) //irgendwann muessen wir mit irgendeinem Anfangen!
1263 pCntnt = pStart->FindPageFrm()->GetUpper()->ContainsCntnt();
1264 while ( pCntnt && !pCntnt->IsInDocBody() )
1265 pCntnt = pCntnt->GetNextCntntFrm();
1266 if ( !pCntnt )
1267 return 0; //Es gibt noch keine Dokumentinhalt!
1270 else
1272 ++nMaxPage;
1273 if ( pStart->GetPrev() )
1275 if( !pStart->GetPrev()->IsLayoutFrm() )
1276 return 0;
1277 pStart = (SwLayoutFrm*)pStart->GetPrev();
1278 pCntnt = pStart->ContainsCntnt();
1280 else //irgendwann muessen wir mit irgendeinem Anfangen!
1281 pCntnt = pStart->FindPageFrm()->GetUpper()->ContainsCntnt();
1283 pActual = pCntnt;
1285 else
1286 break;
1289 #ifndef PRODUCT
1290 ASSERT( pActual, "Keinen Cntnt gefunden." );
1291 if ( bBodyOnly )
1292 ASSERT( pActual->IsInDocBody(), "Cnt nicht im Body." );
1293 #endif
1295 //Spezialfall fuer das selektieren von Tabellen, nicht in wiederholte
1296 //TblHedlines.
1297 if ( pActual->IsInTab() && pCMS && pCMS->eState == MV_TBLSEL )
1299 const SwTabFrm *pTab = pActual->FindTabFrm();
1300 if ( pTab->IsFollow() && pTab->IsInHeadline( *pActual ) )
1302 ((SwCrsrMoveState*)pCMS)->bStop = TRUE;
1303 return 0;
1307 //Jetzt noch eine kleine Korrektur beim ersten/letzten
1308 Size aActualSize( pActual->Prt().SSize() );
1309 if ( aActualSize.Height() > pActual->GetUpper()->Prt().Height() )
1310 aActualSize.Height() = pActual->GetUpper()->Prt().Height();
1312 SWRECTFN( pActual )
1313 if ( !pActual->GetPrev() &&
1314 (*fnRect->fnYDiff)( (pActual->*fnRect->fnGetPrtTop)(),
1315 bVert ? rPoint.X() : rPoint.Y() ) > 0 )
1317 aPoint.Y() = pActual->Frm().Top() + pActual->Prt().Top();
1318 aPoint.X() = pActual->Frm().Left() +
1319 ( pActual->IsRightToLeft() || bVert ?
1320 pActual->Prt().Right() :
1321 pActual->Prt().Left() );
1323 else if ( !pActual->GetNext() &&
1324 (*fnRect->fnYDiff)( (pActual->*fnRect->fnGetPrtBottom)(),
1325 bVert ? rPoint.X() : rPoint.Y() ) < 0 )
1327 aPoint.Y() = pActual->Frm().Top() + pActual->Prt().Bottom();
1328 aPoint.X() = pActual->Frm().Left() +
1329 ( pActual->IsRightToLeft() || bVert ?
1330 pActual->Prt().Left() :
1331 pActual->Prt().Right() );
1334 //Und den Point in die PrtArea bringen
1335 if ( bCalc )
1336 pActual->Calc();
1337 const SwRect aRect( pActual->Frm().Pos() + pActual->Prt().Pos(),
1338 aActualSize );
1339 if ( aPoint.Y() < aRect.Top() )
1340 aPoint.Y() = aRect.Top();
1341 else if ( aPoint.Y() > aRect.Bottom() )
1342 aPoint.Y() = aRect.Bottom();
1343 if ( aPoint.X() < aRect.Left() )
1344 aPoint.X() = aRect.Left();
1345 else if ( aPoint.X() > aRect.Right() )
1346 aPoint.X() = aRect.Right();
1347 rPoint = aPoint;
1348 return pActual;
1351 /*************************************************************************
1353 |* SwPageFrm::GetCntntPosition()
1355 |* Beschreibung Analog zu SwLayoutFrm::GetCntntPos().
1356 |* Spezialisiert fuer Felder in Rahmen.
1358 |* Ersterstellung MA 22. Mar. 95
1359 |* Letzte Aenderung MA 07. Nov. 95
1361 |*************************************************************************/
1362 void SwPageFrm::GetCntntPosition( const Point &rPt, SwPosition &rPos ) const
1364 //Ersten CntntFrm ermitteln.
1365 const SwCntntFrm *pCntnt = ContainsCntnt();
1366 if ( pCntnt )
1368 //Einen weiter zurueck schauen (falls moeglich).
1369 const SwCntntFrm *pTmp = pCntnt->GetPrevCntntFrm();
1370 while ( pTmp && !pTmp->IsInDocBody() )
1371 pTmp = pTmp->GetPrevCntntFrm();
1372 if ( pTmp )
1373 pCntnt = pTmp;
1375 else
1376 pCntnt = GetUpper()->ContainsCntnt();
1378 const SwCntntFrm *pAct = pCntnt;
1379 Point aAct = rPt;
1380 ULONG nDist = ULONG_MAX;
1382 while ( pCntnt )
1384 SwRect aCntFrm( pCntnt->UnionFrm() );
1385 if ( aCntFrm.IsInside( rPt ) )
1387 //dichter gehts nimmer.
1388 pAct = pCntnt;
1389 break;
1392 //Die Strecke von rPt zum dichtesten Punkt von pCntnt berechnen.
1393 Point aPoint( rPt );
1395 //Erst die vertikale Position einstellen
1396 if ( aCntFrm.Top() > rPt.Y() )
1397 aPoint.Y() = aCntFrm.Top();
1398 else if ( aCntFrm.Bottom() < rPt.Y() )
1399 aPoint.Y() = aCntFrm.Bottom();
1401 //Jetzt die horizontale Position
1402 if ( aCntFrm.Left() > rPt.X() )
1403 aPoint.X() = aCntFrm.Left();
1404 else if ( aCntFrm.Right() < rPt.X() )
1405 aPoint.X() = aCntFrm.Right();
1407 const ULONG nDiff = ::CalcDiff( aPoint, rPt );
1408 if ( nDiff < nDist )
1410 aAct = aPoint;
1411 nDist = nDiff;
1412 pAct = pCntnt;
1414 else if ( aCntFrm.Top() > Frm().Bottom() )
1415 //Dichter wirds im Sinne der Felder nicht mehr!
1416 break;
1418 pCntnt = pCntnt->GetNextCntntFrm();
1419 while ( pCntnt && !pCntnt->IsInDocBody() )
1420 pCntnt = pCntnt->GetNextCntntFrm();
1423 //Und den Point in die PrtArea bringen
1424 const SwRect aRect( pAct->Frm().Pos() + pAct->Prt().Pos(), pAct->Prt().SSize() );
1425 if ( aAct.Y() < aRect.Top() )
1426 aAct.Y() = aRect.Top();
1427 else if ( aAct.Y() > aRect.Bottom() )
1428 aAct.Y() = aRect.Bottom();
1429 if ( aAct.X() < aRect.Left() )
1430 aAct.X() = aRect.Left();
1431 else if ( aAct.X() > aRect.Right() )
1432 aAct.X() = aRect.Right();
1434 if( !pAct->IsValid() )
1436 // CntntFrm nicht formatiert -> immer auf Node-Anfang
1437 SwCntntNode* pCNd = (SwCntntNode*)pAct->GetNode();
1438 ASSERT( pCNd, "Wo ist mein CntntNode?" );
1439 rPos.nNode = *pCNd;
1440 rPos.nContent.Assign( pCNd, 0 );
1442 else
1444 SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
1445 pAct->GetCrsrOfst( &rPos, aAct, &aTmpState );
1449 /*************************************************************************
1451 |* SwRootFrm::GetNextPrevCntntPos()
1453 |* Beschreibung Es wird der naechstliegende Cntnt zum uebergebenen
1454 |* Point gesucht. Es wird nur im BodyText gesucht.
1455 |* Ersterstellung MA 15. Jul. 92
1456 |* Letzte Aenderung JP 11.10.2001
1458 |*************************************************************************/
1460 // --> OD 2005-05-25 #123110# - helper class to disable creation of an action
1461 // by a callback event - e.g., change event from a drawing object
1462 class DisableCallbackAction
1464 private:
1465 SwRootFrm& mrRootFrm;
1466 BOOL mbOldCallbackActionState;
1468 public:
1469 DisableCallbackAction( const SwRootFrm& _rRootFrm ) :
1470 mrRootFrm( const_cast<SwRootFrm&>(_rRootFrm) ),
1471 mbOldCallbackActionState( _rRootFrm.IsCallbackActionEnabled() )
1473 mrRootFrm.SetCallbackActionEnabled( FALSE );
1476 ~DisableCallbackAction()
1478 mrRootFrm.SetCallbackActionEnabled( mbOldCallbackActionState );
1481 // <--
1483 //!!!!! Es wird nur der vertikal naechstliegende gesucht.
1484 //JP 11.10.2001: only in tables we try to find the right column - Bug 72294
1485 Point SwRootFrm::GetNextPrevCntntPos( const Point& rPoint, BOOL bNext ) const
1487 // --> OD 2005-05-25 #123110# - disable creation of an action by a callback
1488 // event during processing of this method. Needed because formatting is
1489 // triggered by this method.
1490 DisableCallbackAction aDisableCallbackAction( *this );
1491 // <--
1492 //Ersten CntntFrm und seinen Nachfolger im Body-Bereich suchen
1493 //Damit wir uns nicht tot suchen (und vor allem nicht zuviel formatieren)
1494 //gehen wir schon mal von der richtigen Seite aus.
1495 SwLayoutFrm *pPage = (SwLayoutFrm*)Lower();
1496 if( pPage )
1497 while( pPage->GetNext() && pPage->Frm().Bottom() < rPoint.Y() )
1498 pPage = (SwLayoutFrm*)pPage->GetNext();
1500 const SwCntntFrm *pCnt = pPage ? pPage->ContainsCntnt() : ContainsCntnt();
1501 while ( pCnt && !pCnt->IsInDocBody() )
1502 pCnt = pCnt->GetNextCntntFrm();
1504 if ( !pCnt )
1505 return Point( 0, 0 );
1507 pCnt->Calc();
1508 if( !bNext )
1510 // Solange der Point vor dem ersten CntntFrm liegt und es noch
1511 // vorhergehende Seiten gibt gehe ich jeweils eine Seite nach vorn.
1512 while ( rPoint.Y() < pCnt->Frm().Top() && pPage->GetPrev() )
1514 pPage = (SwLayoutFrm*)pPage->GetPrev();
1515 pCnt = pPage->ContainsCntnt();
1516 while ( !pCnt )
1518 pPage = (SwLayoutFrm*)pPage->GetPrev();
1519 if ( pPage )
1520 pCnt = pPage->ContainsCntnt();
1521 else
1522 return ContainsCntnt()->UnionFrm().Pos();
1524 pCnt->Calc();
1528 //Liegt der Point ueber dem ersten CntntFrm?
1529 if ( rPoint.Y() < pCnt->Frm().Top() && !lcl_IsInRepeatedHeadline( pCnt ) )
1530 return pCnt->UnionFrm().Pos();
1532 while ( pCnt )
1534 //Liegt der Point im aktuellen CntntFrm?
1535 SwRect aCntFrm( pCnt->UnionFrm() );
1536 if ( aCntFrm.IsInside( rPoint ) && !lcl_IsInRepeatedHeadline( pCnt ))
1537 return rPoint;
1539 //Ist der aktuelle der letzte CntntFrm? ||
1540 //Wenn der naechste CntntFrm hinter dem Point liegt, ist der
1541 //aktuelle der gesuchte.
1542 const SwCntntFrm *pNxt = pCnt->GetNextCntntFrm();
1543 while ( pNxt && !pNxt->IsInDocBody() )
1544 pNxt = pNxt->GetNextCntntFrm();
1546 //Liegt der Point hinter dem letzten CntntFrm?
1547 if ( !pNxt )
1548 return Point( aCntFrm.Right(), aCntFrm.Bottom() );
1550 //Wenn der naechste CntntFrm hinter dem Point liegt ist er der
1551 //gesuchte.
1552 const SwTabFrm* pTFrm;
1553 pNxt->Calc();
1554 if( pNxt->Frm().Top() > rPoint.Y() &&
1555 !lcl_IsInRepeatedHeadline( pCnt, &pTFrm ) &&
1556 ( !pTFrm || pNxt->Frm().Left() > rPoint.X() ))
1558 if( bNext )
1559 return pNxt->Frm().Pos();
1560 return Point( aCntFrm.Right(), aCntFrm.Bottom() );
1562 pCnt = pNxt;
1564 return Point( 0, 0 );
1567 /*************************************************************************
1569 |* SwRootFrm::GetPagePos()
1571 |* Beschreibung: Liefert die absolute Dokumentpositon der gewuenschten
1572 |* Seite.
1573 |* Formatiert wird nur soweit notwendig und nur dann wenn bFormat=TRUE
1574 |* Liefert Null, wenn die Operation nicht moeglich ist.
1575 |* Die Pos ist die der letzten Seite, wenn die Seitenzahl zu gross
1576 |* gewaehlt wurde.
1577 |* Ersterstellung MA 01. Jun. 92
1578 |* Letzte Aenderung MA 09. Oct. 97
1580 |*************************************************************************/
1581 Point SwRootFrm::GetPagePos( USHORT nPageNum ) const
1583 ASSERT( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." );
1585 const SwPageFrm *pPage = (const SwPageFrm*)Lower();
1586 while ( TRUE )
1588 if ( pPage->GetPhyPageNum() >= nPageNum || !pPage->GetNext() )
1589 break;
1590 pPage = (const SwPageFrm*)pPage->GetNext();
1592 return pPage->Frm().Pos();
1595 /** get page frame by phyiscal page number
1597 OD 14.01.2003 #103492#
1599 @return pointer to the page frame with the given physical page number
1601 SwPageFrm* SwRootFrm::GetPageByPageNum( sal_uInt16 _nPageNum ) const
1603 const SwPageFrm* pPageFrm = static_cast<const SwPageFrm*>( Lower() );
1604 while ( pPageFrm && pPageFrm->GetPhyPageNum() < _nPageNum )
1606 pPageFrm = static_cast<const SwPageFrm*>( pPageFrm->GetNext() );
1609 if ( pPageFrm && pPageFrm->GetPhyPageNum() == _nPageNum )
1611 return const_cast<SwPageFrm*>( pPageFrm );
1613 else
1615 return 0;
1619 /*************************************************************************
1621 |* SwRootFrm::IsDummyPage(USHORT)
1623 |* Description: Returns TRUE, when the given physical pagenumber does't exist
1624 |* or this page is an empty page.
1625 |*************************************************************************/
1626 BOOL SwRootFrm::IsDummyPage( USHORT nPageNum ) const
1628 if( !Lower() || !nPageNum || nPageNum > GetPageNum() )
1629 return TRUE;
1631 const SwPageFrm *pPage = (const SwPageFrm*)Lower();
1632 while( pPage && nPageNum < pPage->GetPhyPageNum() )
1633 pPage = (const SwPageFrm*)pPage->GetNext();
1634 return pPage ? pPage->IsEmptyPage() : TRUE;
1638 /*************************************************************************
1640 |* SwFrm::IsProtected()
1642 |* Beschreibung Ist der Frm bzw. die Section in der er steht
1643 |* geschuetzt?
1644 |* Auch Fly in Fly in ... und Fussnoten
1646 |* Ersterstellung MA 28. Jul. 93
1647 |* Letzte Aenderung MA 06. Nov. 97
1649 |*************************************************************************/
1650 BOOL SwFrm::IsProtected() const
1652 if (this->IsCntntFrm() && ((SwCntntFrm*)this)->GetNode())
1654 const SwDoc *pDoc=((SwCntntFrm*)this)->GetNode()->GetDoc();
1655 bool isFormProtected=pDoc->get(IDocumentSettingAccess::PROTECT_FORM );
1656 if (isFormProtected)
1658 return FALSE; // TODO a hack for now, well deal with it laster, I we return true here we have a "double" locking
1661 //Der Frm kann in Rahmen, Zellen oder Bereichen geschuetzt sein.
1662 //Geht auch FlyFrms rekursiv hoch. Geht auch von Fussnoten zum Anker.
1663 const SwFrm *pFrm = this;
1666 if ( pFrm->IsCntntFrm() )
1668 if ( ((SwCntntFrm*)pFrm)->GetNode() &&
1669 ((SwCntntFrm*)pFrm)->GetNode()->IsInProtectSect() )
1670 return TRUE;
1672 else
1674 if ( ((SwLayoutFrm*)pFrm)->GetFmt() &&
1675 ((SwLayoutFrm*)pFrm)->GetFmt()->
1676 GetProtect().IsCntntProtected() )
1677 return TRUE;
1678 if ( pFrm->IsCoveredCell() )
1679 return TRUE;
1681 if ( pFrm->IsFlyFrm() )
1683 //Der Schutz des Inhaltes kann bei Verkettung vom Master der Kette
1684 //vorgegeben werden.
1685 if ( ((SwFlyFrm*)pFrm)->GetPrevLink() )
1687 SwFlyFrm *pMaster = (SwFlyFrm*)pFrm;
1689 { pMaster = pMaster->GetPrevLink();
1690 } while ( pMaster->GetPrevLink() );
1691 if ( pMaster->IsProtected() )
1692 return TRUE;
1694 pFrm = ((SwFlyFrm*)pFrm)->GetAnchorFrm();
1696 else if ( pFrm->IsFtnFrm() )
1697 pFrm = ((SwFtnFrm*)pFrm)->GetRef();
1698 else
1699 pFrm = pFrm->GetUpper();
1701 } while ( pFrm );
1703 return FALSE;
1706 /*************************************************************************
1708 |* SwFrm::GetPhyPageNum()
1709 |* Beschreibung: Liefert die physikalische Seitennummer
1711 |* Ersterstellung OK 06.07.93 08:35
1712 |* Letzte Aenderung MA 30. Nov. 94
1714 |*************************************************************************/
1715 USHORT SwFrm::GetPhyPageNum() const
1717 const SwPageFrm *pPage = FindPageFrm();
1718 return pPage ? pPage->GetPhyPageNum() : 0;
1721 /*-----------------26.02.01 11:25-------------------
1722 * SwFrm::WannaRightPage()
1723 * decides if the page want to be a rightpage or not.
1724 * If the first content of the page has a page descriptor,
1725 * we take the follow of the page descriptor of the last not empty page.
1726 * If this descriptor allows only right(left) pages and the page
1727 * isn't an empty page then it wanna be such right(left) page.
1728 * If the descriptor allows right and left pages, we look for a number offset
1729 * in the first content. If there is one, odd number results right pages,
1730 * even number results left pages.
1731 * If there is no number offset, we take the physical page number instead,
1732 * but a previous empty page don't count.
1733 * --------------------------------------------------*/
1735 BOOL SwFrm::WannaRightPage() const
1737 const SwPageFrm *pPage = FindPageFrm();
1738 if ( !pPage || !pPage->GetUpper() )
1739 return TRUE;
1741 const SwFrm *pFlow = pPage->FindFirstBodyCntnt();
1742 SwPageDesc *pDesc = 0;
1743 USHORT nPgNum = 0;
1744 if ( pFlow )
1746 if ( pFlow->IsInTab() )
1747 pFlow = pFlow->FindTabFrm();
1748 const SwFlowFrm *pTmp = SwFlowFrm::CastFlowFrm( pFlow );
1749 if ( !pTmp->IsFollow() )
1751 const SwFmtPageDesc& rPgDesc = pFlow->GetAttrSet()->GetPageDesc();
1752 pDesc = (SwPageDesc*)rPgDesc.GetPageDesc();
1753 nPgNum = rPgDesc.GetNumOffset();
1756 if ( !pDesc )
1758 SwPageFrm *pPrv = (SwPageFrm*)pPage->GetPrev();
1759 if( pPrv && pPrv->IsEmptyPage() )
1760 pPrv = (SwPageFrm*)pPrv->GetPrev();
1761 if( pPrv )
1762 pDesc = pPrv->GetPageDesc()->GetFollow();
1763 else
1765 const SwDoc* pDoc = pPage->GetFmt()->GetDoc();
1766 pDesc = (SwPageDesc*)&pDoc->GetPageDesc( 0 );
1769 ASSERT( pDesc, "No pagedescriptor" );
1770 BOOL bOdd;
1771 if( nPgNum )
1772 bOdd = nPgNum % 2 ? TRUE : FALSE;
1773 else
1775 bOdd = pPage->OnRightPage();
1776 if( pPage->GetPrev() && ((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() )
1777 bOdd = !bOdd;
1779 if( !pPage->IsEmptyPage() )
1781 if( !pDesc->GetRightFmt() )
1782 bOdd = FALSE;
1783 else if( !pDesc->GetLeftFmt() )
1784 bOdd = TRUE;
1786 return bOdd;
1789 /*************************************************************************
1791 |* SwFrm::GetVirtPageNum()
1792 |* Beschreibung: Liefert die virtuelle Seitennummer mit Offset
1794 |* Ersterstellung OK 06.07.93 08:35
1795 |* Letzte Aenderung MA 30. Nov. 94
1797 |*************************************************************************/
1798 USHORT SwFrm::GetVirtPageNum() const
1800 const SwPageFrm *pPage = FindPageFrm();
1801 if ( !pPage || !pPage->GetUpper() )
1802 return 0;
1804 USHORT nPhyPage = pPage->GetPhyPageNum();
1805 if ( !((SwRootFrm*)pPage->GetUpper())->IsVirtPageNum() )
1806 return nPhyPage;
1808 //Den am naechsten stehenden Absatz mit virtueller Seitennummer suchen.
1809 //Da das rueckwaertsuchen insgesamt sehr viel Zeit verschlingt suchen
1810 //wir jetzt gezielt ueber die Abhaengigkeiten.
1811 //von den PageDescs bekommen wir die Attribute, von den Attributen
1812 //wiederum bekommen wir die Absaetze.
1813 const SwPageFrm *pVirtPage = 0;
1814 const SwFrm *pFrm = 0;
1815 const SfxItemPool &rPool = pPage->GetFmt()->GetDoc()->GetAttrPool();
1816 const SfxPoolItem* pItem;
1817 USHORT nMaxItems = rPool.GetItemCount( RES_PAGEDESC );
1818 for( USHORT n = 0; n < nMaxItems; ++n )
1820 if( 0 == (pItem = rPool.GetItem( RES_PAGEDESC, n ) ))
1821 continue;
1823 const SwFmtPageDesc *pDesc = (SwFmtPageDesc*)pItem;
1824 if ( pDesc->GetNumOffset() && pDesc->GetDefinedIn() )
1826 const SwModify *pMod = pDesc->GetDefinedIn();
1827 SwVirtPageNumInfo aInfo( pPage );
1828 pMod->GetInfo( aInfo );
1829 if ( aInfo.GetPage() )
1831 if( !pVirtPage || ( pVirtPage && aInfo.GetPage()->
1832 GetPhyPageNum() > pVirtPage->GetPhyPageNum() ) )
1834 pVirtPage = aInfo.GetPage();
1835 pFrm = aInfo.GetFrm();
1840 if ( pFrm )
1841 return nPhyPage - pFrm->GetPhyPageNum() +
1842 pFrm->GetAttrSet()->GetPageDesc().GetNumOffset();
1843 return nPhyPage;
1846 /*************************************************************************
1848 |* SwRootFrm::MakeTblCrsrs()
1850 |* Ersterstellung MA 14. May. 93
1851 |* Letzte Aenderung MA 02. Feb. 94
1853 |*************************************************************************/
1854 //Ermitteln und einstellen derjenigen Zellen die von der Selektion
1855 //eingeschlossen sind.
1857 bool SwRootFrm::MakeTblCrsrs( SwTableCursor& rTblCrsr )
1859 //Union-Rects und Tabellen (Follows) der Selektion besorgen.
1860 ASSERT( rTblCrsr.GetCntntNode() && rTblCrsr.GetCntntNode( FALSE ),
1861 "Tabselection nicht auf Cnt." );
1863 bool bRet = false;
1865 // For new table models there's no need to ask the layout..
1866 if( rTblCrsr.NewTableSelection() )
1867 return true;
1869 Point aPtPt, aMkPt;
1871 SwShellCrsr* pShCrsr = dynamic_cast<SwShellCrsr*>(&rTblCrsr);
1873 if( pShCrsr )
1875 aPtPt = pShCrsr->GetPtPos();
1876 aMkPt = pShCrsr->GetMkPos();
1880 // --> FME 2008-01-14 #151012# Made code robust here:
1881 const SwCntntNode* pTmpStartNode = rTblCrsr.GetCntntNode();
1882 const SwCntntNode* pTmpEndNode = rTblCrsr.GetCntntNode(FALSE);
1884 const SwFrm* pTmpStartFrm = pTmpStartNode ? pTmpStartNode->GetFrm( &aPtPt, 0, FALSE ) : 0;
1885 const SwFrm* pTmpEndFrm = pTmpEndNode ? pTmpEndNode->GetFrm( &aMkPt, 0, FALSE ) : 0;
1887 const SwLayoutFrm* pStart = pTmpStartFrm ? pTmpStartFrm->GetUpper() : 0;
1888 const SwLayoutFrm* pEnd = pTmpEndFrm ? pTmpEndFrm->GetUpper() : 0;
1890 ASSERT( pStart && pEnd, "MakeTblCrsrs: Good to have the code robust here!" )
1891 // <--
1893 /* #109590# Only change table boxes if the frames are
1894 valid. Needed because otherwise the table cursor after moving
1895 table cells by dnd resulted in an empty tables cursor. */
1896 if ( pStart && pEnd && pStart->IsValid() && pEnd->IsValid())
1898 SwSelUnions aUnions;
1899 ::MakeSelUnions( aUnions, pStart, pEnd );
1901 SwSelBoxes aNew;
1903 const BOOL bReadOnlyAvailable = rTblCrsr.IsReadOnlyAvailable();
1905 for ( USHORT i = 0; i < aUnions.Count(); ++i )
1907 SwSelUnion *pUnion = aUnions[i];
1908 const SwTabFrm *pTable = pUnion->GetTable();
1910 // Skip any repeated headlines in the follow:
1911 SwLayoutFrm* pRow = pTable->IsFollow() ?
1912 pTable->GetFirstNonHeadlineRow() :
1913 (SwLayoutFrm*)pTable->Lower();
1915 while ( pRow )
1917 if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
1919 const SwLayoutFrm *pCell = pRow->FirstCell();
1921 while ( pCell && pRow->IsAnLower( pCell ) )
1923 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" );
1924 if( IsFrmInTblSel( pUnion->GetUnion(), pCell ) &&
1925 (bReadOnlyAvailable ||
1926 !pCell->GetFmt()->GetProtect().IsCntntProtected()))
1928 SwTableBox* pInsBox = (SwTableBox*)
1929 ((SwCellFrm*)pCell)->GetTabBox();
1930 aNew.Insert( pInsBox );
1932 if ( pCell->GetNext() )
1934 pCell = (const SwLayoutFrm*)pCell->GetNext();
1935 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
1936 pCell = pCell->FirstCell();
1938 else
1940 const SwLayoutFrm* pLastCell = pCell;
1943 pCell = pCell->GetNextLayoutLeaf();
1944 } while ( pCell && pLastCell->IsAnLower( pCell ) );
1945 // Fuer (spaltige) Bereiche...
1946 if( pCell && pCell->IsInTab() )
1948 while( !pCell->IsCellFrm() )
1950 pCell = pCell->GetUpper();
1951 ASSERT( pCell, "Where's my cell?" );
1957 pRow = (SwLayoutFrm*)pRow->GetNext();
1961 rTblCrsr.ActualizeSelection( aNew );
1962 bRet = true;
1965 return bRet;
1969 /*************************************************************************
1971 |* SwRootFrm::CalcFrmRects
1973 |* Ersterstellung MA 24. Aug. 92
1974 |* Letzte Aenderung MA 24. Aug. 93
1976 |*************************************************************************/
1979 * nun koennen folgende Situationen auftreten:
1980 * 1. Start und Ende liegen in einer Bildschirm - Zeile und im
1981 * gleichen Node
1982 * -> aus Start und End ein Rectangle, dann Ok
1983 * 2. Start und Ende liegen in einem Frame (dadurch im gleichen Node!)
1984 * -> Start nach rechts, End nach links erweitern,
1985 * und bei mehr als 2 Bildschirm - Zeilen, das dazwischen
1986 * liegende berechnen
1987 * 3. Start und Ende liegen in verschiedenen Frames
1988 * -> Start nach rechts erweitern, bis Frame-Ende Rect berechnen
1989 * Ende nach links erweitern, bis Frame-Start Rect berechnen
1990 * und bei mehr als 2 Frames von allen dazwischen liegenden
1991 * Frames die PrtArea dazu.
1992 * 4. Wenn es sich um eine Tabellenselektion handelt wird fuer jeden
1993 * PaM im Ring der CellFrm besorgt, dessen PrtArea wird zu den
1994 * Rechtecken addiert.
1996 * Grosser Umbau wg. der FlyFrm; denn diese muessen ausgespart werden.
1997 * Ausnahmen: - Der Fly in dem die Selektion stattfindet (wenn sie in einem Fly
1998 * stattfindet).
1999 * - Die Flys, die vom Text unterlaufen werden.
2000 * Arbeitsweise: Zuerst wird eine SwRegion mit der Root initialisiert.
2001 * Aus der Region werden die zu invertierenden Bereiche
2002 * ausgestantzt. Die Region wird Komprimiert und letztlich
2003 * invertiert. Damit liegen dann die zu invertierenden
2004 * Rechtecke vor.
2005 * Am Ende werden die Flys aus der Region ausgestanzt.
2008 inline void Sub( SwRegionRects& rRegion, const SwRect& rRect )
2010 if( rRect.Width() > 1 && rRect.Height() > 1 &&
2011 rRect.IsOver( rRegion.GetOrigin() ))
2012 rRegion -= rRect;
2015 void SwRootFrm::CalcFrmRects( SwShellCrsr &rCrsr, BOOL bIsTblMode )
2017 const SwNodes &rNds = GetFmt()->GetDoc()->GetNodes();
2018 SwPosition *pStartPos = rCrsr.Start(),
2019 *pEndPos = rCrsr.GetPoint() == pStartPos ?
2020 rCrsr.GetMark() : rCrsr.GetPoint();
2022 ViewShell *pSh = GetShell();
2024 // --> FME 2004-06-08 #i12836# enhanced pdf
2025 SwRegionRects aRegion( pSh && !pSh->GetViewOptions()->IsPDFExport() ?
2026 pSh->VisArea() :
2027 Frm() );
2028 // <--
2029 if( !pStartPos->nNode.GetNode().IsCntntNode() ||
2030 !pStartPos->nNode.GetNode().GetCntntNode()->GetFrm() ||
2031 ( pStartPos->nNode != pEndPos->nNode &&
2032 ( !pEndPos->nNode.GetNode().IsCntntNode() ||
2033 !pEndPos->nNode.GetNode().GetCntntNode()->GetFrm() ) ) )
2035 /* For SelectAll we will need something like this later on...
2036 const SwFrm* pPageFrm = GetLower();
2037 while( pPageFrm )
2039 SwRect aTmp( pPageFrm->Prt() );
2040 aTmp.Pos() += pPageFrm->Frm().Pos();
2041 Sub( aRegion, aTmp );
2042 pPageFrm = pPageFrm->GetNext();
2044 aRegion.Invert();
2045 rCrsr.Remove( 0, rCrsr.Count() );
2046 rCrsr.Insert( &aRegion, 0 );
2048 return;
2051 //Erstmal die CntntFrms zum Start und End besorgen, die brauch ich auf
2052 //jedenfall.
2053 const SwCntntFrm *pStartFrm = rNds[ pStartPos->nNode ]->
2054 GetCntntNode()->GetFrm( &rCrsr.GetSttPos(), pStartPos );
2056 const SwCntntFrm *pEndFrm = rNds[ pEndPos->nNode ]->
2057 GetCntntNode()->GetFrm( &rCrsr.GetEndPos(), pEndPos );
2059 ASSERT( (pStartFrm && pEndFrm), "Keine CntntFrms gefunden." );
2061 //Damit die FlyFrms, in denen selektierte Frames stecken, nicht
2062 //abgezogen werden
2063 SwSortedObjs aSortObjs;
2064 if ( pStartFrm->IsInFly() )
2066 const SwAnchoredObject* pObj = pStartFrm->FindFlyFrm();
2067 aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj)) );
2068 const SwAnchoredObject* pObj2 = pEndFrm->FindFlyFrm();
2069 aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj2)) );
2072 //Fall 4: Tabellenselection
2073 if( bIsTblMode )
2075 const SwFrm *pCell = pStartFrm->GetUpper();
2076 while ( !pCell->IsCellFrm() )
2077 pCell = pCell->GetUpper();
2078 SwRect aTmp( pCell->Prt() );
2079 aTmp.Pos() += pCell->Frm().Pos();
2080 aRegion.ChangeOrigin( aTmp );
2081 aRegion.Remove( 0, aRegion.Count() );
2082 aRegion.Insert( aTmp, 0 );
2084 else
2086 // falls eine nicht erlaubte Selection besteht, dann korrigiere das
2087 // nicht erlaubt ist Header/Footer/TableHeadline ueber 2 Seiten
2088 do { // middle check loop
2089 const SwLayoutFrm* pSttLFrm = pStartFrm->GetUpper();
2090 const USHORT cHdFtTblHd = FRM_HEADER | FRM_FOOTER | FRM_TAB;
2091 while( pSttLFrm &&
2092 ! (cHdFtTblHd & pSttLFrm->GetType() ))
2093 pSttLFrm = pSttLFrm->GetUpper();
2094 if( !pSttLFrm )
2095 break;
2096 const SwLayoutFrm* pEndLFrm = pEndFrm->GetUpper();
2097 while( pEndLFrm &&
2098 ! (cHdFtTblHd & pEndLFrm->GetType() ))
2099 pEndLFrm = pEndLFrm->GetUpper();
2100 if( !pEndLFrm )
2101 break;
2103 ASSERT( pEndLFrm->GetType() == pSttLFrm->GetType(),
2104 "Selection ueber unterschiedliche Inhalte" );
2105 switch( pSttLFrm->GetType() )
2107 case FRM_HEADER:
2108 case FRM_FOOTER:
2109 // auf unterschiedlichen Seiten ??
2110 // dann immer auf die Start-Seite
2111 if( pEndLFrm->FindPageFrm() != pSttLFrm->FindPageFrm() )
2113 // End- auf den Start-CntntFrame setzen
2114 if( pStartPos == rCrsr.GetPoint() )
2115 pEndFrm = pStartFrm;
2116 else
2117 pStartFrm = pEndFrm;
2119 break;
2120 case FRM_TAB:
2121 // auf unterschiedlichen Seiten ??
2122 // existiert
2123 // dann teste auf Tabelle-Headline
2125 const SwTabFrm* pTabFrm = (SwTabFrm*)pSttLFrm;
2126 if( ( pTabFrm->GetFollow() ||
2127 ((SwTabFrm*)pEndLFrm)->GetFollow() ) &&
2128 pTabFrm->GetTable()->GetRowsToRepeat() > 0 &&
2129 pTabFrm->GetLower() != ((SwTabFrm*)pEndLFrm)->GetLower() &&
2130 ( lcl_IsInRepeatedHeadline( pStartFrm ) ||
2131 lcl_IsInRepeatedHeadline( pEndFrm ) ) )
2133 // End- auf den Start-CntntFrame setzen
2134 if( pStartPos == rCrsr.GetPoint() )
2135 pEndFrm = pStartFrm;
2136 else
2137 pStartFrm = pEndFrm;
2140 break;
2142 } while( FALSE );
2144 SwCrsrMoveState aTmpState( MV_NONE );
2145 aTmpState.b2Lines = sal_True;
2146 aTmpState.bNoScroll = sal_True;
2147 aTmpState.nCursorBidiLevel = pStartFrm->IsRightToLeft() ? 1 : 0;
2149 //CntntRects zu Start- und EndFrms.
2150 SwRect aStRect, aEndRect;
2151 pStartFrm->GetCharRect( aStRect, *pStartPos, &aTmpState );
2152 Sw2LinesPos *pSt2Pos = aTmpState.p2Lines;
2153 aTmpState.p2Lines = NULL;
2154 aTmpState.nCursorBidiLevel = pEndFrm->IsRightToLeft() ? 1 : 0;
2156 pEndFrm->GetCharRect ( aEndRect, *pEndPos, &aTmpState );
2157 Sw2LinesPos *pEnd2Pos = aTmpState.p2Lines;
2159 SwRect aStFrm ( pStartFrm->UnionFrm( sal_True ) );
2160 aStFrm.Intersection( pStartFrm->PaintArea() );
2161 SwRect aEndFrm( pStartFrm == pEndFrm ? aStFrm :
2162 pEndFrm->UnionFrm( sal_True ) );
2163 if( pStartFrm != pEndFrm )
2164 aEndFrm.Intersection( pEndFrm->PaintArea() );
2165 SWRECTFN( pStartFrm )
2166 const BOOL bR2L = pStartFrm->IsRightToLeft();
2167 const BOOL bEndR2L = pEndFrm->IsRightToLeft();
2169 // If there's no doubleline portion involved or start and end are both
2170 // in the same doubleline portion, all works fine, but otherwise
2171 // we need the following...
2172 if( pSt2Pos != pEnd2Pos && ( !pSt2Pos || !pEnd2Pos ||
2173 pSt2Pos->aPortion != pEnd2Pos->aPortion ) )
2175 // If we have a start(end) position inside a doubleline portion
2176 // the surrounded part of the doubleline portion is subtracted
2177 // from the region and the aStRect(aEndRect) is set to the
2178 // end(start) of the doubleline portion.
2179 if( pSt2Pos )
2181 SwRect aTmp( aStRect );
2183 // BiDi-Portions are swimming against the current.
2184 const sal_Bool bPorR2L = ( MT_BIDI == pSt2Pos->nMultiType ) ?
2185 ! bR2L :
2186 bR2L;
2188 if( MT_BIDI == pSt2Pos->nMultiType &&
2189 (pSt2Pos->aPortion2.*fnRect->fnGetWidth)() )
2191 // nested bidi portion
2192 long nRightAbs = (pSt2Pos->aPortion.*fnRect->fnGetRight)();
2193 nRightAbs -= (pSt2Pos->aPortion2.*fnRect->fnGetLeft)();
2194 long nLeftAbs = nRightAbs - (pSt2Pos->aPortion2.*fnRect->fnGetWidth)();
2196 (aTmp.*fnRect->fnSetRight)( nRightAbs );
2198 if ( ! pEnd2Pos || pEnd2Pos->aPortion != pSt2Pos->aPortion )
2200 SwRect aTmp2( pSt2Pos->aPortion );
2201 (aTmp2.*fnRect->fnSetRight)( nLeftAbs );
2202 aTmp2.Intersection( aEndFrm );
2203 Sub( aRegion, aTmp2 );
2206 else
2208 if( bPorR2L )
2209 (aTmp.*fnRect->fnSetLeft)(
2210 (pSt2Pos->aPortion.*fnRect->fnGetLeft)() );
2211 else
2212 (aTmp.*fnRect->fnSetRight)(
2213 (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
2216 if( MT_ROT_90 == pSt2Pos->nMultiType ||
2217 (pSt2Pos->aPortion.*fnRect->fnGetTop)() ==
2218 (aTmp.*fnRect->fnGetTop)() )
2220 (aTmp.*fnRect->fnSetTop)(
2221 (pSt2Pos->aLine.*fnRect->fnGetTop)() );
2224 aTmp.Intersection( aStFrm );
2225 Sub( aRegion, aTmp );
2227 SwTwips nTmp = (pSt2Pos->aLine.*fnRect->fnGetBottom)();
2228 if( MT_ROT_90 != pSt2Pos->nMultiType &&
2229 (aStRect.*fnRect->fnBottomDist)( nTmp ) > 0 )
2231 (aTmp.*fnRect->fnSetTop)( (aTmp.*fnRect->fnGetBottom)() );
2232 (aTmp.*fnRect->fnSetBottom)( nTmp );
2233 if( (aStRect.*fnRect->fnBottomDist)(
2234 (pSt2Pos->aPortion.*fnRect->fnGetBottom)() ) > 0 )
2236 if( bPorR2L )
2237 (aTmp.*fnRect->fnSetRight)(
2238 (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
2239 else
2240 (aTmp.*fnRect->fnSetLeft)(
2241 (pSt2Pos->aPortion.*fnRect->fnGetLeft)() );
2243 aTmp.Intersection( aStFrm );
2244 Sub( aRegion, aTmp );
2247 aStRect = pSt2Pos->aLine;
2248 (aStRect.*fnRect->fnSetLeft)( bR2L ?
2249 (pSt2Pos->aPortion.*fnRect->fnGetLeft)() :
2250 (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
2251 (aStRect.*fnRect->fnSetWidth)( 1 );
2254 if( pEnd2Pos )
2256 SWRECTFNX( pEndFrm )
2257 SwRect aTmp( aEndRect );
2259 // BiDi-Portions are swimming against the current.
2260 const sal_Bool bPorR2L = ( MT_BIDI == pEnd2Pos->nMultiType ) ?
2261 ! bEndR2L :
2262 bEndR2L;
2264 if( MT_BIDI == pEnd2Pos->nMultiType &&
2265 (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)() )
2267 // nested bidi portion
2268 long nRightAbs = (pEnd2Pos->aPortion.*fnRectX->fnGetRight)();
2269 nRightAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetLeft)();
2270 long nLeftAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)();
2272 (aTmp.*fnRectX->fnSetLeft)( nLeftAbs );
2274 if ( ! pSt2Pos || pSt2Pos->aPortion != pEnd2Pos->aPortion )
2276 SwRect aTmp2( pEnd2Pos->aPortion );
2277 (aTmp2.*fnRectX->fnSetLeft)( nRightAbs );
2278 aTmp2.Intersection( aEndFrm );
2279 Sub( aRegion, aTmp2 );
2282 else
2284 if ( bPorR2L )
2285 (aTmp.*fnRectX->fnSetRight)(
2286 (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() );
2287 else
2288 (aTmp.*fnRectX->fnSetLeft)(
2289 (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() );
2292 if( MT_ROT_90 == pEnd2Pos->nMultiType ||
2293 (pEnd2Pos->aPortion.*fnRectX->fnGetBottom)() ==
2294 (aEndRect.*fnRectX->fnGetBottom)() )
2296 (aTmp.*fnRectX->fnSetBottom)(
2297 (pEnd2Pos->aLine.*fnRectX->fnGetBottom)() );
2300 aTmp.Intersection( aEndFrm );
2301 Sub( aRegion, aTmp );
2303 // The next statement means neither ruby nor rotate(90):
2304 if( !( MT_RUBY & pEnd2Pos->nMultiType ) )
2306 SwTwips nTmp = (pEnd2Pos->aLine.*fnRectX->fnGetTop)();
2307 if( (aEndRect.*fnRectX->fnGetTop)() != nTmp )
2309 (aTmp.*fnRectX->fnSetBottom)(
2310 (aTmp.*fnRectX->fnGetTop)() );
2311 (aTmp.*fnRectX->fnSetTop)( nTmp );
2312 if( (aEndRect.*fnRectX->fnGetTop)() !=
2313 (pEnd2Pos->aPortion.*fnRectX->fnGetTop)() )
2314 if( bPorR2L )
2315 (aTmp.*fnRectX->fnSetLeft)(
2316 (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() );
2317 else
2318 (aTmp.*fnRectX->fnSetRight)(
2319 (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() );
2320 aTmp.Intersection( aEndFrm );
2321 Sub( aRegion, aTmp );
2325 aEndRect = pEnd2Pos->aLine;
2326 (aEndRect.*fnRectX->fnSetLeft)( bEndR2L ?
2327 (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() :
2328 (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() );
2329 (aEndRect.*fnRectX->fnSetWidth)( 1 );
2332 else if( pSt2Pos && pEnd2Pos &&
2333 MT_BIDI == pSt2Pos->nMultiType &&
2334 MT_BIDI == pEnd2Pos->nMultiType &&
2335 pSt2Pos->aPortion == pEnd2Pos->aPortion &&
2336 pSt2Pos->aPortion2 != pEnd2Pos->aPortion2 )
2338 // This is the ugly special case, where the selection starts and
2339 // ends in the same bidi portion but one start or end is inside a
2340 // nested bidi portion.
2342 if ( (pSt2Pos->aPortion2.*fnRect->fnGetWidth)() )
2344 SwRect aTmp( aStRect );
2345 long nRightAbs = (pSt2Pos->aPortion.*fnRect->fnGetRight)();
2346 nRightAbs -= (pSt2Pos->aPortion2.*fnRect->fnGetLeft)();
2347 long nLeftAbs = nRightAbs - (pSt2Pos->aPortion2.*fnRect->fnGetWidth)();
2349 (aTmp.*fnRect->fnSetRight)( nRightAbs );
2350 aTmp.Intersection( aStFrm );
2351 Sub( aRegion, aTmp );
2353 aStRect = pSt2Pos->aLine;
2354 (aStRect.*fnRect->fnSetLeft)( bR2L ? nRightAbs : nLeftAbs );
2355 (aStRect.*fnRect->fnSetWidth)( 1 );
2358 SWRECTFNX( pEndFrm )
2359 if ( (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)() )
2361 SwRect aTmp( aEndRect );
2362 long nRightAbs = (pEnd2Pos->aPortion.*fnRectX->fnGetRight)();
2363 nRightAbs -= (pEnd2Pos->aPortion2.*fnRectX->fnGetLeft)();
2364 long nLeftAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)();
2366 (aTmp.*fnRectX->fnSetLeft)( nLeftAbs );
2367 aTmp.Intersection( aEndFrm );
2368 Sub( aRegion, aTmp );
2370 aEndRect = pEnd2Pos->aLine;
2371 (aEndRect.*fnRectX->fnSetLeft)( bEndR2L ? nLeftAbs : nRightAbs );
2372 (aEndRect.*fnRectX->fnSetWidth)( 1 );
2376 // The charrect may be outside the paintarea (for cursortravelling)
2377 // but the selection has to be restricted to the paintarea
2378 if( aStRect.Left() < aStFrm.Left() )
2379 aStRect.Left( aStFrm.Left() );
2380 else if( aStRect.Left() > aStFrm.Right() )
2381 aStRect.Left( aStFrm.Right() );
2382 SwTwips nTmp = aStRect.Right();
2383 if( nTmp < aStFrm.Left() )
2384 aStRect.Right( aStFrm.Left() );
2385 else if( nTmp > aStFrm.Right() )
2386 aStRect.Right( aStFrm.Right() );
2387 if( aEndRect.Left() < aEndFrm.Left() )
2388 aEndRect.Left( aEndFrm.Left() );
2389 else if( aEndRect.Left() > aEndFrm.Right() )
2390 aEndRect.Left( aEndFrm.Right() );
2391 nTmp = aEndRect.Right();
2392 if( nTmp < aEndFrm.Left() )
2393 aEndRect.Right( aEndFrm.Left() );
2394 else if( nTmp > aEndFrm.Right() )
2395 aEndRect.Right( aEndFrm.Right() );
2397 if( pStartFrm == pEndFrm )
2399 sal_Bool bSameRotatedOrBidi = pSt2Pos && pEnd2Pos &&
2400 ( MT_BIDI & pSt2Pos->nMultiType ) &&
2401 pSt2Pos->aPortion == pEnd2Pos->aPortion;
2402 //case 1: (Same frame and same row)
2403 if( bSameRotatedOrBidi ||
2404 (aStRect.*fnRect->fnGetTop)() == (aEndRect.*fnRect->fnGetTop)() )
2406 Point aTmpSt( aStRect.Pos() );
2407 Point aTmpEnd( aEndRect.Right(), aEndRect.Bottom() );
2408 if( bSameRotatedOrBidi || bR2L )
2410 if( aTmpSt.Y() > aTmpEnd.Y() )
2412 long nTmpY = aTmpEnd.Y();
2413 aTmpEnd.Y() = aTmpSt.Y();
2414 aTmpSt.Y() = nTmpY;
2416 if( aTmpSt.X() > aTmpEnd.X() )
2418 long nTmpX = aTmpEnd.X();
2419 aTmpEnd.X() = aTmpSt.X();
2420 aTmpSt.X() = nTmpX;
2424 SwRect aTmp = SwRect( aTmpSt, aTmpEnd );
2425 // Bug 34888: falls Inhalt selektiert ist, der keinen Platz
2426 // einnimmt (z.B. PostIts,RefMarks, TOXMarks),
2427 // dann mindestens die Breite des Crsr setzen.
2428 if( 1 == (aTmp.*fnRect->fnGetWidth)() &&
2429 pStartPos->nContent.GetIndex() !=
2430 pEndPos->nContent.GetIndex() )
2432 OutputDevice* pOut = pSh->GetOut();
2433 long nCrsrWidth = pOut->GetSettings().GetStyleSettings().
2434 GetCursorSize();
2435 (aTmp.*fnRect->fnSetWidth)( pOut->PixelToLogic(
2436 Size( nCrsrWidth, 0 ) ).Width() );
2438 aTmp.Intersection( aStFrm );
2439 Sub( aRegion, aTmp );
2441 //case 2: (Same frame, but not the same line)
2442 else
2444 SwTwips lLeft, lRight;
2445 if( pSt2Pos && pEnd2Pos && pSt2Pos->aPortion == pEnd2Pos->aPortion )
2447 lLeft = (pSt2Pos->aPortion.*fnRect->fnGetLeft)();
2448 lRight = (pSt2Pos->aPortion.*fnRect->fnGetRight)();
2450 else
2452 lLeft = (pStartFrm->Frm().*fnRect->fnGetLeft)() +
2453 (pStartFrm->Prt().*fnRect->fnGetLeft)();
2454 lRight = (pStartFrm->Frm().*fnRect->fnGetLeft)() +
2455 (pStartFrm->Prt().*fnRect->fnGetRight)();
2457 if( lLeft < (aStFrm.*fnRect->fnGetLeft)() )
2458 lLeft = (aStFrm.*fnRect->fnGetLeft)();
2459 if( lRight > (aStFrm.*fnRect->fnGetRight)() )
2460 lRight = (aStFrm.*fnRect->fnGetRight)();
2461 SwRect aSubRect( aStRect );
2462 //First line
2463 if( bR2L )
2464 (aSubRect.*fnRect->fnSetLeft)( lLeft );
2465 else
2466 (aSubRect.*fnRect->fnSetRight)( lRight );
2467 Sub( aRegion, aSubRect );
2469 //If there's at least a twips between start- and endline,
2470 //so the whole area between will be added.
2471 SwTwips aTmpBottom = (aStRect.*fnRect->fnGetBottom)();
2472 SwTwips aTmpTop = (aEndRect.*fnRect->fnGetTop)();
2473 if( aTmpBottom != aTmpTop )
2475 (aSubRect.*fnRect->fnSetLeft)( lLeft );
2476 (aSubRect.*fnRect->fnSetRight)( lRight );
2477 (aSubRect.*fnRect->fnSetTop)( aTmpBottom );
2478 (aSubRect.*fnRect->fnSetBottom)( aTmpTop );
2479 Sub( aRegion, aSubRect );
2481 //and the last line
2482 aSubRect = aEndRect;
2483 if( bR2L )
2484 (aSubRect.*fnRect->fnSetRight)( lRight );
2485 else
2486 (aSubRect.*fnRect->fnSetLeft)( lLeft );
2487 Sub( aRegion, aSubRect );
2490 //case 3: (Different frames, maybe with ohther frames between
2491 else
2493 //The startframe first...
2494 SwRect aSubRect( aStRect );
2495 if( bR2L )
2496 (aSubRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)());
2497 else
2498 (aSubRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)());
2499 Sub( aRegion, aSubRect );
2500 SwTwips nTmpTwips = (aStRect.*fnRect->fnGetBottom)();
2501 if( (aStFrm.*fnRect->fnGetBottom)() != nTmpTwips )
2503 aSubRect = aStFrm;
2504 (aSubRect.*fnRect->fnSetTop)( nTmpTwips );
2505 Sub( aRegion, aSubRect );
2508 //Now the frames between, if there are any
2509 BOOL bBody = pStartFrm->IsInDocBody();
2510 const SwTableBox* pCellBox = pStartFrm->GetUpper()->IsCellFrm() ?
2511 ((SwCellFrm*)pStartFrm->GetUpper())->GetTabBox() : 0;
2512 const SwCntntFrm *pCntnt = pStartFrm->GetNextCntntFrm();
2513 SwRect aPrvRect;
2515 // --> OD 2006-01-24 #123908# - introduce robust code:
2516 // The stacktrace issue reveals that <pCntnt> could be NULL.
2517 // One root cause found by AMA - see #130650#
2518 ASSERT( pCntnt,
2519 "<SwRootFrm::CalcFrmRects(..)> - no content frame. This is a serious defect -> please inform OD" );
2520 while ( pCntnt && pCntnt != pEndFrm )
2521 // <--
2523 if ( pCntnt->IsInFly() )
2525 const SwAnchoredObject* pObj = pCntnt->FindFlyFrm();
2526 aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj)) );
2529 // Consider only frames which have the same IsInDocBody value like pStartFrm
2530 // If pStartFrm is inside a SwCellFrm, consider only frames which are inside the
2531 // same cell frame (or its follow cell)
2532 const SwTableBox* pTmpCellBox = pCntnt->GetUpper()->IsCellFrm() ?
2533 ((SwCellFrm*)pCntnt->GetUpper())->GetTabBox() : 0;
2534 if ( bBody == pCntnt->IsInDocBody() &&
2535 ( !pCellBox || pCellBox == pTmpCellBox ) )
2537 SwRect aCRect( pCntnt->UnionFrm( sal_True ) );
2538 aCRect.Intersection( pCntnt->PaintArea() );
2539 if( aCRect.IsOver( aRegion.GetOrigin() ))
2541 SwRect aTmp( aPrvRect );
2542 aTmp.Union( aCRect );
2543 if ( (aPrvRect.Height() * aPrvRect.Width() +
2544 aCRect.Height() * aCRect.Width()) ==
2545 (aTmp.Height() * aTmp.Width()) )
2547 aPrvRect.Union( aCRect );
2549 else
2551 if ( aPrvRect.HasArea() )
2552 Sub( aRegion, aPrvRect );
2553 aPrvRect = aCRect;
2557 pCntnt = pCntnt->GetNextCntntFrm();
2558 // --> OD 2006-01-24 #123908#
2559 ASSERT( pCntnt,
2560 "<SwRootFrm::CalcFrmRects(..)> - no content frame. This is a serious defect -> please inform OD" );
2561 // <--
2563 if ( aPrvRect.HasArea() )
2564 Sub( aRegion, aPrvRect );
2566 //At least the endframe...
2567 bVert = pEndFrm->IsVertical();
2568 bRev = pEndFrm->IsReverse();
2569 fnRect = bVert ? ( bRev ? fnRectVL2R : fnRectVert ) :
2570 ( bRev ? fnRectB2T : fnRectHori );
2571 nTmpTwips = (aEndRect.*fnRect->fnGetTop)();
2572 if( (aEndFrm.*fnRect->fnGetTop)() != nTmpTwips )
2574 aSubRect = aEndFrm;
2575 (aSubRect.*fnRect->fnSetBottom)( nTmpTwips );
2576 Sub( aRegion, aSubRect );
2578 aSubRect = aEndRect;
2579 if( bEndR2L )
2580 (aSubRect.*fnRect->fnSetRight)((aEndFrm.*fnRect->fnGetRight)());
2581 else
2582 (aSubRect.*fnRect->fnSetLeft)( (aEndFrm.*fnRect->fnGetLeft)() );
2583 Sub( aRegion, aSubRect );
2586 // aRegion.Compress( FALSE );
2587 aRegion.Invert();
2588 delete pSt2Pos;
2589 delete pEnd2Pos;
2592 //Flys mit Durchlauf ausstanzen. Nicht ausgestanzt werden Flys:
2593 //- die Lower des StartFrm/EndFrm sind (FlyInCnt und alle Flys die wiederum
2594 // darin sitzen)
2595 //- in der Z-Order ueber denjenigen Flys stehen in denen sich der StartFrm
2596 // befindet.
2597 const SwPageFrm *pPage = pStartFrm->FindPageFrm();
2598 const SwPageFrm *pEndPage = pEndFrm->FindPageFrm();
2600 while ( pPage )
2602 if ( pPage->GetSortedObjs() )
2604 const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
2605 for ( USHORT i = 0; i < rObjs.Count(); ++i )
2607 SwAnchoredObject* pAnchoredObj = rObjs[i];
2608 if ( !pAnchoredObj->ISA(SwFlyFrm) )
2609 continue;
2610 const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj);
2611 const SwVirtFlyDrawObj* pObj = pFly->GetVirtDrawObj();
2612 const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround();
2613 if ( !pFly->IsAnLower( pStartFrm ) &&
2614 (rSur.GetSurround() != SURROUND_THROUGHT &&
2615 !rSur.IsContour()) )
2617 if ( aSortObjs.Contains( *pAnchoredObj ) )
2618 continue;
2620 BOOL bSub = TRUE;
2621 const UINT32 nPos = pObj->GetOrdNum();
2622 for ( USHORT k = 0; bSub && k < aSortObjs.Count(); ++k )
2624 ASSERT( aSortObjs[k]->ISA(SwFlyFrm),
2625 "<SwRootFrm::CalcFrmRects(..)> - object in <aSortObjs> of unexcepted type" );
2626 const SwFlyFrm* pTmp = static_cast<SwFlyFrm*>(aSortObjs[k]);
2628 { if ( nPos < pTmp->GetVirtDrawObj()->GetOrdNumDirect() )
2629 bSub = FALSE;
2630 else
2631 pTmp = pTmp->GetAnchorFrm()->FindFlyFrm();
2632 } while ( bSub && pTmp );
2634 if ( bSub )
2635 Sub( aRegion, pFly->Frm() );
2639 if ( pPage == pEndPage )
2640 break;
2641 else
2642 pPage = (SwPageFrm*)pPage->GetNext();
2645 //Weil's besser aussieht noch die DropCaps ausschliessen.
2646 SwRect aDropRect;
2647 if ( pStartFrm->IsTxtFrm() )
2649 if ( ((SwTxtFrm*)pStartFrm)->GetDropRect( aDropRect ) )
2650 Sub( aRegion, aDropRect );
2652 if ( pEndFrm != pStartFrm && pEndFrm->IsTxtFrm() )
2654 if ( ((SwTxtFrm*)pEndFrm)->GetDropRect( aDropRect ) )
2655 Sub( aRegion, aDropRect );
2658 rCrsr.Remove( 0, rCrsr.Count() );
2659 rCrsr.Insert( &aRegion, 0 );