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