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 <editeng/keepitem.hxx> 30 #include <editeng/hyznitem.hxx> 31 #include <pagefrm.hxx> // ChangeFtnRef 32 #include <ndtxt.hxx> // MakeFrm() 33 #include <dcontact.hxx> // SwDrawContact 34 #include <dflyobj.hxx> // SwVirtFlyDrawObj 35 #include <flyfrm.hxx> 36 #include <ftnfrm.hxx> // SwFtnFrm 37 #include <txtftn.hxx> 38 #include <fmtftn.hxx> 39 #include <paratr.hxx> 40 #include <viewopt.hxx> // SwViewOptions 41 #include <viewsh.hxx> // ViewShell 42 #include <frmatr.hxx> 43 #include <pam.hxx> 44 #include <flyfrms.hxx> 45 #include <fmtanchr.hxx> 46 #include <txtcfg.hxx> 47 #include <itrform2.hxx> // SwTxtFormatter 48 #include <widorp.hxx> // Widows and Orphans 49 #include <txtcache.hxx> 50 #include <porrst.hxx> // SwEmptyPortion 51 #include <blink.hxx> // pBlink 52 #include <porfld.hxx> // SwFldPortion 53 #include <sectfrm.hxx> // SwSectionFrm 54 #include <pormulti.hxx> // SwMultiPortion 55 56 #include <rootfrm.hxx> 57 #include <frmfmt.hxx> // SwFrmFmt 58 // OD 2004-05-24 #i28701# 59 #include <sortedobjs.hxx> 60 61 class FormatLevel 62 { 63 static MSHORT nLevel; 64 public: 65 inline FormatLevel() { ++nLevel; } 66 inline ~FormatLevel() { --nLevel; } 67 inline MSHORT GetLevel() const { return nLevel; } 68 static sal_Bool LastLevel() { return 10 < nLevel; } 69 }; 70 MSHORT FormatLevel::nLevel = 0; 71 72 /************************************************************************* 73 * ValidateTxt/Frm() 74 *************************************************************************/ 75 76 void ValidateTxt( SwFrm *pFrm ) // Freund vom Frame 77 { 78 if ( ( ! pFrm->IsVertical() && 79 pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) || 80 ( pFrm->IsVertical() && 81 pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() ) ) 82 pFrm->bValidSize = sal_True; 83 /* 84 pFrm->bValidPrtArea = sal_True; 85 //Die Position validieren um nicht unnoetige (Test-)Moves zu provozieren. 86 //Dabei darf allerdings nicht eine tatsaechlich falsche Coordinate 87 //validiert werden. 88 if ( !pFrm->bValidPos ) 89 { 90 //Leider muessen wir dazu die korrekte Position berechnen. 91 Point aOld( pFrm->Frm().Pos() ); 92 pFrm->MakePos(); 93 if ( aOld != pFrm->Pos() ) 94 { 95 pFrm->Frm().Pos( aOld ); 96 pFrm->bValidPos = sal_False; 97 } 98 } 99 */ 100 } 101 102 void SwTxtFrm::ValidateFrm() 103 { 104 // Umgebung validieren, um Oszillationen zu verhindern. 105 SWAP_IF_SWAPPED( this ) 106 107 if ( !IsInFly() && !IsInTab() ) 108 { //Innerhalb eines Flys nur this validieren, der Rest sollte eigentlich 109 //nur fuer Fussnoten notwendig sein und die gibt es innerhalb von 110 //Flys nicht. Fix fuer 5544 111 SwSectionFrm* pSct = FindSctFrm(); 112 if( pSct ) 113 { 114 if( !pSct->IsColLocked() ) 115 pSct->ColLock(); 116 else 117 pSct = NULL; 118 } 119 120 SwFrm *pUp = GetUpper(); 121 pUp->Calc(); 122 if( pSct ) 123 pSct->ColUnlock(); 124 } 125 ValidateTxt( this ); 126 127 //MA: mindestens das MustFit-Flag muessen wir retten! 128 ASSERT( HasPara(), "ResetPreps(), missing ParaPortion." ); 129 SwParaPortion *pPara = GetPara(); 130 const sal_Bool bMustFit = pPara->IsPrepMustFit(); 131 ResetPreps(); 132 pPara->SetPrepMustFit( bMustFit ); 133 134 UNDO_SWAP( this ) 135 } 136 137 /************************************************************************* 138 * ValidateBodyFrm() 139 *************************************************************************/ 140 141 // nach einem RemoveFtn muss der BodyFrm und alle innenliegenden kalkuliert 142 // werden, damit die DeadLine richtig sitzt. 143 // Erst wird nach aussen hin gesucht, beim Rueckweg werden alle kalkuliert. 144 145 void _ValidateBodyFrm( SwFrm *pFrm ) 146 { 147 if( pFrm && !pFrm->IsCellFrm() ) 148 { 149 if( !pFrm->IsBodyFrm() && pFrm->GetUpper() ) 150 _ValidateBodyFrm( pFrm->GetUpper() ); 151 if( !pFrm->IsSctFrm() ) 152 pFrm->Calc(); 153 else 154 { 155 sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked(); 156 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_True ); 157 pFrm->Calc(); 158 if( !bOld ) 159 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_False ); 160 } 161 } 162 } 163 164 void SwTxtFrm::ValidateBodyFrm() 165 { 166 SWAP_IF_SWAPPED( this ) 167 168 //siehe Kommtar in ValidateFrm() 169 if ( !IsInFly() && !IsInTab() && 170 !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) ) 171 _ValidateBodyFrm( GetUpper() ); 172 173 UNDO_SWAP( this ) 174 } 175 176 /************************************************************************* 177 * SwTxtFrm::FindBodyFrm() 178 *************************************************************************/ 179 180 sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const 181 { 182 SWAP_IF_NOT_SWAPPED( this ) 183 184 ASSERT( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." ); 185 SwTxtSizeInfo aInf( (SwTxtFrm*)this ); 186 SwTxtMargin aLine( (SwTxtFrm*)this, &aInf ); 187 if( aLine.GetDropLines() ) 188 { 189 rRect.Top( aLine.Y() ); 190 rRect.Left( aLine.GetLineStart() ); 191 rRect.Height( aLine.GetDropHeight() ); 192 rRect.Width( aLine.GetDropLeft() ); 193 194 if ( IsRightToLeft() ) 195 SwitchLTRtoRTL( rRect ); 196 197 if ( IsVertical() ) 198 SwitchHorizontalToVertical( rRect ); 199 UNDO_SWAP( this ) 200 return sal_True; 201 } 202 203 UNDO_SWAP( this ) 204 205 return sal_False; 206 } 207 208 /************************************************************************* 209 * SwTxtFrm::FindBodyFrm() 210 *************************************************************************/ 211 212 const SwBodyFrm *SwTxtFrm::FindBodyFrm() const 213 { 214 if ( IsInDocBody() ) 215 { 216 const SwFrm *pFrm = GetUpper(); 217 while( pFrm && !pFrm->IsBodyFrm() ) 218 pFrm = pFrm->GetUpper(); 219 return (const SwBodyFrm*)pFrm; 220 } 221 return 0; 222 } 223 224 /************************************************************************* 225 * SwTxtFrm::CalcFollow() 226 *************************************************************************/ 227 228 sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst ) 229 { 230 SWAP_IF_SWAPPED( this ) 231 232 ASSERT( HasFollow(), "CalcFollow: missing Follow." ); 233 234 SwTxtFrm* pMyFollow = GetFollow(); 235 236 SwParaPortion *pPara = GetPara(); 237 sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False; 238 239 if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst || 240 bFollowFld || pMyFollow->IsFieldFollow() || 241 ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) || 242 ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) ) 243 { 244 #ifdef DBG_UTIL 245 const SwFrm *pOldUp = GetUpper(); 246 #endif 247 248 SWRECTFN ( this ) 249 SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)(); 250 SwTwips nMyPos = (Frm().*fnRect->fnGetTop)(); 251 252 const SwPageFrm *pPage = 0; 253 sal_Bool bOldInvaCntnt = sal_True; 254 if ( !IsInFly() && GetNext() ) 255 { 256 pPage = FindPageFrm(); 257 //Minimieren - sprich ggf. zuruecksetzen - der Invalidierungen s.u. 258 bOldInvaCntnt = pPage->IsInvalidCntnt(); 259 } 260 261 pMyFollow->_SetOfst( nTxtOfst ); 262 pMyFollow->SetFieldFollow( bFollowFld ); 263 if( HasFtn() || pMyFollow->HasFtn() ) 264 { 265 ValidateFrm(); 266 ValidateBodyFrm(); 267 if( pPara ) 268 { 269 *(pPara->GetReformat()) = SwCharRange(); 270 *(pPara->GetDelta()) = 0; 271 } 272 } 273 274 //Der Fussnotenbereich darf sich keinesfalls vergrossern. 275 SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX ); 276 277 pMyFollow->CalcFtnFlag(); 278 if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() ) 279 nOldBottom = bVert ? 0 : LONG_MAX; 280 281 while( sal_True ) 282 { 283 if( !FormatLevel::LastLevel() ) 284 { 285 // Weenn der Follow in einem spaltigen Bereich oder einem 286 // spaltigen Rahmen steckt, muss zunaechst dieser kalkuliert 287 // werden, da das FormatWidthCols() nicht funktioniert, wenn 288 // es aus dem MakeAll des _gelockten_ Follows heraus gerufen 289 // wird. 290 SwSectionFrm* pSct = pMyFollow->FindSctFrm(); 291 if( pSct && !pSct->IsAnLower( this ) ) 292 { 293 if( pSct->GetFollow() ) 294 pSct->SimpleFormat(); 295 else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) || 296 ( ! pSct->IsVertical() && !pSct->Frm().Height() ) ) 297 break; 298 } 299 // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled. 300 if ( FollowFormatAllowed() ) 301 { 302 // OD 14.03.2003 #i11760# - no nested format of follows, if 303 // text frame is contained in a column frame. 304 // Thus, forbid intrinsic format of follow. 305 { 306 bool bIsFollowInColumn = false; 307 SwFrm* pFollowUpper = pMyFollow->GetUpper(); 308 while ( pFollowUpper ) 309 { 310 if ( pFollowUpper->IsColumnFrm() ) 311 { 312 bIsFollowInColumn = true; 313 break; 314 } 315 if ( pFollowUpper->IsPageFrm() || 316 pFollowUpper->IsFlyFrm() ) 317 { 318 break; 319 } 320 pFollowUpper = pFollowUpper->GetUpper(); 321 } 322 if ( bIsFollowInColumn ) 323 { 324 pMyFollow->ForbidFollowFormat(); 325 } 326 } 327 328 pMyFollow->Calc(); 329 // Der Follow merkt anhand seiner Frm().Height(), dass was schief 330 // gelaufen ist. 331 ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" ); 332 if( pMyFollow->GetPrev() ) 333 { 334 pMyFollow->Prepare( PREP_CLEAR ); 335 pMyFollow->Calc(); 336 ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" ); 337 } 338 339 // OD 14.03.2003 #i11760# - reset control flag for follow format. 340 pMyFollow->AllowFollowFormat(); 341 } 342 343 //Sicherstellen, dass der Follow gepaintet wird. 344 pMyFollow->SetCompletePaint(); 345 } 346 347 pPara = GetPara(); 348 //Solange der Follow wg. Orphans Zeilen angefordert, bekommt er 349 //diese und wird erneut formatiert, falls moeglich. 350 if( pPara && pPara->IsPrepWidows() ) 351 CalcPreps(); 352 else 353 break; 354 } 355 356 if( HasFtn() || pMyFollow->HasFtn() ) 357 { 358 ValidateBodyFrm(); 359 ValidateFrm(); 360 if( pPara ) 361 { 362 *(pPara->GetReformat()) = SwCharRange(); 363 *(pPara->GetDelta()) = 0; 364 } 365 } 366 367 if ( pPage ) 368 { 369 if ( !bOldInvaCntnt ) 370 pPage->ValidateCntnt(); 371 } 372 373 #ifdef DBG_UTIL 374 ASSERT( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" ); 375 #endif 376 377 const long nRemaining = 378 - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom ); 379 if ( nRemaining > 0 && !GetUpper()->IsSctFrm() && 380 nRemaining != ( bVert ? 381 nMyPos - Frm().Right() : 382 Frm().Top() - nMyPos ) ) 383 { 384 UNDO_SWAP( this ) 385 return sal_True; 386 } 387 } 388 389 UNDO_SWAP( this ) 390 391 return sal_False; 392 } 393 394 /************************************************************************* 395 * SwTxtFrm::AdjustFrm() 396 *************************************************************************/ 397 398 void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit ) 399 { 400 if( IsUndersized() ) 401 { 402 if( GetOfst() && !IsFollow() ) // ein gescrollter Absatz (undersized) 403 return; 404 SetUndersized( nChgHght == 0 || bHasToFit ); 405 } 406 407 // AdjustFrm is called with a swapped frame during 408 // formatting but the frame is not swapped during FormatEmpty 409 SWAP_IF_SWAPPED( this ) 410 SWRECTFN ( this ) 411 412 // Die Size-Variable des Frames wird durch Grow inkrementiert 413 // oder durch Shrink dekrementiert. Wenn die Groesse 414 // unveraendert ist, soll nichts passieren! 415 if( nChgHght >= 0) 416 { 417 SwTwips nChgHeight = nChgHght; 418 if( nChgHght && !bHasToFit ) 419 { 420 if( IsInFtn() && !IsInSct() ) 421 { 422 SwTwips nReal = Grow( nChgHght, sal_True ); 423 if( nReal < nChgHght ) 424 { 425 SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(), 426 nChgHght - nReal ); 427 SwFrm* pCont = FindFtnFrm()->GetUpper(); 428 429 if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 ) 430 { 431 (Frm().*fnRect->fnAddBottom)( nChgHght ); 432 if( bVert ) 433 Prt().SSize().Width() += nChgHght; 434 else 435 Prt().SSize().Height() += nChgHght; 436 UNDO_SWAP( this ) 437 return; 438 } 439 } 440 } 441 442 Grow( nChgHght ); 443 444 if ( IsInFly() ) 445 { 446 //MA 06. May. 93: Wenn einer der Upper ein Fly ist, so ist es 447 //sehr wahrscheinlich, dass dieser Fly durch das Grow seine 448 //Position veraendert - also muss auch meine Position korrigiert 449 //werden (sonst ist die Pruefung s.u. nicht aussagekraeftig). 450 //Die Vorgaenger muessen berechnet werden, damit die Position 451 //korrekt berechnet werden kann. 452 if ( GetPrev() ) 453 { 454 SwFrm *pPre = GetUpper()->Lower(); 455 do 456 { pPre->Calc(); 457 pPre = pPre->GetNext(); 458 } while ( pPre && pPre != this ); 459 } 460 const Point aOldPos( Frm().Pos() ); 461 MakePos(); 462 if ( aOldPos != Frm().Pos() ) 463 { 464 // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)> 465 // No format is performed for the floating screen objects. 466 InvalidateObjs( true ); 467 } 468 } 469 nChgHeight = 0; 470 } 471 // Ein Grow() wird von der Layout-Seite immer akzeptiert, 472 // also auch, wenn die FixSize des umgebenden Layoutframes 473 // dies nicht zulassen sollte. Wir ueberpruefen diesen 474 // Fall und korrigieren die Werte. 475 // MA 06. May. 93: Der Frm darf allerdings auch im Notfall nicht 476 // weiter geschrumpft werden als es seine Groesse zulaesst. 477 SwTwips nRstHeight; 478 if ( IsVertical() ) 479 { 480 ASSERT( ! IsSwapped(),"Swapped frame while calculating nRstHeight" ); 481 482 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin 483 if ( IsVertLR() ) 484 nRstHeight = GetUpper()->Frm().Left() 485 + GetUpper()->Prt().Left() 486 + GetUpper()->Prt().Width() 487 - Frm().Left(); 488 else 489 nRstHeight = Frm().Left() + Frm().Width() - 490 ( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() ); 491 } 492 else 493 nRstHeight = GetUpper()->Frm().Top() 494 + GetUpper()->Prt().Top() 495 + GetUpper()->Prt().Height() 496 - Frm().Top(); 497 498 //In Tabellenzellen kann ich mir evtl. noch ein wenig dazuholen, weil 499 //durch eine vertikale Ausrichtung auch oben noch Raum sein kann. 500 // --> OD 2004-11-25 #115759# - assure, that first lower in upper 501 // is the current one or is valid. 502 if ( IsInTab() && 503 ( GetUpper()->Lower() == this || 504 GetUpper()->Lower()->IsValid() ) ) 505 // <-- 506 { 507 long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(), 508 (GetUpper()->*fnRect->fnGetPrtTop)() ); 509 ASSERT( nAdd >= 0, "Ey" ); 510 nRstHeight += nAdd; 511 } 512 513 /* ------------------------------------ 514 * #50964#: nRstHeight < 0 bedeutet, dass der TxtFrm komplett ausserhalb seines 515 * Upper liegt. Dies kann passieren, wenn er innerhalb eines FlyAtCntFrm liegt, der 516 * durch das Grow() die Seite gewechselt hat. In so einem Fall ist es falsch, der 517 * folgenden Grow-Versuch durchzufuehren. Im Bugfall fuehrte dies sogar zur 518 * Endlosschleife. 519 * -----------------------------------*/ 520 SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)(); 521 SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)(); 522 523 if( nRstHeight < nFrmHeight ) 524 { 525 //Kann sein, dass ich die richtige Grosse habe, der Upper aber zu 526 //klein ist und der Upper noch Platz schaffen kann. 527 if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit ) 528 nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight ); 529 // In spaltigen Bereichen wollen wir moeglichst nicht zu gross werden, damit 530 // nicht ueber GetNextSctLeaf weitere Bereiche angelegt werden. Stattdessen 531 // schrumpfen wir und notieren bUndersized, damit FormatWidthCols die richtige 532 // Spaltengroesse ermitteln kann. 533 if ( nRstHeight < nFrmHeight ) 534 { 535 if( bHasToFit || !IsMoveable() || 536 ( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) ) 537 { 538 SetUndersized( sal_True ); 539 Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) ); 540 } 541 else 542 SetUndersized( sal_False ); 543 } 544 } 545 else if( nChgHeight ) 546 { 547 if( nRstHeight - nFrmHeight < nChgHeight ) 548 nChgHeight = nRstHeight - nFrmHeight; 549 if( nChgHeight ) 550 Grow( nChgHeight ); 551 } 552 } 553 else 554 Shrink( -nChgHght ); 555 556 UNDO_SWAP( this ) 557 } 558 559 /************************************************************************* 560 * SwTxtFrm::AdjustFollow() 561 *************************************************************************/ 562 563 /* AdjustFollow erwartet folgende Situation: 564 * Der SwTxtIter steht am unteren Ende des Masters, der Offset wird 565 * im Follow eingestellt. 566 * nOffset haelt den Offset im Textstring, ab dem der Master abschliesst 567 * und der Follow beginnt. Wenn er 0 ist, wird der FolgeFrame geloescht. 568 */ 569 570 void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine, 571 const xub_StrLen nOffset, const xub_StrLen nEnd, 572 const sal_uInt8 nMode ) 573 { 574 SwFrmSwapper aSwapper( this, sal_False ); 575 576 // Wir haben den Rest der Textmasse: alle Follows loeschen 577 // Sonderfall sind DummyPortions() 578 // - special cases are controlled by parameter <nMode>. 579 if( HasFollow() && !(nMode & 1) && nOffset == nEnd ) 580 { 581 while( GetFollow() ) 582 { 583 if( ((SwTxtFrm*)GetFollow())->IsLocked() ) 584 { 585 ASSERT( sal_False, "+SwTxtFrm::JoinFrm: Follow ist locked." ); 586 return; 587 } 588 JoinFrm(); 589 } 590 591 return; 592 } 593 594 // Tanz auf dem Vulkan: Wir formatieren eben schnell noch einmal 595 // die letzte Zeile fuer das QuoVadis-Geraffel. Selbstverstaendlich 596 // kann sich dadurch auch der Offset verschieben: 597 const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ? 598 rLine.FormatQuoVadis(nOffset) : nOffset; 599 600 if( !(nMode & 1) ) 601 { 602 // Wir klauen unseren Follows Textmasse, dabei kann es passieren, 603 // dass wir einige Follows Joinen muessen. 604 while( GetFollow() && GetFollow()->GetFollow() && 605 nNewOfst >= GetFollow()->GetFollow()->GetOfst() ) 606 { 607 DBG_LOOP; 608 JoinFrm(); 609 } 610 } 611 612 // Der Ofst hat sich verschoben. 613 if( GetFollow() ) 614 { 615 #if OSL_DEBUG_LEVEL > 1 616 static sal_Bool bTest = sal_False; 617 if( !bTest || ( nMode & 1 ) ) 618 #endif 619 if ( nMode ) 620 GetFollow()->ManipOfst( 0 ); 621 622 if ( CalcFollow( nNewOfst ) ) // CalcFollow erst zum Schluss, dort erfolgt ein SetOfst 623 rLine.SetOnceMore( sal_True ); 624 } 625 } 626 627 /************************************************************************* 628 * SwTxtFrm::JoinFrm() 629 *************************************************************************/ 630 631 SwCntntFrm *SwTxtFrm::JoinFrm() 632 { 633 ASSERT( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" ); 634 SwTxtFrm *pFoll = GetFollow(); 635 636 SwTxtFrm *pNxt = pFoll->GetFollow(); 637 638 // Alle Fussnoten des zu zerstoerenden Follows werden auf uns 639 // umgehaengt. 640 xub_StrLen nStart = pFoll->GetOfst(); 641 if ( pFoll->HasFtn() ) 642 { 643 const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints(); 644 if( pHints ) 645 { 646 SwFtnBossFrm *pFtnBoss = 0; 647 SwFtnBossFrm *pEndBoss = 0; 648 for ( sal_uInt16 i = 0; i < pHints->Count(); ++i ) 649 { 650 const SwTxtAttr *pHt = (*pHints)[i]; 651 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart ) 652 { 653 if( pHt->GetFtn().IsEndNote() ) 654 { 655 if( !pEndBoss ) 656 pEndBoss = pFoll->FindFtnBossFrm(); 657 pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this ); 658 } 659 else 660 { 661 if( !pFtnBoss ) 662 pFtnBoss = pFoll->FindFtnBossFrm( sal_True ); 663 pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this ); 664 } 665 SetFtn( sal_True ); 666 } 667 } 668 } 669 } 670 671 #ifdef DBG_UTIL 672 else if ( pFoll->GetValidPrtAreaFlag() || 673 pFoll->GetValidSizeFlag() ) 674 { 675 pFoll->CalcFtnFlag(); 676 ASSERT( !pFoll->HasFtn(), "Missing FtnFlag." ); 677 } 678 #endif 679 680 pFoll->MoveFlyInCnt( this, nStart, STRING_LEN ); 681 pFoll->SetFtn( sal_False ); 682 // --> OD 2005-12-01 #i27138# 683 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation. 684 // Relation CONTENT_FLOWS_FROM for current next paragraph will change 685 // and relation CONTENT_FLOWS_TO for current previous paragraph, which 686 // is <this>, will change. 687 { 688 ViewShell* pViewShell( pFoll->getRootFrm()->GetCurrShell() ); 689 if ( pViewShell && pViewShell->GetLayout() && 690 pViewShell->GetLayout()->IsAnyShellAccessible() ) 691 { 692 pViewShell->InvalidateAccessibleParaFlowRelation( 693 dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )), 694 this ); 695 } 696 } 697 // <-- 698 pFoll->Cut(); 699 delete pFoll; 700 pFollow = pNxt; 701 return pNxt; 702 } 703 704 /************************************************************************* 705 * SwTxtFrm::SplitFrm() 706 *************************************************************************/ 707 708 SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos ) 709 { 710 SWAP_IF_SWAPPED( this ) 711 712 // Durch das Paste wird ein Modify() an mich verschickt. 713 // Damit meine Daten nicht verschwinden, locke ich mich. 714 SwTxtFrmLocker aLock( this ); 715 SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm( this )); 716 pNew->bIsFollow = sal_True; 717 718 pNew->SetFollow( GetFollow() ); 719 SetFollow( pNew ); 720 721 pNew->Paste( GetUpper(), GetNext() ); 722 // --> OD 2005-12-01 #i27138# 723 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation. 724 // Relation CONTENT_FLOWS_FROM for current next paragraph will change 725 // and relation CONTENT_FLOWS_TO for current previous paragraph, which 726 // is <this>, will change. 727 { 728 ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() ); 729 if ( pViewShell && pViewShell->GetLayout() && 730 pViewShell->GetLayout()->IsAnyShellAccessible() ) 731 { 732 pViewShell->InvalidateAccessibleParaFlowRelation( 733 dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )), 734 this ); 735 } 736 } 737 // <-- 738 739 // Wenn durch unsere Aktionen Fussnoten in pNew landen, 740 // so muessen sie umgemeldet werden. 741 if ( HasFtn() ) 742 { 743 const SwpHints *pHints = GetTxtNode()->GetpSwpHints(); 744 if( pHints ) 745 { 746 SwFtnBossFrm *pFtnBoss = 0; 747 SwFtnBossFrm *pEndBoss = 0; 748 for ( sal_uInt16 i = 0; i < pHints->Count(); ++i ) 749 { 750 const SwTxtAttr *pHt = (*pHints)[i]; 751 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos ) 752 { 753 if( pHt->GetFtn().IsEndNote() ) 754 { 755 if( !pEndBoss ) 756 pEndBoss = FindFtnBossFrm(); 757 pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew ); 758 } 759 else 760 { 761 if( !pFtnBoss ) 762 pFtnBoss = FindFtnBossFrm( sal_True ); 763 pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew ); 764 } 765 pNew->SetFtn( sal_True ); 766 } 767 } 768 } 769 } 770 771 #ifdef DBG_UTIL 772 else 773 { 774 CalcFtnFlag( nTxtPos-1 ); 775 ASSERT( !HasFtn(), "Missing FtnFlag." ); 776 } 777 #endif 778 779 MoveFlyInCnt( pNew, nTxtPos, STRING_LEN ); 780 781 // Kein SetOfst oder CalcFollow, weil gleich ohnehin ein AdjustFollow folgt. 782 783 pNew->ManipOfst( nTxtPos ); 784 785 UNDO_SWAP( this ) 786 return pNew; 787 } 788 789 790 /************************************************************************* 791 * virtual SwTxtFrm::SetOfst() 792 *************************************************************************/ 793 794 void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst ) 795 { 796 #ifdef DBGTXT 797 // Es gibt tatsaechlich einen Sonderfall, in dem ein SetOfst(0) 798 // zulaessig ist: bug 3496 799 ASSERT( nNewOfst, "!SwTxtFrm::SetOfst: missing JoinFrm()." ); 800 #endif 801 802 // Die Invalidierung unseres Follows ist nicht noetig. 803 // Wir sind ein Follow, werden gleich formatiert und 804 // rufen von dort aus das SetOfst() ! 805 nOfst = nNewOfst; 806 SwParaPortion *pPara = GetPara(); 807 if( pPara ) 808 { 809 SwCharRange &rReformat = *(pPara->GetReformat()); 810 rReformat.Start() = 0; 811 rReformat.Len() = GetTxt().Len(); 812 *(pPara->GetDelta()) = rReformat.Len(); 813 } 814 InvalidateSize(); 815 } 816 817 /************************************************************************* 818 * SwTxtFrm::CalcPreps 819 *************************************************************************/ 820 821 sal_Bool SwTxtFrm::CalcPreps() 822 { 823 ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" ); 824 SWRECTFN( this ); 825 826 SwParaPortion *pPara = GetPara(); 827 if ( !pPara ) 828 return sal_False; 829 sal_Bool bPrep = pPara->IsPrep(); 830 sal_Bool bPrepWidows = pPara->IsPrepWidows(); 831 sal_Bool bPrepAdjust = pPara->IsPrepAdjust(); 832 sal_Bool bPrepMustFit = pPara->IsPrepMustFit(); 833 ResetPreps(); 834 835 sal_Bool bRet = sal_False; 836 if( bPrep && !pPara->GetReformat()->Len() ) 837 { 838 // PREP_WIDOWS bedeutet, dass im Follow die Orphans-Regel 839 // zuschlug. 840 // Es kann in unguenstigen Faellen vorkommen, dass auch ein 841 // PrepAdjust vorliegt (3680)! 842 if( bPrepWidows ) 843 { 844 if( !GetFollow() ) 845 { 846 ASSERT( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" ); 847 return sal_False; 848 } 849 850 // Wir muessen uns auf zwei Faelle einstellen: 851 // Wir konnten dem Follow noch ein paar Zeilen abgeben, 852 // -> dann muessen wir schrumpfen 853 // oder wir muessen auf die naechste Seite 854 // -> dann lassen wir unseren Frame zu gross werden. 855 856 SwTwips nChgHeight = GetParHeight(); 857 if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() ) 858 { 859 if( bPrepMustFit ) 860 { 861 GetFollow()->SetJustWidow( sal_True ); 862 GetFollow()->Prepare( PREP_CLEAR ); 863 } 864 else if ( bVert ) 865 { 866 Frm().Width( Frm().Width() + Frm().Left() ); 867 Prt().Width( Prt().Width() + Frm().Left() ); 868 Frm().Left( 0 ); 869 SetWidow( sal_True ); 870 } 871 else 872 { 873 SwTwips nTmp = LONG_MAX - (Frm().Top()+10000); 874 SwTwips nDiff = nTmp - Frm().Height(); 875 Frm().Height( nTmp ); 876 Prt().Height( Prt().Height() + nDiff ); 877 SetWidow( sal_True ); 878 } 879 } 880 else 881 { 882 ASSERT( nChgHeight < (Prt().*fnRect->fnGetHeight)(), 883 "+SwTxtFrm::CalcPrep: wanna shrink" ); 884 885 nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight; 886 887 GetFollow()->SetJustWidow( sal_True ); 888 GetFollow()->Prepare( PREP_CLEAR ); 889 Shrink( nChgHeight ); 890 SwRect &rRepaint = *(pPara->GetRepaint()); 891 892 if ( bVert ) 893 { 894 SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() ); 895 SwitchVerticalToHorizontal( aRepaint ); 896 rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() ); 897 } 898 else 899 rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() ); 900 901 // 6792: Rrand < LRand und Repaint 902 if( 0 >= rRepaint.Width() ) 903 rRepaint.Width(1); 904 } 905 bRet = sal_True; 906 } 907 908 else if ( bPrepAdjust ) 909 { 910 if ( HasFtn() ) 911 { 912 if( !CalcPrepFtnAdjust() ) 913 { 914 if( bPrepMustFit ) 915 { 916 SwTxtLineAccess aAccess( this ); 917 aAccess.GetPara()->SetPrepMustFit( sal_True ); 918 } 919 return sal_False; 920 } 921 } 922 923 SWAP_IF_NOT_SWAPPED( this ) 924 925 SwTxtFormatInfo aInf( this ); 926 SwTxtFormatter aLine( this, &aInf ); 927 928 WidowsAndOrphans aFrmBreak( this ); 929 // Egal was die Attribute meinen, bei MustFit wird 930 // der Absatz im Notfall trotzdem gesplittet... 931 if( bPrepMustFit ) 932 { 933 aFrmBreak.SetKeep( sal_False ); 934 aFrmBreak.ClrOrphLines(); 935 } 936 // Bevor wir FormatAdjust aufrufen muessen wir dafuer 937 // sorgen, dass die Zeilen, die unten raushaengen 938 // auch tatsaechlich abgeschnitten werden. 939 // OD 2004-02-25 #i16128# - method renamed 940 sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine ); 941 bRet = sal_True; 942 while( !bBreak && aLine.Next() ) 943 { 944 // OD 2004-02-25 #i16128# - method renamed 945 bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine ); 946 } 947 if( bBreak ) 948 { 949 // Es gibt Komplikationen: wenn TruncLines gerufen wird, 950 // veraendern sich ploetzlich die Bedingungen in 951 // IsInside, so dass IsBreakNow andere Ergebnisse 952 // liefern kann. Aus diesem Grund wird rFrmBreak bekannt 953 // gegeben, dass da wo rLine steht, das Ende erreicht 954 // ist. Mal sehen, ob's klappt ... 955 aLine.TruncLines(); 956 aFrmBreak.SetRstHeight( aLine ); 957 FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() ); 958 } 959 else 960 { 961 if( !GetFollow() ) 962 { 963 FormatAdjust( aLine, aFrmBreak, 964 aInf.GetTxt().Len(), aInf.IsStop() ); 965 } 966 else if ( !aFrmBreak.IsKeepAlways() ) 967 { 968 // Siehe Bug: 2320 969 // Vor dem Master wird eine Zeile geloescht, der Follow 970 // koennte eine Zeile abgeben. 971 const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 ); 972 *(pPara->GetReformat()) += aFollowRg; 973 // Es soll weitergehen! 974 bRet = sal_False; 975 } 976 } 977 978 UNDO_SWAP( this ) 979 // Eine letzte Ueberpruefung, falls das FormatAdjust() nichts 980 // brachte, muessen wir amputieren. 981 if( bPrepMustFit ) 982 { 983 const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)(); 984 const SwTwips nIs = (Frm().*fnRect->fnGetBottom)(); 985 986 if( bVert && nIs < nMust ) 987 { 988 Shrink( nMust - nIs ); 989 if( Prt().Width() < 0 ) 990 Prt().Width( 0 ); 991 SetUndersized( sal_True ); 992 } 993 else if ( ! bVert && nIs > nMust ) 994 { 995 Shrink( nIs - nMust ); 996 if( Prt().Height() < 0 ) 997 Prt().Height( 0 ); 998 SetUndersized( sal_True ); 999 } 1000 } 1001 } 1002 } 1003 pPara->SetPrepMustFit( bPrepMustFit ); 1004 return bRet; 1005 } 1006 1007 1008 /************************************************************************* 1009 * SwTxtFrm::FormatAdjust() 1010 *************************************************************************/ 1011 1012 // Hier werden die Fussnoten und "als Zeichen"-gebundenen Objekte umgehaengt 1013 #define CHG_OFFSET( pFrm, nNew )\ 1014 {\ 1015 if( pFrm->GetOfst() < nNew )\ 1016 pFrm->MoveFlyInCnt( this, 0, nNew );\ 1017 else if( pFrm->GetOfst() > nNew )\ 1018 MoveFlyInCnt( pFrm, nNew, STRING_LEN );\ 1019 } 1020 1021 void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine, 1022 WidowsAndOrphans &rFrmBreak, 1023 const xub_StrLen nStrLen, 1024 const sal_Bool bDummy ) 1025 { 1026 SWAP_IF_NOT_SWAPPED( this ) 1027 1028 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); 1029 1030 xub_StrLen nEnd = rLine.GetStart(); 1031 1032 sal_Bool bHasToFit = pPara->IsPrepMustFit(); 1033 1034 // Das StopFlag wird durch Fussnoten gesetzt, 1035 // die auf die naechste Seite wollen. 1036 // OD, FME 2004-03-03 - call base class method <SwTxtFrmBreak::IsBreakNow(..)> 1037 // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break, 1038 // even if due to widow rule no enough lines exists. 1039 sal_uInt8 nNew = ( !GetFollow() && 1040 nEnd < nStrLen && 1041 ( rLine.IsStop() || 1042 ( bHasToFit 1043 ? ( rLine.GetLineNr() > 1 && 1044 !rFrmBreak.IsInside( rLine ) ) 1045 : rFrmBreak.IsBreakNow( rLine ) ) ) ) 1046 ? 1 : 0; 1047 // --> OD #i84870# 1048 // no split of text frame, which only contains a as-character anchored object 1049 const bool bOnlyContainsAsCharAnchoredObj = 1050 !IsFollow() && nStrLen == 1 && 1051 GetDrawObjs() && GetDrawObjs()->Count() == 1 && 1052 (*GetDrawObjs())[0]->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR; 1053 if ( nNew && bOnlyContainsAsCharAnchoredObj ) 1054 { 1055 nNew = 0; 1056 } 1057 // <-- 1058 if ( nNew ) 1059 { 1060 SplitFrm( nEnd ); 1061 } 1062 1063 const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm()); 1064 1065 const long nBodyHeight = pBodyFrm ? ( IsVertical() ? 1066 pBodyFrm->Frm().Width() : 1067 pBodyFrm->Frm().Height() ) : 0; 1068 1069 // Wenn die aktuellen Werte berechnet wurden, anzeigen, dass 1070 // sie jetzt gueltig sind. 1071 *(pPara->GetReformat()) = SwCharRange(); 1072 sal_Bool bDelta = *pPara->GetDelta() != 0; 1073 *(pPara->GetDelta()) = 0; 1074 1075 if( rLine.IsStop() ) 1076 { 1077 rLine.TruncLines( sal_True ); 1078 nNew = 1; 1079 } 1080 1081 // FindBreak schneidet die letzte Zeile ab. 1082 if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) ) 1083 { 1084 // Wenn wir bis zum Ende durchformatiert haben, wird nEnd auf das Ende 1085 // gesetzt. In AdjustFollow wird dadurch ggf. JoinFrm() ausgefuehrt. 1086 // Ansonsten ist nEnd das Ende der letzten Zeile im Master. 1087 xub_StrLen nOld = nEnd; 1088 nEnd = rLine.GetEnd(); 1089 if( GetFollow() ) 1090 { 1091 if( nNew && nOld < nEnd ) 1092 RemoveFtn( nOld, nEnd - nOld ); 1093 CHG_OFFSET( GetFollow(), nEnd ) 1094 if( !bDelta ) 1095 GetFollow()->ManipOfst( nEnd ); 1096 } 1097 } 1098 else 1099 { // Wenn wir Zeilen abgeben, darf kein Join auf den Folows gerufen werden, 1100 // im Gegenteil, es muss ggf. sogar ein Follow erzeugt werden. 1101 // Dies muss auch geschehen, wenn die Textmasse komplett im Master 1102 // bleibt, denn es k???nnte ja ein harter Zeilenumbruch noch eine weitere 1103 // Zeile (ohne Textmassse) notwendig machen! 1104 nEnd = rLine.GetEnd(); 1105 if( GetFollow() ) 1106 { 1107 // OD 21.03.2003 #108121# - Another case for not joining the follow: 1108 // Text frame has no content, but a numbering. Then, do *not* join. 1109 // Example of this case: When an empty, but numbered paragraph 1110 // at the end of page is completely displaced by a fly frame. 1111 // Thus, the text frame introduced a follow by a 1112 // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows 1113 // the numbering and must stay. 1114 if ( GetFollow()->GetOfst() != nEnd || 1115 GetFollow()->IsFieldFollow() || 1116 ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) ) 1117 { 1118 nNew |= 3; 1119 } 1120 CHG_OFFSET( GetFollow(), nEnd ) 1121 GetFollow()->ManipOfst( nEnd ); 1122 } 1123 else 1124 { 1125 // OD 21.03.2003 #108121# - Only split frame, if the frame contains 1126 // content or contains no content, but has a numbering. 1127 // OD #i84870# - no split, if text frame only contains one 1128 // as-character anchored object. 1129 if ( !bOnlyContainsAsCharAnchoredObj && 1130 ( nStrLen > 0 || 1131 ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) ) 1132 ) 1133 { 1134 SplitFrm( nEnd ); 1135 nNew |= 3; 1136 } 1137 } 1138 // Wenn sich die Resthoehe geaendert hat, z.B. durch RemoveFtn() 1139 // dann muessen wir auffuellen, um Oszillationen zu vermeiden! 1140 if( bDummy && pBodyFrm && 1141 nBodyHeight < ( IsVertical() ? 1142 pBodyFrm->Frm().Width() : 1143 pBodyFrm->Frm().Height() ) ) 1144 rLine.MakeDummyLine(); 1145 } 1146 1147 // In AdjustFrm() stellen wir uns selbst per Grow/Shrink ein, 1148 // in AdjustFollow() stellen wir unseren FolgeFrame ein. 1149 1150 const SwTwips nDocPrtTop = Frm().Top() + Prt().Top(); 1151 const SwTwips nOldHeight = Prt().SSize().Height(); 1152 SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight; 1153 // --> OD #i84870# - no shrink of text frame, if it only contains one 1154 // as-character anchored object. 1155 if ( nChg < 0 && 1156 bOnlyContainsAsCharAnchoredObj ) 1157 { 1158 nChg = 0; 1159 } 1160 // <-- 1161 1162 // Vertical Formatting: 1163 // The (rotated) repaint rectangle's x coordinate referes to the frame. 1164 // If the frame grows (or shirks) the repaint rectangle cannot simply 1165 // be rotated back after formatting, because we use the upper left point 1166 // of the frame for rotation. This point changes when growing/shrinking. 1167 1168 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin 1169 if ( IsVertical() && !IsVertLR() && nChg ) 1170 { 1171 SwRect &rRepaint = *(pPara->GetRepaint()); 1172 rRepaint.Left( rRepaint.Left() - nChg ); 1173 rRepaint.Width( rRepaint.Width() - nChg ); 1174 } 1175 1176 AdjustFrm( nChg, bHasToFit ); 1177 1178 /* 1179 // FME 16.07.2003 #i16930# - removed this code because it did not 1180 // work correctly. In SwCntntFrm::MakeAll, the frame did not move to the 1181 // next page, instead the print area was recalculated and 1182 // Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False ) invalidated 1183 // the other flags => loop 1184 1185 // OD 04.04.2003 #108446# - handle special case: 1186 // If text frame contains no content and just has split, because of a 1187 // line stop, it has to move forward. To force this forward move without 1188 // unnecessary formatting of its footnotes and its follow, especially in 1189 // columned sections, adjust frame height to zero (0) and do not perform 1190 // the intrinsic format of the follow. 1191 // The formating method <SwCntntFrm::MakeAll()> will initiate the move forward. 1192 sal_Bool bForcedNoIntrinsicFollowCalc = sal_False; 1193 if ( nEnd == 0 && 1194 rLine.IsStop() && HasFollow() && nNew == 1 1195 ) 1196 { 1197 AdjustFrm( -Frm().SSize().Height(), bHasToFit ); 1198 Prt().Pos().Y() = 0; 1199 Prt().Height( Frm().Height() ); 1200 if ( FollowFormatAllowed() ) 1201 { 1202 bForcedNoIntrinsicFollowCalc = sal_True; 1203 ForbidFollowFormat(); 1204 } 1205 } 1206 else 1207 { 1208 AdjustFrm( nChg, bHasToFit ); 1209 } 1210 */ 1211 1212 if( HasFollow() || IsInFtn() ) 1213 _AdjustFollow( rLine, nEnd, nStrLen, nNew ); 1214 1215 // FME 16.07.2003 #i16930# - removed this code because it did not work 1216 // correctly 1217 // OD 04.04.2003 #108446# - allow intrinsic format of follow, if above 1218 // special case has forbit it. 1219 /* if ( bForcedNoIntrinsicFollowCalc ) 1220 { 1221 AllowFollowFormat(); 1222 } 1223 */ 1224 1225 pPara->SetPrepMustFit( sal_False ); 1226 1227 UNDO_SWAP( this ) 1228 } 1229 1230 /************************************************************************* 1231 * SwTxtFrm::FormatLine() 1232 *************************************************************************/ 1233 1234 // bPrev zeigt an, ob Reformat.Start() wegen Prev() vorgezogen wurde. 1235 // Man weiss sonst nicht, ob man Repaint weiter einschraenken kann oder nicht. 1236 1237 1238 sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev ) 1239 { 1240 ASSERT( ! IsVertical() || IsSwapped(), 1241 "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" ); 1242 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); 1243 // Nach rLine.FormatLine() haelt nStart den neuen Wert, 1244 // waehrend in pOldStart der alte Offset gepflegt wird. 1245 // Ueber diesen Weg soll das nDelta ersetzt werden. 1246 // *pOldStart += rLine.GetCurr()->GetLen(); 1247 const SwLineLayout *pOldCur = rLine.GetCurr(); 1248 const xub_StrLen nOldLen = pOldCur->GetLen(); 1249 const KSHORT nOldAscent = pOldCur->GetAscent(); 1250 const KSHORT nOldHeight = pOldCur->Height(); 1251 const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin(); 1252 const sal_Bool bOldHyph = pOldCur->IsEndHyph(); 1253 SwTwips nOldTop = 0; 1254 SwTwips nOldBottom = 0; 1255 if( rLine.GetCurr()->IsClipping() ) 1256 rLine.CalcUnclipped( nOldTop, nOldBottom ); 1257 1258 const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() ); 1259 1260 ASSERT( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(), 1261 "SwTxtFrm::FormatLine: frame leaves orbit." ); 1262 ASSERT( rLine.GetCurr()->Height(), 1263 "SwTxtFrm::FormatLine: line height is zero" ); 1264 1265 // Das aktuelle Zeilenumbruchobjekt. 1266 const SwLineLayout *pNew = rLine.GetCurr(); 1267 1268 sal_Bool bUnChg = nOldLen == pNew->GetLen() && 1269 bOldHyph == pNew->IsEndHyph(); 1270 if ( bUnChg && !bPrev ) 1271 { 1272 // 6672: Toleranz von SLOPPY_TWIPS (5 Twips); vgl. 6922 1273 const long nWidthDiff = nOldWidth > pNew->Width() 1274 ? nOldWidth - pNew->Width() 1275 : pNew->Width() - nOldWidth; 1276 1277 // we only declare a line as unchanged, if its main values have not 1278 // changed and it is not the last line (!paragraph end symbol!) 1279 bUnChg = nOldHeight == pNew->Height() && 1280 nOldAscent == pNew->GetAscent() && 1281 nWidthDiff <= SLOPPY_TWIPS && 1282 pOldCur->GetNext(); 1283 } 1284 1285 // rRepaint wird berechnet: 1286 const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight(); 1287 SwRepaint &rRepaint = *(pPara->GetRepaint()); 1288 if( bUnChg && rRepaint.Top() == rLine.Y() 1289 && (bPrev || nNewStart <= pPara->GetReformat()->Start()) 1290 && ( nNewStart < GetTxtNode()->GetTxt().Len() ) ) 1291 { 1292 rRepaint.Top( nBottom ); 1293 rRepaint.Height( 0 ); 1294 } 1295 else 1296 { 1297 if( nOldTop ) 1298 { 1299 if( nOldTop < rRepaint.Top() ) 1300 rRepaint.Top( nOldTop ); 1301 if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() ) 1302 { 1303 rRepaint.Bottom( nOldBottom - 1 ); 1304 rLine.SetUnclipped( sal_True ); 1305 } 1306 } 1307 if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() ) 1308 { 1309 SwTwips nTmpTop, nTmpBottom; 1310 rLine.CalcUnclipped( nTmpTop, nTmpBottom ); 1311 if( nTmpTop < rRepaint.Top() ) 1312 rRepaint.Top( nTmpTop ); 1313 if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() ) 1314 { 1315 rRepaint.Bottom( nTmpBottom - 1 ); 1316 rLine.SetUnclipped( sal_True ); 1317 } 1318 } 1319 else 1320 { 1321 if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() ) 1322 { 1323 rRepaint.Bottom( nBottom - 1 ); 1324 rLine.SetUnclipped( sal_False ); 1325 } 1326 } 1327 SwTwips nRght = Max( nOldWidth, pNew->Width() + 1328 pNew->GetHangingMargin() ); 1329 ViewShell *pSh = getRootFrm()->GetCurrShell(); 1330 const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0; 1331 if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) ) 1332 nRght += ( Max( nOldAscent, pNew->GetAscent() ) ); 1333 else 1334 nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4); 1335 nRght += rLine.GetLeftMargin(); 1336 if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght ) 1337 rRepaint.SetRightOfst( nRght ); 1338 1339 // Finally we enlarge the repaint rectangle if we found an underscore 1340 // within our line. 40 Twips should be enough 1341 const sal_Bool bHasUnderscore = 1342 ( rLine.GetInfo().GetUnderScorePos() < nNewStart ); 1343 if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() ) 1344 rRepaint.Bottom( rRepaint.Bottom() + 40 ); 1345 1346 ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore ); 1347 } 1348 if( !bUnChg ) 1349 rLine.SetChanges(); 1350 1351 // Die gute, alte nDelta-Berechnung: 1352 *(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen); 1353 1354 // Stop! 1355 if( rLine.IsStop() ) 1356 return sal_False; 1357 1358 // Unbedingt noch eine Zeile 1359 if( rLine.IsNewLine() ) 1360 return sal_True; 1361 1362 // bis zum Ende des Strings ? 1363 if( nNewStart >= GetTxtNode()->GetTxt().Len() ) 1364 return sal_False; 1365 1366 if( rLine.GetInfo().IsShift() ) 1367 return sal_True; 1368 1369 // Ende des Reformats erreicht ? 1370 const xub_StrLen nEnd = pPara->GetReformat()->Start() + 1371 pPara->GetReformat()->Len(); 1372 1373 if( nNewStart <= nEnd ) 1374 return sal_True; 1375 1376 return 0 != *(pPara->GetDelta()); 1377 } 1378 1379 /************************************************************************* 1380 * SwTxtFrm::_Format() 1381 *************************************************************************/ 1382 1383 void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf, 1384 const sal_Bool bAdjust ) 1385 { 1386 ASSERT( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" ); 1387 1388 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); 1389 rLine.SetUnclipped( sal_False ); 1390 1391 // Das war dem C30 zu kompliziert: aString( GetTxt() ); 1392 const XubString &rString = GetTxtNode()->GetTxt(); 1393 const xub_StrLen nStrLen = rString.Len(); 1394 1395 SwCharRange &rReformat = *(pPara->GetReformat()); 1396 SwRepaint &rRepaint = *(pPara->GetRepaint()); 1397 SwRepaint *pFreeze = NULL; 1398 1399 // Aus Performancegruenden wird in Init() rReformat auf STRING_LEN gesetzt. 1400 // Fuer diesen Fall wird rReformat angepasst. 1401 if( rReformat.Len() > nStrLen ) 1402 rReformat.Len() = nStrLen; 1403 1404 // Optimiert: 1405 xub_StrLen nEnd = rReformat.Start() + rReformat.Len(); 1406 if( nEnd > nStrLen ) 1407 { 1408 rReformat.Len() = nStrLen - rReformat.Start(); 1409 nEnd = nStrLen; 1410 } 1411 1412 SwTwips nOldBottom; 1413 if( GetOfst() && !IsFollow() ) 1414 { 1415 rLine.Bottom(); 1416 nOldBottom = rLine.Y(); 1417 rLine.Top(); 1418 } 1419 else 1420 nOldBottom = 0; 1421 rLine.CharToLine( rReformat.Start() ); 1422 1423 // Worte koennen durch Fortfall oder Einfuegen eines Space 1424 // auf die Zeile vor der editierten hinausgezogen werden, 1425 // deshalb muss diese ebenfalls formatiert werden. 1426 // Optimierung: Wenn rReformat erst hinter dem ersten Wort der 1427 // Zeile beginnt, so kann diese Zeile die vorige nicht mehr beeinflussen. 1428 // AMA: Leider doch, Textgroessenaenderungen + FlyFrames, die Rueckwirkung 1429 // kann im Extremfall mehrere Zeilen (Frames!!!) betreffen! 1430 1431 // --> FME 2005-04-18 #i46560# 1432 // FME: Yes, consider this case: (word ) has to go to the next line 1433 // because ) is a forbidden character at the beginning of a line although 1434 // (word would still fit on the previous line. Adding text right in front 1435 // of ) would not trigger a reformatting of the previous line. Adding 1 1436 // to the result of FindBrk() does not solve the problem in all cases, 1437 // nevertheless it should be sufficient. 1438 // <-- 1439 sal_Bool bPrev = rLine.GetPrev() && 1440 ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 ) 1441 // --> FME 2005-04-18 #i46560# 1442 + 1 1443 // <-- 1444 >= rReformat.Start() || 1445 rLine.GetCurr()->IsRest() ); 1446 if( bPrev ) 1447 { 1448 while( rLine.Prev() ) 1449 if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() ) 1450 { 1451 if( !rLine.GetStart() ) 1452 rLine.Top(); // damit NumDone nicht durcheinander kommt 1453 break; 1454 } 1455 xub_StrLen nNew = rLine.GetStart() + rLine.GetLength(); 1456 if( nNew ) 1457 { 1458 --nNew; 1459 if( CH_BREAK == rString.GetChar( nNew ) ) 1460 { 1461 ++nNew; 1462 rLine.Next(); 1463 bPrev = sal_False; 1464 } 1465 } 1466 rReformat.Len() += rReformat.Start() - nNew; 1467 rReformat.Start() = nNew; 1468 } 1469 1470 rRepaint.SetOfst( 0 ); 1471 rRepaint.SetRightOfst( 0 ); 1472 rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() ); 1473 if( pPara->IsMargin() ) 1474 rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() ); 1475 rRepaint.Top( rLine.Y() ); 1476 // 6792: Rrand < LRand und Repaint 1477 if( 0 >= rRepaint.Width() ) 1478 rRepaint.Width(1); 1479 WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 ); 1480 1481 // rLine steht jetzt auf der ersten Zeile, die formatiert werden 1482 // muss. Das Flag bFirst sorgt dafuer, dass nicht Next() gerufen wird. 1483 // Das ganze sieht verdreht aus, aber es muss sichergestellt werden, 1484 // dass bei IsBreakNow rLine auf der Zeile zum stehen kommt, die 1485 // nicht mehr passt. 1486 sal_Bool bFirst = sal_True; 1487 sal_Bool bFormat = sal_True; 1488 1489 // 5383: Das CharToLine() kann uns auch in den roten Bereich fuehren. 1490 // In diesem Fall muessen wir zurueckwandern, bis die Zeile, die 1491 // nicht mehr passt in rLine eingestellt ist. Ansonsten geht Textmasse 1492 // verloren, weil der Ofst im Follow falsch eingestellt wird. 1493 1494 // OD 2004-02-25 #i16128# - method renamed 1495 sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 ) 1496 && aFrmBreak.IsBreakNowWidAndOrp( rLine ); 1497 if( bBreak ) 1498 { 1499 sal_Bool bPrevDone = 0 != rLine.Prev(); 1500 // OD 2004-02-25 #i16128# - method renamed 1501 while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) ) 1502 bPrevDone = 0 != rLine.Prev(); 1503 if( bPrevDone ) 1504 { 1505 aFrmBreak.SetKeep( sal_False ); 1506 rLine.Next(); 1507 } 1508 rLine.TruncLines(); 1509 1510 // auf Nummer sicher: 1511 // OD 2004-02-25 #i16128# - method renamed 1512 bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) && 1513 ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 ); 1514 } 1515 1516 /* Bedeutung der folgenden Flags: 1517 Ist das Watch(End/Mid)Hyph-Flag gesetzt, so muss formatiert werden, wenn 1518 eine Trennung am (Zeilenende/Fly) vorliegt, sofern MaxHyph erreicht ist. 1519 Das Jump(End/Mid)Flag bedeutet, dass die naechste Zeile, bei der keine 1520 Trennung (Zeilenende/Fly) vorliegt, formatiert werden muss, da jetzt 1521 umgebrochen werden koennte, was vorher moeglicherweise durch MaxHyph 1522 verboten war. 1523 Watch(End/Mid)Hyph wird gesetzt, wenn die letzte formatierte Zeile eine 1524 Trennstelle erhalten hat, vorher aber keine hatte, 1525 Jump(End/Mid)Hyph, wenn eine Trennstelle verschwindet. 1526 */ 1527 sal_Bool bJumpEndHyph = sal_False, 1528 bWatchEndHyph = sal_False, 1529 bJumpMidHyph = sal_False, 1530 bWatchMidHyph = sal_False; 1531 1532 const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet(); 1533 sal_Bool bMaxHyph = ( 0 != 1534 ( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) ); 1535 if ( bMaxHyph ) 1536 rLine.InitCntHyph(); 1537 1538 if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() ) 1539 { 1540 const SwLineLayout* pLine; 1541 { 1542 SwTxtFrm *pMaster = FindMaster(); 1543 ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" ); 1544 if( !pMaster->HasPara() ) 1545 pMaster->GetFormatted(); 1546 SwTxtSizeInfo aInf( pMaster ); 1547 SwTxtIter aMasterLine( pMaster, &aInf ); 1548 aMasterLine.Bottom(); 1549 pLine = aMasterLine.GetCurr(); 1550 } 1551 SwLinePortion* pRest = 1552 rLine.MakeRestPortion( pLine, GetOfst() ); 1553 if( pRest ) 1554 rInf.SetRest( pRest ); 1555 else 1556 SetFieldFollow( sal_False ); 1557 } 1558 1559 /* Zum Abbruchkriterium: 1560 * Um zu erkennen, dass eine Zeile nicht mehr auf die Seite passt, 1561 * muss sie formatiert werden. Dieser Ueberhang wird z.B. in AdjustFollow 1562 * wieder entfernt. 1563 * Eine weitere Komplikation: wenn wir der Master sind, so muessen 1564 * wir die Zeilen durchgehen, da es ja sein kann, dass eine Zeile 1565 * vom Follow in den Master rutschen kann. 1566 */ 1567 do 1568 { 1569 DBG_LOOP; 1570 if( bFirst ) 1571 bFirst = sal_False; 1572 else 1573 { 1574 if ( bMaxHyph ) 1575 { 1576 if ( rLine.GetCurr()->IsEndHyph() ) 1577 rLine.CntEndHyph()++; 1578 else 1579 rLine.CntEndHyph() = 0; 1580 if ( rLine.GetCurr()->IsMidHyph() ) 1581 rLine.CntMidHyph()++; 1582 else 1583 rLine.CntMidHyph() = 0; 1584 } 1585 if( !rLine.Next() ) 1586 { 1587 if( !bFormat ) 1588 { 1589 SwLinePortion* pRest = 1590 rLine.MakeRestPortion( rLine.GetCurr(), rLine.GetEnd() ); 1591 if( pRest ) 1592 rInf.SetRest( pRest ); 1593 } 1594 rLine.Insert( new SwLineLayout() ); 1595 rLine.Next(); 1596 bFormat = sal_True; 1597 } 1598 } 1599 if ( !bFormat && bMaxHyph && 1600 (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) ) 1601 { 1602 if ( rLine.GetCurr()->IsEndHyph() ) 1603 { 1604 if ( bWatchEndHyph ) 1605 bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() ); 1606 } 1607 else 1608 { 1609 bFormat = bJumpEndHyph; 1610 bWatchEndHyph = sal_False; 1611 bJumpEndHyph = sal_False; 1612 } 1613 if ( rLine.GetCurr()->IsMidHyph() ) 1614 { 1615 if ( bWatchMidHyph && !bFormat ) 1616 bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() ); 1617 } 1618 else 1619 { 1620 bFormat = bFormat || bJumpMidHyph; 1621 bWatchMidHyph = sal_False; 1622 bJumpMidHyph = sal_False; 1623 } 1624 } 1625 if( bFormat ) 1626 { 1627 sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph(); 1628 sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph(); 1629 bFormat = FormatLine( rLine, bPrev ); 1630 //9334: Es kann nur ein bPrev geben... (???) 1631 bPrev = sal_False; 1632 if ( bMaxHyph ) 1633 { 1634 if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph ) 1635 { 1636 bWatchEndHyph = !bOldEndHyph; 1637 bJumpEndHyph = bOldEndHyph; 1638 } 1639 if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph ) 1640 { 1641 bWatchMidHyph = !bOldMidHyph; 1642 bJumpMidHyph = bOldMidHyph; 1643 } 1644 } 1645 } 1646 1647 if( !rInf.IsNewLine() ) 1648 { 1649 if( !bFormat ) 1650 bFormat = 0 != rInf.GetRest(); 1651 if( rInf.IsStop() || rInf.GetIdx() >= nStrLen ) 1652 break; 1653 if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph && 1654 !bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) ) 1655 { 1656 if( GetFollow() ) 1657 { 1658 while( rLine.Next() ) 1659 ; //Nothing 1660 pFreeze = new SwRepaint( rRepaint ); // to minimize painting 1661 } 1662 else 1663 break; 1664 } 1665 } 1666 // OD 2004-02-25 #i16128# - method renamed 1667 bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine); 1668 }while( !bBreak ); 1669 1670 if( pFreeze ) 1671 { 1672 rRepaint = *pFreeze; 1673 delete pFreeze; 1674 } 1675 1676 if( !rLine.IsStop() ) 1677 { 1678 // Wurde aller Text formatiert und gibt es noch weitere 1679 // Zeilenobjekte, dann sind diese jetzt ueberfluessig, 1680 // weil der Text kuerzer geworden ist. 1681 if( rLine.GetStart() + rLine.GetLength() >= nStrLen && 1682 rLine.GetCurr()->GetNext() ) 1683 { 1684 rLine.TruncLines(); 1685 rLine.SetTruncLines( sal_True ); 1686 } 1687 } 1688 1689 if( !rInf.IsTest() ) 1690 { 1691 // Bei OnceMore lohnt sich kein FormatAdjust 1692 if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() ) 1693 { 1694 FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() ); 1695 } 1696 if( rRepaint.HasArea() ) 1697 SetRepaint(); 1698 rLine.SetTruncLines( sal_False ); 1699 if( nOldBottom ) // Bei "gescollten" Absaetzen wird 1700 { // noch ueberprueft, ob durch Schrumpfen 1701 rLine.Bottom(); // das Scrolling ueberfluessig wurde. 1702 SwTwips nNewBottom = rLine.Y(); 1703 if( nNewBottom < nOldBottom ) 1704 _SetOfst( 0 ); 1705 } 1706 } 1707 } 1708 1709 /************************************************************************* 1710 * SwTxtFrm::Format() 1711 *************************************************************************/ 1712 1713 void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf ) 1714 { 1715 ASSERT( ! IsVertical() || IsSwapped(), 1716 "A frame is not swapped in SwTxtFrm::FormatOnceMore" ); 1717 1718 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); 1719 if( !pPara ) 1720 return; 1721 1722 // ggf gegen pPara 1723 KSHORT nOld = ((const SwTxtMargin&)rLine).GetDropHeight(); 1724 sal_Bool bShrink = sal_False, 1725 bGrow = sal_False, 1726 bGoOn = rLine.IsOnceMore(); 1727 sal_uInt8 nGo = 0; 1728 while( bGoOn ) 1729 { 1730 #ifdef DBGTXT 1731 aDbstream << "OnceMore!" << endl; 1732 #endif 1733 ++nGo; 1734 rInf.Init(); 1735 rLine.Top(); 1736 if( !rLine.GetDropFmt() ) 1737 rLine.SetOnceMore( sal_False ); 1738 SwCharRange aRange( 0, rInf.GetTxt().Len() ); 1739 *(pPara->GetReformat()) = aRange; 1740 _Format( rLine, rInf ); 1741 1742 bGoOn = rLine.IsOnceMore(); 1743 if( bGoOn ) 1744 { 1745 const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight(); 1746 if( nOld == nNew ) 1747 bGoOn = sal_False; 1748 else 1749 { 1750 if( nOld > nNew ) 1751 bShrink = sal_True; 1752 else 1753 bGrow = sal_True; 1754 1755 if( bShrink == bGrow || 5 < nGo ) 1756 bGoOn = sal_False; 1757 1758 nOld = nNew; 1759 } 1760 1761 // 6107: Wenn was schief ging, muss noch einmal formatiert werden. 1762 if( !bGoOn ) 1763 { 1764 rInf.CtorInitTxtFormatInfo( this ); 1765 rLine.CtorInitTxtFormatter( this, &rInf ); 1766 rLine.SetDropLines( 1 ); 1767 rLine.CalcDropHeight( 1 ); 1768 SwCharRange aTmpRange( 0, rInf.GetTxt().Len() ); 1769 *(pPara->GetReformat()) = aTmpRange; 1770 _Format( rLine, rInf, sal_True ); 1771 // 8047: Wir painten alles... 1772 SetCompletePaint(); 1773 } 1774 } 1775 } 1776 } 1777 1778 /************************************************************************* 1779 * SwTxtFrm::_Format() 1780 *************************************************************************/ 1781 1782 1783 void SwTxtFrm::_Format( SwParaPortion *pPara ) 1784 { 1785 const xub_StrLen nStrLen = GetTxt().Len(); 1786 1787 // AMA: Wozu soll das gut sein? Scheint mir zuoft zu einem kompletten 1788 // Formatieren und Repainten zu fuehren??? 1789 // if ( !(*pPara->GetDelta()) ) 1790 // *(pPara->GetDelta()) = nStrLen; 1791 // else 1792 if ( !nStrLen ) 1793 { 1794 // Leere Zeilen werden nicht lange gequaelt: 1795 // pPara wird blank geputzt 1796 // entspricht *pPara = SwParaPortion; 1797 sal_Bool bMustFit = pPara->IsPrepMustFit(); 1798 pPara->Truncate(); 1799 pPara->FormatReset(); 1800 if( pBlink && pPara->IsBlinking() ) 1801 pBlink->Delete( pPara ); 1802 1803 // delete pSpaceAdd und pKanaComp 1804 pPara->FinishSpaceAdd(); 1805 pPara->FinishKanaComp(); 1806 pPara->ResetFlags(); 1807 pPara->SetPrepMustFit( bMustFit ); 1808 } 1809 1810 ASSERT( ! IsSwapped(), "A frame is swapped before _Format" ); 1811 1812 if ( IsVertical() ) 1813 SwapWidthAndHeight(); 1814 1815 SwTxtFormatInfo aInf( this ); 1816 SwTxtFormatter aLine( this, &aInf ); 1817 1818 // OD 2004-01-15 #110582# 1819 HideAndShowObjects(); 1820 1821 _Format( aLine, aInf ); 1822 1823 if( aLine.IsOnceMore() ) 1824 FormatOnceMore( aLine, aInf ); 1825 1826 if ( IsVertical() ) 1827 SwapWidthAndHeight(); 1828 1829 ASSERT( ! IsSwapped(), "A frame is swapped after _Format" ); 1830 1831 if( 1 < aLine.GetDropLines() ) 1832 { 1833 if( SVX_ADJUST_LEFT != aLine.GetAdjust() && 1834 SVX_ADJUST_BLOCK != aLine.GetAdjust() ) 1835 { 1836 aLine.CalcDropAdjust(); 1837 aLine.SetPaintDrop( sal_True ); 1838 } 1839 1840 if( aLine.IsPaintDrop() ) 1841 { 1842 aLine.CalcDropRepaint(); 1843 aLine.SetPaintDrop( sal_False ); 1844 } 1845 } 1846 } 1847 1848 /************************************************************************* 1849 * SwTxtFrm::Format() 1850 *************************************************************************/ 1851 1852 /* 1853 * Format berechnet die Groesse des Textframes und ruft, wenn 1854 * diese feststeht, Shrink() oder Grow(), um die Framegroesse dem 1855 * evtl. veraenderten Platzbedarf anzupassen. 1856 */ 1857 1858 void SwTxtFrm::Format( const SwBorderAttrs * ) 1859 { 1860 DBG_LOOP; 1861 #if OSL_DEBUG_LEVEL > 1 1862 const XubString aXXX = GetTxtNode()->GetTxt(); 1863 const SwTwips nDbgY = Frm().Top(); 1864 (void)nDbgY; 1865 const SwPageFrm *pDbgPage = FindPageFrm(); 1866 const MSHORT nDbgPageNr = pDbgPage->GetPhyPageNum(); 1867 (void)nDbgPageNr; 1868 // Um zu gucken, ob es einen Ftn-Bereich gibt. 1869 const SwFrm *pDbgFtnCont = (const SwFrm*)(FindPageFrm()->FindFtnCont()); 1870 (void)pDbgFtnCont; 1871 1872 #ifdef DBG_UTIL 1873 // nStopAt laesst sich vom CV bearbeiten. 1874 static MSHORT nStopAt = 0; 1875 if( nStopAt == GetFrmId() ) 1876 { 1877 int i = GetFrmId(); 1878 (void)i; 1879 } 1880 #endif 1881 #endif 1882 1883 #ifdef DEBUG_FTN 1884 //Fussnote darf nicht auf einer Seite vor ihrer Referenz stehen. 1885 if( IsInFtn() ) 1886 { 1887 const SwFtnFrm *pFtn = (SwFtnFrm*)GetUpper(); 1888 const SwPageFrm *pFtnPage = pFtn->GetRef()->FindPageFrm(); 1889 const MSHORT nFtnPageNr = pFtnPage->GetPhyPageNum(); 1890 if( !IsLocked() ) 1891 { 1892 if( nFtnPageNr > nDbgPageNr ) 1893 { 1894 SwTxtFrmLocker aLock(this); 1895 ASSERT( nFtnPageNr <= nDbgPageNr, "!Ftn steht vor der Referenz." ); 1896 MSHORT i = 0; 1897 } 1898 } 1899 } 1900 #endif 1901 1902 SWRECTFN( this ) 1903 1904 // --> OD 2008-01-31 #newlistlevelattrs# 1905 CalcAdditionalFirstLineOffset(); 1906 // <-- 1907 1908 // Vom Berichtsautopiloten oder ueber die BASIC-Schnittstelle kommen 1909 // gelegentlich TxtFrms mit einer Breite <=0. 1910 if( (Prt().*fnRect->fnGetWidth)() <= 0 ) 1911 { 1912 // Wenn MustFit gesetzt ist, schrumpfen wir ggf. auf die Unterkante 1913 // des Uppers, ansonsten nehmen wir einfach eine Standardgroesse 1914 // von 12 Pt. ein (240 Twip). 1915 SwTxtLineAccess aAccess( this ); 1916 long nFrmHeight = (Frm().*fnRect->fnGetHeight)(); 1917 if( aAccess.GetPara()->IsPrepMustFit() ) 1918 { 1919 const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)(); 1920 const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit ); 1921 if( nDiff > 0 ) 1922 Shrink( nDiff ); 1923 } 1924 else if( 240 < nFrmHeight ) 1925 Shrink( nFrmHeight - 240 ); 1926 else if( 240 > nFrmHeight ) 1927 Grow( 240 - nFrmHeight ); 1928 nFrmHeight = (Frm().*fnRect->fnGetHeight)(); 1929 1930 long nTop = (this->*fnRect->fnGetTopMargin)(); 1931 if( nTop > nFrmHeight ) 1932 (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 ); 1933 else if( (Prt().*fnRect->fnGetHeight)() < 0 ) 1934 (Prt().*fnRect->fnSetHeight)( 0 ); 1935 return; 1936 } 1937 1938 const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len(); 1939 if ( nStrLen || !FormatEmpty() ) 1940 { 1941 1942 SetEmpty( sal_False ); 1943 // Um nicht durch verschachtelte Formats irritiert zu werden. 1944 FormatLevel aLevel; 1945 if( 12 == aLevel.GetLevel() ) 1946 return; 1947 1948 // Die Formatinformationen duerfen u.U. nicht veraendert werden. 1949 if( IsLocked() ) 1950 return; 1951 1952 // 8708: Vorsicht, das Format() kann auch durch GetFormatted() 1953 // angestossen werden. 1954 if( IsHiddenNow() ) 1955 { 1956 long nPrtHeight = (Prt().*fnRect->fnGetHeight)(); 1957 if( nPrtHeight ) 1958 { 1959 HideHidden(); 1960 Shrink( nPrtHeight ); 1961 } 1962 else 1963 { 1964 // OD 2004-01-20 #110582# - assure that objects anchored 1965 // at paragraph resp. at/as character inside paragraph 1966 // are hidden. 1967 HideAndShowObjects(); 1968 } 1969 ChgThisLines(); 1970 return; 1971 } 1972 1973 // Waehrend wir formatieren, wollen wir nicht gestoert werden. 1974 SwTxtFrmLocker aLock(this); 1975 SwTxtLineAccess aAccess( this ); 1976 const sal_Bool bNew = !aAccess.SwTxtLineAccess::IsAvailable(); 1977 const sal_Bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() ); 1978 1979 if( CalcPreps() ) 1980 ; // nothing 1981 // Wir returnen, wenn schon formatiert wurde, nicht aber, wenn 1982 // der TxtFrm gerade erzeugt wurde und ueberhaupt keine Format- 1983 // informationen vorliegen. 1984 else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() ) 1985 { 1986 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() ) 1987 { 1988 aAccess.GetPara()->SetPrepAdjust( sal_True ); 1989 aAccess.GetPara()->SetPrep( sal_True ); 1990 CalcPreps(); 1991 } 1992 SetWidow( sal_False ); 1993 } 1994 else if( bSetOfst && IsFollow() ) 1995 { 1996 SwTxtFrm *pMaster = FindMaster(); 1997 ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" ); 1998 if( pMaster ) 1999 pMaster->Prepare( PREP_FOLLOW_FOLLOWS ); 2000 SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)(); 2001 if( (Frm().*fnRect->fnOverStep)( nMaxY ) ) 2002 (this->*fnRect->fnSetLimit)( nMaxY ); 2003 else if( (Frm().*fnRect->fnBottomDist)( nMaxY ) < 0 ) 2004 (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() ); 2005 } 2006 else 2007 { 2008 // bSetOfst here means that we have the "red arrow situation" 2009 if ( bSetOfst ) 2010 _SetOfst( 0 ); 2011 2012 const sal_Bool bOrphan = IsWidow(); 2013 const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0; 2014 SwTwips nFtnHeight = 0; 2015 if( pFtnBoss ) 2016 { 2017 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont(); 2018 nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0; 2019 } 2020 do 2021 { 2022 _Format( aAccess.GetPara() ); 2023 if( pFtnBoss && nFtnHeight ) 2024 { 2025 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont(); 2026 SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0; 2027 // If we lost some footnotes, we may have more space 2028 // for our main text, so we have to format again ... 2029 if( nNewHeight < nFtnHeight ) 2030 nFtnHeight = nNewHeight; 2031 else 2032 break; 2033 } 2034 else 2035 break; 2036 } while ( pFtnBoss ); 2037 if( bOrphan ) 2038 { 2039 ValidateFrm(); 2040 SetWidow( sal_False ); 2041 } 2042 } 2043 if( IsEmptyMaster() ) 2044 { 2045 SwFrm* pPre = GetPrev(); 2046 if( pPre && 2047 // --> FME 2004-07-22 #i10826# It's the first, it cannot keep! 2048 pPre->GetIndPrev() && 2049 // <-- 2050 pPre->GetAttrSet()->GetKeep().GetValue() ) 2051 { 2052 pPre->InvalidatePos(); 2053 } 2054 } 2055 } 2056 2057 ChgThisLines(); 2058 2059 // the PrepMustFit should not survive a Format operation 2060 SwParaPortion *pPara = GetPara(); 2061 if ( pPara ) 2062 pPara->SetPrepMustFit( sal_False ); 2063 2064 #if OSL_DEBUG_LEVEL > 1 2065 // Hier ein Instrumentarium, um ungewoehnlichen Master/Follow-Kombinationen, 2066 // insbesondere bei Fussnoten, auf die Schliche zu kommen 2067 if( IsFollow() || GetFollow() ) 2068 { 2069 SwTxtFrm *pTmpFrm = IsFollow() ? FindMaster() : this; 2070 const SwPageFrm *pTmpPage = pTmpFrm->FindPageFrm(); 2071 MSHORT nPgNr = pTmpPage->GetPhyPageNum(); 2072 MSHORT nLast; 2073 MSHORT nDummy = 0; // nur zum Breakpoint setzen 2074 while( pTmpFrm->GetFollow() ) 2075 { 2076 pTmpFrm = pTmpFrm->GetFollow(); 2077 nLast = nPgNr; 2078 pTmpPage = pTmpFrm->FindPageFrm(); 2079 nPgNr = pTmpPage->GetPhyPageNum(); 2080 if( nLast > nPgNr ) 2081 ++nDummy; // schon fast eine Assertion wert 2082 else if( nLast == nPgNr ) 2083 ++nDummy; // bei Spalten voellig normal, aber sonst!? 2084 else if( nLast < nPgNr - 1 ) 2085 ++nDummy; // kann schon mal temporaer vorkommen 2086 } 2087 } 2088 #endif 2089 2090 CalcBaseOfstForFly(); 2091 // OD 2004-03-17 #i11860# 2092 _CalcHeightOfLastLine(); 2093 } 2094 2095 /************************************************************************* 2096 * SwTxtFrm::FormatQuick() 2097 * 2098 * bForceQuickFormat is set if GetFormatted() has been called during the 2099 * painting process. Actually I cannot imagine a situation which requires 2100 * a full formatting of the paragraph during painting, on the other hand 2101 * a full formatting can cause the invalidation of other layout frames, 2102 * e.g., if there are footnotes in this paragraph, and invalid layout 2103 * frames will not calculated during the painting. So I actually want to 2104 * avoid a formatting during painting, but since I'm a coward, I'll only 2105 * force the quick formatting in the situation of issue i29062. 2106 *************************************************************************/ 2107 2108 sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat ) 2109 { 2110 ASSERT( ! IsVertical() || ! IsSwapped(), 2111 "SwTxtFrm::FormatQuick with swapped frame" ); 2112 2113 DBG_LOOP; 2114 #if OSL_DEBUG_LEVEL > 1 2115 const XubString aXXX = GetTxtNode()->GetTxt(); 2116 const SwTwips nDbgY = Frm().Top(); 2117 (void)nDbgY; 2118 #ifdef DBG_UTIL 2119 // nStopAt laesst sich vom CV bearbeiten. 2120 static MSHORT nStopAt = 0; 2121 if( nStopAt == GetFrmId() ) 2122 { 2123 int i = GetFrmId(); 2124 (void)i; 2125 } 2126 #endif 2127 #endif 2128 2129 if( IsEmpty() && FormatEmpty() ) 2130 return sal_True; 2131 2132 // Wir sind sehr waehlerisch: 2133 if( HasPara() || IsWidow() || IsLocked() 2134 || !GetValidSizeFlag() || 2135 ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) ) 2136 return sal_False; 2137 2138 SwTxtLineAccess aAccess( this ); 2139 SwParaPortion *pPara = aAccess.GetPara(); 2140 if( !pPara ) 2141 return sal_False; 2142 2143 SwFrmSwapper aSwapper( this, sal_True ); 2144 2145 SwTxtFrmLocker aLock(this); 2146 SwTxtFormatInfo aInf( this, sal_False, sal_True ); 2147 if( 0 != aInf.MaxHyph() ) // 27483: MaxHyphen beachten! 2148 return sal_False; 2149 2150 SwTxtFormatter aLine( this, &aInf ); 2151 2152 // DropCaps sind zu kompliziert... 2153 if( aLine.GetDropFmt() ) 2154 return sal_False; 2155 2156 xub_StrLen nStart = GetOfst(); 2157 const xub_StrLen nEnd = GetFollow() 2158 ? GetFollow()->GetOfst() : aInf.GetTxt().Len(); 2159 do 2160 { 2161 //DBG_LOOP; shadows declaration above. 2162 //resolved into: 2163 #if OSL_DEBUG_LEVEL > 1 2164 #ifdef DBG_UTIL 2165 DbgLoop aDbgLoop2( (const void*) this ); 2166 #endif 2167 #endif 2168 nStart = aLine.FormatLine( nStart ); 2169 if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) ) 2170 aLine.Insert( new SwLineLayout() ); 2171 } while( aLine.Next() ); 2172 2173 // Last exit: die Hoehen muessen uebereinstimmen. 2174 Point aTopLeft( Frm().Pos() ); 2175 aTopLeft += Prt().Pos(); 2176 const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight(); 2177 const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height(); 2178 2179 if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() ) 2180 { 2181 // Achtung: Durch FormatLevel==12 kann diese Situation auftreten, don't panic! 2182 // ASSERT( nNewHeight == nOldHeight, "!FormatQuick: rosebud" ); 2183 const xub_StrLen nStrt = GetOfst(); 2184 _InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) ); 2185 return sal_False; 2186 } 2187 2188 if( pFollow && nStart != ((SwTxtFrm*)pFollow)->GetOfst() ) 2189 return sal_False; // kann z.B. durch Orphans auftreten (35083,35081) 2190 2191 // Geschafft, wir sind durch ... 2192 2193 // Repaint setzen 2194 pPara->GetRepaint()->Pos( aTopLeft ); 2195 pPara->GetRepaint()->SSize( Prt().SSize() ); 2196 2197 // Reformat loeschen 2198 *(pPara->GetReformat()) = SwCharRange(); 2199 *(pPara->GetDelta()) = 0; 2200 2201 return sal_True; 2202 } 2203