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