update dev300-m58
[ooovba.git] / sw / source / core / text / txtfrm.cxx
blob5bceef690fdb8cd746ebd873a34ad9d22389d2a7
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: txtfrm.cxx,v $
10 * $Revision: 1.108.30.1 $
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"
33 #include <hintids.hxx>
34 #include <hints.hxx>
35 #include <svtools/ctloptions.hxx>
36 #include <sfx2/printer.hxx>
37 #include <sfx2/sfxuno.hxx>
38 #include <svx/langitem.hxx>
39 #include <svx/lspcitem.hxx>
40 #include <svx/lrspitem.hxx>
41 #include <svx/ulspitem.hxx>
42 #include <svx/brshitem.hxx>
43 #include <svx/pgrditem.hxx>
44 #include <swmodule.hxx>
45 #include <SwSmartTagMgr.hxx>
46 #include <doc.hxx> // GetDoc()
47 #include <pagefrm.hxx> // InvalidateSpelling
48 #include <rootfrm.hxx>
49 #include <viewsh.hxx> // ViewShell
50 #include <pam.hxx> // SwPosition
51 #include <ndtxt.hxx> // SwTxtNode
52 #include <txtatr.hxx>
53 #include <paratr.hxx>
54 #include <viewopt.hxx>
55 #include <dflyobj.hxx>
56 #include <flyfrm.hxx>
57 #include <tabfrm.hxx>
58 #include <frmtool.hxx>
59 #include <pagedesc.hxx> // SwPageDesc
60 #include <tgrditem.hxx>
61 #include <dbg_lay.hxx>
62 #include <fmtfld.hxx>
63 #include <fmtftn.hxx>
64 #include <txtfld.hxx>
65 #include <txtftn.hxx>
66 #include <charatr.hxx>
67 #include <ftninfo.hxx>
68 #ifndef _FMTLINE_HXX
69 #include <fmtline.hxx>
70 #endif
71 #include <txtfrm.hxx> // SwTxtFrm
72 #include <sectfrm.hxx> // SwSectFrm
73 #include <txtcfg.hxx> // DBG_LOOP
74 #include <itrform2.hxx> // Iteratoren
75 #include <widorp.hxx> // SwFrmBreak
76 #include <txtcache.hxx>
77 #include <fntcache.hxx> // GetLineSpace benutzt pLastFont
78 #include <SwGrammarMarkUp.hxx>
79 #ifndef _LINEINFO_HXX
80 #include <lineinfo.hxx>
81 #endif
82 #include <SwPortionHandler.hxx>
83 // OD 2004-01-15 #110582#
84 #include <dcontact.hxx>
85 // OD 2004-05-24 #i28701#
86 #include <sortedobjs.hxx>
87 // --> OD 2005-03-30 #???#
88 #include <txtflcnt.hxx> // SwTxtFlyCnt
89 #include <fmtflcnt.hxx> // SwFmtFlyCnt
90 #include <fmtcntnt.hxx> // SwFmtCntnt
91 // <--
92 // --> OD 2008-01-31 #newlistlevelattrs#
93 #include <numrule.hxx>
94 // <--
95 #include <swtable.hxx>
96 #include <fldupde.hxx>
97 #include <IGrammarContact.hxx>
99 #if OSL_DEBUG_LEVEL > 1
100 #include <txtpaint.hxx> // DbgRect
101 extern const sal_Char *GetPrepName( const enum PrepareHint ePrep );
102 #endif
104 TYPEINIT1( SwTxtFrm, SwCntntFrm );
106 // Switches width and height of the text frame
107 void SwTxtFrm::SwapWidthAndHeight()
109 if ( ! bIsSwapped )
111 const long nPrtOfstX = Prt().Pos().X();
112 Prt().Pos().X() = Prt().Pos().Y();
113 Prt().Pos().Y() = Frm().Width() - ( nPrtOfstX + Prt().Width() );
115 else
117 const long nPrtOfstY = Prt().Pos().Y();
118 Prt().Pos().Y() = Prt().Pos().X();
119 Prt().Pos().X() = Frm().Height() - ( nPrtOfstY + Prt().Height() );
122 const long nFrmWidth = Frm().Width();
123 Frm().Width( Frm().Height() );
124 Frm().Height( nFrmWidth );
125 const long nPrtWidth = Prt().Width();
126 Prt().Width( Prt().Height() );
127 Prt().Height( nPrtWidth );
129 bIsSwapped = ! bIsSwapped;
132 // Calculates the coordinates of a rectangle when switching from
133 // horizontal to vertical layout.
134 void SwTxtFrm::SwitchHorizontalToVertical( SwRect& rRect ) const
136 // calc offset inside frame
137 const long nOfstX = rRect.Left() - Frm().Left();
138 const long nOfstY = rRect.Top() + rRect.Height() - Frm().Top();
139 const long nWidth = rRect.Width();
140 const long nHeight = rRect.Height();
142 if ( bIsSwapped )
143 rRect.Left( Frm().Left() + Frm().Height() - nOfstY );
144 else
145 // frame is rotated
146 rRect.Left( Frm().Left() + Frm().Width() - nOfstY );
148 rRect.Top( Frm().Top() + nOfstX );
149 rRect.Width( nHeight );
150 rRect.Height( nWidth );
153 // Calculates the coordinates of a point when switching from
154 // horizontal to vertical layout.
155 void SwTxtFrm::SwitchHorizontalToVertical( Point& rPoint ) const
157 // calc offset inside frame
158 const long nOfstX = rPoint.X() - Frm().Left();
159 const long nOfstY = rPoint.Y() - Frm().Top();
161 if ( bIsSwapped )
162 rPoint.X() = Frm().Left() + Frm().Height() - nOfstY;
163 else
164 // calc rotated coords
165 rPoint.X() = Frm().Left() + Frm().Width() - nOfstY;
167 rPoint.Y() = Frm().Top() + nOfstX;
170 // Calculates the a limit value when switching from
171 // horizontal to vertical layout.
172 long SwTxtFrm::SwitchHorizontalToVertical( long nLimit ) const
174 Point aTmp( 0, nLimit );
175 SwitchHorizontalToVertical( aTmp );
176 return aTmp.X();
179 // Calculates the coordinates of a rectangle when switching from
180 // vertical to horizontal layout.
181 void SwTxtFrm::SwitchVerticalToHorizontal( SwRect& rRect ) const
183 long nOfstX;
185 // calc offset inside frame
186 if ( bIsSwapped )
187 nOfstX = Frm().Left() + Frm().Height() - ( rRect.Left() + rRect.Width() );
188 else
189 nOfstX = Frm().Left() + Frm().Width() - ( rRect.Left() + rRect.Width() );
191 const long nOfstY = rRect.Top() - Frm().Top();
192 const long nWidth = rRect.Height();
193 const long nHeight = rRect.Width();
195 // calc rotated coords
196 rRect.Left( Frm().Left() + nOfstY );
197 rRect.Top( Frm().Top() + nOfstX );
198 rRect.Width( nWidth );
199 rRect.Height( nHeight );
202 // Calculates the coordinates of a point when switching from
203 // vertical to horizontal layout.
204 void SwTxtFrm::SwitchVerticalToHorizontal( Point& rPoint ) const
206 long nOfstX;
208 // calc offset inside frame
209 if ( bIsSwapped )
210 nOfstX = Frm().Left() + Frm().Height() - rPoint.X();
211 else
212 nOfstX = Frm().Left() + Frm().Width() - rPoint.X();
214 const long nOfstY = rPoint.Y() - Frm().Top();
216 // calc rotated coords
217 rPoint.X() = Frm().Left() + nOfstY;
218 rPoint.Y() = Frm().Top() + nOfstX;
221 // Calculates the a limit value when switching from
222 // vertical to horizontal layout.
223 long SwTxtFrm::SwitchVerticalToHorizontal( long nLimit ) const
225 Point aTmp( nLimit, 0 );
226 SwitchVerticalToHorizontal( aTmp );
227 return aTmp.Y();
230 SwFrmSwapper::SwFrmSwapper( const SwTxtFrm* pTxtFrm, sal_Bool bSwapIfNotSwapped )
231 : pFrm( pTxtFrm ), bUndo( sal_False )
233 if ( pFrm->IsVertical() &&
234 ( ( bSwapIfNotSwapped && ! pFrm->IsSwapped() ) ||
235 ( ! bSwapIfNotSwapped && pFrm->IsSwapped() ) ) )
237 bUndo = sal_True;
238 ((SwTxtFrm*)pFrm)->SwapWidthAndHeight();
242 SwFrmSwapper::~SwFrmSwapper()
244 if ( bUndo )
245 ((SwTxtFrm*)pFrm)->SwapWidthAndHeight();
248 void SwTxtFrm::SwitchLTRtoRTL( SwRect& rRect ) const
250 SWAP_IF_NOT_SWAPPED( this )
252 long nWidth = rRect.Width();
253 rRect.Left( 2 * ( Frm().Left() + Prt().Left() ) +
254 Prt().Width() - rRect.Right() - 1 );
256 rRect.Width( nWidth );
258 UNDO_SWAP( this )
261 void SwTxtFrm::SwitchLTRtoRTL( Point& rPoint ) const
263 SWAP_IF_NOT_SWAPPED( this )
265 rPoint.X() = 2 * ( Frm().Left() + Prt().Left() ) + Prt().Width() - rPoint.X() - 1;
267 UNDO_SWAP( this )
270 SwLayoutModeModifier::SwLayoutModeModifier( const OutputDevice& rOutp ) :
271 rOut( rOutp ), nOldLayoutMode( rOutp.GetLayoutMode() )
275 SwLayoutModeModifier::~SwLayoutModeModifier()
277 ((OutputDevice&)rOut).SetLayoutMode( nOldLayoutMode );
280 void SwLayoutModeModifier::Modify( sal_Bool bChgToRTL )
282 ((OutputDevice&)rOut).SetLayoutMode( bChgToRTL ?
283 TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL :
284 TEXT_LAYOUT_BIDI_STRONG );
287 void SwLayoutModeModifier::SetAuto()
289 const ULONG nNewLayoutMode = nOldLayoutMode & ~TEXT_LAYOUT_BIDI_STRONG;
290 ((OutputDevice&)rOut).SetLayoutMode( nNewLayoutMode );
293 SwDigitModeModifier::SwDigitModeModifier( const OutputDevice& rOutp, LanguageType eCurLang ) :
294 rOut( rOutp ), nOldLanguageType( rOutp.GetDigitLanguage() )
296 LanguageType eLang = eCurLang;
297 const SvtCTLOptions::TextNumerals nTextNumerals = SW_MOD()->GetCTLOptions().GetCTLTextNumerals();
299 if ( SvtCTLOptions::NUMERALS_HINDI == nTextNumerals )
300 eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
301 else if ( SvtCTLOptions::NUMERALS_ARABIC == nTextNumerals )
302 eLang = LANGUAGE_ENGLISH;
303 else if ( SvtCTLOptions::NUMERALS_SYSTEM == nTextNumerals )
304 eLang = (LanguageType)::GetAppLanguage();
306 ((OutputDevice&)rOut).SetDigitLanguage( eLang );
309 SwDigitModeModifier::~SwDigitModeModifier()
311 ((OutputDevice&)rOut).SetDigitLanguage( nOldLanguageType );
314 /*************************************************************************
315 * SwTxtFrm::Init()
316 *************************************************************************/
318 void SwTxtFrm::Init()
320 ASSERT( !IsLocked(), "+SwTxtFrm::Init: this ist locked." );
321 if( !IsLocked() )
323 ClearPara();
324 ResetBlinkPor();
325 //Die Flags direkt setzen um ResetPreps und damit ein unnuetzes GetPara
326 //einzusparen.
327 // Nicht bOrphan, bLocked oder bWait auf sal_False setzen !
328 // bOrphan = bFlag7 = bFlag8 = sal_False;
332 /*************************************************************************
333 |* SwTxtFrm::CTORen/DTOR
334 |*************************************************************************/
336 void SwTxtFrm::InitCtor()
338 nCacheIdx = MSHRT_MAX;
339 nOfst = 0;
340 nAllLines = 0;
341 nThisLines = 0;
342 mnFlyAnchorOfst = 0;
343 mnFlyAnchorOfstNoWrap = 0;
344 mnFtnLine = 0;
345 // OD 2004-03-17 #i11860#
346 mnHeightOfLastLine = 0;
347 // --> OD 2008-01-31 #newlistlevelattrs#
348 mnAdditionalFirstLineOffset = 0;
349 // <--
351 nType = FRMC_TXT;
352 bLocked = bFormatted = bWidow = bUndersized = bJustWidow =
353 bEmpty = bInFtnConnect = bFtn = bRepaint = bBlinkPor =
354 bFieldFollow = bHasAnimation = bIsSwapped = sal_False;
355 // OD 14.03.2003 #i11760#
356 mbFollowFormatAllowed = sal_True;
359 /*************************************************************************
360 * SwTxtFrm::SwTxtFrm()
361 *************************************************************************/
362 SwTxtFrm::SwTxtFrm(SwTxtNode * const pNode)
363 : SwCntntFrm(pNode)
365 InitCtor();
368 /*************************************************************************
369 * SwTxtFrm::~SwTxtFrm()
370 *************************************************************************/
371 SwTxtFrm::~SwTxtFrm()
373 // Remove associated SwParaPortion from pTxtCache
374 ClearPara();
377 const XubString& SwTxtFrm::GetTxt() const
379 return GetTxtNode()->GetTxt();
382 void SwTxtFrm::ResetPreps()
384 if ( GetCacheIdx() != MSHRT_MAX )
386 SwParaPortion *pPara;
387 if( 0 != (pPara = GetPara()) )
388 pPara->ResetPreps();
392 /*************************************************************************
393 * SwTxtFrm::IsHiddenNow()
394 *************************************************************************/
395 sal_Bool SwTxtFrm::IsHiddenNow() const
397 SwFrmSwapper aSwapper( this, sal_True );
399 if( !Frm().Width() && IsValid() && GetUpper()->IsValid() )
400 //bei Stackueberlauf (StackHack) invalid!
402 // ASSERT( false, "SwTxtFrm::IsHiddenNow: thin frame" );
403 return sal_True;
406 const bool bHiddenCharsHidePara = GetTxtNode()->HasHiddenCharAttribute( true );
407 const bool bHiddenParaField = GetTxtNode()->HasHiddenParaField();
408 const ViewShell* pVsh = GetShell();
410 if ( pVsh && ( bHiddenCharsHidePara || bHiddenParaField ) )
412 if (
413 ( bHiddenParaField &&
414 ( !pVsh->GetViewOptions()->IsShowHiddenPara() &&
415 !pVsh->GetViewOptions()->IsFldName() ) ) ||
416 ( bHiddenCharsHidePara &&
417 !pVsh->GetViewOptions()->IsShowHiddenChar() ) )
419 return sal_True;
423 return sal_False;
427 /*************************************************************************
428 * SwTxtFrm::HideHidden()
429 *************************************************************************/
430 // Entfernt die Anhaengsel des Textfrms wenn dieser hidden ist
432 void SwTxtFrm::HideHidden()
434 ASSERT( !GetFollow() && IsHiddenNow(),
435 "HideHidden on visible frame of hidden frame has follow" );
437 const xub_StrLen nEnd = STRING_LEN;
438 HideFootnotes( GetOfst(), nEnd );
439 // OD 2004-01-15 #110582#
440 HideAndShowObjects();
442 //Die Formatinfos sind jetzt obsolete
443 ClearPara();
446 /*************************************************************************
447 * SwTxtFrm::HideFootnotes()
448 *************************************************************************/
449 void SwTxtFrm::HideFootnotes( xub_StrLen nStart, xub_StrLen nEnd )
451 const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
452 if( pHints )
454 const USHORT nSize = pHints->Count();
455 SwPageFrm *pPage = 0;
456 for ( USHORT i = 0; i < nSize; ++i )
458 const SwTxtAttr *pHt = (*pHints)[i];
459 if ( pHt->Which() == RES_TXTATR_FTN )
461 const xub_StrLen nIdx = *pHt->GetStart();
462 if ( nEnd < nIdx )
463 break;
464 if( nStart <= nIdx )
466 if( !pPage )
467 pPage = FindPageFrm();
468 pPage->RemoveFtn( this, (SwTxtFtn*)pHt );
475 // --> OD 2005-03-30 #120729# - hotfix: WW8 documents contain at its end hidden,
476 // as-character anchored graphics, which are used for a graphic bullet list.
477 // As long as these graphic bullet list aren't imported, do not hide a
478 // at-character anchored object, if
479 // (a) the document is an imported WW8 document -
480 // checked by checking certain compatibility options -,
481 // (b) the paragraph is the last content in the document and
482 // (c) the anchor character is an as-character anchored graphic.
483 bool lcl_HideObj( const SwTxtFrm& _rFrm,
484 const RndStdIds _eAnchorType,
485 const xub_StrLen _nObjAnchorPos,
486 SwAnchoredObject* _pAnchoredObj )
488 bool bRet( true );
490 if ( _eAnchorType == FLY_AUTO_CNTNT )
492 const IDocumentSettingAccess* pIDSA = _rFrm.GetTxtNode()->getIDocumentSettingAccess();
493 if ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
494 !pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING) &&
495 !pIDSA->get(IDocumentSettingAccess::USE_FORMER_OBJECT_POS) &&
496 pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
497 _rFrm.IsInDocBody() && !_rFrm.FindNextCnt() )
499 const xub_Unicode cAnchorChar =
500 _rFrm.GetTxtNode()->GetTxt().GetChar( _nObjAnchorPos );
501 if ( cAnchorChar == CH_TXTATR_BREAKWORD )
503 SwpHints* pHints =
504 const_cast<SwTxtFrm&>(_rFrm).GetTxtNode()->GetpSwpHints();
505 const SwTxtAttr* pHint( 0 );
506 if( pHints )
508 for ( USHORT i = 0; i < pHints->Count(); ++i )
510 SwTxtAttr* pPos = pHints->GetTextHint(i);
511 xub_StrLen nStart = *pPos->GetStart();
512 if ( _nObjAnchorPos < nStart )
513 break;
514 if ( _nObjAnchorPos == nStart && !pPos->GetEnd() )
516 pHint = pPos;
517 break;
521 if ( pHint &&
522 pHint->Which() == RES_TXTATR_FLYCNT )
524 const SwFrmFmt* pFrmFmt =
525 static_cast<const SwTxtFlyCnt*>(pHint)->GetFlyCnt().GetFrmFmt();
526 if ( pFrmFmt->Which() == RES_FLYFRMFMT )
528 SwNodeIndex nCntntIndex = *(pFrmFmt->GetCntnt().GetCntntIdx());
529 nCntntIndex++;
530 if ( nCntntIndex.GetNode().IsNoTxtNode() )
532 bRet = false;
533 // set needed data structure values for object positioning
534 SWRECTFN( (&_rFrm) );
535 SwRect aLastCharRect( _rFrm.Frm() );
536 (aLastCharRect.*fnRect->fnSetWidth)( 1 );
537 _pAnchoredObj->maLastCharRect = aLastCharRect;
538 _pAnchoredObj->mnLastTopOfLine = (aLastCharRect.*fnRect->fnGetTop)();
546 return bRet;
548 // <--
549 /*************************************************************************
550 * SwTxtFrm::HideAndShowObjects()
551 *************************************************************************/
552 /** method to hide/show objects
554 OD 2004-01-15 #110582#
555 method hides respectively shows objects, which are anchored at paragraph,
556 at/as a character of the paragraph, corresponding to the paragraph and
557 paragraph portion visibility.
559 - is called from HideHidden() - should hide objects in hidden paragraphs and
560 - from _Format() - should hide/show objects in partly visible paragraphs
562 @author OD
564 void SwTxtFrm::HideAndShowObjects()
566 if ( GetDrawObjs() )
568 if ( IsHiddenNow() )
570 // complete paragraph is hidden. Thus, hide all objects
571 for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i )
573 SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
574 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
575 // --> OD 2005-03-30 #120729# - hotfix: do not hide object
576 // under certain conditions
577 const RndStdIds eAnchorType( pContact->GetAnchorId() );
578 const xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex();
579 if ( eAnchorType != FLY_AUTO_CNTNT ||
580 lcl_HideObj( *this, eAnchorType, nObjAnchorPos, (*GetDrawObjs())[i] ) )
582 pContact->MoveObjToInvisibleLayer( pObj );
584 // <--
587 else
589 // paragraph is visible, but can contain hidden text portion.
590 // first we check if objects are allowed to be hidden:
591 const SwTxtNode& rNode = *GetTxtNode();
592 const ViewShell* pVsh = GetShell();
593 const bool bShouldBeHidden = !pVsh || !pVsh->GetWin() ||
594 !pVsh->GetViewOptions()->IsShowHiddenChar();
596 // Thus, show all objects, which are anchored at paragraph and
597 // hide/show objects, which are anchored at/as character, according
598 // to the visibility of the anchor character.
599 for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i )
601 SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
602 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
603 // --> OD 2005-03-30 #120729# - determine anchor type only once
604 const RndStdIds eAnchorType( pContact->GetAnchorId() );
605 // <--
607 if ( eAnchorType == FLY_AT_CNTNT )
609 pContact->MoveObjToVisibleLayer( pObj );
611 else if ( eAnchorType == FLY_AUTO_CNTNT ||
612 eAnchorType == FLY_IN_CNTNT )
614 xub_StrLen nHiddenStart;
615 xub_StrLen nHiddenEnd;
616 xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex();
617 SwScriptInfo::GetBoundsOfHiddenRange( rNode, nObjAnchorPos, nHiddenStart, nHiddenEnd, 0 );
618 // --> OD 2005-03-30 #120729# - hotfix: do not hide object
619 // under certain conditions
620 if ( nHiddenStart != STRING_LEN && bShouldBeHidden &&
621 lcl_HideObj( *this, eAnchorType, nObjAnchorPos, (*GetDrawObjs())[i] ) )
622 // <--
623 pContact->MoveObjToInvisibleLayer( pObj );
624 else
625 pContact->MoveObjToVisibleLayer( pObj );
627 else
629 ASSERT( false,
630 "<SwTxtFrm::HideAndShowObjects()> - object not anchored at/inside paragraph!?" );
636 if ( IsFollow() )
638 FindMaster()->HideAndShowObjects();
642 /*************************************************************************
643 * SwTxtFrm::FindBrk()
645 * Liefert die erste Trennmoeglichkeit in der aktuellen Zeile zurueck.
646 * Die Methode wird in SwTxtFrm::Format() benutzt, um festzustellen, ob
647 * die Vorgaengerzeile mitformatiert werden muss.
648 * nFound ist <= nEndLine.
649 *************************************************************************/
651 xub_StrLen SwTxtFrm::FindBrk( const XubString &rTxt,
652 const xub_StrLen nStart, const xub_StrLen nEnd ) const
654 xub_StrLen nFound = nStart;
655 const xub_StrLen nEndLine = Min( nEnd, rTxt.Len() );
657 // Wir ueberlesen erst alle Blanks am Anfang der Zeile (vgl. Bug 2235).
658 while( nFound <= nEndLine && ' ' == rTxt.GetChar( nFound ) )
659 ++nFound;
661 // Eine knifflige Sache mit den TxtAttr-Dummy-Zeichen (hier "$"):
662 // "Dr.$Meyer" am Anfang der zweiten Zeile. Dahinter ein Blank eingegeben
663 // und das Wort rutscht nicht in die erste Zeile, obwohl es ginge.
664 // Aus diesem Grund nehmen wir das Dummy-Zeichen noch mit.
665 while( nFound <= nEndLine && ' ' != rTxt.GetChar( nFound ) )
666 ++nFound;
668 return nFound;
671 /*************************************************************************
672 * SwTxtFrm::IsIdxInside()
673 *************************************************************************/
675 sal_Bool SwTxtFrm::IsIdxInside( const xub_StrLen nPos, const xub_StrLen nLen ) const
677 if( GetOfst() > nPos + nLen ) // d.h., der Bereich liegt komplett vor uns.
678 return sal_False;
680 if( !GetFollow() ) // der Bereich liegt nicht komplett vor uns,
681 return sal_True; // nach uns kommt niemand mehr.
683 const xub_StrLen nMax = GetFollow()->GetOfst();
685 // der Bereich liegt nicht komplett hinter uns bzw.
686 // unser Text ist geloescht worden.
687 if( nMax > nPos || nMax > GetTxt().Len() )
688 return sal_True;
690 // changes made in the first line of a follow can modify the master
691 const SwParaPortion* pPara = GetFollow()->GetPara();
692 return pPara && ( nPos <= nMax + pPara->GetLen() );
695 /*************************************************************************
696 * SwTxtFrm::InvalidateRange()
697 *************************************************************************/
698 inline void SwTxtFrm::InvalidateRange(const SwCharRange &aRange, const long nD)
700 if ( IsIdxInside( aRange.Start(), aRange.Len() ) )
701 _InvalidateRange( aRange, nD );
704 /*************************************************************************
705 * SwTxtFrm::_InvalidateRange()
706 *************************************************************************/
708 void SwTxtFrm::_InvalidateRange( const SwCharRange &aRange, const long nD)
710 if ( !HasPara() )
711 { InvalidateSize();
712 return;
715 SetWidow( sal_False );
716 SwParaPortion *pPara = GetPara();
718 sal_Bool bInv = sal_False;
719 if( 0 != nD )
721 //Auf nDelta werden die Differenzen zwischen alter und
722 //neuer Zeilenlaenge aufaddiert, deshalb ist es negativ,
723 //wenn Zeichen eingefuegt wurden, positiv, wenn Zeichen
724 //geloescht wurden.
725 *(pPara->GetDelta()) += nD;
726 bInv = sal_True;
728 SwCharRange &rReformat = *(pPara->GetReformat());
729 if(aRange != rReformat) {
730 if( STRING_LEN == rReformat.Len() )
731 rReformat = aRange;
732 else
733 rReformat += aRange;
734 bInv = sal_True;
736 if(bInv)
738 // 90365: nD is passed to a follow two times
739 // if( GetFollow() )
740 // ((SwTxtFrm*)GetFollow())->InvalidateRange( aRange, nD );
741 InvalidateSize();
745 /*************************************************************************
746 * SwTxtFrm::CalcLineSpace()
747 *************************************************************************/
749 void SwTxtFrm::CalcLineSpace()
751 ASSERT( ! IsVertical() || ! IsSwapped(),
752 "SwTxtFrm::CalcLineSpace with swapped frame!" )
754 if( IsLocked() || !HasPara() )
755 return;
757 SwParaPortion *pPara;
758 if( GetDrawObjs() ||
759 GetTxtNode()->GetSwAttrSet().GetLRSpace().IsAutoFirst() ||
760 ( pPara = GetPara() )->IsFixLineHeight() )
762 Init();
763 return;
766 Size aNewSize( Prt().SSize() );
768 SwTxtFormatInfo aInf( this );
769 SwTxtFormatter aLine( this, &aInf );
770 if( aLine.GetDropLines() )
772 Init();
773 return;
776 aLine.Top();
777 aLine.RecalcRealHeight();
779 aNewSize.Height() = (aLine.Y() - Frm().Top()) + aLine.GetLineHeight();
781 SwTwips nDelta = aNewSize.Height() - Prt().Height();
782 // 4291: Unterlauf bei Flys
783 if( aInf.GetTxtFly()->IsOn() )
785 SwRect aTmpFrm( Frm() );
786 if( nDelta < 0 )
787 aTmpFrm.Height( Prt().Height() );
788 else
789 aTmpFrm.Height( aNewSize.Height() );
790 if( aInf.GetTxtFly()->Relax( aTmpFrm ) )
792 Init();
793 return;
797 if( nDelta )
799 SwTxtFrmBreak aBreak( this );
800 if( GetFollow() || aBreak.IsBreakNow( aLine ) )
802 // Wenn es einen Follow() gibt, oder wenn wir an dieser
803 // Stelle aufbrechen muessen, so wird neu formatiert.
804 Init();
806 else
808 // Alles nimmt seinen gewohnten Gang ...
809 pPara->SetPrepAdjust();
810 pPara->SetPrep();
816 // SET_WRONG( nPos, nCnt, bMove )
818 #define SET_WRONG( nPos, nCnt, bMove ) \
820 lcl_SetWrong( *this, nPos, nCnt, bMove ); \
823 void lcl_SetWrong( SwTxtFrm& rFrm, xub_StrLen nPos, long nCnt, bool bMove )
825 if ( !rFrm.IsFollow() )
827 SwTxtNode* pTxtNode = rFrm.GetTxtNode();
828 IGrammarContact* pGrammarContact = getGrammarContact( *pTxtNode );
829 SwGrammarMarkUp* pWrongGrammar = pGrammarContact ?
830 pGrammarContact->getGrammarCheck( *pTxtNode, false ) :
831 pTxtNode->GetGrammarCheck();
832 bool bGrammarProxy = pWrongGrammar != pTxtNode->GetGrammarCheck();
833 if( bMove )
835 if( pTxtNode->GetWrong() )
836 pTxtNode->GetWrong()->Move( nPos, nCnt );
837 if( pWrongGrammar )
838 pWrongGrammar->MoveGrammar( nPos, nCnt );
839 if( bGrammarProxy && pTxtNode->GetGrammarCheck() )
840 pTxtNode->GetGrammarCheck()->MoveGrammar( nPos, nCnt );
841 if( pTxtNode->GetSmartTags() )
842 pTxtNode->GetSmartTags()->Move( nPos, nCnt );
844 else
846 xub_StrLen nLen = (xub_StrLen)nCnt;
847 if( pTxtNode->GetWrong() )
848 pTxtNode->GetWrong()->Invalidate( nPos, nLen );
849 if( pWrongGrammar )
850 pWrongGrammar->Invalidate( nPos, nLen );
851 if( pTxtNode->GetSmartTags() )
852 pTxtNode->GetSmartTags()->Invalidate( nPos, nLen );
854 if ( !pTxtNode->GetWrong() && !pTxtNode->IsWrongDirty() )
856 pTxtNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
857 pTxtNode->GetWrong()->SetInvalid( nPos, nPos + (USHORT)( nCnt > 0 ? nCnt : 1 ) );
859 if ( !pTxtNode->GetSmartTags() && !pTxtNode->IsSmartTagDirty() )
861 // SMARTTAGS
862 pTxtNode->SetSmartTags( new SwWrongList( WRONGLIST_SMARTTAG ) );
863 pTxtNode->GetSmartTags()->SetInvalid( nPos, nPos + (USHORT)( nCnt > 0 ? nCnt : 1 ) );
865 pTxtNode->SetWrongDirty( true );
866 pTxtNode->SetGrammarCheckDirty( true );
867 pTxtNode->SetWordCountDirty( true );
868 pTxtNode->SetAutoCompleteWordDirty( true );
869 // SMARTTAGS
870 pTxtNode->SetSmartTagDirty( true );
873 SwRootFrm *pRootFrm = rFrm.FindRootFrm();
874 if (pRootFrm)
876 pRootFrm->SetNeedGrammarCheck( TRUE );
879 SwPageFrm *pPage = rFrm.FindPageFrm();
880 if( pPage )
882 pPage->InvalidateSpelling();
883 pPage->InvalidateAutoCompleteWords();
884 pPage->InvalidateWordCount();
885 pPage->InvalidateSmartTags();
890 // SET_SCRIPT_INVAL( nPos )
893 #define SET_SCRIPT_INVAL( nPos )\
894 lcl_SetScriptInval( *this, nPos );
896 void lcl_SetScriptInval( SwTxtFrm& rFrm, xub_StrLen nPos )
898 if( rFrm.GetPara() )
899 rFrm.GetPara()->GetScriptInfo().SetInvalidity( nPos );
902 void lcl_ModifyOfst( SwTxtFrm* pFrm, xub_StrLen nPos, xub_StrLen nLen )
904 while( pFrm && pFrm->GetOfst() <= nPos )
905 pFrm = pFrm->GetFollow();
906 while( pFrm )
908 pFrm->ManipOfst( pFrm->GetOfst() + nLen );
909 pFrm = pFrm->GetFollow();
913 /*************************************************************************
914 * SwTxtFrm::Modify()
915 *************************************************************************/
917 void SwTxtFrm::Modify( SfxPoolItem *pOld, SfxPoolItem *pNew )
919 const MSHORT nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
921 //Wuensche die FrmAttribute betreffen werden von der Basisklasse
922 //verarbeitet.
923 if( IsInRange( aFrmFmtSetRange, nWhich ) || RES_FMT_CHG == nWhich )
925 SwCntntFrm::Modify( pOld, pNew );
926 if( nWhich == RES_FMT_CHG && GetShell() )
928 // Collection hat sich geaendert
929 Prepare( PREP_CLEAR );
930 _InvalidatePrt();
931 SET_WRONG( 0, STRING_LEN, false );
932 SetDerivedR2L( sal_False );
933 CheckDirChange();
934 // OD 09.12.2002 #105576# - Force complete paint due to existing
935 // indents.
936 SetCompletePaint();
937 InvalidateLineNum();
939 return;
942 // Im gelockten Zustand werden keine Bestellungen angenommen.
943 if( IsLocked() )
944 return;
946 // Dies spart Stack, man muss nur aufpassen,
947 // dass sie Variablen gesetzt werden.
948 xub_StrLen nPos, nLen;
949 sal_Bool bSetFldsDirty = sal_False;
950 sal_Bool bRecalcFtnFlag = sal_False;
952 switch( nWhich )
954 case RES_LINENUMBER:
956 InvalidateLineNum();
958 break;
959 case RES_INS_CHR:
961 nPos = ((SwInsChr*)pNew)->nPos;
962 InvalidateRange( SwCharRange( nPos, 1 ), 1 );
963 SET_WRONG( nPos, 1, true )
964 SET_SCRIPT_INVAL( nPos )
965 bSetFldsDirty = sal_True;
966 if( HasFollow() )
967 lcl_ModifyOfst( this, nPos, 1 );
969 break;
970 case RES_INS_TXT:
972 nPos = ((SwInsTxt*)pNew)->nPos;
973 nLen = ((SwInsTxt*)pNew)->nLen;
974 if( IsIdxInside( nPos, nLen ) )
976 if( !nLen )
978 // 6969: Aktualisierung der NumPortions auch bei leeren Zeilen!
979 if( nPos )
980 InvalidateSize();
981 else
982 Prepare( PREP_CLEAR );
984 else
985 _InvalidateRange( SwCharRange( nPos, nLen ), nLen );
987 SET_WRONG( nPos, nLen, true )
988 SET_SCRIPT_INVAL( nPos )
989 bSetFldsDirty = sal_True;
990 if( HasFollow() )
991 lcl_ModifyOfst( this, nPos, nLen );
993 break;
994 case RES_DEL_CHR:
996 nPos = ((SwDelChr*)pNew)->nPos;
997 InvalidateRange( SwCharRange( nPos, 1 ), -1 );
998 SET_WRONG( nPos, -1, true )
999 SET_SCRIPT_INVAL( nPos )
1000 bSetFldsDirty = bRecalcFtnFlag = sal_True;
1001 if( HasFollow() )
1002 lcl_ModifyOfst( this, nPos, STRING_LEN );
1004 break;
1005 case RES_DEL_TXT:
1007 nPos = ((SwDelTxt*)pNew)->nStart;
1008 nLen = ((SwDelTxt*)pNew)->nLen;
1009 long m = nLen;
1010 m *= -1;
1011 if( IsIdxInside( nPos, nLen ) )
1013 if( !nLen )
1014 InvalidateSize();
1015 else
1016 InvalidateRange( SwCharRange( nPos, 1 ), m );
1018 SET_WRONG( nPos, m, true )
1019 SET_SCRIPT_INVAL( nPos )
1020 bSetFldsDirty = bRecalcFtnFlag = sal_True;
1021 if( HasFollow() )
1022 lcl_ModifyOfst( this, nPos, nLen );
1024 break;
1025 case RES_UPDATE_ATTR:
1027 nPos = ((SwUpdateAttr*)pNew)->nStart;
1028 nLen = ((SwUpdateAttr*)pNew)->nEnd - nPos;
1029 if( IsIdxInside( nPos, nLen ) )
1031 // Es muss in jedem Fall neu formatiert werden,
1032 // auch wenn der invalidierte Bereich null ist.
1033 // Beispiel: leere Zeile, 14Pt einstellen !
1034 // if( !nLen ) nLen = 1;
1036 // 6680: FtnNummern muessen formatiert werden.
1037 if( !nLen )
1038 nLen = 1;
1040 _InvalidateRange( SwCharRange( nPos, nLen) );
1041 MSHORT nTmp = ((SwUpdateAttr*)pNew)->nWhichAttr;
1043 if( ! nTmp || RES_TXTATR_CHARFMT == nTmp || RES_TXTATR_AUTOFMT == nTmp ||
1044 RES_FMT_CHG == nTmp || RES_ATTRSET_CHG == nTmp )
1046 SET_WRONG( nPos, nPos + nLen, false )
1047 SET_SCRIPT_INVAL( nPos )
1051 break;
1052 case RES_OBJECTDYING:
1053 break;
1055 case RES_PARATR_LINESPACING:
1057 CalcLineSpace();
1058 InvalidateSize();
1059 _InvalidatePrt();
1060 if( IsInSct() && !GetPrev() )
1062 SwSectionFrm *pSect = FindSctFrm();
1063 if( pSect->ContainsAny() == this )
1064 pSect->InvalidatePrt();
1067 // OD 09.01.2004 #i11859# - correction:
1068 // (1) Also invalidate next frame on next page/column.
1069 // (2) Skip empty sections and hidden paragraphs
1070 // Thus, use method <InvalidateNextPrtArea()>
1071 InvalidateNextPrtArea();
1073 SetCompletePaint();
1075 break;
1076 case RES_TXTATR_FIELD:
1078 nPos = *((SwFmtFld*)pNew)->GetTxtFld()->GetStart();
1079 if( IsIdxInside( nPos, 1 ) )
1081 if( pNew == pOld )
1083 // Nur repainten
1084 // opt: invalidate aufs Window ?
1085 InvalidatePage();
1086 SetCompletePaint();
1088 else
1089 _InvalidateRange( SwCharRange( nPos, 1 ) );
1091 bSetFldsDirty = sal_True;
1092 // ST2
1093 if ( SwSmartTagMgr::Get().IsSmartTagsEnabled() )
1094 SET_WRONG( nPos, nPos + 1, false )
1096 break;
1097 case RES_TXTATR_FTN :
1099 nPos = *((SwFmtFtn*)pNew)->GetTxtFtn()->GetStart();
1100 if( IsInFtn() || IsIdxInside( nPos, 1 ) )
1101 Prepare( PREP_FTN, ((SwFmtFtn*)pNew)->GetTxtFtn() );
1102 break;
1105 case RES_ATTRSET_CHG:
1107 InvalidateLineNum();
1109 SwAttrSet& rNewSet = *((SwAttrSetChg*)pNew)->GetChgSet();
1110 const SfxPoolItem* pItem;
1111 int nClear = 0;
1112 MSHORT nCount = rNewSet.Count();
1114 if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FTN,
1115 sal_False, &pItem ))
1117 nPos = *((SwFmtFtn*)pItem)->GetTxtFtn()->GetStart();
1118 if( IsIdxInside( nPos, 1 ) )
1119 Prepare( PREP_FTN, pNew );
1120 nClear = 0x01;
1121 --nCount;
1124 if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FIELD,
1125 sal_False, &pItem ))
1127 nPos = *((SwFmtFld*)pItem)->GetTxtFld()->GetStart();
1128 if( IsIdxInside( nPos, 1 ) )
1130 const SfxPoolItem& rOldItem = ((SwAttrSetChg*)pOld)->
1131 GetChgSet()->Get( RES_TXTATR_FIELD );
1132 if( pItem == &rOldItem )
1134 // Nur repainten
1135 // opt: invalidate aufs Window ?
1136 InvalidatePage();
1137 SetCompletePaint();
1139 else
1140 _InvalidateRange( SwCharRange( nPos, 1 ) );
1142 nClear |= 0x02;
1143 --nCount;
1145 sal_Bool bLineSpace = SFX_ITEM_SET == rNewSet.GetItemState(
1146 RES_PARATR_LINESPACING, sal_False ),
1147 bRegister = SFX_ITEM_SET == rNewSet.GetItemState(
1148 RES_PARATR_REGISTER, sal_False );
1149 if ( bLineSpace || bRegister )
1151 Prepare( bRegister ? PREP_REGISTER : PREP_ADJUST_FRM );
1152 CalcLineSpace();
1153 InvalidateSize();
1154 _InvalidatePrt();
1156 // OD 09.01.2004 #i11859# - correction:
1157 // (1) Also invalidate next frame on next page/column.
1158 // (2) Skip empty sections and hidden paragraphs
1159 // Thus, use method <InvalidateNextPrtArea()>
1160 InvalidateNextPrtArea();
1162 SetCompletePaint();
1163 nClear |= 0x04;
1164 if ( bLineSpace )
1166 --nCount;
1167 if( IsInSct() && !GetPrev() )
1169 SwSectionFrm *pSect = FindSctFrm();
1170 if( pSect->ContainsAny() == this )
1171 pSect->InvalidatePrt();
1174 if ( bRegister )
1175 --nCount;
1177 if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_PARATR_SPLIT,
1178 sal_False ))
1180 if ( GetPrev() )
1181 CheckKeep();
1182 Prepare( PREP_CLEAR );
1183 InvalidateSize();
1184 nClear |= 0x08;
1185 --nCount;
1188 if( SFX_ITEM_SET == rNewSet.GetItemState( RES_BACKGROUND, sal_False)
1189 && !IsFollow() && GetDrawObjs() )
1191 SwSortedObjs *pObjs = GetDrawObjs();
1192 for ( int i = 0; GetDrawObjs() && i < int(pObjs->Count()); ++i )
1194 SwAnchoredObject* pAnchoredObj = (*pObjs)[MSHORT(i)];
1195 if ( pAnchoredObj->ISA(SwFlyFrm) )
1197 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
1198 if( !pFly->IsFlyInCntFrm() )
1200 const SvxBrushItem &rBack =
1201 pFly->GetAttrSet()->GetBackground();
1202 // OD 20.08.2002 #99657# #GetTransChg#
1203 // following condition determines, if the fly frame
1204 // "inherites" the background color of text frame.
1205 // This is the case, if fly frame background
1206 // color is "no fill"/"auto fill" and if the fly frame
1207 // has no background graphic.
1208 // Thus, check complete fly frame background
1209 // color and *not* only its transparency value
1210 if ( (rBack.GetColor() == COL_TRANSPARENT) &&
1211 //if( rBack.GetColor().GetTransparency() &&
1212 rBack.GetGraphicPos() == GPOS_NONE )
1214 pFly->SetCompletePaint();
1215 pFly->InvalidatePage();
1222 if ( SFX_ITEM_SET ==
1223 rNewSet.GetItemState( RES_TXTATR_CHARFMT, sal_False ) )
1225 SET_WRONG( 0, STRING_LEN, false )
1226 SET_SCRIPT_INVAL( 0 )
1228 else if ( SFX_ITEM_SET ==
1229 rNewSet.GetItemState( RES_CHRATR_LANGUAGE, sal_False ) ||
1230 SFX_ITEM_SET ==
1231 rNewSet.GetItemState( RES_CHRATR_CJK_LANGUAGE, sal_False ) ||
1232 SFX_ITEM_SET ==
1233 rNewSet.GetItemState( RES_CHRATR_CTL_LANGUAGE, sal_False ) )
1234 SET_WRONG( 0, STRING_LEN, false )
1235 else if ( SFX_ITEM_SET ==
1236 rNewSet.GetItemState( RES_CHRATR_FONT, sal_False ) ||
1237 SFX_ITEM_SET ==
1238 rNewSet.GetItemState( RES_CHRATR_CJK_FONT, sal_False ) ||
1239 SFX_ITEM_SET ==
1240 rNewSet.GetItemState( RES_CHRATR_CTL_FONT, sal_False ) )
1241 SET_SCRIPT_INVAL( 0 )
1242 else if ( SFX_ITEM_SET ==
1243 rNewSet.GetItemState( RES_FRAMEDIR, sal_False ) )
1245 SetDerivedR2L( sal_False );
1246 CheckDirChange();
1247 // OD 09.12.2002 #105576# - Force complete paint due to existing
1248 // indents.
1249 SetCompletePaint();
1253 if( nCount )
1255 if( GetShell() )
1257 Prepare( PREP_CLEAR );
1258 _InvalidatePrt();
1261 if( nClear )
1263 SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld );
1264 SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew );
1266 if( 0x01 & nClear )
1268 aOldSet.ClearItem( RES_TXTATR_FTN );
1269 aNewSet.ClearItem( RES_TXTATR_FTN );
1271 if( 0x02 & nClear )
1273 aOldSet.ClearItem( RES_TXTATR_FIELD );
1274 aNewSet.ClearItem( RES_TXTATR_FIELD );
1276 if ( 0x04 & nClear )
1278 if ( bLineSpace )
1280 aOldSet.ClearItem( RES_PARATR_LINESPACING );
1281 aNewSet.ClearItem( RES_PARATR_LINESPACING );
1283 if ( bRegister )
1285 aOldSet.ClearItem( RES_PARATR_REGISTER );
1286 aNewSet.ClearItem( RES_PARATR_REGISTER );
1289 if ( 0x08 & nClear )
1291 aOldSet.ClearItem( RES_PARATR_SPLIT );
1292 aNewSet.ClearItem( RES_PARATR_SPLIT );
1294 SwCntntFrm::Modify( &aOldSet, &aNewSet );
1296 else
1297 SwCntntFrm::Modify( pOld, pNew );
1300 // --> OD 2009-01-06 #i88069#
1301 if ( GetShell() )
1303 GetShell()->InvalidateAccessibleParaAttrs( *this );
1305 // <--
1307 break;
1309 /* Seit dem neuen Blocksatz muessen wir immer neu formatieren:
1310 case RES_PARATR_ADJUST:
1312 if( GetShell() )
1314 Prepare( PREP_CLEAR );
1316 break;
1319 // 6870: SwDocPosUpdate auswerten.
1320 case RES_DOCPOS_UPDATE:
1322 if( pOld && pNew )
1324 const SwDocPosUpdate *pDocPos = (const SwDocPosUpdate*)pOld;
1325 if( pDocPos->nDocPos <= aFrm.Top() )
1327 const SwFmtFld *pFld = (const SwFmtFld *)pNew;
1328 InvalidateRange(
1329 SwCharRange( *pFld->GetTxtFld()->GetStart(), 1 ) );
1332 break;
1334 case RES_PARATR_SPLIT:
1335 if ( GetPrev() )
1336 CheckKeep();
1337 Prepare( PREP_CLEAR );
1338 bSetFldsDirty = sal_True;
1339 break;
1340 case RES_FRAMEDIR :
1341 SetDerivedR2L( sal_False );
1342 CheckDirChange();
1343 break;
1344 default:
1346 Prepare( PREP_CLEAR );
1347 _InvalidatePrt();
1348 if ( !nWhich )
1350 //Wird z.B. bei HiddenPara mit 0 gerufen.
1351 SwFrm *pNxt;
1352 if ( 0 != (pNxt = FindNext()) )
1353 pNxt->InvalidatePrt();
1356 } // switch
1358 if( bSetFldsDirty )
1359 GetNode()->getIDocumentFieldsAccess()->SetFieldsDirty( sal_True, GetNode(), 1 );
1361 if ( bRecalcFtnFlag )
1362 CalcFtnFlag();
1365 sal_Bool SwTxtFrm::GetInfo( SfxPoolItem &rHnt ) const
1367 if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && ! IsFollow() )
1369 SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt;
1370 const SwPageFrm *pPage = FindPageFrm();
1371 if ( pPage )
1373 if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
1375 //Das sollte er sein (kann allenfalls temporaer anders sein,
1376 // sollte uns das beunruhigen?)
1377 rInfo.SetInfo( pPage, this );
1378 return sal_False;
1380 if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
1381 (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
1383 //Das koennte er sein.
1384 rInfo.SetInfo( pPage, this );
1388 return sal_True;
1391 /*************************************************************************
1392 * SwTxtFrm::PrepWidows()
1393 *************************************************************************/
1395 void SwTxtFrm::PrepWidows( const MSHORT nNeed, sal_Bool bNotify )
1397 ASSERT(GetFollow() && nNeed, "+SwTxtFrm::Prepare: lost all friends");
1399 SwParaPortion *pPara = GetPara();
1400 if ( !pPara )
1401 return;
1402 pPara->SetPrepWidows( sal_True );
1404 // These two lines of code have been deleted for #102340#.
1405 // Obviously the widow control does not work if we have a
1406 // pMaster->pFollow->pFollow situation:
1408 // returnen oder nicht ist hier die Frage.
1409 // Ohne IsLocked() ist 5156 gefaehrlich,
1410 // ohne IsFollow() werden die Orphans unterdrueckt: 6968.
1411 // Abfrage auf IsLocked erst hier, weil das Flag gesetzt werden soll.
1412 // if( IsLocked() && IsFollow() )
1413 // return;
1415 MSHORT nHave = nNeed;
1417 // Wir geben ein paar Zeilen ab und schrumpfen im CalcPreps()
1418 SWAP_IF_NOT_SWAPPED( this )
1420 SwTxtSizeInfo aInf( this );
1421 SwTxtMargin aLine( this, &aInf );
1422 aLine.Bottom();
1423 xub_StrLen nTmpLen = aLine.GetCurr()->GetLen();
1424 while( nHave && aLine.PrevLine() )
1426 if( nTmpLen )
1427 --nHave;
1428 nTmpLen = aLine.GetCurr()->GetLen();
1430 // In dieser Ecke tummelten sich einige Bugs: 7513, 7606.
1431 // Wenn feststeht, dass Zeilen abgegeben werden koennen,
1432 // muss der Master darueber hinaus die Widow-Regel ueberpruefen.
1433 if( !nHave )
1435 sal_Bool bSplit;
1436 if( !IsFollow() ) //Nur ein Master entscheidet ueber Orphans
1438 const WidowsAndOrphans aWidOrp( this );
1439 bSplit = ( aLine.GetLineNr() >= aWidOrp.GetOrphansLines() &&
1440 aLine.GetLineNr() >= aLine.GetDropLines() );
1442 else
1443 bSplit = sal_True;
1445 if( bSplit )
1447 GetFollow()->SetOfst( aLine.GetEnd() );
1448 aLine.TruncLines( sal_True );
1449 if( pPara->IsFollowField() )
1450 GetFollow()->SetFieldFollow( sal_True );
1453 if ( bNotify )
1455 _InvalidateSize();
1456 InvalidatePage();
1459 UNDO_SWAP( this )
1462 /*************************************************************************
1463 * SwTxtFrm::Prepare
1464 *************************************************************************/
1466 sal_Bool lcl_ErgoVadis( SwTxtFrm* pFrm, xub_StrLen &rPos, const PrepareHint ePrep )
1468 const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1469 if( ePrep == PREP_ERGOSUM )
1471 if( !rFtnInfo.aErgoSum.Len() )
1472 return sal_False;;
1473 rPos = pFrm->GetOfst();
1475 else
1477 if( !rFtnInfo.aQuoVadis.Len() )
1478 return sal_False;
1479 if( pFrm->HasFollow() )
1480 rPos = pFrm->GetFollow()->GetOfst();
1481 else
1482 rPos = pFrm->GetTxt().Len();
1483 if( rPos )
1484 --rPos; // unser letztes Zeichen
1486 return sal_True;
1489 void SwTxtFrm::Prepare( const PrepareHint ePrep, const void* pVoid,
1490 sal_Bool bNotify )
1492 SwFrmSwapper aSwapper( this, sal_False );
1494 #if OSL_DEBUG_LEVEL > 1
1495 const SwTwips nDbgY = Frm().Top();
1496 (void)nDbgY;
1497 #endif
1499 if ( IsEmpty() )
1501 switch ( ePrep )
1503 case PREP_BOSS_CHGD:
1504 SetInvalidVert( TRUE ); // Test
1505 case PREP_WIDOWS_ORPHANS:
1506 case PREP_WIDOWS:
1507 case PREP_FTN_GONE : return;
1509 case PREP_POS_CHGD :
1511 // Auch in (spaltigen) Bereichen ist ein InvalidateSize notwendig,
1512 // damit formatiert wird und ggf. das bUndersized gesetzt wird.
1513 if( IsInFly() || IsInSct() )
1515 SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1516 GetUpper()->Prt().Bottom();
1517 if( nTmpBottom < Frm().Bottom() )
1518 break;
1520 // Gibt es ueberhaupt Flys auf der Seite ?
1521 SwTxtFly aTxtFly( this );
1522 if( aTxtFly.IsOn() )
1524 // Ueberlappt irgendein Fly ?
1525 aTxtFly.Relax();
1526 if ( aTxtFly.IsOn() || IsUndersized() )
1527 break;
1529 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue())
1530 break;
1532 GETGRID( FindPageFrm() )
1533 if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1534 break;
1536 // --> OD 2004-07-16 #i28701# - consider anchored objects
1537 if ( GetDrawObjs() )
1538 break;
1539 // <--
1541 return;
1543 default:
1544 break;
1548 if( !HasPara() && PREP_MUST_FIT != ePrep )
1550 SetInvalidVert( TRUE ); // Test
1551 ASSERT( !IsLocked(), "SwTxtFrm::Prepare: three of a perfect pair" );
1552 if ( bNotify )
1553 InvalidateSize();
1554 else
1555 _InvalidateSize();
1556 return;
1559 //Objekt mit Locking aus dem Cache holen.
1560 SwTxtLineAccess aAccess( this );
1561 SwParaPortion *pPara = aAccess.GetPara();
1563 switch( ePrep )
1565 case PREP_MOVEFTN : Frm().Height(0);
1566 Prt().Height(0);
1567 _InvalidatePrt();
1568 _InvalidateSize();
1569 // KEIN break
1570 case PREP_ADJUST_FRM : pPara->SetPrepAdjust( sal_True );
1571 if( IsFtnNumFrm() != pPara->IsFtnNum() ||
1572 IsUndersized() )
1574 InvalidateRange( SwCharRange( 0, 1 ), 1);
1575 if( GetOfst() && !IsFollow() )
1576 _SetOfst( 0 );
1578 break;
1579 case PREP_MUST_FIT : pPara->SetPrepMustFit( sal_True );
1580 /* no break here */
1581 case PREP_WIDOWS_ORPHANS : pPara->SetPrepAdjust( sal_True );
1582 break;
1584 case PREP_WIDOWS :
1585 // MustFit ist staerker als alles anderes
1586 if( pPara->IsPrepMustFit() )
1587 return;
1588 // Siehe Kommentar in WidowsAndOrphans::FindOrphans und CalcPreps()
1589 PrepWidows( *(const MSHORT *)pVoid, bNotify );
1590 break;
1592 case PREP_FTN :
1594 SwTxtFtn *pFtn = (SwTxtFtn *)pVoid;
1595 if( IsInFtn() )
1597 // Bin ich der erste TxtFrm einer Fussnote ?
1598 if( !GetPrev() )
1599 // Wir sind also ein TxtFrm der Fussnote, die
1600 // die Fussnotenzahl zur Anzeige bringen muss.
1601 // Oder den ErgoSum-Text...
1602 InvalidateRange( SwCharRange( 0, 1 ), 1);
1604 if( !GetNext() )
1606 // Wir sind der letzte Ftn, jetzt muessten die
1607 // QuoVadis-Texte geupdated werden.
1608 const SwFtnInfo &rFtnInfo = GetNode()->GetDoc()->GetFtnInfo();
1609 if( !pPara->UpdateQuoVadis( rFtnInfo.aQuoVadis ) )
1611 xub_StrLen nPos = pPara->GetParLen();
1612 if( nPos )
1613 --nPos;
1614 InvalidateRange( SwCharRange( nPos, 1 ), 1);
1618 else
1620 // Wir sind also der TxtFrm _mit_ der Fussnote
1621 const xub_StrLen nPos = *pFtn->GetStart();
1622 InvalidateRange( SwCharRange( nPos, 1 ), 1);
1624 break;
1626 case PREP_BOSS_CHGD :
1628 // Test
1630 SetInvalidVert( FALSE );
1631 BOOL bOld = IsVertical();
1632 SetInvalidVert( TRUE );
1633 if( bOld != IsVertical() )
1634 InvalidateRange( SwCharRange( GetOfst(), STRING_LEN ) );
1637 if( HasFollow() )
1639 xub_StrLen nNxtOfst = GetFollow()->GetOfst();
1640 if( nNxtOfst )
1641 --nNxtOfst;
1642 InvalidateRange( SwCharRange( nNxtOfst, 1 ), 1);
1644 if( IsInFtn() )
1646 xub_StrLen nPos;
1647 if( lcl_ErgoVadis( this, nPos, PREP_QUOVADIS ) )
1648 InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1649 if( lcl_ErgoVadis( this, nPos, PREP_ERGOSUM ) )
1650 InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1652 // 4739: Wenn wir ein Seitennummernfeld besitzen, muessen wir
1653 // die Stellen invalidieren.
1654 SwpHints *pHints = GetTxtNode()->GetpSwpHints();
1655 if( pHints )
1657 const USHORT nSize = pHints->Count();
1658 const xub_StrLen nEnd = GetFollow() ?
1659 GetFollow()->GetOfst() : STRING_LEN;
1660 for ( USHORT i = 0; i < nSize; ++i )
1662 const SwTxtAttr *pHt = (*pHints)[i];
1663 const xub_StrLen nStart = *pHt->GetStart();
1664 if( nStart >= GetOfst() )
1666 if( nStart >= nEnd )
1667 i = nSize; // fuehrt das Ende herbei
1668 else
1670 // 4029: wenn wir zurueckfliessen und eine Ftn besitzen, so
1671 // fliesst die Ftn in jedem Fall auch mit. Damit sie nicht im
1672 // Weg steht, schicken wir uns ein ADJUST_FRM.
1673 // pVoid != 0 bedeutet MoveBwd()
1674 const MSHORT nWhich = pHt->Which();
1675 if( RES_TXTATR_FIELD == nWhich ||
1676 (HasFtn() && pVoid && RES_TXTATR_FTN == nWhich))
1677 InvalidateRange( SwCharRange( nStart, 1 ), 1 );
1682 // A new boss, a new chance for growing
1683 if( IsUndersized() )
1685 _InvalidateSize();
1686 InvalidateRange( SwCharRange( GetOfst(), 1 ), 1);
1688 break;
1691 case PREP_POS_CHGD :
1693 if ( GetValidPrtAreaFlag() )
1695 GETGRID( FindPageFrm() )
1696 if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1697 InvalidatePrt();
1700 // Falls wir mit niemandem ueberlappen:
1701 // Ueberlappte irgendein Fly _vor_ der Positionsaenderung ?
1702 sal_Bool bFormat = pPara->HasFly();
1703 if( !bFormat )
1705 if( IsInFly() )
1707 SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1708 GetUpper()->Prt().Bottom();
1709 if( nTmpBottom < Frm().Bottom() )
1710 bFormat = sal_True;
1712 if( !bFormat )
1714 if ( GetDrawObjs() )
1716 const sal_uInt32 nCnt = GetDrawObjs()->Count();
1717 for ( MSHORT i = 0; i < nCnt; ++i )
1719 SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i];
1720 // --> OD 2004-07-16 #i28701# - consider all
1721 // to-character anchored objects
1722 if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
1723 == FLY_AUTO_CNTNT )
1725 bFormat = sal_True;
1726 break;
1730 if( !bFormat )
1732 // Gibt es ueberhaupt Flys auf der Seite ?
1733 SwTxtFly aTxtFly( this );
1734 if( aTxtFly.IsOn() )
1736 // Ueberlappt irgendein Fly ?
1737 aTxtFly.Relax();
1738 bFormat = aTxtFly.IsOn() || IsUndersized();
1744 if( bFormat )
1746 if( !IsLocked() )
1748 if( pPara->GetRepaint()->HasArea() )
1749 SetCompletePaint();
1750 Init();
1751 pPara = 0;
1752 _InvalidateSize();
1755 else
1757 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1758 Prepare( PREP_REGISTER, 0, bNotify );
1759 // Durch Positionsverschiebungen mit Ftns muessen die
1760 // Frames neu adjustiert werden.
1761 else if( HasFtn() )
1763 Prepare( PREP_ADJUST_FRM, 0, bNotify );
1764 _InvalidateSize();
1766 else
1767 return; // damit kein SetPrep() erfolgt.
1769 break;
1771 case PREP_REGISTER:
1772 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1774 pPara->SetPrepAdjust( sal_True );
1775 CalcLineSpace();
1776 InvalidateSize();
1777 _InvalidatePrt();
1778 SwFrm* pNxt;
1779 if ( 0 != ( pNxt = GetIndNext() ) )
1781 pNxt->_InvalidatePrt();
1782 if ( pNxt->IsLayoutFrm() )
1783 pNxt->InvalidatePage();
1785 SetCompletePaint();
1787 break;
1788 case PREP_FTN_GONE :
1790 // Wenn ein Follow uns ruft, weil eine Fussnote geloescht wird, muss unsere
1791 // letzte Zeile formatiert werden, damit ggf. die erste Zeile des Follows
1792 // hochrutschen kann, die extra auf die naechste Seite gerutscht war, um mit
1793 // der Fussnote zusammen zu sein, insbesondere bei spaltigen Bereichen.
1794 ASSERT( GetFollow(), "PREP_FTN_GONE darf nur vom Follow gerufen werden" );
1795 xub_StrLen nPos = GetFollow()->GetOfst();
1796 if( IsFollow() && GetOfst() == nPos ) // falls wir gar keine Textmasse besitzen,
1797 FindMaster()->Prepare( PREP_FTN_GONE ); // rufen wir das Prepare unseres Masters
1798 if( nPos )
1799 --nPos; // das Zeichen vor unserem Follow
1800 InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1801 return;
1803 case PREP_ERGOSUM:
1804 case PREP_QUOVADIS:
1806 xub_StrLen nPos;
1807 if( lcl_ErgoVadis( this, nPos, ePrep ) )
1808 InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1810 break;
1811 case PREP_FLY_ATTR_CHG:
1813 if( pVoid )
1815 xub_StrLen nWhere = CalcFlyPos( (SwFrmFmt*)pVoid );
1816 ASSERT( STRING_LEN != nWhere, "Prepare: Why me?" );
1817 InvalidateRange( SwCharRange( nWhere, 1 ) );
1818 return;
1820 // else ... Laufe in den Default-Switch
1822 case PREP_CLEAR:
1823 default:
1825 if( IsLocked() )
1827 if( PREP_FLY_ARRIVE == ePrep || PREP_FLY_LEAVE == ePrep )
1829 xub_StrLen nLen = ( GetFollow() ? GetFollow()->GetOfst() :
1830 STRING_LEN ) - GetOfst();
1831 InvalidateRange( SwCharRange( GetOfst(), nLen ), 0 );
1834 else
1836 if( pPara->GetRepaint()->HasArea() )
1837 SetCompletePaint();
1838 Init();
1839 pPara = 0;
1840 if( GetOfst() && !IsFollow() )
1841 _SetOfst( 0 );
1842 if ( bNotify )
1843 InvalidateSize();
1844 else
1845 _InvalidateSize();
1847 return; // damit kein SetPrep() erfolgt.
1850 if( pPara )
1851 pPara->SetPrep( sal_True );
1854 /* -----------------11.02.99 17:56-------------------
1855 * Kleine Hilfsklasse mit folgender Funktion:
1856 * Sie soll eine Probeformatierung vorbereiten.
1857 * Der Frame wird in Groesse und Position angepasst, sein SwParaPortion zur Seite
1858 * gestellt und eine neue erzeugt, dazu wird formatiert mit gesetztem bTestFormat.
1859 * Im Dtor wird der TxtFrm wieder in seinen alten Zustand zurueckversetzt.
1861 * --------------------------------------------------*/
1863 class SwTestFormat
1865 SwTxtFrm *pFrm;
1866 SwParaPortion *pOldPara;
1867 SwRect aOldFrm, aOldPrt;
1868 public:
1869 SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPrv, SwTwips nMaxHeight );
1870 ~SwTestFormat();
1873 SwTestFormat::SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPre, SwTwips nMaxHeight )
1874 : pFrm( pTxtFrm )
1876 aOldFrm = pFrm->Frm();
1877 aOldPrt = pFrm->Prt();
1879 SWRECTFN( pFrm )
1880 SwTwips nLower = (pFrm->*fnRect->fnGetBottomMargin)();
1882 pFrm->Frm() = pFrm->GetUpper()->Prt();
1883 pFrm->Frm() += pFrm->GetUpper()->Frm().Pos();
1885 (pFrm->Frm().*fnRect->fnSetHeight)( nMaxHeight );
1886 if( pFrm->GetPrev() )
1887 (pFrm->Frm().*fnRect->fnSetPosY)(
1888 (pFrm->GetPrev()->Frm().*fnRect->fnGetBottom)() -
1889 ( bVert ? nMaxHeight + 1 : 0 ) );
1891 SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
1892 const SwBorderAttrs &rAttrs = *aAccess.Get();
1893 (pFrm->Prt().*fnRect->fnSetPosX)( rAttrs.CalcLeft( pFrm ) );
1895 if( pPre )
1897 SwTwips nUpper = pFrm->CalcUpperSpace( &rAttrs, pPre );
1898 (pFrm->Prt().*fnRect->fnSetPosY)( nUpper );
1900 (pFrm->Prt().*fnRect->fnSetHeight)(
1901 Max( 0L , (pFrm->Frm().*fnRect->fnGetHeight)() -
1902 (pFrm->Prt().*fnRect->fnGetTop)() - nLower ) );
1903 (pFrm->Prt().*fnRect->fnSetWidth)(
1904 (pFrm->Frm().*fnRect->fnGetWidth)() -
1905 // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
1906 ( rAttrs.CalcLeft( pFrm ) + rAttrs.CalcRight( pFrm ) ) );
1907 pOldPara = pFrm->HasPara() ? pFrm->GetPara() : NULL;
1908 pFrm->SetPara( new SwParaPortion(), sal_False );
1910 ASSERT( ! pFrm->IsSwapped(), "A frame is swapped before _Format" );
1912 if ( pFrm->IsVertical() )
1913 pFrm->SwapWidthAndHeight();
1915 SwTxtFormatInfo aInf( pFrm, sal_False, sal_True, sal_True );
1916 SwTxtFormatter aLine( pFrm, &aInf );
1918 pFrm->_Format( aLine, aInf );
1920 if ( pFrm->IsVertical() )
1921 pFrm->SwapWidthAndHeight();
1923 ASSERT( ! pFrm->IsSwapped(), "A frame is swapped after _Format" );
1926 SwTestFormat::~SwTestFormat()
1928 pFrm->Frm() = aOldFrm;
1929 pFrm->Prt() = aOldPrt;
1930 pFrm->SetPara( pOldPara );
1933 sal_Bool SwTxtFrm::TestFormat( const SwFrm* pPrv, SwTwips &rMaxHeight, sal_Bool &bSplit )
1935 PROTOCOL_ENTER( this, PROT_TESTFORMAT, 0, 0 )
1937 if( IsLocked() && GetUpper()->Prt().Width() <= 0 )
1938 return sal_False;
1940 SwTestFormat aSave( this, pPrv, rMaxHeight );
1942 return SwTxtFrm::WouldFit( rMaxHeight, bSplit, sal_True );
1946 /*************************************************************************
1947 * SwTxtFrm::WouldFit()
1948 *************************************************************************/
1950 /* SwTxtFrm::WouldFit()
1951 * sal_True: wenn ich aufspalten kann.
1952 * Es soll und braucht nicht neu formatiert werden.
1953 * Wir gehen davon aus, dass bereits formatiert wurde und dass
1954 * die Formatierungsdaten noch aktuell sind.
1955 * Wir gehen davon aus, dass die Framebreiten des evtl. Masters und
1956 * Follows gleich sind. Deswegen wird kein FindBreak() mit FindOrphans()
1957 * gerufen.
1958 * Die benoetigte Hoehe wird von nMaxHeight abgezogen!
1961 sal_Bool SwTxtFrm::WouldFit( SwTwips &rMaxHeight, sal_Bool &bSplit, sal_Bool bTst )
1963 ASSERT( ! IsVertical() || ! IsSwapped(),
1964 "SwTxtFrm::WouldFit with swapped frame" );
1965 SWRECTFN( this );
1967 if( IsLocked() )
1968 return sal_False;
1970 //Kann gut sein, dass mir der IdleCollector mir die gecachten
1971 //Informationen entzogen hat.
1972 if( !IsEmpty() )
1973 GetFormatted();
1975 // OD 2004-05-24 #i27801# - correction: 'short cut' for empty paragraph
1976 // can *not* be applied, if test format is in progress. The test format doesn't
1977 // adjust the frame and the printing area - see method <SwTxtFrm::_Format(..)>,
1978 // which is called in <SwTxtFrm::TestFormat(..)>
1979 if ( IsEmpty() && !bTst )
1981 bSplit = sal_False;
1982 SwTwips nHeight = bVert ? Prt().SSize().Width() : Prt().SSize().Height();
1983 if( rMaxHeight < nHeight )
1984 return sal_False;
1985 else
1987 rMaxHeight -= nHeight;
1988 return sal_True;
1992 // In sehr unguenstigen Faellen kann GetPara immer noch 0 sein.
1993 // Dann returnen wir sal_True, um auf der neuen Seite noch einmal
1994 // anformatiert zu werden.
1995 ASSERT( HasPara() || IsHiddenNow(), "WouldFit: GetFormatted() and then !HasPara()" );
1996 if( !HasPara() || ( !(Frm().*fnRect->fnGetHeight)() && IsHiddenNow() ) )
1997 return sal_True;
1999 // Da das Orphan-Flag nur sehr fluechtig existiert, wird als zweite
2000 // Bedingung ueberprueft, ob die Rahmengroesse durch CalcPreps
2001 // auf riesengross gesetzt wird, um ein MoveFwd zu erzwingen.
2002 if( IsWidow() || ( bVert ?
2003 ( 0 == Frm().Left() ) :
2004 ( LONG_MAX - 20000 < Frm().Bottom() ) ) )
2006 SetWidow(sal_False);
2007 if ( GetFollow() )
2009 // Wenn wir hier durch eine Widow-Anforderung unseres Follows gelandet
2010 // sind, wird ueberprueft, ob es ueberhaupt einen Follow mit einer
2011 // echten Hoehe gibt, andernfalls (z.B. in neu angelegten SctFrms)
2012 // ignorieren wir das IsWidow() und pruefen doch noch, ob wir
2013 // genung Platz finden.
2014 if( ( ( ! bVert && LONG_MAX - 20000 >= Frm().Bottom() ) ||
2015 ( bVert && 0 < Frm().Left() ) ) &&
2016 ( GetFollow()->IsVertical() ?
2017 !GetFollow()->Frm().Width() :
2018 !GetFollow()->Frm().Height() ) )
2020 SwTxtFrm* pFoll = GetFollow()->GetFollow();
2021 while( pFoll &&
2022 ( pFoll->IsVertical() ?
2023 !pFoll->Frm().Width() :
2024 !pFoll->Frm().Height() ) )
2025 pFoll = pFoll->GetFollow();
2026 if( pFoll )
2027 return sal_False;
2029 else
2030 return sal_False;
2034 SWAP_IF_NOT_SWAPPED( this );
2036 SwTxtSizeInfo aInf( this );
2037 SwTxtMargin aLine( this, &aInf );
2039 WidowsAndOrphans aFrmBreak( this, rMaxHeight, bSplit );
2041 sal_Bool bRet = sal_True;
2043 aLine.Bottom();
2044 // Ist Aufspalten ueberhaupt notwendig?
2045 if ( 0 != ( bSplit = !aFrmBreak.IsInside( aLine ) ) )
2046 bRet = !aFrmBreak.IsKeepAlways() && aFrmBreak.WouldFit( aLine, rMaxHeight, bTst );
2047 else
2049 //Wir brauchen die Gesamthoehe inklusive der aktuellen Zeile
2050 aLine.Top();
2053 rMaxHeight -= aLine.GetLineHeight();
2054 } while ( aLine.Next() );
2057 UNDO_SWAP( this )
2059 return bRet;
2063 /*************************************************************************
2064 * SwTxtFrm::GetParHeight()
2065 *************************************************************************/
2067 KSHORT SwTxtFrm::GetParHeight() const
2069 ASSERT( ! IsVertical() || ! IsSwapped(),
2070 "SwTxtFrm::GetParHeight with swapped frame" )
2072 if( !HasPara() )
2073 { // Fuer nichtleere Absaetze ist dies ein Sonderfall, da koennen wir
2074 // bei UnderSized ruhig nur 1 Twip mehr anfordern.
2075 KSHORT nRet = (KSHORT)Prt().SSize().Height();
2076 if( IsUndersized() )
2078 if( IsEmpty() )
2079 nRet = (KSHORT)EmptyHeight();
2080 else
2081 ++nRet;
2083 return nRet;
2086 // FME, OD 08.01.2004 #i11859# - refactoring and improve code
2087 const SwLineLayout* pLineLayout = GetPara();
2088 KSHORT nHeight = pLineLayout->GetRealHeight();
2089 if( GetOfst() && !IsFollow() ) // Ist dieser Absatz gescrollt? Dann ist unsere
2090 nHeight *= 2; // bisherige Hoehe mind. eine Zeilenhoehe zu gering
2091 // OD 2004-03-04 #115793#
2092 while ( pLineLayout && pLineLayout->GetNext() )
2094 pLineLayout = pLineLayout->GetNext();
2095 nHeight = nHeight + pLineLayout->GetRealHeight();
2098 return nHeight;
2102 /*************************************************************************
2103 * SwTxtFrm::GetFormatted()
2104 *************************************************************************/
2106 // returnt this _immer_ im formatierten Zustand!
2107 SwTxtFrm* SwTxtFrm::GetFormatted( bool bForceQuickFormat )
2109 SWAP_IF_SWAPPED( this )
2111 //Kann gut sein, dass mir der IdleCollector mir die gecachten
2112 //Informationen entzogen hat. Calc() ruft unser Format.
2113 //Nicht bei leeren Absaetzen!
2114 if( !HasPara() && !(IsValid() && IsEmpty()) )
2116 // Calc() muss gerufen werden, weil unsere Frameposition
2117 // nicht stimmen muss.
2118 const sal_Bool bFormat = GetValidSizeFlag();
2119 Calc();
2120 // Es kann durchaus sein, dass Calc() das Format()
2121 // nicht anstiess (weil wir einst vom Idle-Zerstoerer
2122 // aufgefordert wurden unsere Formatinformationen wegzuschmeissen).
2123 // 6995: Optimierung mit FormatQuick()
2124 if( bFormat && !FormatQuick( bForceQuickFormat ) )
2125 Format();
2128 UNDO_SWAP( this )
2130 return this;
2133 /*************************************************************************
2134 * SwTxtFrm::CalcFitToContent()
2135 *************************************************************************/
2137 SwTwips SwTxtFrm::CalcFitToContent()
2139 // --> FME 2004-07-16 #i31490#
2140 // If we are currently locked, we better return with a
2141 // fairly reasonable value:
2142 if ( IsLocked() )
2143 return Prt().Width();
2144 // <--
2146 SwParaPortion* pOldPara = GetPara();
2147 SwParaPortion *pDummy = new SwParaPortion();
2148 SetPara( pDummy, false );
2149 const SwPageFrm* pPage = FindPageFrm();
2151 const Point aOldFrmPos = Frm().Pos();
2152 const SwTwips nOldFrmWidth = Frm().Width();
2153 const SwTwips nOldPrtWidth = Prt().Width();
2154 const SwTwips nPageWidth = GetUpper()->IsVertical() ?
2155 pPage->Prt().Height() :
2156 pPage->Prt().Width();
2158 Frm().Width( nPageWidth );
2159 Prt().Width( nPageWidth );
2161 // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
2162 if ( IsRightToLeft() )
2163 Frm().Pos().X() += nOldFrmWidth - nPageWidth;
2165 // --> FME 2004-07-16 #i31490#
2166 SwTxtFrmLocker aLock( this );
2167 // <--
2169 SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
2170 aInf.SetIgnoreFly( sal_True );
2171 SwTxtFormatter aLine( this, &aInf );
2172 SwHookOut aHook( aInf );
2174 // --> OD 2005-09-06 #i54031# - assure mininum of MINLAY twips.
2175 const SwTwips nMax = Max( (SwTwips)MINLAY,
2176 aLine._CalcFitToContent() + 1 );
2177 // <--
2179 Frm().Width( nOldFrmWidth );
2180 Prt().Width( nOldPrtWidth );
2182 // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
2183 if ( IsRightToLeft() )
2184 Frm().Pos() = aOldFrmPos;
2187 SetPara( pOldPara );
2189 return nMax;
2192 /** simulate format for a list item paragraph, whose list level attributes
2193 are in LABEL_ALIGNMENT mode, in order to determine additional first
2194 line offset for the real text formatting due to the value of label
2195 adjustment attribute of the list level.
2197 OD 2008-01-31 #newlistlevelattrs#
2199 @author OD
2201 void SwTxtFrm::CalcAdditionalFirstLineOffset()
2203 if ( IsLocked() )
2204 return;
2206 // reset additional first line offset
2207 mnAdditionalFirstLineOffset = 0;
2209 const SwTxtNode* pTxtNode( GetTxtNode() );
2210 if ( pTxtNode && pTxtNode->IsNumbered() && pTxtNode->IsCountedInList() &&
2211 pTxtNode->GetNumRule() )
2213 const SwNumFmt& rNumFmt =
2214 pTxtNode->GetNumRule()->Get( static_cast<USHORT>(pTxtNode->GetActualListLevel()) );
2215 if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2217 // keep current paragraph portion and apply dummy paragraph portion
2218 SwParaPortion* pOldPara = GetPara();
2219 SwParaPortion *pDummy = new SwParaPortion();
2220 SetPara( pDummy, false );
2222 // lock paragraph
2223 SwTxtFrmLocker aLock( this );
2225 // simulate text formatting
2226 SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
2227 aInf.SetIgnoreFly( sal_True );
2228 SwTxtFormatter aLine( this, &aInf );
2229 SwHookOut aHook( aInf );
2230 aLine._CalcFitToContent();
2232 // determine additional first line offset
2233 const SwLinePortion* pFirstPortion = aLine.GetCurr()->GetFirstPortion();
2234 if ( pFirstPortion->InNumberGrp() && !pFirstPortion->IsFtnNumPortion() )
2236 SwTwips nNumberPortionWidth( pFirstPortion->Width() );
2238 const SwLinePortion* pPortion = pFirstPortion->GetPortion();
2239 while ( pPortion &&
2240 pPortion->InNumberGrp() && !pPortion->IsFtnNumPortion())
2242 nNumberPortionWidth += pPortion->Width();
2243 pPortion = pPortion->GetPortion();
2246 if ( ( IsRightToLeft() &&
2247 rNumFmt.GetNumAdjust() == SVX_ADJUST_LEFT ) ||
2248 ( !IsRightToLeft() &&
2249 rNumFmt.GetNumAdjust() == SVX_ADJUST_RIGHT ) )
2251 mnAdditionalFirstLineOffset = -nNumberPortionWidth;
2253 else if ( rNumFmt.GetNumAdjust() == SVX_ADJUST_CENTER )
2255 mnAdditionalFirstLineOffset = -(nNumberPortionWidth/2);
2259 // restore paragraph portion
2260 SetPara( pOldPara );
2265 /** determine height of last line for the calculation of the proportional line
2266 spacing
2268 OD 08.01.2004 #i11859#
2269 OD 2004-03-17 #i11860# - method <GetHeightOfLastLineForPropLineSpacing()>
2270 replace by method <_CalcHeightOfLastLine()>. Height of last line will be
2271 stored in new member <mnHeightOfLastLine> and can be accessed via method
2272 <GetHeightOfLastLine()>
2273 OD 2005-05-20 #i47162# - introduce new optional parameter <_bUseFont>
2274 in order to force the usage of the former algorithm to determine the
2275 height of the last line, which uses the font.
2277 @author OD
2279 void SwTxtFrm::_CalcHeightOfLastLine( const bool _bUseFont )
2281 // --> OD 2006-11-13 #i71281#
2282 // invalidate printing area, if height of last line changes
2283 const SwTwips mnOldHeightOfLastLine( mnHeightOfLastLine );
2284 // <--
2285 // determine output device
2286 ViewShell* pVsh = GetShell();
2287 ASSERT( pVsh, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no ViewShell" );
2288 // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
2289 // There could be no <ViewShell> instance in the case of loading a binary
2290 // StarOffice file format containing an embedded Writer document.
2291 if ( !pVsh )
2293 return;
2295 OutputDevice* pOut = pVsh->GetOut();
2296 const IDocumentSettingAccess* pIDSA = GetTxtNode()->getIDocumentSettingAccess();
2297 if ( !pIDSA->get(IDocumentSettingAccess::BROWSE_MODE) ||
2298 pVsh->GetViewOptions()->IsPrtFormat() )
2300 pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
2302 ASSERT( pOut, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no OutputDevice" );
2303 // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
2304 if ( !pOut )
2306 return;
2308 // <--
2310 // determine height of last line
2312 if ( _bUseFont || pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING ) )
2314 // former determination of last line height for proprotional line
2315 // spacing - take height of font set at the paragraph
2316 SwFont aFont( GetAttrSet(), pIDSA );
2318 // Wir muessen dafuer sorgen, dass am OutputDevice der Font
2319 // korrekt restauriert wird, sonst droht ein Last!=Owner.
2320 if ( pLastFont )
2322 SwFntObj *pOldFont = pLastFont;
2323 pLastFont = NULL;
2324 aFont.SetFntChg( sal_True );
2325 aFont.ChgPhysFnt( pVsh, *pOut );
2326 mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2327 pLastFont->Unlock();
2328 pLastFont = pOldFont;
2329 pLastFont->SetDevFont( pVsh, *pOut );
2331 else
2333 Font aOldFont = pOut->GetFont();
2334 aFont.SetFntChg( sal_True );
2335 aFont.ChgPhysFnt( pVsh, *pOut );
2336 mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2337 pLastFont->Unlock();
2338 pLastFont = NULL;
2339 pOut->SetFont( aOldFont );
2342 else
2344 // new determination of last line height - take actually height of last line
2345 // --> OD 2008-05-06 #i89000#
2346 // assure same results, if paragraph is undersized
2347 if ( IsUndersized() )
2349 mnHeightOfLastLine = 0;
2351 else
2353 bool bCalcHeightOfLastLine = true;
2354 if ( !HasPara() )
2356 if ( IsEmpty() )
2358 mnHeightOfLastLine = EmptyHeight();
2359 bCalcHeightOfLastLine = false;
2363 if ( bCalcHeightOfLastLine )
2365 ASSERT( HasPara(),
2366 "<SwTxtFrm::_CalcHeightOfLastLine()> - missing paragraph portions." );
2367 const SwLineLayout* pLineLayout = GetPara();
2368 while ( pLineLayout && pLineLayout->GetNext() )
2370 // iteration to last line
2371 pLineLayout = pLineLayout->GetNext();
2373 if ( pLineLayout )
2375 SwTwips nAscent, nDescent, nDummy1, nDummy2;
2376 // --> OD 2005-05-20 #i47162# - suppress consideration of
2377 // fly content portions and the line portion.
2378 pLineLayout->MaxAscentDescent( nAscent, nDescent,
2379 nDummy1, nDummy2,
2380 0, true );
2381 // <--
2382 // --> OD 2006-11-22 #i71281#
2383 // Suppress wrong invalidation of printing area, if method is
2384 // called recursive.
2385 // Thus, member <mnHeightOfLastLine> is only set directly, if
2386 // no recursive call is needed.
2387 // mnHeightOfLastLine = nAscent + nDescent;
2388 const SwTwips nNewHeightOfLastLine = nAscent + nDescent;
2389 // --> OD 2005-05-20 #i47162# - if last line only contains
2390 // fly content portions, <mnHeightOfLastLine> is zero.
2391 // In this case determine height of last line by the font
2392 if ( nNewHeightOfLastLine == 0 )
2394 _CalcHeightOfLastLine( true );
2396 else
2398 mnHeightOfLastLine = nNewHeightOfLastLine;
2400 // <--
2401 // <--
2405 // <--
2407 // --> OD 2006-11-13 #i71281#
2408 // invalidate printing area, if height of last line changes
2409 if ( mnHeightOfLastLine != mnOldHeightOfLastLine )
2411 InvalidatePrt();
2413 // <--
2416 /*************************************************************************
2417 * SwTxtFrm::GetLineSpace()
2418 *************************************************************************/
2419 // OD 07.01.2004 #i11859# - change return data type
2420 // add default parameter <_bNoPropLineSpacing> to control, if the
2421 // value of a proportional line spacing is returned or not
2422 // OD 07.01.2004 - trying to describe purpose of method:
2423 // Method returns the value of the inter line spacing for a text frame.
2424 // Such a value exists for proportional line spacings ("1,5 Lines",
2425 // "Double", "Proportional" and for leading line spacing ("Leading").
2426 // By parameter <_bNoPropLineSpace> (default value false) it can be
2427 // controlled, if the value of a proportional line spacing is returned.
2428 long SwTxtFrm::GetLineSpace( const bool _bNoPropLineSpace ) const
2430 long nRet = 0;
2432 const SwAttrSet* pSet = GetAttrSet();
2433 const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
2435 switch( rSpace.GetInterLineSpaceRule() )
2437 case SVX_INTER_LINE_SPACE_PROP:
2439 // OD 07.01.2004 #i11859#
2440 if ( _bNoPropLineSpace )
2442 break;
2445 // OD 2004-03-17 #i11860# - use method <GetHeightOfLastLine()>
2446 nRet = GetHeightOfLastLine();
2448 long nTmp = nRet;
2449 nTmp *= rSpace.GetPropLineSpace();
2450 nTmp /= 100;
2451 nTmp -= nRet;
2452 if ( nTmp > 0 )
2453 nRet = nTmp;
2454 else
2455 nRet = 0;
2457 break;
2458 case SVX_INTER_LINE_SPACE_FIX:
2460 if ( rSpace.GetInterLineSpace() > 0 )
2461 nRet = rSpace.GetInterLineSpace();
2463 break;
2464 default:
2465 break;
2467 return nRet;
2470 /*************************************************************************
2471 * SwTxtFrm::FirstLineHeight()
2472 *************************************************************************/
2474 KSHORT SwTxtFrm::FirstLineHeight() const
2476 if ( !HasPara() )
2478 if( IsEmpty() && IsValid() )
2479 return IsVertical() ? (KSHORT)Prt().Width() : (KSHORT)Prt().Height();
2480 return KSHRT_MAX;
2482 const SwParaPortion *pPara = GetPara();
2483 if ( !pPara )
2484 return KSHRT_MAX;
2486 return pPara->Height();
2489 MSHORT SwTxtFrm::GetLineCount( xub_StrLen nPos )
2491 MSHORT nRet = 0;
2492 SwTxtFrm *pFrm = this;
2495 pFrm->GetFormatted();
2496 if( !pFrm->HasPara() )
2497 break;
2498 SwTxtSizeInfo aInf( pFrm );
2499 SwTxtMargin aLine( pFrm, &aInf );
2500 if( STRING_LEN == nPos )
2501 aLine.Bottom();
2502 else
2503 aLine.CharToLine( nPos );
2504 nRet = nRet + aLine.GetLineNr();
2505 pFrm = pFrm->GetFollow();
2506 } while ( pFrm && pFrm->GetOfst() <= nPos );
2507 return nRet;
2510 void SwTxtFrm::ChgThisLines()
2512 //not necassary to format here (GerFormatted etc.), because we have to come from there!
2514 ULONG nNew = 0;
2515 const SwLineNumberInfo &rInf = GetNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo();
2516 if ( GetTxt().Len() && HasPara() )
2518 SwTxtSizeInfo aInf( this );
2519 SwTxtMargin aLine( this, &aInf );
2520 if ( rInf.IsCountBlankLines() )
2522 aLine.Bottom();
2523 nNew = (ULONG)aLine.GetLineNr();
2525 else
2529 if( aLine.GetCurr()->HasCntnt() )
2530 ++nNew;
2531 } while ( aLine.NextLine() );
2534 else if ( rInf.IsCountBlankLines() )
2535 nNew = 1;
2537 if ( nNew != nThisLines )
2539 if ( !IsInTab() && GetAttrSet()->GetLineNumber().IsCount() )
2541 nAllLines -= nThisLines;
2542 nThisLines = nNew;
2543 nAllLines += nThisLines;
2544 SwFrm *pNxt = GetNextCntntFrm();
2545 while( pNxt && pNxt->IsInTab() )
2547 if( 0 != (pNxt = pNxt->FindTabFrm()) )
2548 pNxt = pNxt->FindNextCnt();
2550 if( pNxt )
2551 pNxt->InvalidateLineNum();
2553 //Extend repaint to the bottom.
2554 if ( HasPara() )
2556 SwRepaint *pRepaint = GetPara()->GetRepaint();
2557 pRepaint->Bottom( Max( pRepaint->Bottom(),
2558 Frm().Top()+Prt().Bottom()));
2561 else //Paragraphs which are not counted should not manipulate the AllLines.
2562 nThisLines = nNew;
2567 void SwTxtFrm::RecalcAllLines()
2569 ValidateLineNum();
2571 const SwAttrSet *pAttrSet = GetAttrSet();
2573 if ( !IsInTab() )
2575 const ULONG nOld = GetAllLines();
2576 const SwFmtLineNumber &rLineNum = pAttrSet->GetLineNumber();
2577 ULONG nNewNum;
2578 const bool bRestart = GetTxtNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo().IsRestartEachPage();
2580 if ( !IsFollow() && rLineNum.GetStartValue() && rLineNum.IsCount() )
2581 nNewNum = rLineNum.GetStartValue() - 1;
2582 //If it is a follow or not has not be considered if it is a restart at each page; the
2583 //restart should also take affekt at follows.
2584 else if ( bRestart && FindPageFrm()->FindFirstBodyCntnt() == this )
2586 nNewNum = 0;
2588 else
2590 SwCntntFrm *pPrv = GetPrevCntntFrm();
2591 while ( pPrv &&
2592 (pPrv->IsInTab() || pPrv->IsInDocBody() != IsInDocBody()) )
2593 pPrv = pPrv->GetPrevCntntFrm();
2595 // --> FME 2007-06-22 #i78254# Restart line numbering at page change:
2596 // First body content may be in table!
2597 if ( bRestart && pPrv && pPrv->FindPageFrm() != FindPageFrm() )
2598 pPrv = 0;
2599 // <--
2601 nNewNum = pPrv ? ((SwTxtFrm*)pPrv)->GetAllLines() : 0;
2603 if ( rLineNum.IsCount() )
2604 nNewNum += GetThisLines();
2606 if ( nOld != nNewNum )
2608 nAllLines = nNewNum;
2609 SwCntntFrm *pNxt = GetNextCntntFrm();
2610 while ( pNxt &&
2611 (pNxt->IsInTab() || pNxt->IsInDocBody() != IsInDocBody()) )
2612 pNxt = pNxt->GetNextCntntFrm();
2613 if ( pNxt )
2615 if ( pNxt->GetUpper() != GetUpper() )
2616 pNxt->InvalidateLineNum();
2617 else
2618 pNxt->_InvalidateLineNum();
2624 void SwTxtFrm::VisitPortions( SwPortionHandler& rPH ) const
2626 const SwParaPortion* pPara = GetPara();
2628 if( pPara )
2630 if ( IsFollow() )
2631 rPH.Skip( GetOfst() );
2633 const SwLineLayout* pLine = pPara;
2634 while ( pLine )
2636 const SwLinePortion* pPor = pLine->GetFirstPortion();
2637 while ( pPor )
2639 pPor->HandlePortion( rPH );
2640 pPor = pPor->GetPortion();
2643 rPH.LineBreak();
2644 pLine = pLine->GetNext();
2648 rPH.Finish();
2652 /*************************************************************************
2653 * SwTxtFrm::GetScriptInfo()
2654 *************************************************************************/
2656 const SwScriptInfo* SwTxtFrm::GetScriptInfo() const
2658 const SwParaPortion* pPara = GetPara();
2659 return pPara ? &pPara->GetScriptInfo() : 0;
2662 /*************************************************************************
2663 * lcl_CalcFlyBasePos()
2664 * Helper function for SwTxtFrm::CalcBasePosForFly()
2665 *************************************************************************/
2667 SwTwips lcl_CalcFlyBasePos( const SwTxtFrm& rFrm, SwRect aFlyRect,
2668 SwTxtFly& rTxtFly )
2670 SWRECTFN( (&rFrm) )
2671 SwTwips nRet = rFrm.IsRightToLeft() ?
2672 (rFrm.Frm().*fnRect->fnGetRight)() :
2673 (rFrm.Frm().*fnRect->fnGetLeft)();
2677 SwRect aRect = rTxtFly.GetFrm( aFlyRect );
2678 if ( 0 != (aRect.*fnRect->fnGetWidth)() )
2680 if ( rFrm.IsRightToLeft() )
2682 if ( (aRect.*fnRect->fnGetRight)() -
2683 (aFlyRect.*fnRect->fnGetRight)() >= 0 )
2685 (aFlyRect.*fnRect->fnSetRight)(
2686 (aRect.*fnRect->fnGetLeft)() );
2687 nRet = (aRect.*fnRect->fnGetLeft)();
2689 else
2690 break;
2692 else
2694 if ( (aFlyRect.*fnRect->fnGetLeft)() -
2695 (aRect.*fnRect->fnGetLeft)() >= 0 )
2697 (aFlyRect.*fnRect->fnSetLeft)(
2698 (aRect.*fnRect->fnGetRight)() + 1 );
2699 nRet = (aRect.*fnRect->fnGetRight)();
2701 else
2702 break;
2705 else
2706 break;
2708 while ( (aFlyRect.*fnRect->fnGetWidth)() > 0 );
2710 return nRet;
2713 /*************************************************************************
2714 * SwTxtFrm::CalcBasePosForFly()
2715 *************************************************************************/
2717 void SwTxtFrm::CalcBaseOfstForFly()
2719 ASSERT( !IsVertical() || !IsSwapped(),
2720 "SwTxtFrm::CalcBasePosForFly with swapped frame!" )
2722 const SwNode* pNode = GetTxtNode();
2723 if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_FLY_OFFSETS) )
2724 return;
2726 SWRECTFN( this )
2728 SwRect aFlyRect( Frm().Pos() + Prt().Pos(), Prt().SSize() );
2730 // Get first 'real' line and adjust position and height of line rectangle
2731 // OD 08.09.2003 #110978#, #108749#, #110354# - correct behaviour,
2732 // if no 'real' line exists (empty paragraph with and without a dummy portion)
2734 SwTwips nTop = (aFlyRect.*fnRect->fnGetTop)();
2735 const SwLineLayout* pLay = GetPara();
2736 SwTwips nLineHeight = 200;
2737 while( pLay && pLay->IsDummy() && pLay->GetNext() )
2739 nTop += pLay->Height();
2740 pLay = pLay->GetNext();
2742 if ( pLay )
2744 nLineHeight = pLay->Height();
2746 (aFlyRect.*fnRect->fnSetTopAndHeight)( nTop, nLineHeight );
2749 SwTxtFly aTxtFly( this );
2750 aTxtFly.SetIgnoreCurrentFrame( sal_True );
2751 aTxtFly.SetIgnoreContour( sal_True );
2752 // --> OD 2004-12-17 #118809# - ignore objects in page header|footer for
2753 // text frames not in page header|footer
2754 aTxtFly.SetIgnoreObjsInHeaderFooter( sal_True );
2755 // <--
2756 SwTwips nRet1 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
2757 aTxtFly.SetIgnoreCurrentFrame( sal_False );
2758 SwTwips nRet2 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
2760 // make values relative to frame start position
2761 SwTwips nLeft = IsRightToLeft() ?
2762 (Frm().*fnRect->fnGetRight)() :
2763 (Frm().*fnRect->fnGetLeft)();
2765 mnFlyAnchorOfst = nRet1 - nLeft;
2766 mnFlyAnchorOfstNoWrap = nRet2 - nLeft;