merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / text / frmform.cxx
blob55ddcdadd9053ddb40e5558399b73adbba422b28
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: frmform.cxx,v $
10 * $Revision: 1.71 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <svx/keepitem.hxx>
37 #include <svx/hyznitem.hxx>
38 #include <pagefrm.hxx> // ChangeFtnRef
39 #include <ndtxt.hxx> // MakeFrm()
40 #include <dcontact.hxx> // SwDrawContact
41 #include <dflyobj.hxx> // SwVirtFlyDrawObj
42 #include <flyfrm.hxx>
43 #include <ftnfrm.hxx> // SwFtnFrm
44 #include <txtftn.hxx>
45 #include <fmtftn.hxx>
46 #include <paratr.hxx>
47 #include <viewopt.hxx> // SwViewOptions
48 #include <viewsh.hxx> // ViewShell
49 #include <frmatr.hxx>
50 #include <pam.hxx>
51 #include <flyfrms.hxx>
52 #include <fmtanchr.hxx>
53 #include <txtcfg.hxx>
54 #include <itrform2.hxx> // SwTxtFormatter
55 #include <widorp.hxx> // Widows and Orphans
56 #include <txtcache.hxx>
57 #include <porrst.hxx> // SwEmptyPortion
58 #include <blink.hxx> // pBlink
59 #include <porfld.hxx> // SwFldPortion
60 #include <sectfrm.hxx> // SwSectionFrm
61 #include <pormulti.hxx> // SwMultiPortion
63 #include <rootfrm.hxx>
64 #include <frmfmt.hxx> // SwFrmFmt
65 // OD 2004-05-24 #i28701#
66 #include <sortedobjs.hxx>
68 class FormatLevel
70 static MSHORT nLevel;
71 public:
72 inline FormatLevel() { ++nLevel; }
73 inline ~FormatLevel() { --nLevel; }
74 inline MSHORT GetLevel() const { return nLevel; }
75 static sal_Bool LastLevel() { return 10 < nLevel; }
77 MSHORT FormatLevel::nLevel = 0;
79 /*************************************************************************
80 * ValidateTxt/Frm()
81 *************************************************************************/
83 void ValidateTxt( SwFrm *pFrm ) // Freund vom Frame
85 if ( ( ! pFrm->IsVertical() &&
86 pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) ||
87 pFrm->IsVertical() &&
88 pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() )
89 pFrm->bValidSize = sal_True;
91 pFrm->bValidPrtArea = sal_True;
92 //Die Position validieren um nicht unnoetige (Test-)Moves zu provozieren.
93 //Dabei darf allerdings nicht eine tatsaechlich falsche Coordinate
94 //validiert werden.
95 if ( !pFrm->bValidPos )
97 //Leider muessen wir dazu die korrekte Position berechnen.
98 Point aOld( pFrm->Frm().Pos() );
99 pFrm->MakePos();
100 if ( aOld != pFrm->Pos() )
102 pFrm->Frm().Pos( aOld );
103 pFrm->bValidPos = sal_False;
109 void SwTxtFrm::ValidateFrm()
111 // Umgebung validieren, um Oszillationen zu verhindern.
112 SWAP_IF_SWAPPED( this )
114 if ( !IsInFly() && !IsInTab() )
115 { //Innerhalb eines Flys nur this validieren, der Rest sollte eigentlich
116 //nur fuer Fussnoten notwendig sein und die gibt es innerhalb von
117 //Flys nicht. Fix fuer 5544
118 SwSectionFrm* pSct = FindSctFrm();
119 if( pSct )
121 if( !pSct->IsColLocked() )
122 pSct->ColLock();
123 else
124 pSct = NULL;
127 SwFrm *pUp = GetUpper();
128 pUp->Calc();
129 if( pSct )
130 pSct->ColUnlock();
132 ValidateTxt( this );
134 //MA: mindestens das MustFit-Flag muessen wir retten!
135 ASSERT( HasPara(), "ResetPreps(), missing ParaPortion." );
136 SwParaPortion *pPara = GetPara();
137 const sal_Bool bMustFit = pPara->IsPrepMustFit();
138 ResetPreps();
139 pPara->SetPrepMustFit( bMustFit );
141 UNDO_SWAP( this )
144 /*************************************************************************
145 * ValidateBodyFrm()
146 *************************************************************************/
148 // nach einem RemoveFtn muss der BodyFrm und alle innenliegenden kalkuliert
149 // werden, damit die DeadLine richtig sitzt.
150 // Erst wird nach aussen hin gesucht, beim Rueckweg werden alle kalkuliert.
152 void _ValidateBodyFrm( SwFrm *pFrm )
154 if( pFrm && !pFrm->IsCellFrm() )
156 if( !pFrm->IsBodyFrm() && pFrm->GetUpper() )
157 _ValidateBodyFrm( pFrm->GetUpper() );
158 if( !pFrm->IsSctFrm() )
159 pFrm->Calc();
160 else
162 sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked();
163 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_True );
164 pFrm->Calc();
165 if( !bOld )
166 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_False );
171 void SwTxtFrm::ValidateBodyFrm()
173 SWAP_IF_SWAPPED( this )
175 //siehe Kommtar in ValidateFrm()
176 if ( !IsInFly() && !IsInTab() &&
177 !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) )
178 _ValidateBodyFrm( GetUpper() );
180 UNDO_SWAP( this )
183 /*************************************************************************
184 * SwTxtFrm::FindBodyFrm()
185 *************************************************************************/
187 sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const
189 SWAP_IF_NOT_SWAPPED( this )
191 ASSERT( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." );
192 SwTxtSizeInfo aInf( (SwTxtFrm*)this );
193 SwTxtMargin aLine( (SwTxtFrm*)this, &aInf );
194 if( aLine.GetDropLines() )
196 rRect.Top( aLine.Y() );
197 rRect.Left( aLine.GetLineStart() );
198 rRect.Height( aLine.GetDropHeight() );
199 rRect.Width( aLine.GetDropLeft() );
201 if ( IsRightToLeft() )
202 SwitchLTRtoRTL( rRect );
204 if ( IsVertical() )
205 SwitchHorizontalToVertical( rRect );
206 UNDO_SWAP( this )
207 return sal_True;
210 UNDO_SWAP( this )
212 return sal_False;
215 /*************************************************************************
216 * SwTxtFrm::FindBodyFrm()
217 *************************************************************************/
219 const SwBodyFrm *SwTxtFrm::FindBodyFrm() const
221 if ( IsInDocBody() )
223 const SwFrm *pFrm = GetUpper();
224 while( pFrm && !pFrm->IsBodyFrm() )
225 pFrm = pFrm->GetUpper();
226 return (const SwBodyFrm*)pFrm;
228 return 0;
231 /*************************************************************************
232 * SwTxtFrm::CalcFollow()
233 *************************************************************************/
235 sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst )
237 SWAP_IF_SWAPPED( this )
239 ASSERT( HasFollow(), "CalcFollow: missing Follow." );
241 SwTxtFrm* pMyFollow = GetFollow();
243 SwParaPortion *pPara = GetPara();
244 sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False;
246 if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst ||
247 bFollowFld || pMyFollow->IsFieldFollow() ||
248 ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) ||
249 ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) )
251 #ifndef PRODUCT
252 const SwFrm *pOldUp = GetUpper();
253 #endif
255 SWRECTFN ( this )
256 SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)();
257 SwTwips nMyPos = (Frm().*fnRect->fnGetTop)();
259 const SwPageFrm *pPage = 0;
260 sal_Bool bOldInvaCntnt = sal_True;
261 if ( !IsInFly() && GetNext() )
263 pPage = FindPageFrm();
264 //Minimieren - sprich ggf. zuruecksetzen - der Invalidierungen s.u.
265 bOldInvaCntnt = pPage->IsInvalidCntnt();
268 pMyFollow->_SetOfst( nTxtOfst );
269 pMyFollow->SetFieldFollow( bFollowFld );
270 if( HasFtn() || pMyFollow->HasFtn() )
272 ValidateFrm();
273 ValidateBodyFrm();
274 if( pPara )
276 *(pPara->GetReformat()) = SwCharRange();
277 *(pPara->GetDelta()) = 0;
281 //Der Fussnotenbereich darf sich keinesfalls vergrossern.
282 SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX );
284 pMyFollow->CalcFtnFlag();
285 if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() )
286 nOldBottom = bVert ? 0 : LONG_MAX;
288 while( sal_True )
290 if( !FormatLevel::LastLevel() )
292 // Weenn der Follow in einem spaltigen Bereich oder einem
293 // spaltigen Rahmen steckt, muss zunaechst dieser kalkuliert
294 // werden, da das FormatWidthCols() nicht funktioniert, wenn
295 // es aus dem MakeAll des _gelockten_ Follows heraus gerufen
296 // wird.
297 SwSectionFrm* pSct = pMyFollow->FindSctFrm();
298 if( pSct && !pSct->IsAnLower( this ) )
300 if( pSct->GetFollow() )
301 pSct->SimpleFormat();
302 else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) ||
303 ( ! pSct->IsVertical() && !pSct->Frm().Height() ) )
304 break;
306 // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled.
307 if ( FollowFormatAllowed() )
309 // OD 14.03.2003 #i11760# - no nested format of follows, if
310 // text frame is contained in a column frame.
311 // Thus, forbid intrinsic format of follow.
313 bool bIsFollowInColumn = false;
314 SwFrm* pFollowUpper = pMyFollow->GetUpper();
315 while ( pFollowUpper )
317 if ( pFollowUpper->IsColumnFrm() )
319 bIsFollowInColumn = true;
320 break;
322 if ( pFollowUpper->IsPageFrm() ||
323 pFollowUpper->IsFlyFrm() )
325 break;
327 pFollowUpper = pFollowUpper->GetUpper();
329 if ( bIsFollowInColumn )
331 pMyFollow->ForbidFollowFormat();
335 pMyFollow->Calc();
336 // Der Follow merkt anhand seiner Frm().Height(), dass was schief
337 // gelaufen ist.
338 ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" );
339 if( pMyFollow->GetPrev() )
341 pMyFollow->Prepare( PREP_CLEAR );
342 pMyFollow->Calc();
343 ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" );
346 // OD 14.03.2003 #i11760# - reset control flag for follow format.
347 pMyFollow->AllowFollowFormat();
350 //Sicherstellen, dass der Follow gepaintet wird.
351 pMyFollow->SetCompletePaint();
354 pPara = GetPara();
355 //Solange der Follow wg. Orphans Zeilen angefordert, bekommt er
356 //diese und wird erneut formatiert, falls moeglich.
357 if( pPara && pPara->IsPrepWidows() )
358 CalcPreps();
359 else
360 break;
363 if( HasFtn() || pMyFollow->HasFtn() )
365 ValidateBodyFrm();
366 ValidateFrm();
367 if( pPara )
369 *(pPara->GetReformat()) = SwCharRange();
370 *(pPara->GetDelta()) = 0;
374 if ( pPage )
376 if ( !bOldInvaCntnt )
377 pPage->ValidateCntnt();
380 #ifndef PRODUCT
381 ASSERT( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" );
382 #endif
384 const long nRemaining =
385 - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom );
386 if ( nRemaining > 0 && !GetUpper()->IsSctFrm() &&
387 nRemaining != ( bVert ?
388 nMyPos - Frm().Right() :
389 Frm().Top() - nMyPos ) )
391 UNDO_SWAP( this )
392 return sal_True;
396 UNDO_SWAP( this )
398 return sal_False;
401 /*************************************************************************
402 * SwTxtFrm::AdjustFrm()
403 *************************************************************************/
405 void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit )
407 if( IsUndersized() )
409 if( GetOfst() && !IsFollow() ) // ein gescrollter Absatz (undersized)
410 return;
411 SetUndersized( nChgHght == 0 || bHasToFit );
414 // AdjustFrm is called with a swapped frame during
415 // formatting but the frame is not swapped during FormatEmpty
416 SWAP_IF_SWAPPED( this )
417 SWRECTFN ( this )
419 // Die Size-Variable des Frames wird durch Grow inkrementiert
420 // oder durch Shrink dekrementiert. Wenn die Groesse
421 // unveraendert ist, soll nichts passieren!
422 if( nChgHght >= 0)
424 SwTwips nChgHeight = nChgHght;
425 if( nChgHght && !bHasToFit )
427 if( IsInFtn() && !IsInSct() )
429 SwTwips nReal = Grow( nChgHght, sal_True );
430 if( nReal < nChgHght )
432 SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(),
433 nChgHght - nReal );
434 SwFrm* pCont = FindFtnFrm()->GetUpper();
436 if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 )
438 (Frm().*fnRect->fnAddBottom)( nChgHght );
439 if( bVert )
440 Prt().SSize().Width() += nChgHght;
441 else
442 Prt().SSize().Height() += nChgHght;
443 UNDO_SWAP( this )
444 return;
449 Grow( nChgHght );
451 if ( IsInFly() )
453 //MA 06. May. 93: Wenn einer der Upper ein Fly ist, so ist es
454 //sehr wahrscheinlich, dass dieser Fly durch das Grow seine
455 //Position veraendert - also muss auch meine Position korrigiert
456 //werden (sonst ist die Pruefung s.u. nicht aussagekraeftig).
457 //Die Vorgaenger muessen berechnet werden, damit die Position
458 //korrekt berechnet werden kann.
459 if ( GetPrev() )
461 SwFrm *pPre = GetUpper()->Lower();
463 { pPre->Calc();
464 pPre = pPre->GetNext();
465 } while ( pPre && pPre != this );
467 const Point aOldPos( Frm().Pos() );
468 MakePos();
469 if ( aOldPos != Frm().Pos() )
471 // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)>
472 // No format is performed for the floating screen objects.
473 InvalidateObjs( true );
476 nChgHeight = 0;
478 // Ein Grow() wird von der Layout-Seite immer akzeptiert,
479 // also auch, wenn die FixSize des umgebenden Layoutframes
480 // dies nicht zulassen sollte. Wir ueberpruefen diesen
481 // Fall und korrigieren die Werte.
482 // MA 06. May. 93: Der Frm darf allerdings auch im Notfall nicht
483 // weiter geschrumpft werden als es seine Groesse zulaesst.
484 SwTwips nRstHeight;
485 if ( IsVertical() )
487 ASSERT( ! IsSwapped(),"Swapped frame while calculating nRstHeight" );
488 nRstHeight = Frm().Left() + Frm().Width() -
489 ( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() );
491 else
492 nRstHeight = GetUpper()->Frm().Top()
493 + GetUpper()->Prt().Top()
494 + GetUpper()->Prt().Height()
495 - Frm().Top();
497 //In Tabellenzellen kann ich mir evtl. noch ein wenig dazuholen, weil
498 //durch eine vertikale Ausrichtung auch oben noch Raum sein kann.
499 // --> OD 2004-11-25 #115759# - assure, that first lower in upper
500 // is the current one or is valid.
501 if ( IsInTab() &&
502 ( GetUpper()->Lower() == this ||
503 GetUpper()->Lower()->IsValid() ) )
504 // <--
506 long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(),
507 (GetUpper()->*fnRect->fnGetPrtTop)() );
508 ASSERT( nAdd >= 0, "Ey" );
509 nRstHeight += nAdd;
512 /* ------------------------------------
513 * #50964#: nRstHeight < 0 bedeutet, dass der TxtFrm komplett ausserhalb seines
514 * Upper liegt. Dies kann passieren, wenn er innerhalb eines FlyAtCntFrm liegt, der
515 * durch das Grow() die Seite gewechselt hat. In so einem Fall ist es falsch, der
516 * folgenden Grow-Versuch durchzufuehren. Im Bugfall fuehrte dies sogar zur
517 * Endlosschleife.
518 * -----------------------------------*/
519 SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)();
520 SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)();
522 if( nRstHeight < nFrmHeight )
524 //Kann sein, dass ich die richtige Grosse habe, der Upper aber zu
525 //klein ist und der Upper noch Platz schaffen kann.
526 if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit )
527 nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight );
528 // In spaltigen Bereichen wollen wir moeglichst nicht zu gross werden, damit
529 // nicht ueber GetNextSctLeaf weitere Bereiche angelegt werden. Stattdessen
530 // schrumpfen wir und notieren bUndersized, damit FormatWidthCols die richtige
531 // Spaltengroesse ermitteln kann.
532 if ( nRstHeight < nFrmHeight )
534 if( bHasToFit || !IsMoveable() ||
535 ( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) )
537 SetUndersized( sal_True );
538 Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) );
540 else
541 SetUndersized( sal_False );
544 else if( nChgHeight )
546 if( nRstHeight - nFrmHeight < nChgHeight )
547 nChgHeight = nRstHeight - nFrmHeight;
548 if( nChgHeight )
549 Grow( nChgHeight );
552 else
553 Shrink( -nChgHght );
555 UNDO_SWAP( this )
558 /*************************************************************************
559 * SwTxtFrm::AdjustFollow()
560 *************************************************************************/
562 /* AdjustFollow erwartet folgende Situation:
563 * Der SwTxtIter steht am unteren Ende des Masters, der Offset wird
564 * im Follow eingestellt.
565 * nOffset haelt den Offset im Textstring, ab dem der Master abschliesst
566 * und der Follow beginnt. Wenn er 0 ist, wird der FolgeFrame geloescht.
569 void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine,
570 const xub_StrLen nOffset, const xub_StrLen nEnd,
571 const sal_uInt8 nMode )
573 SwFrmSwapper aSwapper( this, sal_False );
575 // Wir haben den Rest der Textmasse: alle Follows loeschen
576 // Sonderfall sind DummyPortions()
577 // - special cases are controlled by parameter <nMode>.
578 if( HasFollow() && !(nMode & 1) && nOffset == nEnd )
580 while( GetFollow() )
582 if( ((SwTxtFrm*)GetFollow())->IsLocked() )
584 ASSERT( sal_False, "+SwTxtFrm::JoinFrm: Follow ist locked." );
585 return;
587 JoinFrm();
590 return;
593 // Tanz auf dem Vulkan: Wir formatieren eben schnell noch einmal
594 // die letzte Zeile fuer das QuoVadis-Geraffel. Selbstverstaendlich
595 // kann sich dadurch auch der Offset verschieben:
596 const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ?
597 rLine.FormatQuoVadis(nOffset) : nOffset;
599 if( !(nMode & 1) )
601 // Wir klauen unseren Follows Textmasse, dabei kann es passieren,
602 // dass wir einige Follows Joinen muessen.
603 while( GetFollow() && GetFollow()->GetFollow() &&
604 nNewOfst >= GetFollow()->GetFollow()->GetOfst() )
606 DBG_LOOP;
607 JoinFrm();
611 // Der Ofst hat sich verschoben.
612 if( GetFollow() )
614 #if OSL_DEBUG_LEVEL > 1
615 static sal_Bool bTest = sal_False;
616 if( !bTest || ( nMode & 1 ) )
617 #endif
618 if ( nMode )
619 GetFollow()->ManipOfst( 0 );
621 if ( CalcFollow( nNewOfst ) ) // CalcFollow erst zum Schluss, dort erfolgt ein SetOfst
622 rLine.SetOnceMore( sal_True );
626 /*************************************************************************
627 * SwTxtFrm::JoinFrm()
628 *************************************************************************/
630 SwCntntFrm *SwTxtFrm::JoinFrm()
632 ASSERT( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" );
633 SwTxtFrm *pFoll = GetFollow();
635 SwTxtFrm *pNxt = pFoll->GetFollow();
637 // Alle Fussnoten des zu zerstoerenden Follows werden auf uns
638 // umgehaengt.
639 xub_StrLen nStart = pFoll->GetOfst();
640 if ( pFoll->HasFtn() )
642 const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints();
643 if( pHints )
645 SwFtnBossFrm *pFtnBoss = 0;
646 SwFtnBossFrm *pEndBoss = 0;
647 for ( USHORT i = 0; i < pHints->Count(); ++i )
649 const SwTxtAttr *pHt = (*pHints)[i];
650 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart )
652 if( pHt->GetFtn().IsEndNote() )
654 if( !pEndBoss )
655 pEndBoss = pFoll->FindFtnBossFrm();
656 pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
658 else
660 if( !pFtnBoss )
661 pFtnBoss = pFoll->FindFtnBossFrm( sal_True );
662 pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
664 SetFtn( sal_True );
670 #ifndef PRODUCT
671 else if ( pFoll->GetValidPrtAreaFlag() ||
672 pFoll->GetValidSizeFlag() )
674 pFoll->CalcFtnFlag();
675 ASSERT( !pFoll->HasFtn(), "Missing FtnFlag." );
677 #endif
679 pFoll->MoveFlyInCnt( this, nStart, STRING_LEN );
680 pFoll->SetFtn( FALSE );
681 // --> OD 2005-12-01 #i27138#
682 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
683 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
684 // and relation CONTENT_FLOWS_TO for current previous paragraph, which
685 // is <this>, will change.
687 ViewShell* pViewShell( pFoll->GetShell() );
688 if ( pViewShell && pViewShell->GetLayout() &&
689 pViewShell->GetLayout()->IsAnyShellAccessible() )
691 pViewShell->InvalidateAccessibleParaFlowRelation(
692 dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )),
693 this );
696 // <--
697 pFoll->Cut();
698 delete pFoll;
699 pFollow = pNxt;
700 return pNxt;
703 /*************************************************************************
704 * SwTxtFrm::SplitFrm()
705 *************************************************************************/
707 SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos )
709 SWAP_IF_SWAPPED( this )
711 // Durch das Paste wird ein Modify() an mich verschickt.
712 // Damit meine Daten nicht verschwinden, locke ich mich.
713 SwTxtFrmLocker aLock( this );
714 SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm());
715 pNew->bIsFollow = sal_True;
717 pNew->SetFollow( GetFollow() );
718 SetFollow( pNew );
720 pNew->Paste( GetUpper(), GetNext() );
721 // --> OD 2005-12-01 #i27138#
722 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
723 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
724 // and relation CONTENT_FLOWS_TO for current previous paragraph, which
725 // is <this>, will change.
727 ViewShell* pViewShell( pNew->GetShell() );
728 if ( pViewShell && pViewShell->GetLayout() &&
729 pViewShell->GetLayout()->IsAnyShellAccessible() )
731 pViewShell->InvalidateAccessibleParaFlowRelation(
732 dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
733 this );
736 // <--
738 // Wenn durch unsere Aktionen Fussnoten in pNew landen,
739 // so muessen sie umgemeldet werden.
740 if ( HasFtn() )
742 const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
743 if( pHints )
745 SwFtnBossFrm *pFtnBoss = 0;
746 SwFtnBossFrm *pEndBoss = 0;
747 for ( USHORT i = 0; i < pHints->Count(); ++i )
749 const SwTxtAttr *pHt = (*pHints)[i];
750 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos )
752 if( pHt->GetFtn().IsEndNote() )
754 if( !pEndBoss )
755 pEndBoss = FindFtnBossFrm();
756 pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
758 else
760 if( !pFtnBoss )
761 pFtnBoss = FindFtnBossFrm( sal_True );
762 pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
764 pNew->SetFtn( sal_True );
770 #ifndef PRODUCT
771 else
773 CalcFtnFlag( nTxtPos-1 );
774 ASSERT( !HasFtn(), "Missing FtnFlag." );
776 #endif
778 MoveFlyInCnt( pNew, nTxtPos, STRING_LEN );
780 // Kein SetOfst oder CalcFollow, weil gleich ohnehin ein AdjustFollow folgt.
782 pNew->ManipOfst( nTxtPos );
784 UNDO_SWAP( this )
785 return pNew;
789 /*************************************************************************
790 * virtual SwTxtFrm::SetOfst()
791 *************************************************************************/
793 void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst )
795 #ifdef DBGTXT
796 // Es gibt tatsaechlich einen Sonderfall, in dem ein SetOfst(0)
797 // zulaessig ist: bug 3496
798 ASSERT( nNewOfst, "!SwTxtFrm::SetOfst: missing JoinFrm()." );
799 #endif
801 // Die Invalidierung unseres Follows ist nicht noetig.
802 // Wir sind ein Follow, werden gleich formatiert und
803 // rufen von dort aus das SetOfst() !
804 nOfst = nNewOfst;
805 SwParaPortion *pPara = GetPara();
806 if( pPara )
808 SwCharRange &rReformat = *(pPara->GetReformat());
809 rReformat.Start() = 0;
810 rReformat.Len() = GetTxt().Len();
811 *(pPara->GetDelta()) = rReformat.Len();
813 InvalidateSize();
816 /*************************************************************************
817 * SwTxtFrm::CalcPreps
818 *************************************************************************/
820 sal_Bool SwTxtFrm::CalcPreps()
822 ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" );
823 SWRECTFN( this );
825 SwParaPortion *pPara = GetPara();
826 if ( !pPara )
827 return sal_False;
828 sal_Bool bPrep = pPara->IsPrep();
829 sal_Bool bPrepWidows = pPara->IsPrepWidows();
830 sal_Bool bPrepAdjust = pPara->IsPrepAdjust();
831 sal_Bool bPrepMustFit = pPara->IsPrepMustFit();
832 ResetPreps();
834 sal_Bool bRet = sal_False;
835 if( bPrep && !pPara->GetReformat()->Len() )
837 // PREP_WIDOWS bedeutet, dass im Follow die Orphans-Regel
838 // zuschlug.
839 // Es kann in unguenstigen Faellen vorkommen, dass auch ein
840 // PrepAdjust vorliegt (3680)!
841 if( bPrepWidows )
843 if( !GetFollow() )
845 ASSERT( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" );
846 return sal_False;
849 // Wir muessen uns auf zwei Faelle einstellen:
850 // Wir konnten dem Follow noch ein paar Zeilen abgeben,
851 // -> dann muessen wir schrumpfen
852 // oder wir muessen auf die naechste Seite
853 // -> dann lassen wir unseren Frame zu gross werden.
855 SwTwips nChgHeight = GetParHeight();
856 if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() )
858 if( bPrepMustFit )
860 GetFollow()->SetJustWidow( sal_True );
861 GetFollow()->Prepare( PREP_CLEAR );
863 else if ( bVert )
865 Frm().Width( Frm().Width() + Frm().Left() );
866 Prt().Width( Prt().Width() + Frm().Left() );
867 Frm().Left( 0 );
868 SetWidow( sal_True );
870 else
872 SwTwips nTmp = LONG_MAX - (Frm().Top()+10000);
873 SwTwips nDiff = nTmp - Frm().Height();
874 Frm().Height( nTmp );
875 Prt().Height( Prt().Height() + nDiff );
876 SetWidow( sal_True );
879 else
881 ASSERT( nChgHeight < (Prt().*fnRect->fnGetHeight)(),
882 "+SwTxtFrm::CalcPrep: wanna shrink" );
884 nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight;
886 GetFollow()->SetJustWidow( sal_True );
887 GetFollow()->Prepare( PREP_CLEAR );
888 Shrink( nChgHeight );
889 SwRect &rRepaint = *(pPara->GetRepaint());
891 if ( bVert )
893 SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() );
894 SwitchVerticalToHorizontal( aRepaint );
895 rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() );
897 else
898 rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
900 // 6792: Rrand < LRand und Repaint
901 if( 0 >= rRepaint.Width() )
902 rRepaint.Width(1);
904 bRet = sal_True;
907 else if ( bPrepAdjust )
909 if ( HasFtn() )
911 if( !CalcPrepFtnAdjust() )
913 if( bPrepMustFit )
915 SwTxtLineAccess aAccess( this );
916 aAccess.GetPara()->SetPrepMustFit( sal_True );
918 return sal_False;
922 SWAP_IF_NOT_SWAPPED( this )
924 SwTxtFormatInfo aInf( this );
925 SwTxtFormatter aLine( this, &aInf );
927 WidowsAndOrphans aFrmBreak( this );
928 // Egal was die Attribute meinen, bei MustFit wird
929 // der Absatz im Notfall trotzdem gesplittet...
930 if( bPrepMustFit )
932 aFrmBreak.SetKeep( sal_False );
933 aFrmBreak.ClrOrphLines();
935 // Bevor wir FormatAdjust aufrufen muessen wir dafuer
936 // sorgen, dass die Zeilen, die unten raushaengen
937 // auch tatsaechlich abgeschnitten werden.
938 // OD 2004-02-25 #i16128# - method renamed
939 sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
940 bRet = sal_True;
941 while( !bBreak && aLine.Next() )
943 // OD 2004-02-25 #i16128# - method renamed
944 bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
946 if( bBreak )
948 // Es gibt Komplikationen: wenn TruncLines gerufen wird,
949 // veraendern sich ploetzlich die Bedingungen in
950 // IsInside, so dass IsBreakNow andere Ergebnisse
951 // liefern kann. Aus diesem Grund wird rFrmBreak bekannt
952 // gegeben, dass da wo rLine steht, das Ende erreicht
953 // ist. Mal sehen, ob's klappt ...
954 aLine.TruncLines();
955 aFrmBreak.SetRstHeight( aLine );
956 FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() );
958 else
960 if( !GetFollow() )
962 FormatAdjust( aLine, aFrmBreak,
963 aInf.GetTxt().Len(), aInf.IsStop() );
965 else if ( !aFrmBreak.IsKeepAlways() )
967 // Siehe Bug: 2320
968 // Vor dem Master wird eine Zeile geloescht, der Follow
969 // koennte eine Zeile abgeben.
970 const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 );
971 *(pPara->GetReformat()) += aFollowRg;
972 // Es soll weitergehen!
973 bRet = sal_False;
977 UNDO_SWAP( this )
978 // Eine letzte Ueberpruefung, falls das FormatAdjust() nichts
979 // brachte, muessen wir amputieren.
980 if( bPrepMustFit )
982 const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)();
983 const SwTwips nIs = (Frm().*fnRect->fnGetBottom)();
985 if( bVert && nIs < nMust )
987 Shrink( nMust - nIs );
988 if( Prt().Width() < 0 )
989 Prt().Width( 0 );
990 SetUndersized( sal_True );
992 else if ( ! bVert && nIs > nMust )
994 Shrink( nIs - nMust );
995 if( Prt().Height() < 0 )
996 Prt().Height( 0 );
997 SetUndersized( sal_True );
1002 pPara->SetPrepMustFit( bPrepMustFit );
1003 return bRet;
1007 /*************************************************************************
1008 * SwTxtFrm::FormatAdjust()
1009 *************************************************************************/
1011 // Hier werden die Fussnoten und "als Zeichen"-gebundenen Objekte umgehaengt
1012 #define CHG_OFFSET( pFrm, nNew )\
1014 if( pFrm->GetOfst() < nNew )\
1015 pFrm->MoveFlyInCnt( this, 0, nNew );\
1016 else if( pFrm->GetOfst() > nNew )\
1017 MoveFlyInCnt( pFrm, nNew, STRING_LEN );\
1020 void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine,
1021 WidowsAndOrphans &rFrmBreak,
1022 const xub_StrLen nStrLen,
1023 const sal_Bool bDummy )
1025 SWAP_IF_NOT_SWAPPED( this )
1027 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1029 xub_StrLen nEnd = rLine.GetStart();
1031 sal_Bool bHasToFit = pPara->IsPrepMustFit();
1033 // Das StopFlag wird durch Fussnoten gesetzt,
1034 // die auf die naechste Seite wollen.
1035 // OD, FME 2004-03-03 - call base class method <SwTxtFrmBreak::IsBreakNow(..)>
1036 // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break,
1037 // even if due to widow rule no enough lines exists.
1038 sal_uInt8 nNew = ( !GetFollow() &&
1039 nEnd < nStrLen &&
1040 ( rLine.IsStop() ||
1041 ( bHasToFit
1042 ? ( rLine.GetLineNr() > 1 &&
1043 !rFrmBreak.IsInside( rLine ) )
1044 : rFrmBreak.IsBreakNow( rLine ) ) ) )
1045 ? 1 : 0;
1046 if ( nNew )
1047 SplitFrm( nEnd );
1049 const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm());
1051 const long nBodyHeight = pBodyFrm ? ( IsVertical() ?
1052 pBodyFrm->Frm().Width() :
1053 pBodyFrm->Frm().Height() ) : 0;
1055 // Wenn die aktuellen Werte berechnet wurden, anzeigen, dass
1056 // sie jetzt gueltig sind.
1057 *(pPara->GetReformat()) = SwCharRange();
1058 sal_Bool bDelta = *pPara->GetDelta() != 0;
1059 *(pPara->GetDelta()) = 0;
1061 if( rLine.IsStop() )
1063 rLine.TruncLines( sal_True );
1064 nNew = 1;
1067 // FindBreak schneidet die letzte Zeile ab.
1068 if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) )
1070 // Wenn wir bis zum Ende durchformatiert haben, wird nEnd auf das Ende
1071 // gesetzt. In AdjustFollow wird dadurch ggf. JoinFrm() ausgefuehrt.
1072 // Ansonsten ist nEnd das Ende der letzten Zeile im Master.
1073 xub_StrLen nOld = nEnd;
1074 nEnd = rLine.GetEnd();
1075 if( GetFollow() )
1077 if( nNew && nOld < nEnd )
1078 RemoveFtn( nOld, nEnd - nOld );
1079 CHG_OFFSET( GetFollow(), nEnd )
1080 if( !bDelta )
1081 GetFollow()->ManipOfst( nEnd );
1084 else
1085 { // Wenn wir Zeilen abgeben, darf kein Join auf den Folows gerufen werden,
1086 // im Gegenteil, es muss ggf. sogar ein Follow erzeugt werden.
1087 // Dies muss auch geschehen, wenn die Textmasse komplett im Master
1088 // bleibt, denn es k???nnte ja ein harter Zeilenumbruch noch eine weitere
1089 // Zeile (ohne Textmassse) notwendig machen!
1090 nEnd = rLine.GetEnd();
1091 if( GetFollow() )
1093 // OD 21.03.2003 #108121# - Another case for not joining the follow:
1094 // Text frame has no content, but a numbering. Then, do *not* join.
1095 // Example of this case: When an empty, but numbered paragraph
1096 // at the end of page is completely displaced by a fly frame.
1097 // Thus, the text frame introduced a follow by a
1098 // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows
1099 // the numbering and must stay.
1100 if ( GetFollow()->GetOfst() != nEnd ||
1101 GetFollow()->IsFieldFollow() ||
1102 ( nStrLen == 0 && GetTxtNode()->GetNumRule())
1105 nNew |= 3;
1107 CHG_OFFSET( GetFollow(), nEnd )
1108 GetFollow()->ManipOfst( nEnd );
1110 else
1112 // OD 21.03.2003 #108121# - Only split frame, if the frame contains
1113 // content or contains no content, but has a numbering.
1114 if ( nStrLen > 0 ||
1115 ( nStrLen == 0 && GetTxtNode()->GetNumRule())
1118 SplitFrm( nEnd );
1119 nNew |= 3;
1122 // Wenn sich die Resthoehe geaendert hat, z.B. durch RemoveFtn()
1123 // dann muessen wir auffuellen, um Oszillationen zu vermeiden!
1124 if( bDummy && pBodyFrm &&
1125 nBodyHeight < ( IsVertical() ?
1126 pBodyFrm->Frm().Width() :
1127 pBodyFrm->Frm().Height() ) )
1128 rLine.MakeDummyLine();
1131 // In AdjustFrm() stellen wir uns selbst per Grow/Shrink ein,
1132 // in AdjustFollow() stellen wir unseren FolgeFrame ein.
1134 const SwTwips nDocPrtTop = Frm().Top() + Prt().Top();
1135 const SwTwips nOldHeight = Prt().SSize().Height();
1136 const SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight;
1138 // Vertical Formatting:
1139 // The (rotated) repaint rectangle's x coordinate referes to the frame.
1140 // If the frame grows (or shirks) the repaint rectangle cannot simply
1141 // be rotated back after formatting, because we use the upper left point
1142 // of the frame for rotation. This point changes when growing/shrinking.
1143 if ( IsVertical() && nChg )
1145 SwRect &rRepaint = *(pPara->GetRepaint());
1146 rRepaint.Left( rRepaint.Left() - nChg );
1147 rRepaint.Width( rRepaint.Width() - nChg );
1150 AdjustFrm( nChg, bHasToFit );
1153 // FME 16.07.2003 #i16930# - removed this code because it did not
1154 // work correctly. In SwCntntFrm::MakeAll, the frame did not move to the
1155 // next page, instead the print area was recalculated and
1156 // Prepare( PREP_POS_CHGD, (const void*)&bFormatted, FALSE ) invalidated
1157 // the other flags => loop
1159 // OD 04.04.2003 #108446# - handle special case:
1160 // If text frame contains no content and just has split, because of a
1161 // line stop, it has to move forward. To force this forward move without
1162 // unnecessary formatting of its footnotes and its follow, especially in
1163 // columned sections, adjust frame height to zero (0) and do not perform
1164 // the intrinsic format of the follow.
1165 // The formating method <SwCntntFrm::MakeAll()> will initiate the move forward.
1166 sal_Bool bForcedNoIntrinsicFollowCalc = sal_False;
1167 if ( nEnd == 0 &&
1168 rLine.IsStop() && HasFollow() && nNew == 1
1171 AdjustFrm( -Frm().SSize().Height(), bHasToFit );
1172 Prt().Pos().Y() = 0;
1173 Prt().Height( Frm().Height() );
1174 if ( FollowFormatAllowed() )
1176 bForcedNoIntrinsicFollowCalc = sal_True;
1177 ForbidFollowFormat();
1180 else
1182 AdjustFrm( nChg, bHasToFit );
1186 if( HasFollow() || IsInFtn() )
1187 _AdjustFollow( rLine, nEnd, nStrLen, nNew );
1189 // FME 16.07.2003 #i16930# - removed this code because it did not work
1190 // correctly
1191 // OD 04.04.2003 #108446# - allow intrinsic format of follow, if above
1192 // special case has forbit it.
1193 /* if ( bForcedNoIntrinsicFollowCalc )
1195 AllowFollowFormat();
1199 pPara->SetPrepMustFit( sal_False );
1201 UNDO_SWAP( this )
1204 /*************************************************************************
1205 * SwTxtFrm::FormatLine()
1206 *************************************************************************/
1208 // bPrev zeigt an, ob Reformat.Start() wegen Prev() vorgezogen wurde.
1209 // Man weiss sonst nicht, ob man Repaint weiter einschraenken kann oder nicht.
1212 sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev )
1214 ASSERT( ! IsVertical() || IsSwapped(),
1215 "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" );
1216 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1217 // Nach rLine.FormatLine() haelt nStart den neuen Wert,
1218 // waehrend in pOldStart der alte Offset gepflegt wird.
1219 // Ueber diesen Weg soll das nDelta ersetzt werden.
1220 // *pOldStart += rLine.GetCurr()->GetLen();
1221 const SwLineLayout *pOldCur = rLine.GetCurr();
1222 const xub_StrLen nOldLen = pOldCur->GetLen();
1223 const KSHORT nOldAscent = pOldCur->GetAscent();
1224 const KSHORT nOldHeight = pOldCur->Height();
1225 const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin();
1226 const sal_Bool bOldHyph = pOldCur->IsEndHyph();
1227 SwTwips nOldTop = 0;
1228 SwTwips nOldBottom = 0;
1229 if( rLine.GetCurr()->IsClipping() )
1230 rLine.CalcUnclipped( nOldTop, nOldBottom );
1232 const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() );
1234 ASSERT( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(),
1235 "SwTxtFrm::FormatLine: frame leaves orbit." );
1236 ASSERT( rLine.GetCurr()->Height(),
1237 "SwTxtFrm::FormatLine: line height is zero" );
1239 // Das aktuelle Zeilenumbruchobjekt.
1240 const SwLineLayout *pNew = rLine.GetCurr();
1242 sal_Bool bUnChg = nOldLen == pNew->GetLen() &&
1243 bOldHyph == pNew->IsEndHyph();
1244 if ( bUnChg && !bPrev )
1246 // 6672: Toleranz von SLOPPY_TWIPS (5 Twips); vgl. 6922
1247 const long nWidthDiff = nOldWidth > pNew->Width()
1248 ? nOldWidth - pNew->Width()
1249 : pNew->Width() - nOldWidth;
1251 // we only declare a line as unchanged, if its main values have not
1252 // changed and it is not the last line (!paragraph end symbol!)
1253 bUnChg = nOldHeight == pNew->Height() &&
1254 nOldAscent == pNew->GetAscent() &&
1255 nWidthDiff <= SLOPPY_TWIPS &&
1256 pOldCur->GetNext();
1259 // rRepaint wird berechnet:
1260 const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight();
1261 SwRepaint &rRepaint = *(pPara->GetRepaint());
1262 if( bUnChg && rRepaint.Top() == rLine.Y()
1263 && (bPrev || nNewStart <= pPara->GetReformat()->Start())
1264 && ( nNewStart < GetTxtNode()->GetTxt().Len() ) )
1266 rRepaint.Top( nBottom );
1267 rRepaint.Height( 0 );
1269 else
1271 if( nOldTop )
1273 if( nOldTop < rRepaint.Top() )
1274 rRepaint.Top( nOldTop );
1275 if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() )
1277 rRepaint.Bottom( nOldBottom - 1 );
1278 rLine.SetUnclipped( sal_True );
1281 if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() )
1283 SwTwips nTmpTop, nTmpBottom;
1284 rLine.CalcUnclipped( nTmpTop, nTmpBottom );
1285 if( nTmpTop < rRepaint.Top() )
1286 rRepaint.Top( nTmpTop );
1287 if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() )
1289 rRepaint.Bottom( nTmpBottom - 1 );
1290 rLine.SetUnclipped( sal_True );
1293 else
1295 if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() )
1297 rRepaint.Bottom( nBottom - 1 );
1298 rLine.SetUnclipped( sal_False );
1301 SwTwips nRght = Max( nOldWidth, pNew->Width() +
1302 pNew->GetHangingMargin() );
1303 ViewShell *pSh = GetShell();
1304 const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0;
1305 if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) )
1306 nRght += ( Max( nOldAscent, pNew->GetAscent() ) );
1307 else
1308 nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4);
1309 nRght += rLine.GetLeftMargin();
1310 if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght )
1311 rRepaint.SetRightOfst( nRght );
1313 // Finally we enlarge the repaint rectangle if we found an underscore
1314 // within our line. 40 Twips should be enough
1315 const sal_Bool bHasUnderscore =
1316 ( rLine.GetInfo().GetUnderScorePos() < nNewStart );
1317 if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() )
1318 rRepaint.Bottom( rRepaint.Bottom() + 40 );
1320 ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore );
1322 if( !bUnChg )
1323 rLine.SetChanges();
1325 // Die gute, alte nDelta-Berechnung:
1326 *(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen);
1328 // Stop!
1329 if( rLine.IsStop() )
1330 return sal_False;
1332 // Unbedingt noch eine Zeile
1333 if( rLine.IsNewLine() )
1334 return sal_True;
1336 // bis zum Ende des Strings ?
1337 if( nNewStart >= GetTxtNode()->GetTxt().Len() )
1338 return sal_False;
1340 if( rLine.GetInfo().IsShift() )
1341 return sal_True;
1343 // Ende des Reformats erreicht ?
1344 const xub_StrLen nEnd = pPara->GetReformat()->Start() +
1345 pPara->GetReformat()->Len();
1347 if( nNewStart <= nEnd )
1348 return sal_True;
1350 return 0 != *(pPara->GetDelta());
1353 /*************************************************************************
1354 * SwTxtFrm::_Format()
1355 *************************************************************************/
1357 void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf,
1358 const sal_Bool bAdjust )
1360 ASSERT( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" );
1362 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1363 rLine.SetUnclipped( sal_False );
1365 // Das war dem C30 zu kompliziert: aString( GetTxt() );
1366 const XubString &rString = GetTxtNode()->GetTxt();
1367 const xub_StrLen nStrLen = rString.Len();
1369 SwCharRange &rReformat = *(pPara->GetReformat());
1370 SwRepaint &rRepaint = *(pPara->GetRepaint());
1371 SwRepaint *pFreeze = NULL;
1373 // Aus Performancegruenden wird in Init() rReformat auf STRING_LEN gesetzt.
1374 // Fuer diesen Fall wird rReformat angepasst.
1375 if( rReformat.Len() > nStrLen )
1376 rReformat.Len() = nStrLen;
1378 // Optimiert:
1379 xub_StrLen nEnd = rReformat.Start() + rReformat.Len();
1380 if( nEnd > nStrLen )
1382 rReformat.Len() = nStrLen - rReformat.Start();
1383 nEnd = nStrLen;
1386 SwTwips nOldBottom;
1387 if( GetOfst() && !IsFollow() )
1389 rLine.Bottom();
1390 nOldBottom = rLine.Y();
1391 rLine.Top();
1393 else
1394 nOldBottom = 0;
1395 rLine.CharToLine( rReformat.Start() );
1397 // Worte koennen durch Fortfall oder Einfuegen eines Space
1398 // auf die Zeile vor der editierten hinausgezogen werden,
1399 // deshalb muss diese ebenfalls formatiert werden.
1400 // Optimierung: Wenn rReformat erst hinter dem ersten Wort der
1401 // Zeile beginnt, so kann diese Zeile die vorige nicht mehr beeinflussen.
1402 // AMA: Leider doch, Textgroessenaenderungen + FlyFrames, die Rueckwirkung
1403 // kann im Extremfall mehrere Zeilen (Frames!!!) betreffen!
1405 // --> FME 2005-04-18 #i46560#
1406 // FME: Yes, consider this case: (word ) has to go to the next line
1407 // because ) is a forbidden character at the beginning of a line although
1408 // (word would still fit on the previous line. Adding text right in front
1409 // of ) would not trigger a reformatting of the previous line. Adding 1
1410 // to the result of FindBrk() does not solve the problem in all cases,
1411 // nevertheless it should be sufficient.
1412 // <--
1413 sal_Bool bPrev = rLine.GetPrev() &&
1414 ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 )
1415 // --> FME 2005-04-18 #i46560#
1417 // <--
1418 >= rReformat.Start() ||
1419 rLine.GetCurr()->IsRest() );
1420 if( bPrev )
1422 while( rLine.Prev() )
1423 if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() )
1425 if( !rLine.GetStart() )
1426 rLine.Top(); // damit NumDone nicht durcheinander kommt
1427 break;
1429 xub_StrLen nNew = rLine.GetStart() + rLine.GetLength();
1430 if( nNew )
1432 --nNew;
1433 if( CH_BREAK == rString.GetChar( nNew ) )
1435 ++nNew;
1436 rLine.Next();
1437 bPrev = sal_False;
1440 rReformat.Len() += rReformat.Start() - nNew;
1441 rReformat.Start() = nNew;
1444 rRepaint.SetOfst( 0 );
1445 rRepaint.SetRightOfst( 0 );
1446 rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
1447 if( pPara->IsMargin() )
1448 rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() );
1449 rRepaint.Top( rLine.Y() );
1450 // 6792: Rrand < LRand und Repaint
1451 if( 0 >= rRepaint.Width() )
1452 rRepaint.Width(1);
1453 WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 );
1455 // rLine steht jetzt auf der ersten Zeile, die formatiert werden
1456 // muss. Das Flag bFirst sorgt dafuer, dass nicht Next() gerufen wird.
1457 // Das ganze sieht verdreht aus, aber es muss sichergestellt werden,
1458 // dass bei IsBreakNow rLine auf der Zeile zum stehen kommt, die
1459 // nicht mehr passt.
1460 sal_Bool bFirst = sal_True;
1461 sal_Bool bFormat = sal_True;
1463 // 5383: Das CharToLine() kann uns auch in den roten Bereich fuehren.
1464 // In diesem Fall muessen wir zurueckwandern, bis die Zeile, die
1465 // nicht mehr passt in rLine eingestellt ist. Ansonsten geht Textmasse
1466 // verloren, weil der Ofst im Follow falsch eingestellt wird.
1468 // OD 2004-02-25 #i16128# - method renamed
1469 sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 )
1470 && aFrmBreak.IsBreakNowWidAndOrp( rLine );
1471 if( bBreak )
1473 sal_Bool bPrevDone = 0 != rLine.Prev();
1474 // OD 2004-02-25 #i16128# - method renamed
1475 while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) )
1476 bPrevDone = 0 != rLine.Prev();
1477 if( bPrevDone )
1479 aFrmBreak.SetKeep( sal_False );
1480 rLine.Next();
1482 rLine.TruncLines();
1484 // auf Nummer sicher:
1485 // OD 2004-02-25 #i16128# - method renamed
1486 bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) &&
1487 ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 );
1490 /* Bedeutung der folgenden Flags:
1491 Ist das Watch(End/Mid)Hyph-Flag gesetzt, so muss formatiert werden, wenn
1492 eine Trennung am (Zeilenende/Fly) vorliegt, sofern MaxHyph erreicht ist.
1493 Das Jump(End/Mid)Flag bedeutet, dass die naechste Zeile, bei der keine
1494 Trennung (Zeilenende/Fly) vorliegt, formatiert werden muss, da jetzt
1495 umgebrochen werden koennte, was vorher moeglicherweise durch MaxHyph
1496 verboten war.
1497 Watch(End/Mid)Hyph wird gesetzt, wenn die letzte formatierte Zeile eine
1498 Trennstelle erhalten hat, vorher aber keine hatte,
1499 Jump(End/Mid)Hyph, wenn eine Trennstelle verschwindet.
1501 sal_Bool bJumpEndHyph = sal_False,
1502 bWatchEndHyph = sal_False,
1503 bJumpMidHyph = sal_False,
1504 bWatchMidHyph = sal_False;
1506 const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet();
1507 sal_Bool bMaxHyph = ( 0 !=
1508 ( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) );
1509 if ( bMaxHyph )
1510 rLine.InitCntHyph();
1512 if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() )
1514 const SwLineLayout* pLine;
1516 SwTxtFrm *pMaster = FindMaster();
1517 ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
1518 if( !pMaster->HasPara() )
1519 pMaster->GetFormatted();
1520 SwTxtSizeInfo aInf( pMaster );
1521 SwTxtIter aMasterLine( pMaster, &aInf );
1522 aMasterLine.Bottom();
1523 pLine = aMasterLine.GetCurr();
1525 SwLinePortion* pRest =
1526 rLine.MakeRestPortion( pLine, GetOfst() );
1527 if( pRest )
1528 rInf.SetRest( pRest );
1529 else
1530 SetFieldFollow( sal_False );
1533 /* Zum Abbruchkriterium:
1534 * Um zu erkennen, dass eine Zeile nicht mehr auf die Seite passt,
1535 * muss sie formatiert werden. Dieser Ueberhang wird z.B. in AdjustFollow
1536 * wieder entfernt.
1537 * Eine weitere Komplikation: wenn wir der Master sind, so muessen
1538 * wir die Zeilen durchgehen, da es ja sein kann, dass eine Zeile
1539 * vom Follow in den Master rutschen kann.
1543 DBG_LOOP;
1544 if( bFirst )
1545 bFirst = sal_False;
1546 else
1548 if ( bMaxHyph )
1550 if ( rLine.GetCurr()->IsEndHyph() )
1551 rLine.CntEndHyph()++;
1552 else
1553 rLine.CntEndHyph() = 0;
1554 if ( rLine.GetCurr()->IsMidHyph() )
1555 rLine.CntMidHyph()++;
1556 else
1557 rLine.CntMidHyph() = 0;
1559 if( !rLine.Next() )
1561 if( !bFormat )
1563 SwLinePortion* pRest =
1564 rLine.MakeRestPortion( rLine.GetCurr(), rLine.GetEnd() );
1565 if( pRest )
1566 rInf.SetRest( pRest );
1568 rLine.Insert( new SwLineLayout() );
1569 rLine.Next();
1570 bFormat = sal_True;
1573 if ( !bFormat && bMaxHyph &&
1574 (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) )
1576 if ( rLine.GetCurr()->IsEndHyph() )
1578 if ( bWatchEndHyph )
1579 bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
1581 else
1583 bFormat = bJumpEndHyph;
1584 bWatchEndHyph = sal_False;
1585 bJumpEndHyph = sal_False;
1587 if ( rLine.GetCurr()->IsMidHyph() )
1589 if ( bWatchMidHyph && !bFormat )
1590 bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
1592 else
1594 bFormat = bFormat || bJumpMidHyph;
1595 bWatchMidHyph = sal_False;
1596 bJumpMidHyph = sal_False;
1599 if( bFormat )
1601 sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph();
1602 sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph();
1603 bFormat = FormatLine( rLine, bPrev );
1604 //9334: Es kann nur ein bPrev geben... (???)
1605 bPrev = sal_False;
1606 if ( bMaxHyph )
1608 if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph )
1610 bWatchEndHyph = !bOldEndHyph;
1611 bJumpEndHyph = bOldEndHyph;
1613 if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph )
1615 bWatchMidHyph = !bOldMidHyph;
1616 bJumpMidHyph = bOldMidHyph;
1621 if( !rInf.IsNewLine() )
1623 if( !bFormat )
1624 bFormat = 0 != rInf.GetRest();
1625 if( rInf.IsStop() || rInf.GetIdx() >= nStrLen )
1626 break;
1627 if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph &&
1628 !bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) )
1630 if( GetFollow() )
1632 while( rLine.Next() )
1633 ; //Nothing
1634 pFreeze = new SwRepaint( rRepaint ); // to minimize painting
1636 else
1637 break;
1640 // OD 2004-02-25 #i16128# - method renamed
1641 bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine);
1642 }while( !bBreak );
1644 if( pFreeze )
1646 rRepaint = *pFreeze;
1647 delete pFreeze;
1650 if( !rLine.IsStop() )
1652 // Wurde aller Text formatiert und gibt es noch weitere
1653 // Zeilenobjekte, dann sind diese jetzt ueberfluessig,
1654 // weil der Text kuerzer geworden ist.
1655 if( rLine.GetStart() + rLine.GetLength() >= nStrLen &&
1656 rLine.GetCurr()->GetNext() )
1658 rLine.TruncLines();
1659 rLine.SetTruncLines( sal_True );
1663 if( !rInf.IsTest() )
1665 // Bei OnceMore lohnt sich kein FormatAdjust
1666 if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() )
1668 FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() );
1670 if( rRepaint.HasArea() )
1671 SetRepaint();
1672 rLine.SetTruncLines( sal_False );
1673 if( nOldBottom ) // Bei "gescollten" Absaetzen wird
1674 { // noch ueberprueft, ob durch Schrumpfen
1675 rLine.Bottom(); // das Scrolling ueberfluessig wurde.
1676 SwTwips nNewBottom = rLine.Y();
1677 if( nNewBottom < nOldBottom )
1678 _SetOfst( 0 );
1683 /*************************************************************************
1684 * SwTxtFrm::Format()
1685 *************************************************************************/
1687 void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
1689 ASSERT( ! IsVertical() || IsSwapped(),
1690 "A frame is not swapped in SwTxtFrm::FormatOnceMore" );
1692 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1693 if( !pPara )
1694 return;
1696 // ggf gegen pPara
1697 KSHORT nOld = ((const SwTxtMargin&)rLine).GetDropHeight();
1698 sal_Bool bShrink = sal_False,
1699 bGrow = sal_False,
1700 bGoOn = rLine.IsOnceMore();
1701 sal_uInt8 nGo = 0;
1702 while( bGoOn )
1704 #ifdef DBGTXT
1705 aDbstream << "OnceMore!" << endl;
1706 #endif
1707 ++nGo;
1708 rInf.Init();
1709 rLine.Top();
1710 if( !rLine.GetDropFmt() )
1711 rLine.SetOnceMore( sal_False );
1712 SwCharRange aRange( 0, rInf.GetTxt().Len() );
1713 *(pPara->GetReformat()) = aRange;
1714 _Format( rLine, rInf );
1716 bGoOn = rLine.IsOnceMore();
1717 if( bGoOn )
1719 const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight();
1720 if( nOld == nNew )
1721 bGoOn = sal_False;
1722 else
1724 if( nOld > nNew )
1725 bShrink = sal_True;
1726 else
1727 bGrow = sal_True;
1729 if( bShrink == bGrow || 5 < nGo )
1730 bGoOn = sal_False;
1732 nOld = nNew;
1735 // 6107: Wenn was schief ging, muss noch einmal formatiert werden.
1736 if( !bGoOn )
1738 rInf.CtorInitTxtFormatInfo( this );
1739 rLine.CtorInitTxtFormatter( this, &rInf );
1740 rLine.SetDropLines( 1 );
1741 rLine.CalcDropHeight( 1 );
1742 SwCharRange aTmpRange( 0, rInf.GetTxt().Len() );
1743 *(pPara->GetReformat()) = aTmpRange;
1744 _Format( rLine, rInf, sal_True );
1745 // 8047: Wir painten alles...
1746 SetCompletePaint();
1752 /*************************************************************************
1753 * SwTxtFrm::_Format()
1754 *************************************************************************/
1757 void SwTxtFrm::_Format( SwParaPortion *pPara )
1759 const xub_StrLen nStrLen = GetTxt().Len();
1761 // AMA: Wozu soll das gut sein? Scheint mir zuoft zu einem kompletten
1762 // Formatieren und Repainten zu fuehren???
1763 // if ( !(*pPara->GetDelta()) )
1764 // *(pPara->GetDelta()) = nStrLen;
1765 // else
1766 if ( !nStrLen )
1768 // Leere Zeilen werden nicht lange gequaelt:
1769 // pPara wird blank geputzt
1770 // entspricht *pPara = SwParaPortion;
1771 sal_Bool bMustFit = pPara->IsPrepMustFit();
1772 pPara->Truncate();
1773 pPara->FormatReset();
1774 if( pBlink && pPara->IsBlinking() )
1775 pBlink->Delete( pPara );
1777 // delete pSpaceAdd und pKanaComp
1778 pPara->FinishSpaceAdd();
1779 pPara->FinishKanaComp();
1780 pPara->ResetFlags();
1781 pPara->SetPrepMustFit( bMustFit );
1784 ASSERT( ! IsSwapped(), "A frame is swapped before _Format" );
1786 if ( IsVertical() )
1787 SwapWidthAndHeight();
1789 SwTxtFormatInfo aInf( this );
1790 SwTxtFormatter aLine( this, &aInf );
1792 // OD 2004-01-15 #110582#
1793 HideAndShowObjects();
1795 _Format( aLine, aInf );
1797 if( aLine.IsOnceMore() )
1798 FormatOnceMore( aLine, aInf );
1800 if ( IsVertical() )
1801 SwapWidthAndHeight();
1803 ASSERT( ! IsSwapped(), "A frame is swapped after _Format" );
1805 if( 1 < aLine.GetDropLines() )
1807 if( SVX_ADJUST_LEFT != aLine.GetAdjust() &&
1808 SVX_ADJUST_BLOCK != aLine.GetAdjust() )
1810 aLine.CalcDropAdjust();
1811 aLine.SetPaintDrop( sal_True );
1814 if( aLine.IsPaintDrop() )
1816 aLine.CalcDropRepaint();
1817 aLine.SetPaintDrop( sal_False );
1822 /*************************************************************************
1823 * SwTxtFrm::Format()
1824 *************************************************************************/
1827 * Format berechnet die Groesse des Textframes und ruft, wenn
1828 * diese feststeht, Shrink() oder Grow(), um die Framegroesse dem
1829 * evtl. veraenderten Platzbedarf anzupassen.
1832 void SwTxtFrm::Format( const SwBorderAttrs * )
1834 DBG_LOOP;
1835 #if OSL_DEBUG_LEVEL > 1
1836 const XubString aXXX = GetTxtNode()->GetTxt();
1837 const SwTwips nDbgY = Frm().Top();
1838 (void)nDbgY;
1839 const SwPageFrm *pDbgPage = FindPageFrm();
1840 const MSHORT nDbgPageNr = pDbgPage->GetPhyPageNum();
1841 (void)nDbgPageNr;
1842 // Um zu gucken, ob es einen Ftn-Bereich gibt.
1843 const SwFrm *pDbgFtnCont = (const SwFrm*)(FindPageFrm()->FindFtnCont());
1844 (void)pDbgFtnCont;
1846 #ifndef PRODUCT
1847 // nStopAt laesst sich vom CV bearbeiten.
1848 static MSHORT nStopAt = 0;
1849 if( nStopAt == GetFrmId() )
1851 int i = GetFrmId();
1852 (void)i;
1854 #endif
1855 #endif
1857 #ifdef DEBUG_FTN
1858 //Fussnote darf nicht auf einer Seite vor ihrer Referenz stehen.
1859 if( IsInFtn() )
1861 const SwFtnFrm *pFtn = (SwFtnFrm*)GetUpper();
1862 const SwPageFrm *pFtnPage = pFtn->GetRef()->FindPageFrm();
1863 const MSHORT nFtnPageNr = pFtnPage->GetPhyPageNum();
1864 if( !IsLocked() )
1866 if( nFtnPageNr > nDbgPageNr )
1868 SwTxtFrmLocker aLock(this);
1869 ASSERT( nFtnPageNr <= nDbgPageNr, "!Ftn steht vor der Referenz." );
1870 MSHORT i = 0;
1874 #endif
1876 SWRECTFN( this )
1878 // --> OD 2008-01-31 #newlistlevelattrs#
1879 CalcAdditionalFirstLineOffset();
1880 // <--
1882 // Vom Berichtsautopiloten oder ueber die BASIC-Schnittstelle kommen
1883 // gelegentlich TxtFrms mit einer Breite <=0.
1884 if( (Prt().*fnRect->fnGetWidth)() <= 0 )
1886 // Wenn MustFit gesetzt ist, schrumpfen wir ggf. auf die Unterkante
1887 // des Uppers, ansonsten nehmen wir einfach eine Standardgroesse
1888 // von 12 Pt. ein (240 Twip).
1889 SwTxtLineAccess aAccess( this );
1890 long nFrmHeight = (Frm().*fnRect->fnGetHeight)();
1891 if( aAccess.GetPara()->IsPrepMustFit() )
1893 const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
1894 const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit );
1895 if( nDiff > 0 )
1896 Shrink( nDiff );
1898 else if( 240 < nFrmHeight )
1899 Shrink( nFrmHeight - 240 );
1900 else if( 240 > nFrmHeight )
1901 Grow( 240 - nFrmHeight );
1902 nFrmHeight = (Frm().*fnRect->fnGetHeight)();
1904 long nTop = (this->*fnRect->fnGetTopMargin)();
1905 if( nTop > nFrmHeight )
1906 (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 );
1907 else if( (Prt().*fnRect->fnGetHeight)() < 0 )
1908 (Prt().*fnRect->fnSetHeight)( 0 );
1909 return;
1912 const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len();
1913 if ( nStrLen || !FormatEmpty() )
1916 SetEmpty( sal_False );
1917 // Um nicht durch verschachtelte Formats irritiert zu werden.
1918 FormatLevel aLevel;
1919 if( 12 == aLevel.GetLevel() )
1920 return;
1922 // Die Formatinformationen duerfen u.U. nicht veraendert werden.
1923 if( IsLocked() )
1924 return;
1926 // 8708: Vorsicht, das Format() kann auch durch GetFormatted()
1927 // angestossen werden.
1928 if( IsHiddenNow() )
1930 long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
1931 if( nPrtHeight )
1933 HideHidden();
1934 Shrink( nPrtHeight );
1936 else
1938 // OD 2004-01-20 #110582# - assure that objects anchored
1939 // at paragraph resp. at/as character inside paragraph
1940 // are hidden.
1941 HideAndShowObjects();
1943 ChgThisLines();
1944 return;
1947 // Waehrend wir formatieren, wollen wir nicht gestoert werden.
1948 SwTxtFrmLocker aLock(this);
1949 SwTxtLineAccess aAccess( this );
1950 const sal_Bool bNew = !aAccess.SwTxtLineAccess::IsAvailable();
1951 const sal_Bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() );
1953 if( CalcPreps() )
1954 ; // nothing
1955 // Wir returnen, wenn schon formatiert wurde, nicht aber, wenn
1956 // der TxtFrm gerade erzeugt wurde und ueberhaupt keine Format-
1957 // informationen vorliegen.
1958 else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() )
1960 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1962 aAccess.GetPara()->SetPrepAdjust( sal_True );
1963 aAccess.GetPara()->SetPrep( sal_True );
1964 CalcPreps();
1966 SetWidow( sal_False );
1968 else if( bSetOfst && IsFollow() )
1970 SwTxtFrm *pMaster = FindMaster();
1971 ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
1972 if( pMaster )
1973 pMaster->Prepare( PREP_FOLLOW_FOLLOWS );
1974 SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)();
1975 if( (Frm().*fnRect->fnOverStep)( nMaxY ) )
1976 (this->*fnRect->fnSetLimit)( nMaxY );
1977 else if( (Frm().*fnRect->fnBottomDist)( nMaxY ) < 0 )
1978 (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() );
1980 else
1982 // bSetOfst here means that we have the "red arrow situation"
1983 if ( bSetOfst )
1984 _SetOfst( 0 );
1986 const sal_Bool bOrphan = IsWidow();
1987 const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0;
1988 SwTwips nFtnHeight = 0;
1989 if( pFtnBoss )
1991 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
1992 nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
1996 _Format( aAccess.GetPara() );
1997 if( pFtnBoss && nFtnHeight )
1999 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
2000 SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
2001 // If we lost some footnotes, we may have more space
2002 // for our main text, so we have to format again ...
2003 if( nNewHeight < nFtnHeight )
2004 nFtnHeight = nNewHeight;
2005 else
2006 break;
2008 else
2009 break;
2010 } while ( pFtnBoss );
2011 if( bOrphan )
2013 ValidateFrm();
2014 SetWidow( sal_False );
2017 if( IsEmptyMaster() )
2019 SwFrm* pPre = GetPrev();
2020 if( pPre &&
2021 // --> FME 2004-07-22 #i10826# It's the first, it cannot keep!
2022 pPre->GetIndPrev() &&
2023 // <--
2024 pPre->GetAttrSet()->GetKeep().GetValue() )
2026 pPre->InvalidatePos();
2031 ChgThisLines();
2033 // the PrepMustFit should not survive a Format operation
2034 SwParaPortion *pPara = GetPara();
2035 if ( pPara )
2036 pPara->SetPrepMustFit( sal_False );
2038 #if OSL_DEBUG_LEVEL > 1
2039 // Hier ein Instrumentarium, um ungewoehnlichen Master/Follow-Kombinationen,
2040 // insbesondere bei Fussnoten, auf die Schliche zu kommen
2041 if( IsFollow() || GetFollow() )
2043 SwTxtFrm *pTmpFrm = IsFollow() ? FindMaster() : this;
2044 const SwPageFrm *pTmpPage = pTmpFrm->FindPageFrm();
2045 MSHORT nPgNr = pTmpPage->GetPhyPageNum();
2046 MSHORT nLast;
2047 MSHORT nDummy = 0; // nur zum Breakpoint setzen
2048 while( pTmpFrm->GetFollow() )
2050 pTmpFrm = pTmpFrm->GetFollow();
2051 nLast = nPgNr;
2052 pTmpPage = pTmpFrm->FindPageFrm();
2053 nPgNr = pTmpPage->GetPhyPageNum();
2054 if( nLast > nPgNr )
2055 ++nDummy; // schon fast eine Assertion wert
2056 else if( nLast == nPgNr )
2057 ++nDummy; // bei Spalten voellig normal, aber sonst!?
2058 else if( nLast < nPgNr - 1 )
2059 ++nDummy; // kann schon mal temporaer vorkommen
2062 #endif
2064 CalcBaseOfstForFly();
2065 // OD 2004-03-17 #i11860#
2066 _CalcHeightOfLastLine();
2069 /*************************************************************************
2070 * SwTxtFrm::FormatQuick()
2072 * bForceQuickFormat is set if GetFormatted() has been called during the
2073 * painting process. Actually I cannot imagine a situation which requires
2074 * a full formatting of the paragraph during painting, on the other hand
2075 * a full formatting can cause the invalidation of other layout frames,
2076 * e.g., if there are footnotes in this paragraph, and invalid layout
2077 * frames will not calculated during the painting. So I actually want to
2078 * avoid a formatting during painting, but since I'm a coward, I'll only
2079 * force the quick formatting in the situation of issue i29062.
2080 *************************************************************************/
2082 sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat )
2084 ASSERT( ! IsVertical() || ! IsSwapped(),
2085 "SwTxtFrm::FormatQuick with swapped frame" );
2087 DBG_LOOP;
2088 #if OSL_DEBUG_LEVEL > 1
2089 const XubString aXXX = GetTxtNode()->GetTxt();
2090 const SwTwips nDbgY = Frm().Top();
2091 (void)nDbgY;
2092 #ifndef PRODUCT
2093 // nStopAt laesst sich vom CV bearbeiten.
2094 static MSHORT nStopAt = 0;
2095 if( nStopAt == GetFrmId() )
2097 int i = GetFrmId();
2098 (void)i;
2100 #endif
2101 #endif
2103 if( IsEmpty() && FormatEmpty() )
2104 return sal_True;
2106 // Wir sind sehr waehlerisch:
2107 if( HasPara() || IsWidow() || IsLocked()
2108 || !GetValidSizeFlag() ||
2109 ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) )
2110 return sal_False;
2112 SwTxtLineAccess aAccess( this );
2113 SwParaPortion *pPara = aAccess.GetPara();
2114 if( !pPara )
2115 return sal_False;
2117 SwFrmSwapper aSwapper( this, sal_True );
2119 SwTxtFrmLocker aLock(this);
2120 SwTxtFormatInfo aInf( this, sal_False, sal_True );
2121 if( 0 != aInf.MaxHyph() ) // 27483: MaxHyphen beachten!
2122 return sal_False;
2124 SwTxtFormatter aLine( this, &aInf );
2126 // DropCaps sind zu kompliziert...
2127 if( aLine.GetDropFmt() )
2128 return sal_False;
2130 xub_StrLen nStart = GetOfst();
2131 const xub_StrLen nEnd = GetFollow()
2132 ? GetFollow()->GetOfst() : aInf.GetTxt().Len();
2135 //DBG_LOOP; shadows declaration above.
2136 //resolved into:
2137 #if OSL_DEBUG_LEVEL > 1
2138 #ifndef PRODUCT
2139 DbgLoop aDbgLoop2( (const void*) this );
2140 #endif
2141 #endif
2142 nStart = aLine.FormatLine( nStart );
2143 if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) )
2144 aLine.Insert( new SwLineLayout() );
2145 } while( aLine.Next() );
2147 // Last exit: die Hoehen muessen uebereinstimmen.
2148 Point aTopLeft( Frm().Pos() );
2149 aTopLeft += Prt().Pos();
2150 const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight();
2151 const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height();
2153 if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() )
2155 // Achtung: Durch FormatLevel==12 kann diese Situation auftreten, don't panic!
2156 // ASSERT( nNewHeight == nOldHeight, "!FormatQuick: rosebud" );
2157 const xub_StrLen nStrt = GetOfst();
2158 _InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) );
2159 return sal_False;
2162 if( pFollow && nStart != ((SwTxtFrm*)pFollow)->GetOfst() )
2163 return sal_False; // kann z.B. durch Orphans auftreten (35083,35081)
2165 // Geschafft, wir sind durch ...
2167 // Repaint setzen
2168 pPara->GetRepaint()->Pos( aTopLeft );
2169 pPara->GetRepaint()->SSize( Prt().SSize() );
2171 // Reformat loeschen
2172 *(pPara->GetReformat()) = SwCharRange();
2173 *(pPara->GetDelta()) = 0;
2175 return sal_True;