xref: /AOO41X/main/sw/source/core/text/txtfrm.cxx (revision dec99bbd1eb6ae693d6ee672c1a69e3a32d917e7)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include <hintids.hxx>
27 #include <hints.hxx>
28 #include <svl/ctloptions.hxx>
29 #include <sfx2/printer.hxx>
30 #include <sfx2/sfxuno.hxx>
31 #include <editeng/langitem.hxx>
32 #include <editeng/lspcitem.hxx>
33 #include <editeng/lrspitem.hxx>
34 #include <editeng/ulspitem.hxx>
35 #include <editeng/brshitem.hxx>
36 #include <editeng/pgrditem.hxx>
37 #include <swmodule.hxx>
38 #include <SwSmartTagMgr.hxx>
39 #include <doc.hxx>      // GetDoc()
40 #include "rootfrm.hxx"
41 #include <pagefrm.hxx>  // InvalidateSpelling
42 #include <rootfrm.hxx>
43 #include <viewsh.hxx>   // ViewShell
44 #include <pam.hxx>      // SwPosition
45 #include <ndtxt.hxx>        // SwTxtNode
46 #include <txtatr.hxx>
47 #include <paratr.hxx>
48 #include <viewopt.hxx>
49 #include <dflyobj.hxx>
50 #include <flyfrm.hxx>
51 #include <tabfrm.hxx>
52 #include <frmtool.hxx>
53 #include <pagedesc.hxx> // SwPageDesc
54 #include <tgrditem.hxx>
55 #include <dbg_lay.hxx>
56 #include <fmtfld.hxx>
57 #include <fmtftn.hxx>
58 #include <txtfld.hxx>
59 #include <txtftn.hxx>
60 #include <charatr.hxx>
61 #include <ftninfo.hxx>
62 #include <fmtline.hxx>
63 #include <txtfrm.hxx>       // SwTxtFrm
64 #include <sectfrm.hxx>      // SwSectFrm
65 #include <txtcfg.hxx>       // DBG_LOOP
66 #include <itrform2.hxx>       // Iteratoren
67 #include <widorp.hxx>       // SwFrmBreak
68 #include <txtcache.hxx>
69 #include <fntcache.hxx>     // GetLineSpace benutzt pLastFont
70 #include <SwGrammarMarkUp.hxx>
71 #include <lineinfo.hxx>
72 #include <SwPortionHandler.hxx>
73 #include <dcontact.hxx>
74 #include <sortedobjs.hxx>
75 #include <txtflcnt.hxx>     // SwTxtFlyCnt
76 #include <fmtflcnt.hxx>     // SwFmtFlyCnt
77 #include <fmtcntnt.hxx>     // SwFmtCntnt
78 #include <numrule.hxx>
79 #include <swtable.hxx>
80 #include <fldupde.hxx>
81 #include <IGrammarContact.hxx>
82 #include <switerator.hxx>
83 
84 #if OSL_DEBUG_LEVEL > 1
85 #include <txtpaint.hxx>     // DbgRect
86 extern const sal_Char *GetPrepName( const enum PrepareHint ePrep );
87 #endif
88 
89 
90 TYPEINIT1( SwTxtFrm, SwCntntFrm );
91 
92 // Switches width and height of the text frame
SwapWidthAndHeight()93 void SwTxtFrm::SwapWidthAndHeight()
94 {
95     if ( ! bIsSwapped )
96     {
97         const long nPrtOfstX = Prt().Pos().X();
98         Prt().Pos().X() = Prt().Pos().Y();
99         //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
100         if( IsVertLR() )
101             Prt().Pos().Y() = nPrtOfstX;
102         else
103             Prt().Pos().Y() = Frm().Width() - ( nPrtOfstX + Prt().Width() );
104 
105     }
106     else
107     {
108         const long nPrtOfstY = Prt().Pos().Y();
109         Prt().Pos().Y() = Prt().Pos().X();
110         //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
111         if( IsVertLR() )
112             Prt().Pos().X() = nPrtOfstY;
113         else
114             Prt().Pos().X() = Frm().Height() - ( nPrtOfstY + Prt().Height() );
115     }
116 
117     const long nFrmWidth = Frm().Width();
118     Frm().Width( Frm().Height() );
119     Frm().Height( nFrmWidth );
120     const long nPrtWidth = Prt().Width();
121     Prt().Width( Prt().Height() );
122     Prt().Height( nPrtWidth );
123 
124     bIsSwapped = ! bIsSwapped;
125 }
126 
127 // Calculates the coordinates of a rectangle when switching from
128 // horizontal to vertical layout.
SwitchHorizontalToVertical(SwRect & rRect) const129 void SwTxtFrm::SwitchHorizontalToVertical( SwRect& rRect ) const
130 {
131     // calc offset inside frame
132     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
133     long nOfstX, nOfstY;
134     if ( IsVertLR() )
135     {
136         nOfstX = rRect.Left() - Frm().Left();
137         nOfstY = rRect.Top() - Frm().Top();
138     }
139     else
140     {
141         nOfstX = rRect.Left() - Frm().Left();
142         nOfstY = rRect.Top() + rRect.Height() - Frm().Top();
143     }
144 
145     const long nWidth = rRect.Width();
146     const long nHeight = rRect.Height();
147 
148     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
149     if ( IsVertLR() )
150         rRect.Left(Frm().Left() + nOfstY);
151     else
152     {
153         if ( bIsSwapped )
154             rRect.Left( Frm().Left() + Frm().Height() - nOfstY );
155         else
156             // frame is rotated
157             rRect.Left( Frm().Left() + Frm().Width() - nOfstY );
158     }
159 
160     rRect.Top( Frm().Top() + nOfstX );
161     rRect.Width( nHeight );
162     rRect.Height( nWidth );
163 }
164 
165 // Calculates the coordinates of a point when switching from
166 // horizontal to vertical layout.
SwitchHorizontalToVertical(Point & rPoint) const167 void SwTxtFrm::SwitchHorizontalToVertical( Point& rPoint ) const
168 {
169     // calc offset inside frame
170     const long nOfstX = rPoint.X() - Frm().Left();
171     const long nOfstY = rPoint.Y() - Frm().Top();
172     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
173     if ( IsVertLR() )
174         rPoint.X() = Frm().Left() + nOfstY;
175     else
176     {
177         if ( bIsSwapped )
178             rPoint.X() = Frm().Left() + Frm().Height() - nOfstY;
179         else
180             // calc rotated coords
181             rPoint.X() = Frm().Left() + Frm().Width() - nOfstY;
182     }
183 
184     rPoint.Y() = Frm().Top() + nOfstX;
185 }
186 
187 // Calculates the a limit value when switching from
188 // horizontal to vertical layout.
SwitchHorizontalToVertical(long nLimit) const189 long SwTxtFrm::SwitchHorizontalToVertical( long nLimit ) const
190 {
191     Point aTmp( 0, nLimit );
192     SwitchHorizontalToVertical( aTmp );
193     return aTmp.X();
194 }
195 
196 // Calculates the coordinates of a rectangle when switching from
197 // vertical to horizontal layout.
SwitchVerticalToHorizontal(SwRect & rRect) const198 void SwTxtFrm::SwitchVerticalToHorizontal( SwRect& rRect ) const
199 {
200     long nOfstX;
201 
202     // calc offset inside frame
203 
204     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
205     if ( IsVertLR() )
206         nOfstX = rRect.Left() - Frm().Left();
207     else
208     {
209         if ( bIsSwapped )
210             nOfstX = Frm().Left() + Frm().Height() - ( rRect.Left() + rRect.Width() );
211         else
212             nOfstX = Frm().Left() + Frm().Width() - ( rRect.Left() + rRect.Width() );
213     }
214 
215     const long nOfstY = rRect.Top() - Frm().Top();
216     const long nWidth = rRect.Height();
217     const long nHeight = rRect.Width();
218 
219     // calc rotated coords
220     rRect.Left( Frm().Left() + nOfstY );
221     rRect.Top( Frm().Top() + nOfstX );
222     rRect.Width( nWidth );
223     rRect.Height( nHeight );
224 }
225 
226 // Calculates the coordinates of a point when switching from
227 // vertical to horizontal layout.
SwitchVerticalToHorizontal(Point & rPoint) const228 void SwTxtFrm::SwitchVerticalToHorizontal( Point& rPoint ) const
229 {
230     long nOfstX;
231 
232     // calc offset inside frame
233 
234     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
235     if ( IsVertLR() )
236         nOfstX = rPoint.X() - Frm().Left();
237     else
238     {
239         if ( bIsSwapped )
240             nOfstX = Frm().Left() + Frm().Height() - rPoint.X();
241         else
242             nOfstX = Frm().Left() + Frm().Width() - rPoint.X();
243     }
244 
245     const long nOfstY = rPoint.Y() - Frm().Top();
246 
247     // calc rotated coords
248     rPoint.X() = Frm().Left() + nOfstY;
249     rPoint.Y() = Frm().Top() + nOfstX;
250 }
251 
252 // Calculates the a limit value when switching from
253 // vertical to horizontal layout.
SwitchVerticalToHorizontal(long nLimit) const254 long SwTxtFrm::SwitchVerticalToHorizontal( long nLimit ) const
255 {
256     Point aTmp( nLimit, 0 );
257     SwitchVerticalToHorizontal( aTmp );
258     return aTmp.Y();
259 }
260 
SwFrmSwapper(const SwTxtFrm * pTxtFrm,sal_Bool bSwapIfNotSwapped)261 SwFrmSwapper::SwFrmSwapper( const SwTxtFrm* pTxtFrm, sal_Bool bSwapIfNotSwapped )
262     : pFrm( pTxtFrm ), bUndo( sal_False )
263 {
264     if ( pFrm->IsVertical() &&
265         ( (   bSwapIfNotSwapped && ! pFrm->IsSwapped() ) ||
266           ( ! bSwapIfNotSwapped && pFrm->IsSwapped() ) ) )
267     {
268         bUndo = sal_True;
269         ((SwTxtFrm*)pFrm)->SwapWidthAndHeight();
270     }
271 }
272 
~SwFrmSwapper()273 SwFrmSwapper::~SwFrmSwapper()
274 {
275     if ( bUndo )
276         ((SwTxtFrm*)pFrm)->SwapWidthAndHeight();
277 }
278 
SwitchLTRtoRTL(SwRect & rRect) const279 void SwTxtFrm::SwitchLTRtoRTL( SwRect& rRect ) const
280 {
281     SWAP_IF_NOT_SWAPPED( this )
282 
283     long nWidth = rRect.Width();
284     rRect.Left( 2 * ( Frm().Left() + Prt().Left() ) +
285                 Prt().Width() - rRect.Right() - 1 );
286 
287     rRect.Width( nWidth );
288 
289     UNDO_SWAP( this )
290 }
291 
SwitchLTRtoRTL(Point & rPoint) const292 void SwTxtFrm::SwitchLTRtoRTL( Point& rPoint ) const
293 {
294     SWAP_IF_NOT_SWAPPED( this )
295 
296     rPoint.X() = 2 * ( Frm().Left() + Prt().Left() ) + Prt().Width() - rPoint.X() - 1;
297 
298     UNDO_SWAP( this )
299 }
300 
SwLayoutModeModifier(const OutputDevice & rOutp)301 SwLayoutModeModifier::SwLayoutModeModifier( const OutputDevice& rOutp ) :
302         rOut( rOutp ), nOldLayoutMode( rOutp.GetLayoutMode() )
303 {
304 }
305 
~SwLayoutModeModifier()306 SwLayoutModeModifier::~SwLayoutModeModifier()
307 {
308     ((OutputDevice&)rOut).SetLayoutMode( nOldLayoutMode );
309 }
310 
Modify(sal_Bool bChgToRTL)311 void SwLayoutModeModifier::Modify( sal_Bool bChgToRTL )
312 {
313     ((OutputDevice&)rOut).SetLayoutMode( bChgToRTL ?
314                                          TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_BIDI_RTL :
315                                          TEXT_LAYOUT_BIDI_STRONG );
316 }
317 
SetAuto()318 void SwLayoutModeModifier::SetAuto()
319 {
320     const sal_uLong nNewLayoutMode = nOldLayoutMode & ~TEXT_LAYOUT_BIDI_STRONG;
321     ((OutputDevice&)rOut).SetLayoutMode( nNewLayoutMode );
322 }
323 
SwDigitModeModifier(const OutputDevice & rOutp,LanguageType eCurLang)324 SwDigitModeModifier::SwDigitModeModifier( const OutputDevice& rOutp, LanguageType eCurLang ) :
325         rOut( rOutp ), nOldLanguageType( rOutp.GetDigitLanguage() )
326 {
327     LanguageType eLang = eCurLang;
328     const SvtCTLOptions::TextNumerals nTextNumerals = SW_MOD()->GetCTLOptions().GetCTLTextNumerals();
329 
330     if ( SvtCTLOptions::NUMERALS_HINDI == nTextNumerals )
331         eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
332     else if ( SvtCTLOptions::NUMERALS_ARABIC == nTextNumerals )
333         eLang = LANGUAGE_ENGLISH;
334     else if ( SvtCTLOptions::NUMERALS_SYSTEM == nTextNumerals )
335         eLang = (LanguageType)::GetAppLanguage();
336 
337     ((OutputDevice&)rOut).SetDigitLanguage( eLang );
338 }
339 
~SwDigitModeModifier()340 SwDigitModeModifier::~SwDigitModeModifier()
341 {
342     ((OutputDevice&)rOut).SetDigitLanguage( nOldLanguageType );
343 }
344 
345 /*************************************************************************
346  *                      SwTxtFrm::Init()
347  *************************************************************************/
348 
Init()349 void SwTxtFrm::Init()
350 {
351     ASSERT( !IsLocked(), "+SwTxtFrm::Init: this ist locked." );
352     if( !IsLocked() )
353     {
354         ClearPara();
355         ResetBlinkPor();
356         //Die Flags direkt setzen um ResetPreps und damit ein unnuetzes GetPara
357         //einzusparen.
358         // Nicht bOrphan, bLocked oder bWait auf sal_False setzen !
359         // bOrphan = bFlag7 = bFlag8 = sal_False;
360     }
361 }
362 
363 /*************************************************************************
364 |*  SwTxtFrm::CTORen/DTOR
365 |*************************************************************************/
366 
InitCtor()367 void SwTxtFrm::InitCtor()
368 {
369     nCacheIdx = MSHRT_MAX;
370     nOfst = 0;
371     nAllLines = 0;
372     nThisLines = 0;
373     mnFlyAnchorOfst = 0;
374     mnFlyAnchorOfstNoWrap = 0;
375     mnFtnLine = 0;
376     // OD 2004-03-17 #i11860#
377     mnHeightOfLastLine = 0;
378     // --> OD 2008-01-31 #newlistlevelattrs#
379     mnAdditionalFirstLineOffset = 0;
380     // <--
381 
382     nType = FRMC_TXT;
383     bLocked = bFormatted = bWidow = bUndersized = bJustWidow =
384         bEmpty = bInFtnConnect = bFtn = bRepaint = bBlinkPor =
385         bFieldFollow = bHasAnimation = bIsSwapped = sal_False;
386     // OD 14.03.2003 #i11760#
387     mbFollowFormatAllowed = sal_True;
388 }
389 
390 /*************************************************************************
391  *                      SwTxtFrm::SwTxtFrm()
392  *************************************************************************/
SwTxtFrm(SwTxtNode * const pNode,SwFrm * pSib)393 SwTxtFrm::SwTxtFrm(SwTxtNode * const pNode, SwFrm* pSib )
394     : SwCntntFrm( pNode, pSib )
395 {
396     InitCtor();
397 }
398 
399 /*************************************************************************
400  *                      SwTxtFrm::~SwTxtFrm()
401  *************************************************************************/
~SwTxtFrm()402 SwTxtFrm::~SwTxtFrm()
403 {
404     // Remove associated SwParaPortion from pTxtCache
405     ClearPara();
406 }
407 
GetTxt() const408 const XubString& SwTxtFrm::GetTxt() const
409 {
410     return GetTxtNode()->GetTxt();
411 }
412 
ResetPreps()413 void SwTxtFrm::ResetPreps()
414 {
415     if ( GetCacheIdx() != MSHRT_MAX )
416     {
417         SwParaPortion *pPara;
418         if( 0 != (pPara = GetPara()) )
419             pPara->ResetPreps();
420     }
421 }
422 
423 /*************************************************************************
424  *                        SwTxtFrm::IsHiddenNow()
425  *************************************************************************/
IsHiddenNow() const426 sal_Bool SwTxtFrm::IsHiddenNow() const
427 {
428     SwFrmSwapper aSwapper( this, sal_True );
429 
430     if( !Frm().Width() && IsValid() && GetUpper()->IsValid() )
431                                        //bei Stackueberlauf (StackHack) invalid!
432     {
433 //        ASSERT( false, "SwTxtFrm::IsHiddenNow: thin frame" );
434         return sal_True;
435     }
436 
437     const bool bHiddenCharsHidePara = GetTxtNode()->HasHiddenCharAttribute( true );
438     const bool bHiddenParaField = GetTxtNode()->HasHiddenParaField();
439     const ViewShell* pVsh = getRootFrm()->GetCurrShell();
440 
441     if ( pVsh && ( bHiddenCharsHidePara || bHiddenParaField ) )
442     {
443         if (
444              ( bHiddenParaField &&
445                ( !pVsh->GetViewOptions()->IsShowHiddenPara() &&
446                  !pVsh->GetViewOptions()->IsFldName() ) ) ||
447              ( bHiddenCharsHidePara &&
448                !pVsh->GetViewOptions()->IsShowHiddenChar() ) )
449         {
450             return sal_True;
451         }
452     }
453 
454     return sal_False;
455 }
456 
457 
458 /*************************************************************************
459  *                        SwTxtFrm::HideHidden()
460  *************************************************************************/
461 // Entfernt die Anhaengsel des Textfrms wenn dieser hidden ist
462 
HideHidden()463 void SwTxtFrm::HideHidden()
464 {
465     ASSERT( !GetFollow() && IsHiddenNow(),
466             "HideHidden on visible frame of hidden frame has follow" );
467 
468     const xub_StrLen nEnd = STRING_LEN;
469     HideFootnotes( GetOfst(), nEnd );
470     // OD 2004-01-15 #110582#
471     HideAndShowObjects();
472 
473     //Die Formatinfos sind jetzt obsolete
474     ClearPara();
475 }
476 
477 /*************************************************************************
478  *                        SwTxtFrm::HideFootnotes()
479  *************************************************************************/
HideFootnotes(xub_StrLen nStart,xub_StrLen nEnd)480 void SwTxtFrm::HideFootnotes( xub_StrLen nStart, xub_StrLen nEnd )
481 {
482     const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
483     if( pHints )
484     {
485         const sal_uInt16 nSize = pHints->Count();
486         SwPageFrm *pPage = 0;
487         for ( sal_uInt16 i = 0; i < nSize; ++i )
488         {
489             const SwTxtAttr *pHt = (*pHints)[i];
490             if ( pHt->Which() == RES_TXTATR_FTN )
491             {
492                 const xub_StrLen nIdx = *pHt->GetStart();
493                 if ( nEnd < nIdx )
494                     break;
495                 if( nStart <= nIdx )
496                 {
497                     if( !pPage )
498                         pPage = FindPageFrm();
499                     pPage->RemoveFtn( this, (SwTxtFtn*)pHt );
500                 }
501             }
502         }
503     }
504 }
505 
506 // --> OD 2005-03-30 #120729# - hotfix: WW8 documents contain at its end hidden,
507 // as-character anchored graphics, which are used for a graphic bullet list.
508 // As long as these graphic bullet list aren't imported, do not hide a
509 // at-character anchored object, if
510 // (a) the document is an imported WW8 document -
511 //     checked by checking certain compatibility options -,
512 // (b) the paragraph is the last content in the document and
513 // (c) the anchor character is an as-character anchored graphic.
lcl_HideObj(const SwTxtFrm & _rFrm,const RndStdIds _eAnchorType,const xub_StrLen _nObjAnchorPos,SwAnchoredObject * _pAnchoredObj)514 bool lcl_HideObj( const SwTxtFrm& _rFrm,
515                   const RndStdIds _eAnchorType,
516                   const xub_StrLen _nObjAnchorPos,
517                   SwAnchoredObject* _pAnchoredObj )
518 {
519     bool bRet( true );
520 
521     if (_eAnchorType == FLY_AT_CHAR)
522     {
523         const IDocumentSettingAccess* pIDSA = _rFrm.GetTxtNode()->getIDocumentSettingAccess();
524         if ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
525              !pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING) &&
526              !pIDSA->get(IDocumentSettingAccess::USE_FORMER_OBJECT_POS) &&
527               pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
528              _rFrm.IsInDocBody() && !_rFrm.FindNextCnt() )
529         {
530             const xub_Unicode cAnchorChar =
531                         _rFrm.GetTxtNode()->GetTxt().GetChar( _nObjAnchorPos );
532             if ( cAnchorChar == CH_TXTATR_BREAKWORD )
533             {
534                 const SwTxtAttr* const pHint(
535                     _rFrm.GetTxtNode()->GetTxtAttrForCharAt(_nObjAnchorPos,
536                         RES_TXTATR_FLYCNT) );
537                 if ( pHint )
538                 {
539                     const SwFrmFmt* pFrmFmt =
540                         static_cast<const SwTxtFlyCnt*>(pHint)->GetFlyCnt().GetFrmFmt();
541                     if ( pFrmFmt->Which() == RES_FLYFRMFMT )
542                     {
543                         SwNodeIndex nCntntIndex = *(pFrmFmt->GetCntnt().GetCntntIdx());
544                         nCntntIndex++;
545                         if ( nCntntIndex.GetNode().IsNoTxtNode() )
546                         {
547                             bRet = false;
548                             // set needed data structure values for object positioning
549                             SWRECTFN( (&_rFrm) );
550                             SwRect aLastCharRect( _rFrm.Frm() );
551                             (aLastCharRect.*fnRect->fnSetWidth)( 1 );
552                             _pAnchoredObj->maLastCharRect = aLastCharRect;
553                             _pAnchoredObj->mnLastTopOfLine = (aLastCharRect.*fnRect->fnGetTop)();
554                         }
555                     }
556                 }
557             }
558         }
559     }
560 
561     return bRet;
562 }
563 // <--
564 /*************************************************************************
565  *                        SwTxtFrm::HideAndShowObjects()
566  *************************************************************************/
567 /** method to hide/show objects
568 
569     OD 2004-01-15 #110582#
570     method hides respectively shows objects, which are anchored at paragraph,
571     at/as a character of the paragraph, corresponding to the paragraph and
572     paragraph portion visibility.
573 
574     - is called from HideHidden() - should hide objects in hidden paragraphs and
575     - from _Format() - should hide/show objects in partly visible paragraphs
576 
577     @author OD
578 */
HideAndShowObjects()579 void SwTxtFrm::HideAndShowObjects()
580 {
581     if ( GetDrawObjs() )
582     {
583         if ( IsHiddenNow() )
584         {
585             // complete paragraph is hidden. Thus, hide all objects
586             for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i )
587             {
588                 SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
589                 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
590                 // --> OD 2005-03-30 #120729# - hotfix: do not hide object
591                 // under certain conditions
592                 const RndStdIds eAnchorType( pContact->GetAnchorId() );
593                 const xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex();
594                 if ((eAnchorType != FLY_AT_CHAR) ||
595                     lcl_HideObj( *this, eAnchorType, nObjAnchorPos,
596                                  (*GetDrawObjs())[i] ))
597                 {
598                     pContact->MoveObjToInvisibleLayer( pObj );
599                 }
600                 // <--
601             }
602         }
603         else
604         {
605             // paragraph is visible, but can contain hidden text portion.
606             // first we check if objects are allowed to be hidden:
607             const SwTxtNode& rNode = *GetTxtNode();
608             const ViewShell* pVsh = getRootFrm()->GetCurrShell();
609             const bool bShouldBeHidden = !pVsh || !pVsh->GetWin() ||
610                                          !pVsh->GetViewOptions()->IsShowHiddenChar();
611 
612             // Thus, show all objects, which are anchored at paragraph and
613             // hide/show objects, which are anchored at/as character, according
614             // to the visibility of the anchor character.
615             for ( sal_uInt32 i = 0; i < GetDrawObjs()->Count(); ++i )
616             {
617                 SdrObject* pObj = (*GetDrawObjs())[i]->DrawObj();
618                 SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
619                 // --> OD 2005-03-30 #120729# - determine anchor type only once
620                 const RndStdIds eAnchorType( pContact->GetAnchorId() );
621                 // <--
622 
623                 if (eAnchorType == FLY_AT_PARA)
624                 {
625                     pContact->MoveObjToVisibleLayer( pObj );
626                 }
627                 else if ((eAnchorType == FLY_AT_CHAR) ||
628                          (eAnchorType == FLY_AS_CHAR))
629                 {
630                     xub_StrLen nHiddenStart;
631                     xub_StrLen nHiddenEnd;
632                     xub_StrLen nObjAnchorPos = pContact->GetCntntAnchorIndex().GetIndex();
633                     SwScriptInfo::GetBoundsOfHiddenRange( rNode, nObjAnchorPos, nHiddenStart, nHiddenEnd, 0 );
634                     // --> OD 2005-03-30 #120729# - hotfix: do not hide object
635                     // under certain conditions
636                     if ( nHiddenStart != STRING_LEN && bShouldBeHidden &&
637                          lcl_HideObj( *this, eAnchorType, nObjAnchorPos, (*GetDrawObjs())[i] ) )
638                     // <--
639                         pContact->MoveObjToInvisibleLayer( pObj );
640                     else
641                         pContact->MoveObjToVisibleLayer( pObj );
642                 }
643                 else
644                 {
645                     ASSERT( false,
646                             "<SwTxtFrm::HideAndShowObjects()> - object not anchored at/inside paragraph!?" );
647                 }
648             }
649         }
650     }
651 
652     if ( IsFollow() )
653     {
654         FindMaster()->HideAndShowObjects();
655     }
656 }
657 
658 /*************************************************************************
659  *                      SwTxtFrm::FindBrk()
660  *
661  * Liefert die erste Trennmoeglichkeit in der aktuellen Zeile zurueck.
662  * Die Methode wird in SwTxtFrm::Format() benutzt, um festzustellen, ob
663  * die Vorgaengerzeile mitformatiert werden muss.
664  * nFound ist <= nEndLine.
665  *************************************************************************/
666 
FindBrk(const XubString & rTxt,const xub_StrLen nStart,const xub_StrLen nEnd) const667 xub_StrLen SwTxtFrm::FindBrk( const XubString &rTxt,
668                               const xub_StrLen nStart,
669                               const xub_StrLen nEnd ) const
670 {
671     // --> OD 2009-12-28 #i104291# - applying patch to avoid overflow.
672     unsigned long nFound = nStart;
673     const xub_StrLen nEndLine = Min( nEnd, rTxt.Len() );
674 
675     // Wir ueberlesen erst alle Blanks am Anfang der Zeile (vgl. Bug 2235).
676     while( nFound <= nEndLine &&
677            ' ' == rTxt.GetChar( static_cast<xub_StrLen>(nFound) ) )
678     {
679          nFound++;
680     }
681 
682     // Eine knifflige Sache mit den TxtAttr-Dummy-Zeichen (hier "$"):
683     // "Dr.$Meyer" am Anfang der zweiten Zeile. Dahinter ein Blank eingegeben
684     // und das Wort rutscht nicht in die erste Zeile, obwohl es ginge.
685     // Aus diesem Grund nehmen wir das Dummy-Zeichen noch mit.
686     while( nFound <= nEndLine &&
687            ' ' != rTxt.GetChar( static_cast<xub_StrLen>(nFound) ) )
688     {
689         nFound++;
690     }
691 
692     return nFound <= STRING_LEN
693            ? static_cast<xub_StrLen>(nFound)
694            : STRING_LEN;
695     // <--
696 }
697 
698 /*************************************************************************
699  *                      SwTxtFrm::IsIdxInside()
700  *************************************************************************/
701 
IsIdxInside(const xub_StrLen nPos,const xub_StrLen nLen) const702 sal_Bool SwTxtFrm::IsIdxInside( const xub_StrLen nPos, const xub_StrLen nLen ) const
703 {
704     if( GetOfst() > nPos + nLen ) // d.h., der Bereich liegt komplett vor uns.
705         return sal_False;
706 
707     if( !GetFollow() )         // der Bereich liegt nicht komplett vor uns,
708         return sal_True;           // nach uns kommt niemand mehr.
709 
710     const xub_StrLen nMax = GetFollow()->GetOfst();
711 
712     // der Bereich liegt nicht komplett hinter uns bzw.
713     // unser Text ist geloescht worden.
714     if( nMax > nPos || nMax > GetTxt().Len() )
715         return sal_True;
716 
717     // changes made in the first line of a follow can modify the master
718     const SwParaPortion* pPara = GetFollow()->GetPara();
719     return pPara && ( nPos <= nMax + pPara->GetLen() );
720 }
721 
722 /*************************************************************************
723  *                      SwTxtFrm::InvalidateRange()
724  *************************************************************************/
InvalidateRange(const SwCharRange & aRange,const long nD)725 inline void SwTxtFrm::InvalidateRange(const SwCharRange &aRange, const long nD)
726 {
727     if ( IsIdxInside( aRange.Start(), aRange.Len() ) )
728         _InvalidateRange( aRange, nD );
729 }
730 
731 /*************************************************************************
732  *                      SwTxtFrm::_InvalidateRange()
733  *************************************************************************/
734 
_InvalidateRange(const SwCharRange & aRange,const long nD)735 void SwTxtFrm::_InvalidateRange( const SwCharRange &aRange, const long nD)
736 {
737     if ( !HasPara() )
738     {   InvalidateSize();
739         return;
740     }
741 
742     SetWidow( sal_False );
743     SwParaPortion *pPara = GetPara();
744 
745     sal_Bool bInv = sal_False;
746     if( 0 != nD )
747     {
748         //Auf nDelta werden die Differenzen zwischen alter und
749         //neuer Zeilenlaenge aufaddiert, deshalb ist es negativ,
750         //wenn Zeichen eingefuegt wurden, positiv, wenn Zeichen
751         //geloescht wurden.
752         *(pPara->GetDelta()) += nD;
753         bInv = sal_True;
754     }
755     SwCharRange &rReformat = *(pPara->GetReformat());
756     if(aRange != rReformat) {
757         if( STRING_LEN == rReformat.Len() )
758             rReformat = aRange;
759         else
760             rReformat += aRange;
761         bInv = sal_True;
762     }
763     if(bInv)
764     {
765 // 90365: nD is passed to a follow two times
766 //        if( GetFollow() )
767 //            ((SwTxtFrm*)GetFollow())->InvalidateRange( aRange, nD );
768         InvalidateSize();
769     }
770 }
771 
772 /*************************************************************************
773  *                      SwTxtFrm::CalcLineSpace()
774  *************************************************************************/
775 
CalcLineSpace()776 void SwTxtFrm::CalcLineSpace()
777 {
778     ASSERT( ! IsVertical() || ! IsSwapped(),
779             "SwTxtFrm::CalcLineSpace with swapped frame!" )
780 
781     if( IsLocked() || !HasPara() )
782         return;
783 
784     SwParaPortion *pPara;
785     if( GetDrawObjs() ||
786         GetTxtNode()->GetSwAttrSet().GetLRSpace().IsAutoFirst() ||
787         ( pPara = GetPara() )->IsFixLineHeight() )
788     {
789         Init();
790         return;
791     }
792 
793     Size aNewSize( Prt().SSize() );
794 
795     SwTxtFormatInfo aInf( this );
796     SwTxtFormatter aLine( this, &aInf );
797     if( aLine.GetDropLines() )
798     {
799         Init();
800         return;
801     }
802 
803     aLine.Top();
804     aLine.RecalcRealHeight();
805 
806     aNewSize.Height() = (aLine.Y() - Frm().Top()) + aLine.GetLineHeight();
807 
808     SwTwips nDelta = aNewSize.Height() - Prt().Height();
809     // 4291: Unterlauf bei Flys
810     if( aInf.GetTxtFly()->IsOn() )
811     {
812         SwRect aTmpFrm( Frm() );
813         if( nDelta < 0 )
814             aTmpFrm.Height( Prt().Height() );
815         else
816             aTmpFrm.Height( aNewSize.Height() );
817         if( aInf.GetTxtFly()->Relax( aTmpFrm ) )
818         {
819             Init();
820             return;
821         }
822     }
823 
824     if( nDelta )
825     {
826         SwTxtFrmBreak aBreak( this );
827         if( GetFollow() || aBreak.IsBreakNow( aLine ) )
828         {
829             // Wenn es einen Follow() gibt, oder wenn wir an dieser
830             // Stelle aufbrechen muessen, so wird neu formatiert.
831             Init();
832         }
833         else
834         {
835             // Alles nimmt seinen gewohnten Gang ...
836             pPara->SetPrepAdjust();
837             pPara->SetPrep();
838         }
839     }
840 }
841 
842 //
843 // SET_WRONG( nPos, nCnt, bMove )
844 //
845 #define SET_WRONG( nPos, nCnt, bMove ) \
846 { \
847     lcl_SetWrong( *this, nPos, nCnt, bMove ); \
848 }
849 
lcl_SetWrong(SwTxtFrm & rFrm,xub_StrLen nPos,long nCnt,bool bMove)850 void lcl_SetWrong( SwTxtFrm& rFrm, xub_StrLen nPos, long nCnt, bool bMove )
851 {
852     if ( !rFrm.IsFollow() )
853     {
854         SwTxtNode* pTxtNode = rFrm.GetTxtNode();
855         IGrammarContact* pGrammarContact = getGrammarContact( *pTxtNode );
856         SwGrammarMarkUp* pWrongGrammar = pGrammarContact ?
857             pGrammarContact->getGrammarCheck( *pTxtNode, false ) :
858             pTxtNode->GetGrammarCheck();
859         bool bGrammarProxy = pWrongGrammar != pTxtNode->GetGrammarCheck();
860         if( bMove )
861         {
862             if( pTxtNode->GetWrong() )
863                 pTxtNode->GetWrong()->Move( nPos, nCnt );
864             if( pWrongGrammar )
865                 pWrongGrammar->MoveGrammar( nPos, nCnt );
866             if( bGrammarProxy && pTxtNode->GetGrammarCheck() )
867                 pTxtNode->GetGrammarCheck()->MoveGrammar( nPos, nCnt );
868             if( pTxtNode->GetSmartTags() )
869                 pTxtNode->GetSmartTags()->Move( nPos, nCnt );
870         }
871         else
872         {
873             xub_StrLen nLen = (xub_StrLen)nCnt;
874             if( pTxtNode->GetWrong() )
875                 pTxtNode->GetWrong()->Invalidate( nPos, nLen );
876             if( pWrongGrammar )
877                 pWrongGrammar->Invalidate( nPos, nLen );
878             if( pTxtNode->GetSmartTags() )
879                 pTxtNode->GetSmartTags()->Invalidate( nPos, nLen );
880         }
881         if ( !pTxtNode->GetWrong() && !pTxtNode->IsWrongDirty() )
882         {
883             pTxtNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
884             pTxtNode->GetWrong()->SetInvalid( nPos, nPos + (sal_uInt16)( nCnt > 0 ? nCnt : 1 ) );
885         }
886         if ( !pTxtNode->GetSmartTags() && !pTxtNode->IsSmartTagDirty() )
887         {
888             // SMARTTAGS
889             pTxtNode->SetSmartTags( new SwWrongList( WRONGLIST_SMARTTAG ) );
890             pTxtNode->GetSmartTags()->SetInvalid( nPos, nPos + (sal_uInt16)( nCnt > 0 ? nCnt : 1 ) );
891         }
892         pTxtNode->SetWrongDirty( true );
893         pTxtNode->SetGrammarCheckDirty( true );
894         pTxtNode->SetWordCountDirty( true );
895         pTxtNode->SetAutoCompleteWordDirty( true );
896         // SMARTTAGS
897         pTxtNode->SetSmartTagDirty( true );
898     }
899 
900     SwRootFrm *pRootFrm = rFrm.getRootFrm();
901     if (pRootFrm)
902     {
903         pRootFrm->SetNeedGrammarCheck( sal_True );
904     }
905 
906     SwPageFrm *pPage = rFrm.FindPageFrm();
907     if( pPage )
908     {
909         pPage->InvalidateSpelling();
910         pPage->InvalidateAutoCompleteWords();
911         pPage->InvalidateWordCount();
912         pPage->InvalidateSmartTags();
913     }
914 }
915 
916 //
917 // SET_SCRIPT_INVAL( nPos )
918 //
919 
920 #define SET_SCRIPT_INVAL( nPos )\
921     lcl_SetScriptInval( *this, nPos );
922 
lcl_SetScriptInval(SwTxtFrm & rFrm,xub_StrLen nPos)923 void lcl_SetScriptInval( SwTxtFrm& rFrm, xub_StrLen nPos )
924 {
925     if( rFrm.GetPara() )
926         rFrm.GetPara()->GetScriptInfo().SetInvalidity( nPos );
927 }
928 
lcl_ModifyOfst(SwTxtFrm * pFrm,xub_StrLen nPos,xub_StrLen nLen)929 void lcl_ModifyOfst( SwTxtFrm* pFrm, xub_StrLen nPos, xub_StrLen nLen )
930 {
931     while( pFrm && pFrm->GetOfst() <= nPos )
932         pFrm = pFrm->GetFollow();
933     while( pFrm )
934     {
935         pFrm->ManipOfst( pFrm->GetOfst() + nLen );
936         pFrm = pFrm->GetFollow();
937     }
938 }
939 
940 /*************************************************************************
941  *                      SwTxtFrm::Modify()
942  *************************************************************************/
943 
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)944 void SwTxtFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
945 {
946     const MSHORT nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
947 
948     //Wuensche die FrmAttribute betreffen werden von der Basisklasse
949     //verarbeitet.
950     if( IsInRange( aFrmFmtSetRange, nWhich ) || RES_FMT_CHG == nWhich )
951     {
952         SwCntntFrm::Modify( pOld, pNew );
953         if( nWhich == RES_FMT_CHG && getRootFrm()->GetCurrShell() )
954         {
955             // Collection hat sich geaendert
956             Prepare( PREP_CLEAR );
957             _InvalidatePrt();
958             SET_WRONG( 0, STRING_LEN, false );
959             SetDerivedR2L( sal_False );
960             CheckDirChange();
961             // OD 09.12.2002 #105576# - Force complete paint due to existing
962             // indents.
963             SetCompletePaint();
964             InvalidateLineNum();
965         }
966         return;
967     }
968 
969     // Im gelockten Zustand werden keine Bestellungen angenommen.
970     if( IsLocked() )
971         return;
972 
973     // Dies spart Stack, man muss nur aufpassen,
974     // dass sie Variablen gesetzt werden.
975     xub_StrLen nPos, nLen;
976     sal_Bool bSetFldsDirty = sal_False;
977     sal_Bool bRecalcFtnFlag = sal_False;
978 
979     switch( nWhich )
980     {
981         case RES_LINENUMBER:
982         {
983             InvalidateLineNum();
984         }
985         break;
986         case RES_INS_TXT:
987         {
988             nPos = ((SwInsTxt*)pNew)->nPos;
989             nLen = ((SwInsTxt*)pNew)->nLen;
990             if( IsIdxInside( nPos, nLen ) )
991             {
992                 if( !nLen )
993                 {
994                     // 6969: Aktualisierung der NumPortions auch bei leeren Zeilen!
995                     if( nPos )
996                         InvalidateSize();
997                     else
998                         Prepare( PREP_CLEAR );
999                 }
1000                 else
1001                     _InvalidateRange( SwCharRange( nPos, nLen ), nLen );
1002             }
1003             SET_WRONG( nPos, nLen, true )
1004             SET_SCRIPT_INVAL( nPos )
1005             bSetFldsDirty = sal_True;
1006             if( HasFollow() )
1007                 lcl_ModifyOfst( this, nPos, nLen );
1008         }
1009         break;
1010         case RES_DEL_CHR:
1011         {
1012             nPos = ((SwDelChr*)pNew)->nPos;
1013             InvalidateRange( SwCharRange( nPos, 1 ), -1 );
1014             SET_WRONG( nPos, -1, true )
1015             SET_SCRIPT_INVAL( nPos )
1016             bSetFldsDirty = bRecalcFtnFlag = sal_True;
1017             if( HasFollow() )
1018                 lcl_ModifyOfst( this, nPos, STRING_LEN );
1019         }
1020         break;
1021         case RES_DEL_TXT:
1022         {
1023             nPos = ((SwDelTxt*)pNew)->nStart;
1024             nLen = ((SwDelTxt*)pNew)->nLen;
1025             long m = nLen;
1026             m *= -1;
1027             if( IsIdxInside( nPos, nLen ) )
1028             {
1029                 if( !nLen )
1030                     InvalidateSize();
1031                 else
1032                     InvalidateRange( SwCharRange( nPos, 1 ), m );
1033             }
1034             SET_WRONG( nPos, m, true )
1035             SET_SCRIPT_INVAL( nPos )
1036             bSetFldsDirty = bRecalcFtnFlag = sal_True;
1037             if( HasFollow() )
1038                 lcl_ModifyOfst( this, nPos, nLen );
1039         }
1040         break;
1041         case RES_UPDATE_ATTR:
1042         {
1043             nPos = ((SwUpdateAttr*)pNew)->nStart;
1044             nLen = ((SwUpdateAttr*)pNew)->nEnd - nPos;
1045             if( IsIdxInside( nPos, nLen ) )
1046             {
1047                 // Es muss in jedem Fall neu formatiert werden,
1048                 // auch wenn der invalidierte Bereich null ist.
1049                 // Beispiel: leere Zeile, 14Pt einstellen !
1050                 // if( !nLen ) nLen = 1;
1051 
1052                 // 6680: FtnNummern muessen formatiert werden.
1053                 if( !nLen )
1054                     nLen = 1;
1055 
1056                 _InvalidateRange( SwCharRange( nPos, nLen) );
1057                 MSHORT nTmp = ((SwUpdateAttr*)pNew)->nWhichAttr;
1058 
1059                 if( ! nTmp || RES_TXTATR_CHARFMT == nTmp || RES_TXTATR_AUTOFMT == nTmp ||
1060                     RES_FMT_CHG == nTmp || RES_ATTRSET_CHG == nTmp )
1061                 {
1062                     SET_WRONG( nPos, nPos + nLen, false )
1063                     SET_SCRIPT_INVAL( nPos )
1064                 }
1065             }
1066 
1067             // --> OD 2010-02-16 #i104008#
1068             ViewShell* pViewSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
1069             if ( pViewSh  )
1070             {
1071                 pViewSh->InvalidateAccessibleParaAttrs( *this );
1072             }
1073             // <--
1074         }
1075         break;
1076         case RES_OBJECTDYING:
1077         break;
1078 
1079         case RES_PARATR_LINESPACING:
1080             {
1081                 CalcLineSpace();
1082                 InvalidateSize();
1083                 _InvalidatePrt();
1084                 if( IsInSct() && !GetPrev() )
1085                 {
1086                     SwSectionFrm *pSect = FindSctFrm();
1087                     if( pSect->ContainsAny() == this )
1088                         pSect->InvalidatePrt();
1089                 }
1090 
1091                 // OD 09.01.2004 #i11859# - correction:
1092                 //  (1) Also invalidate next frame on next page/column.
1093                 //  (2) Skip empty sections and hidden paragraphs
1094                 //  Thus, use method <InvalidateNextPrtArea()>
1095                 InvalidateNextPrtArea();
1096 
1097                 SetCompletePaint();
1098             }
1099             break;
1100 
1101         case RES_TXTATR_FIELD:
1102         case RES_TXTATR_ANNOTATION:
1103             {
1104                 nPos = *((SwFmtFld*)pNew)->GetTxtFld()->GetStart();
1105                 if( IsIdxInside( nPos, 1 ) )
1106                 {
1107                     if( pNew == pOld )
1108                     {
1109                         // Nur repainten
1110                         // opt: invalidate aufs Window ?
1111                         InvalidatePage();
1112                         SetCompletePaint();
1113                     }
1114                     else
1115                         _InvalidateRange( SwCharRange( nPos, 1 ) );
1116                 }
1117                 bSetFldsDirty = sal_True;
1118                 // ST2
1119                 if ( SwSmartTagMgr::Get().IsSmartTagsEnabled() )
1120                     SET_WRONG( nPos, nPos + 1, false )
1121             }
1122             break;
1123 
1124         case RES_TXTATR_FTN :
1125         {
1126             nPos = *((SwFmtFtn*)pNew)->GetTxtFtn()->GetStart();
1127             if( IsInFtn() || IsIdxInside( nPos, 1 ) )
1128                 Prepare( PREP_FTN, ((SwFmtFtn*)pNew)->GetTxtFtn() );
1129             break;
1130         }
1131 
1132         case RES_ATTRSET_CHG:
1133         {
1134             InvalidateLineNum();
1135 
1136             SwAttrSet& rNewSet = *((SwAttrSetChg*)pNew)->GetChgSet();
1137             const SfxPoolItem* pItem = 0;
1138             int nClear = 0;
1139             MSHORT nCount = rNewSet.Count();
1140 
1141             if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FTN, sal_False, &pItem ))
1142             {
1143                 nPos = *((SwFmtFtn*)pItem)->GetTxtFtn()->GetStart();
1144                 if( IsIdxInside( nPos, 1 ) )
1145                     Prepare( PREP_FTN, pNew );
1146                 nClear = 0x01;
1147                 --nCount;
1148             }
1149 
1150             if( SFX_ITEM_SET == rNewSet.GetItemState( RES_TXTATR_FIELD, sal_False, &pItem ))
1151             {
1152                 nPos = *((SwFmtFld*)pItem)->GetTxtFld()->GetStart();
1153                 if( IsIdxInside( nPos, 1 ) )
1154                 {
1155                     const SfxPoolItem& rOldItem =
1156                         ((SwAttrSetChg*)pOld)->GetChgSet()->Get( RES_TXTATR_FIELD );
1157                     if( pItem == &rOldItem )
1158                     {
1159                         InvalidatePage();
1160                         SetCompletePaint();
1161                     }
1162                     else
1163                         _InvalidateRange( SwCharRange( nPos, 1 ) );
1164                 }
1165                 nClear |= 0x02;
1166                 --nCount;
1167             }
1168             sal_Bool bLineSpace = SFX_ITEM_SET == rNewSet.GetItemState(
1169                                             RES_PARATR_LINESPACING, sal_False ),
1170                      bRegister  = SFX_ITEM_SET == rNewSet.GetItemState(
1171                                             RES_PARATR_REGISTER, sal_False );
1172             if ( bLineSpace || bRegister )
1173             {
1174                 Prepare( bRegister ? PREP_REGISTER : PREP_ADJUST_FRM );
1175                 CalcLineSpace();
1176                 InvalidateSize();
1177                 _InvalidatePrt();
1178 
1179                 // OD 09.01.2004 #i11859# - correction:
1180                 //  (1) Also invalidate next frame on next page/column.
1181                 //  (2) Skip empty sections and hidden paragraphs
1182                 //  Thus, use method <InvalidateNextPrtArea()>
1183                 InvalidateNextPrtArea();
1184 
1185                 SetCompletePaint();
1186                 nClear |= 0x04;
1187                 if ( bLineSpace )
1188                 {
1189                     --nCount;
1190                     if( IsInSct() && !GetPrev() )
1191                     {
1192                         SwSectionFrm *pSect = FindSctFrm();
1193                         if( pSect->ContainsAny() == this )
1194                             pSect->InvalidatePrt();
1195                     }
1196                 }
1197                 if ( bRegister )
1198                     --nCount;
1199             }
1200             if ( SFX_ITEM_SET == rNewSet.GetItemState( RES_PARATR_SPLIT,
1201                                                        sal_False ))
1202             {
1203                 if ( GetPrev() )
1204                     CheckKeep();
1205                 Prepare( PREP_CLEAR );
1206                 InvalidateSize();
1207                 nClear |= 0x08;
1208                 --nCount;
1209             }
1210 
1211             if( SFX_ITEM_SET == rNewSet.GetItemState( RES_BACKGROUND, sal_False)
1212                 && !IsFollow() && GetDrawObjs() )
1213             {
1214                 SwSortedObjs *pObjs = GetDrawObjs();
1215                 for ( int i = 0; GetDrawObjs() && i < int(pObjs->Count()); ++i )
1216                 {
1217                     SwAnchoredObject* pAnchoredObj = (*pObjs)[MSHORT(i)];
1218                     if ( pAnchoredObj->ISA(SwFlyFrm) )
1219                     {
1220                         SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
1221                         if( !pFly->IsFlyInCntFrm() )
1222                         {
1223                             const SvxBrushItem &rBack =
1224                                 pFly->GetAttrSet()->GetBackground();
1225                             // OD 20.08.2002 #99657# #GetTransChg#
1226                             //     following condition determines, if the fly frame
1227                             //     "inherites" the background color of text frame.
1228                             //     This is the case, if fly frame background
1229                             //     color is "no fill"/"auto fill" and if the fly frame
1230                             //     has no background graphic.
1231                             //     Thus, check complete fly frame background
1232                             //     color and *not* only its transparency value
1233                             if ( (rBack.GetColor() == COL_TRANSPARENT)  &&
1234                             //if( rBack.GetColor().GetTransparency() &&
1235                                 rBack.GetGraphicPos() == GPOS_NONE )
1236                             {
1237                                 pFly->SetCompletePaint();
1238                                 pFly->InvalidatePage();
1239                             }
1240                         }
1241                     }
1242                 }
1243             }
1244 
1245             if ( SFX_ITEM_SET ==
1246                  rNewSet.GetItemState( RES_TXTATR_CHARFMT, sal_False ) )
1247             {
1248                 SET_WRONG( 0, STRING_LEN, false )
1249                 SET_SCRIPT_INVAL( 0 )
1250             }
1251             else if ( SFX_ITEM_SET ==
1252                       rNewSet.GetItemState( RES_CHRATR_LANGUAGE, sal_False ) ||
1253                       SFX_ITEM_SET ==
1254                       rNewSet.GetItemState( RES_CHRATR_CJK_LANGUAGE, sal_False ) ||
1255                       SFX_ITEM_SET ==
1256                       rNewSet.GetItemState( RES_CHRATR_CTL_LANGUAGE, sal_False ) )
1257                 SET_WRONG( 0, STRING_LEN, false )
1258             else if ( SFX_ITEM_SET ==
1259                       rNewSet.GetItemState( RES_CHRATR_FONT, sal_False ) ||
1260                       SFX_ITEM_SET ==
1261                       rNewSet.GetItemState( RES_CHRATR_CJK_FONT, sal_False ) ||
1262                       SFX_ITEM_SET ==
1263                       rNewSet.GetItemState( RES_CHRATR_CTL_FONT, sal_False ) )
1264                 SET_SCRIPT_INVAL( 0 )
1265             else if ( SFX_ITEM_SET ==
1266                       rNewSet.GetItemState( RES_FRAMEDIR, sal_False ) )
1267             {
1268                 SetDerivedR2L( sal_False );
1269                 CheckDirChange();
1270                 // OD 09.12.2002 #105576# - Force complete paint due to existing
1271                 // indents.
1272                 SetCompletePaint();
1273             }
1274 
1275 
1276             if( nCount )
1277             {
1278                 if( getRootFrm()->GetCurrShell() )
1279                 {
1280                     Prepare( PREP_CLEAR );
1281                     _InvalidatePrt();
1282                 }
1283 
1284                 if( nClear )
1285                 {
1286                     SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld );
1287                     SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew );
1288 
1289                     if( 0x01 & nClear )
1290                     {
1291                         aOldSet.ClearItem( RES_TXTATR_FTN );
1292                         aNewSet.ClearItem( RES_TXTATR_FTN );
1293                     }
1294                     if( 0x02 & nClear )
1295                     {
1296                         aOldSet.ClearItem( RES_TXTATR_FIELD );
1297                         aNewSet.ClearItem( RES_TXTATR_FIELD );
1298                     }
1299                     if ( 0x04 & nClear )
1300                     {
1301                         if ( bLineSpace )
1302                         {
1303                             aOldSet.ClearItem( RES_PARATR_LINESPACING );
1304                             aNewSet.ClearItem( RES_PARATR_LINESPACING );
1305                         }
1306                         if ( bRegister )
1307                         {
1308                             aOldSet.ClearItem( RES_PARATR_REGISTER );
1309                             aNewSet.ClearItem( RES_PARATR_REGISTER );
1310                         }
1311                     }
1312                     if ( 0x08 & nClear )
1313                     {
1314                         aOldSet.ClearItem( RES_PARATR_SPLIT );
1315                         aNewSet.ClearItem( RES_PARATR_SPLIT );
1316                     }
1317                     SwCntntFrm::Modify( &aOldSet, &aNewSet );
1318                 }
1319                 else
1320                     SwCntntFrm::Modify( pOld, pNew );
1321             }
1322 
1323             // --> OD 2009-01-06 #i88069#
1324             ViewShell* pViewSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
1325             if ( pViewSh  )
1326             {
1327                 pViewSh->InvalidateAccessibleParaAttrs( *this );
1328             }
1329             // <--
1330         }
1331         break;
1332 
1333         // 6870: SwDocPosUpdate auswerten.
1334         case RES_DOCPOS_UPDATE:
1335         {
1336             if( pOld && pNew )
1337             {
1338                 const SwDocPosUpdate *pDocPos = (const SwDocPosUpdate*)pOld;
1339                 if( pDocPos->nDocPos <= aFrm.Top() )
1340                 {
1341                     const SwFmtFld *pFld = (const SwFmtFld *)pNew;
1342                     InvalidateRange(
1343                         SwCharRange( *pFld->GetTxtFld()->GetStart(), 1 ) );
1344                 }
1345             }
1346             break;
1347         }
1348         case RES_PARATR_SPLIT:
1349             if ( GetPrev() )
1350                 CheckKeep();
1351             Prepare( PREP_CLEAR );
1352             bSetFldsDirty = sal_True;
1353             break;
1354         case RES_FRAMEDIR :
1355             SetDerivedR2L( sal_False );
1356             CheckDirChange();
1357             break;
1358         default:
1359         {
1360             Prepare( PREP_CLEAR );
1361             _InvalidatePrt();
1362             if ( !nWhich )
1363             {
1364                 //Wird z.B. bei HiddenPara mit 0 gerufen.
1365                 SwFrm *pNxt;
1366                 if ( 0 != (pNxt = FindNext()) )
1367                     pNxt->InvalidatePrt();
1368             }
1369         }
1370     } // switch
1371 
1372     if( bSetFldsDirty )
1373         GetNode()->getIDocumentFieldsAccess()->SetFieldsDirty( sal_True, GetNode(), 1 );
1374 
1375     if ( bRecalcFtnFlag )
1376         CalcFtnFlag();
1377 }
1378 
GetInfo(SfxPoolItem & rHnt) const1379 sal_Bool SwTxtFrm::GetInfo( SfxPoolItem &rHnt ) const
1380 {
1381     if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && ! IsFollow() )
1382     {
1383         SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt;
1384         const SwPageFrm *pPage = FindPageFrm();
1385         if ( pPage )
1386         {
1387             if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
1388             {
1389                 //Das sollte er sein (kann allenfalls temporaer anders sein,
1390                 //                    sollte uns das beunruhigen?)
1391                 rInfo.SetInfo( pPage, this );
1392                 return sal_False;
1393             }
1394             if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
1395                  (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
1396             {
1397                 //Das koennte er sein.
1398                 rInfo.SetInfo( pPage, this );
1399             }
1400         }
1401     }
1402     return sal_True;
1403 }
1404 
1405 /*************************************************************************
1406  *                      SwTxtFrm::PrepWidows()
1407  *************************************************************************/
1408 
PrepWidows(const MSHORT nNeed,sal_Bool bNotify)1409 void SwTxtFrm::PrepWidows( const MSHORT nNeed, sal_Bool bNotify )
1410 {
1411     ASSERT(GetFollow() && nNeed, "+SwTxtFrm::Prepare: lost all friends");
1412 
1413     SwParaPortion *pPara = GetPara();
1414     if ( !pPara )
1415         return;
1416     pPara->SetPrepWidows( sal_True );
1417 
1418     // These two lines of code have been deleted for #102340#.
1419     // Obviously the widow control does not work if we have a
1420     // pMaster->pFollow->pFollow situation:
1421 
1422     // returnen oder nicht ist hier die Frage.
1423     // Ohne IsLocked() ist 5156 gefaehrlich,
1424     // ohne IsFollow() werden die Orphans unterdrueckt: 6968.
1425     // Abfrage auf IsLocked erst hier, weil das Flag gesetzt werden soll.
1426 //  if( IsLocked() && IsFollow() )
1427 //      return;
1428 
1429     MSHORT nHave = nNeed;
1430 
1431     // Wir geben ein paar Zeilen ab und schrumpfen im CalcPreps()
1432     SWAP_IF_NOT_SWAPPED( this )
1433 
1434     SwTxtSizeInfo aInf( this );
1435     SwTxtMargin aLine( this, &aInf );
1436     aLine.Bottom();
1437     xub_StrLen nTmpLen = aLine.GetCurr()->GetLen();
1438     while( nHave && aLine.PrevLine() )
1439     {
1440         if( nTmpLen )
1441             --nHave;
1442         nTmpLen = aLine.GetCurr()->GetLen();
1443     }
1444     // In dieser Ecke tummelten sich einige Bugs: 7513, 7606.
1445     // Wenn feststeht, dass Zeilen abgegeben werden koennen,
1446     // muss der Master darueber hinaus die Widow-Regel ueberpruefen.
1447     if( !nHave )
1448     {
1449         sal_Bool bSplit;
1450         if( !IsFollow() )   //Nur ein Master entscheidet ueber Orphans
1451         {
1452             const WidowsAndOrphans aWidOrp( this );
1453             bSplit = ( aLine.GetLineNr() >= aWidOrp.GetOrphansLines() &&
1454                        aLine.GetLineNr() >= aLine.GetDropLines() );
1455         }
1456         else
1457             bSplit = sal_True;
1458 
1459         if( bSplit )
1460         {
1461             GetFollow()->SetOfst( aLine.GetEnd() );
1462             aLine.TruncLines( sal_True );
1463             if( pPara->IsFollowField() )
1464                 GetFollow()->SetFieldFollow( sal_True );
1465         }
1466     }
1467     if ( bNotify )
1468     {
1469         _InvalidateSize();
1470         InvalidatePage();
1471     }
1472 
1473     UNDO_SWAP( this )
1474 }
1475 
1476 /*************************************************************************
1477  *                      SwTxtFrm::Prepare
1478  *************************************************************************/
1479 
lcl_ErgoVadis(SwTxtFrm * pFrm,xub_StrLen & rPos,const PrepareHint ePrep)1480 sal_Bool lcl_ErgoVadis( SwTxtFrm* pFrm, xub_StrLen &rPos, const PrepareHint ePrep )
1481 {
1482     const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1483     if( ePrep == PREP_ERGOSUM )
1484     {
1485         if( !rFtnInfo.aErgoSum.Len() )
1486             return sal_False;;
1487         rPos = pFrm->GetOfst();
1488     }
1489     else
1490     {
1491         if( !rFtnInfo.aQuoVadis.Len() )
1492             return sal_False;
1493         if( pFrm->HasFollow() )
1494             rPos = pFrm->GetFollow()->GetOfst();
1495         else
1496             rPos = pFrm->GetTxt().Len();
1497         if( rPos )
1498             --rPos; // unser letztes Zeichen
1499     }
1500     return sal_True;
1501 }
1502 
Prepare(const PrepareHint ePrep,const void * pVoid,sal_Bool bNotify)1503 void SwTxtFrm::Prepare( const PrepareHint ePrep, const void* pVoid,
1504                         sal_Bool bNotify )
1505 {
1506     SwFrmSwapper aSwapper( this, sal_False );
1507 
1508 #if OSL_DEBUG_LEVEL > 1
1509     const SwTwips nDbgY = Frm().Top();
1510     (void)nDbgY;
1511 #endif
1512 
1513     if ( IsEmpty() )
1514     {
1515         switch ( ePrep )
1516         {
1517             case PREP_BOSS_CHGD:
1518                 SetInvalidVert( sal_True );  // Test
1519             case PREP_WIDOWS_ORPHANS:
1520             case PREP_WIDOWS:
1521             case PREP_FTN_GONE :    return;
1522 
1523             case PREP_POS_CHGD :
1524             {
1525                 // Auch in (spaltigen) Bereichen ist ein InvalidateSize notwendig,
1526                 // damit formatiert wird und ggf. das bUndersized gesetzt wird.
1527                 if( IsInFly() || IsInSct() )
1528                 {
1529                     SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1530                         GetUpper()->Prt().Bottom();
1531                     if( nTmpBottom < Frm().Bottom() )
1532                         break;
1533                 }
1534                 // Gibt es ueberhaupt Flys auf der Seite ?
1535                 SwTxtFly aTxtFly( this );
1536                 if( aTxtFly.IsOn() )
1537                 {
1538                     // Ueberlappt irgendein Fly ?
1539                     aTxtFly.Relax();
1540                     if ( aTxtFly.IsOn() || IsUndersized() )
1541                         break;
1542                 }
1543                 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue())
1544                     break;
1545 
1546                 GETGRID( FindPageFrm() )
1547                 if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1548                     break;
1549 
1550                 // --> OD 2004-07-16 #i28701# - consider anchored objects
1551                 if ( GetDrawObjs() )
1552                     break;
1553                 // <--
1554 
1555                 return;
1556             }
1557             default:
1558                 break;
1559         }
1560     }
1561 
1562     if( !HasPara() && PREP_MUST_FIT != ePrep )
1563     {
1564         SetInvalidVert( sal_True );  // Test
1565         ASSERT( !IsLocked(), "SwTxtFrm::Prepare: three of a perfect pair" );
1566         if ( bNotify )
1567             InvalidateSize();
1568         else
1569             _InvalidateSize();
1570         return;
1571     }
1572 
1573     //Objekt mit Locking aus dem Cache holen.
1574     SwTxtLineAccess aAccess( this );
1575     SwParaPortion *pPara = aAccess.GetPara();
1576 
1577     switch( ePrep )
1578     {
1579         case PREP_MOVEFTN :     Frm().Height(0);
1580                                 Prt().Height(0);
1581                                 _InvalidatePrt();
1582                                 _InvalidateSize();
1583                                 // KEIN break
1584         case PREP_ADJUST_FRM :  pPara->SetPrepAdjust( sal_True );
1585                                 if( IsFtnNumFrm() != pPara->IsFtnNum() ||
1586                                     IsUndersized() )
1587                                 {
1588                                     InvalidateRange( SwCharRange( 0, 1 ), 1);
1589                                     if( GetOfst() && !IsFollow() )
1590                                         _SetOfst( 0 );
1591                                 }
1592                                 break;
1593         case PREP_MUST_FIT :        pPara->SetPrepMustFit( sal_True );
1594             /* no break here */
1595         case PREP_WIDOWS_ORPHANS :  pPara->SetPrepAdjust( sal_True );
1596                                     break;
1597 
1598         case PREP_WIDOWS :
1599             // MustFit ist staerker als alles anderes
1600             if( pPara->IsPrepMustFit() )
1601                 return;
1602             // Siehe Kommentar in WidowsAndOrphans::FindOrphans und CalcPreps()
1603             PrepWidows( *(const MSHORT *)pVoid, bNotify );
1604             break;
1605 
1606         case PREP_FTN :
1607         {
1608             SwTxtFtn *pFtn = (SwTxtFtn *)pVoid;
1609             if( IsInFtn() )
1610             {
1611                 // Bin ich der erste TxtFrm einer Fussnote ?
1612                 if( !GetPrev() )
1613                     // Wir sind also ein TxtFrm der Fussnote, die
1614                     // die Fussnotenzahl zur Anzeige bringen muss.
1615                     // Oder den ErgoSum-Text...
1616                     InvalidateRange( SwCharRange( 0, 1 ), 1);
1617 
1618                 if( !GetNext() )
1619                 {
1620                     // Wir sind der letzte Ftn, jetzt muessten die
1621                     // QuoVadis-Texte geupdated werden.
1622                     const SwFtnInfo &rFtnInfo = GetNode()->GetDoc()->GetFtnInfo();
1623                     if( !pPara->UpdateQuoVadis( rFtnInfo.aQuoVadis ) )
1624                     {
1625                         xub_StrLen nPos = pPara->GetParLen();
1626                         if( nPos )
1627                             --nPos;
1628                         InvalidateRange( SwCharRange( nPos, 1 ), 1);
1629                     }
1630                 }
1631             }
1632             else
1633             {
1634                 // Wir sind also der TxtFrm _mit_ der Fussnote
1635                 const xub_StrLen nPos = *pFtn->GetStart();
1636                 InvalidateRange( SwCharRange( nPos, 1 ), 1);
1637             }
1638             break;
1639         }
1640         case PREP_BOSS_CHGD :
1641         {
1642     // Test
1643             {
1644                 SetInvalidVert( sal_False );
1645                 sal_Bool bOld = IsVertical();
1646                 SetInvalidVert( sal_True );
1647                 if( bOld != IsVertical() )
1648                     InvalidateRange( SwCharRange( GetOfst(), STRING_LEN ) );
1649             }
1650 
1651             if( HasFollow() )
1652             {
1653                 xub_StrLen nNxtOfst = GetFollow()->GetOfst();
1654                 if( nNxtOfst )
1655                     --nNxtOfst;
1656                 InvalidateRange( SwCharRange( nNxtOfst, 1 ), 1);
1657             }
1658             if( IsInFtn() )
1659             {
1660                 xub_StrLen nPos;
1661                 if( lcl_ErgoVadis( this, nPos, PREP_QUOVADIS ) )
1662                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1663                 if( lcl_ErgoVadis( this, nPos, PREP_ERGOSUM ) )
1664                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1665             }
1666             // 4739: Wenn wir ein Seitennummernfeld besitzen, muessen wir
1667             // die Stellen invalidieren.
1668             SwpHints *pHints = GetTxtNode()->GetpSwpHints();
1669             if( pHints )
1670             {
1671                 const sal_uInt16 nSize = pHints->Count();
1672                 const xub_StrLen nEnd = GetFollow() ?
1673                                     GetFollow()->GetOfst() : STRING_LEN;
1674                 for ( sal_uInt16 i = 0; i < nSize; ++i )
1675                 {
1676                     const SwTxtAttr *pHt = (*pHints)[i];
1677                     const xub_StrLen nStart = *pHt->GetStart();
1678                     if( nStart >= GetOfst() )
1679                     {
1680                         if( nStart >= nEnd )
1681                             i = nSize;          // fuehrt das Ende herbei
1682                         else
1683                         {
1684                 // 4029: wenn wir zurueckfliessen und eine Ftn besitzen, so
1685                 // fliesst die Ftn in jedem Fall auch mit. Damit sie nicht im
1686                 // Weg steht, schicken wir uns ein ADJUST_FRM.
1687                 // pVoid != 0 bedeutet MoveBwd()
1688                             const MSHORT nWhich = pHt->Which();
1689                             if( RES_TXTATR_FIELD == nWhich ||
1690                                 (HasFtn() && pVoid && RES_TXTATR_FTN == nWhich))
1691                             InvalidateRange( SwCharRange( nStart, 1 ), 1 );
1692                         }
1693                     }
1694                 }
1695             }
1696             // A new boss, a new chance for growing
1697             if( IsUndersized() )
1698             {
1699                 _InvalidateSize();
1700                 InvalidateRange( SwCharRange( GetOfst(), 1 ), 1);
1701             }
1702             break;
1703         }
1704 
1705         case PREP_POS_CHGD :
1706         {
1707             if ( GetValidPrtAreaFlag() )
1708             {
1709                 GETGRID( FindPageFrm() )
1710                 if ( pGrid && GetTxtNode()->GetSwAttrSet().GetParaGrid().GetValue() )
1711                     InvalidatePrt();
1712             }
1713 
1714             // Falls wir mit niemandem ueberlappen:
1715             // Ueberlappte irgendein Fly _vor_ der Positionsaenderung ?
1716             sal_Bool bFormat = pPara->HasFly();
1717             if( !bFormat )
1718             {
1719                 if( IsInFly() )
1720                 {
1721                     SwTwips nTmpBottom = GetUpper()->Frm().Top() +
1722                         GetUpper()->Prt().Bottom();
1723                     if( nTmpBottom < Frm().Bottom() )
1724                         bFormat = sal_True;
1725                 }
1726                 if( !bFormat )
1727                 {
1728                     if ( GetDrawObjs() )
1729                     {
1730                         const sal_uInt32 nCnt = GetDrawObjs()->Count();
1731                         for ( MSHORT i = 0; i < nCnt; ++i )
1732                         {
1733                             SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i];
1734                             // --> OD 2004-07-16 #i28701# - consider all
1735                             // to-character anchored objects
1736                             if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
1737                                     == FLY_AT_CHAR )
1738                             {
1739                                 bFormat = sal_True;
1740                                 break;
1741                             }
1742                         }
1743                     }
1744                     if( !bFormat )
1745                     {
1746                         // Gibt es ueberhaupt Flys auf der Seite ?
1747                         SwTxtFly aTxtFly( this );
1748                         if( aTxtFly.IsOn() )
1749                         {
1750                             // Ueberlappt irgendein Fly ?
1751                             aTxtFly.Relax();
1752                             bFormat = aTxtFly.IsOn() || IsUndersized();
1753                         }
1754                     }
1755                 }
1756             }
1757 
1758             if( bFormat )
1759             {
1760                 if( !IsLocked() )
1761                 {
1762                     if( pPara->GetRepaint()->HasArea() )
1763                         SetCompletePaint();
1764                     Init();
1765                     pPara = 0;
1766                     _InvalidateSize();
1767                 }
1768             }
1769             else
1770             {
1771                 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1772                     Prepare( PREP_REGISTER, 0, bNotify );
1773                 // Durch Positionsverschiebungen mit Ftns muessen die
1774                 // Frames neu adjustiert werden.
1775                 else if( HasFtn() )
1776                 {
1777                     Prepare( PREP_ADJUST_FRM, 0, bNotify );
1778                     _InvalidateSize();
1779                 }
1780                 else
1781                     return;     // damit kein SetPrep() erfolgt.
1782             }
1783             break;
1784         }
1785         case PREP_REGISTER:
1786             if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1787             {
1788                 pPara->SetPrepAdjust( sal_True );
1789                 CalcLineSpace();
1790                 InvalidateSize();
1791                 _InvalidatePrt();
1792                 SwFrm* pNxt;
1793                 if ( 0 != ( pNxt = GetIndNext() ) )
1794                 {
1795                     pNxt->_InvalidatePrt();
1796                     if ( pNxt->IsLayoutFrm() )
1797                         pNxt->InvalidatePage();
1798                 }
1799                 SetCompletePaint();
1800             }
1801             break;
1802         case PREP_FTN_GONE :
1803             {
1804                 // Wenn ein Follow uns ruft, weil eine Fussnote geloescht wird, muss unsere
1805                 // letzte Zeile formatiert werden, damit ggf. die erste Zeile des Follows
1806                 // hochrutschen kann, die extra auf die naechste Seite gerutscht war, um mit
1807                 // der Fussnote zusammen zu sein, insbesondere bei spaltigen Bereichen.
1808                 ASSERT( GetFollow(), "PREP_FTN_GONE darf nur vom Follow gerufen werden" );
1809                 xub_StrLen nPos = GetFollow()->GetOfst();
1810                 if( IsFollow() && GetOfst() == nPos )       // falls wir gar keine Textmasse besitzen,
1811                     FindMaster()->Prepare( PREP_FTN_GONE ); // rufen wir das Prepare unseres Masters
1812                 if( nPos )
1813                     --nPos; // das Zeichen vor unserem Follow
1814                 InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1815                 return;
1816             }
1817         case PREP_ERGOSUM:
1818         case PREP_QUOVADIS:
1819             {
1820                 xub_StrLen nPos;
1821                 if( lcl_ErgoVadis( this, nPos, ePrep ) )
1822                     InvalidateRange( SwCharRange( nPos, 1 ), 0 );
1823             }
1824             break;
1825         case PREP_FLY_ATTR_CHG:
1826         {
1827             if( pVoid )
1828             {
1829                 xub_StrLen nWhere = CalcFlyPos( (SwFrmFmt*)pVoid );
1830                 ASSERT( STRING_LEN != nWhere, "Prepare: Why me?" );
1831                 InvalidateRange( SwCharRange( nWhere, 1 ) );
1832                 return;
1833             }
1834             // else ... Laufe in den Default-Switch
1835         }
1836         case PREP_CLEAR:
1837         default:
1838         {
1839             if( IsLocked() )
1840             {
1841                 if( PREP_FLY_ARRIVE == ePrep || PREP_FLY_LEAVE == ePrep )
1842                 {
1843                     xub_StrLen nLen = ( GetFollow() ? GetFollow()->GetOfst() :
1844                                       STRING_LEN ) - GetOfst();
1845                     InvalidateRange( SwCharRange( GetOfst(), nLen ), 0 );
1846                 }
1847             }
1848             else
1849             {
1850                 if( pPara->GetRepaint()->HasArea() )
1851                     SetCompletePaint();
1852                 Init();
1853                 pPara = 0;
1854                 if( GetOfst() && !IsFollow() )
1855                     _SetOfst( 0 );
1856                 if ( bNotify )
1857                     InvalidateSize();
1858                 else
1859                     _InvalidateSize();
1860             }
1861             return;     // damit kein SetPrep() erfolgt.
1862         }
1863     }
1864     if( pPara )
1865         pPara->SetPrep( sal_True );
1866 }
1867 
1868 /* -----------------11.02.99 17:56-------------------
1869  * Kleine Hilfsklasse mit folgender Funktion:
1870  * Sie soll eine Probeformatierung vorbereiten.
1871  * Der Frame wird in Groesse und Position angepasst, sein SwParaPortion zur Seite
1872  * gestellt und eine neue erzeugt, dazu wird formatiert mit gesetztem bTestFormat.
1873  * Im Dtor wird der TxtFrm wieder in seinen alten Zustand zurueckversetzt.
1874  *
1875  * --------------------------------------------------*/
1876 
1877 class SwTestFormat
1878 {
1879     SwTxtFrm *pFrm;
1880     SwParaPortion *pOldPara;
1881     SwRect aOldFrm, aOldPrt;
1882 public:
1883     SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPrv, SwTwips nMaxHeight );
1884     ~SwTestFormat();
1885 };
1886 
SwTestFormat(SwTxtFrm * pTxtFrm,const SwFrm * pPre,SwTwips nMaxHeight)1887 SwTestFormat::SwTestFormat( SwTxtFrm* pTxtFrm, const SwFrm* pPre, SwTwips nMaxHeight )
1888     : pFrm( pTxtFrm )
1889 {
1890     aOldFrm = pFrm->Frm();
1891     aOldPrt = pFrm->Prt();
1892 
1893     SWRECTFN( pFrm )
1894     SwTwips nLower = (pFrm->*fnRect->fnGetBottomMargin)();
1895 
1896     pFrm->Frm() = pFrm->GetUpper()->Prt();
1897     pFrm->Frm() += pFrm->GetUpper()->Frm().Pos();
1898 
1899     (pFrm->Frm().*fnRect->fnSetHeight)( nMaxHeight );
1900     if( pFrm->GetPrev() )
1901         (pFrm->Frm().*fnRect->fnSetPosY)(
1902                 (pFrm->GetPrev()->Frm().*fnRect->fnGetBottom)() -
1903                 ( bVert ? nMaxHeight + 1 : 0 ) );
1904 
1905     SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
1906     const SwBorderAttrs &rAttrs = *aAccess.Get();
1907     (pFrm->Prt().*fnRect->fnSetPosX)( rAttrs.CalcLeft( pFrm ) );
1908 
1909     if( pPre )
1910     {
1911         SwTwips nUpper = pFrm->CalcUpperSpace( &rAttrs, pPre );
1912         (pFrm->Prt().*fnRect->fnSetPosY)( nUpper );
1913     }
1914     (pFrm->Prt().*fnRect->fnSetHeight)(
1915         Max( 0L , (pFrm->Frm().*fnRect->fnGetHeight)() -
1916                   (pFrm->Prt().*fnRect->fnGetTop)() - nLower ) );
1917     (pFrm->Prt().*fnRect->fnSetWidth)(
1918         (pFrm->Frm().*fnRect->fnGetWidth)() -
1919         // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
1920         ( rAttrs.CalcLeft( pFrm ) + rAttrs.CalcRight( pFrm ) ) );
1921     pOldPara = pFrm->HasPara() ? pFrm->GetPara() : NULL;
1922     pFrm->SetPara( new SwParaPortion(), sal_False );
1923 
1924     ASSERT( ! pFrm->IsSwapped(), "A frame is swapped before _Format" );
1925 
1926     if ( pFrm->IsVertical() )
1927         pFrm->SwapWidthAndHeight();
1928 
1929     SwTxtFormatInfo aInf( pFrm, sal_False, sal_True, sal_True );
1930     SwTxtFormatter  aLine( pFrm, &aInf );
1931 
1932     pFrm->_Format( aLine, aInf );
1933 
1934     if ( pFrm->IsVertical() )
1935         pFrm->SwapWidthAndHeight();
1936 
1937     ASSERT( ! pFrm->IsSwapped(), "A frame is swapped after _Format" );
1938 }
1939 
~SwTestFormat()1940 SwTestFormat::~SwTestFormat()
1941 {
1942     pFrm->Frm() = aOldFrm;
1943     pFrm->Prt() = aOldPrt;
1944     pFrm->SetPara( pOldPara );
1945 }
1946 
TestFormat(const SwFrm * pPrv,SwTwips & rMaxHeight,sal_Bool & bSplit)1947 sal_Bool SwTxtFrm::TestFormat( const SwFrm* pPrv, SwTwips &rMaxHeight, sal_Bool &bSplit )
1948 {
1949     PROTOCOL_ENTER( this, PROT_TESTFORMAT, 0, 0 )
1950 
1951     if( IsLocked() && GetUpper()->Prt().Width() <= 0 )
1952         return sal_False;
1953 
1954     SwTestFormat aSave( this, pPrv, rMaxHeight );
1955 
1956     return SwTxtFrm::WouldFit( rMaxHeight, bSplit, sal_True );
1957 }
1958 
1959 
1960 /*************************************************************************
1961  *                      SwTxtFrm::WouldFit()
1962  *************************************************************************/
1963 
1964 /* SwTxtFrm::WouldFit()
1965  * sal_True: wenn ich aufspalten kann.
1966  * Es soll und braucht nicht neu formatiert werden.
1967  * Wir gehen davon aus, dass bereits formatiert wurde und dass
1968  * die Formatierungsdaten noch aktuell sind.
1969  * Wir gehen davon aus, dass die Framebreiten des evtl. Masters und
1970  * Follows gleich sind. Deswegen wird kein FindBreak() mit FindOrphans()
1971  * gerufen.
1972  * Die benoetigte Hoehe wird von nMaxHeight abgezogen!
1973  */
1974 
WouldFit(SwTwips & rMaxHeight,sal_Bool & bSplit,sal_Bool bTst)1975 sal_Bool SwTxtFrm::WouldFit( SwTwips &rMaxHeight, sal_Bool &bSplit, sal_Bool bTst )
1976 {
1977     ASSERT( ! IsVertical() || ! IsSwapped(),
1978             "SwTxtFrm::WouldFit with swapped frame" );
1979     SWRECTFN( this );
1980 
1981     if( IsLocked() )
1982         return sal_False;
1983 
1984     //Kann gut sein, dass mir der IdleCollector mir die gecachten
1985     //Informationen entzogen hat.
1986     if( !IsEmpty() )
1987         GetFormatted();
1988 
1989     // OD 2004-05-24 #i27801# - correction: 'short cut' for empty paragraph
1990     // can *not* be applied, if test format is in progress. The test format doesn't
1991     // adjust the frame and the printing area - see method <SwTxtFrm::_Format(..)>,
1992     // which is called in <SwTxtFrm::TestFormat(..)>
1993     if ( IsEmpty() && !bTst )
1994     {
1995         bSplit = sal_False;
1996         SwTwips nHeight = bVert ? Prt().SSize().Width() : Prt().SSize().Height();
1997         if( rMaxHeight < nHeight )
1998             return sal_False;
1999         else
2000         {
2001             rMaxHeight -= nHeight;
2002             return sal_True;
2003         }
2004     }
2005 
2006     // In sehr unguenstigen Faellen kann GetPara immer noch 0 sein.
2007     // Dann returnen wir sal_True, um auf der neuen Seite noch einmal
2008     // anformatiert zu werden.
2009     ASSERT( HasPara() || IsHiddenNow(), "WouldFit: GetFormatted() and then !HasPara()" );
2010     if( !HasPara() || ( !(Frm().*fnRect->fnGetHeight)() && IsHiddenNow() ) )
2011         return sal_True;
2012 
2013     // Da das Orphan-Flag nur sehr fluechtig existiert, wird als zweite
2014     // Bedingung  ueberprueft, ob die Rahmengroesse durch CalcPreps
2015     // auf riesengross gesetzt wird, um ein MoveFwd zu erzwingen.
2016     if( IsWidow() || ( bVert ?
2017                        ( 0 == Frm().Left() ) :
2018                        ( LONG_MAX - 20000 < Frm().Bottom() ) ) )
2019     {
2020         SetWidow(sal_False);
2021         if ( GetFollow() )
2022         {
2023             // Wenn wir hier durch eine Widow-Anforderung unseres Follows gelandet
2024             // sind, wird ueberprueft, ob es ueberhaupt einen Follow mit einer
2025             // echten Hoehe gibt, andernfalls (z.B. in neu angelegten SctFrms)
2026             // ignorieren wir das IsWidow() und pruefen doch noch, ob wir
2027             // genung Platz finden.
2028             if( ( ( ! bVert && LONG_MAX - 20000 >= Frm().Bottom() ) ||
2029                   (   bVert && 0 < Frm().Left() ) ) &&
2030                   ( GetFollow()->IsVertical() ?
2031                     !GetFollow()->Frm().Width() :
2032                     !GetFollow()->Frm().Height() ) )
2033             {
2034                 SwTxtFrm* pFoll = GetFollow()->GetFollow();
2035                 while( pFoll &&
2036                         ( pFoll->IsVertical() ?
2037                          !pFoll->Frm().Width() :
2038                          !pFoll->Frm().Height() ) )
2039                     pFoll = pFoll->GetFollow();
2040                 if( pFoll )
2041                     return sal_False;
2042             }
2043             else
2044                 return sal_False;
2045         }
2046     }
2047 
2048     SWAP_IF_NOT_SWAPPED( this );
2049 
2050     SwTxtSizeInfo aInf( this );
2051     SwTxtMargin aLine( this, &aInf );
2052 
2053     WidowsAndOrphans aFrmBreak( this, rMaxHeight, bSplit );
2054 
2055     sal_Bool bRet = sal_True;
2056 
2057     aLine.Bottom();
2058     // Ist Aufspalten ueberhaupt notwendig?
2059     if ( 0 != ( bSplit = !aFrmBreak.IsInside( aLine ) ) )
2060         bRet = !aFrmBreak.IsKeepAlways() && aFrmBreak.WouldFit( aLine, rMaxHeight, bTst );
2061     else
2062     {
2063         //Wir brauchen die Gesamthoehe inklusive der aktuellen Zeile
2064         aLine.Top();
2065         do
2066         {
2067             rMaxHeight -= aLine.GetLineHeight();
2068         } while ( aLine.Next() );
2069     }
2070 
2071     UNDO_SWAP( this )
2072 
2073     return bRet;
2074 }
2075 
2076 
2077 /*************************************************************************
2078  *                      SwTxtFrm::GetParHeight()
2079  *************************************************************************/
2080 
GetParHeight() const2081 KSHORT SwTxtFrm::GetParHeight() const
2082 {
2083     ASSERT( ! IsVertical() || ! IsSwapped(),
2084             "SwTxtFrm::GetParHeight with swapped frame" )
2085 
2086     if( !HasPara() )
2087     {   // Fuer nichtleere Absaetze ist dies ein Sonderfall, da koennen wir
2088         // bei UnderSized ruhig nur 1 Twip mehr anfordern.
2089         KSHORT nRet = (KSHORT)Prt().SSize().Height();
2090         if( IsUndersized() )
2091         {
2092             if( IsEmpty() )
2093                 nRet = (KSHORT)EmptyHeight();
2094             else
2095                 ++nRet;
2096         }
2097         return nRet;
2098     }
2099 
2100     // FME, OD 08.01.2004 #i11859# - refactoring and improve code
2101     const SwLineLayout* pLineLayout = GetPara();
2102     KSHORT nHeight = pLineLayout->GetRealHeight();
2103     if( GetOfst() && !IsFollow() )  // Ist dieser Absatz gescrollt? Dann ist unsere
2104         nHeight *= 2;               // bisherige Hoehe mind. eine Zeilenhoehe zu gering
2105     // OD 2004-03-04 #115793#
2106     while ( pLineLayout && pLineLayout->GetNext() )
2107     {
2108         pLineLayout = pLineLayout->GetNext();
2109         nHeight = nHeight + pLineLayout->GetRealHeight();
2110     }
2111 
2112     return nHeight;
2113 }
2114 
2115 
2116 /*************************************************************************
2117  *                      SwTxtFrm::GetFormatted()
2118  *************************************************************************/
2119 
2120 // returnt this _immer_ im formatierten Zustand!
GetFormatted(bool bForceQuickFormat)2121 SwTxtFrm* SwTxtFrm::GetFormatted( bool bForceQuickFormat )
2122 {
2123     SWAP_IF_SWAPPED( this )
2124 
2125     //Kann gut sein, dass mir der IdleCollector mir die gecachten
2126     //Informationen entzogen hat. Calc() ruft unser Format.
2127                       //Nicht bei leeren Absaetzen!
2128     if( !HasPara() && !(IsValid() && IsEmpty()) )
2129     {
2130         // Calc() muss gerufen werden, weil unsere Frameposition
2131         // nicht stimmen muss.
2132         const sal_Bool bFormat = GetValidSizeFlag();
2133         Calc();
2134         // Es kann durchaus sein, dass Calc() das Format()
2135         // nicht anstiess (weil wir einst vom Idle-Zerstoerer
2136         // aufgefordert wurden unsere Formatinformationen wegzuschmeissen).
2137         // 6995: Optimierung mit FormatQuick()
2138         if( bFormat && !FormatQuick( bForceQuickFormat ) )
2139             Format();
2140     }
2141 
2142     UNDO_SWAP( this )
2143 
2144     return this;
2145 }
2146 
2147 /*************************************************************************
2148  *                      SwTxtFrm::CalcFitToContent()
2149  *************************************************************************/
2150 
CalcFitToContent()2151 SwTwips SwTxtFrm::CalcFitToContent()
2152 {
2153     // --> FME 2004-07-16 #i31490#
2154     // If we are currently locked, we better return with a
2155     // fairly reasonable value:
2156     if ( IsLocked() )
2157         return Prt().Width();
2158     // <--
2159 
2160     SwParaPortion* pOldPara = GetPara();
2161     SwParaPortion *pDummy = new SwParaPortion();
2162     SetPara( pDummy, false );
2163     const SwPageFrm* pPage = FindPageFrm();
2164 
2165     const Point   aOldFrmPos   = Frm().Pos();
2166     const SwTwips nOldFrmWidth = Frm().Width();
2167     const SwTwips nOldPrtWidth = Prt().Width();
2168     const SwTwips nPageWidth = GetUpper()->IsVertical() ?
2169                                pPage->Prt().Height() :
2170                                pPage->Prt().Width();
2171 
2172     Frm().Width( nPageWidth );
2173     Prt().Width( nPageWidth );
2174 
2175     // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
2176     if ( IsRightToLeft() )
2177         Frm().Pos().X() += nOldFrmWidth - nPageWidth;
2178 
2179     // --> FME 2004-07-16 #i31490#
2180     SwTxtFrmLocker aLock( this );
2181     // <--
2182 
2183     SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
2184     aInf.SetIgnoreFly( sal_True );
2185     SwTxtFormatter  aLine( this, &aInf );
2186     SwHookOut aHook( aInf );
2187 
2188     // --> OD 2005-09-06 #i54031# - assure mininum of MINLAY twips.
2189     const SwTwips nMax = Max( (SwTwips)MINLAY,
2190                               aLine._CalcFitToContent() + 1 );
2191     // <--
2192 
2193     Frm().Width( nOldFrmWidth );
2194     Prt().Width( nOldPrtWidth );
2195 
2196     // --> FME 2004-07-19 #i25422# objects anchored as character in RTL
2197     if ( IsRightToLeft() )
2198         Frm().Pos() = aOldFrmPos;
2199 
2200 
2201     SetPara( pOldPara );
2202 
2203     return nMax;
2204 }
2205 
2206 /** simulate format for a list item paragraph, whose list level attributes
2207     are in LABEL_ALIGNMENT mode, in order to determine additional first
2208     line offset for the real text formatting due to the value of label
2209     adjustment attribute of the list level.
2210 
2211     OD 2008-01-31 #newlistlevelattrs#
2212 
2213     @author OD
2214 */
CalcAdditionalFirstLineOffset()2215 void SwTxtFrm::CalcAdditionalFirstLineOffset()
2216 {
2217     if ( IsLocked() )
2218         return;
2219 
2220     // reset additional first line offset
2221     mnAdditionalFirstLineOffset = 0;
2222 
2223     const SwTxtNode* pTxtNode( GetTxtNode() );
2224     if ( pTxtNode && pTxtNode->IsNumbered() && pTxtNode->IsCountedInList() &&
2225          pTxtNode->GetNumRule() )
2226     {
2227         const SwNumFmt& rNumFmt =
2228                 pTxtNode->GetNumRule()->Get( static_cast<sal_uInt16>(pTxtNode->GetActualListLevel()) );
2229         if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2230         {
2231             // keep current paragraph portion and apply dummy paragraph portion
2232             SwParaPortion* pOldPara = GetPara();
2233             SwParaPortion *pDummy = new SwParaPortion();
2234             SetPara( pDummy, false );
2235 
2236             // lock paragraph
2237             SwTxtFrmLocker aLock( this );
2238 
2239             // simulate text formatting
2240             SwTxtFormatInfo aInf( this, sal_False, sal_True, sal_True );
2241             aInf.SetIgnoreFly( sal_True );
2242             SwTxtFormatter aLine( this, &aInf );
2243             SwHookOut aHook( aInf );
2244             aLine._CalcFitToContent();
2245 
2246             // determine additional first line offset
2247             const SwLinePortion* pFirstPortion = aLine.GetCurr()->GetFirstPortion();
2248             if ( pFirstPortion->InNumberGrp() && !pFirstPortion->IsFtnNumPortion() )
2249             {
2250                 SwTwips nNumberPortionWidth( pFirstPortion->Width() );
2251 
2252                 const SwLinePortion* pPortion = pFirstPortion->GetPortion();
2253                 while ( pPortion &&
2254                         pPortion->InNumberGrp() && !pPortion->IsFtnNumPortion())
2255                 {
2256                     nNumberPortionWidth += pPortion->Width();
2257                     pPortion = pPortion->GetPortion();
2258                 }
2259 
2260                 if ( ( IsRightToLeft() &&
2261                        rNumFmt.GetNumAdjust() == SVX_ADJUST_LEFT ) ||
2262                      ( !IsRightToLeft() &&
2263                        rNumFmt.GetNumAdjust() == SVX_ADJUST_RIGHT ) )
2264                 {
2265                     mnAdditionalFirstLineOffset = -nNumberPortionWidth;
2266                 }
2267                 else if ( rNumFmt.GetNumAdjust() == SVX_ADJUST_CENTER )
2268                 {
2269                     mnAdditionalFirstLineOffset = -(nNumberPortionWidth/2);
2270                 }
2271             }
2272 
2273             // restore paragraph portion
2274             SetPara( pOldPara );
2275         }
2276     }
2277 }
2278 
2279 /** determine height of last line for the calculation of the proportional line
2280     spacing
2281 
2282     OD 08.01.2004 #i11859#
2283     OD 2004-03-17 #i11860# - method <GetHeightOfLastLineForPropLineSpacing()>
2284     replace by method <_CalcHeightOfLastLine()>. Height of last line will be
2285     stored in new member <mnHeightOfLastLine> and can be accessed via method
2286     <GetHeightOfLastLine()>
2287     OD 2005-05-20 #i47162# - introduce new optional parameter <_bUseFont>
2288     in order to force the usage of the former algorithm to determine the
2289     height of the last line, which uses the font.
2290 
2291     @author OD
2292 */
_CalcHeightOfLastLine(const bool _bUseFont)2293 void SwTxtFrm::_CalcHeightOfLastLine( const bool _bUseFont )
2294 {
2295     // --> OD 2006-11-13 #i71281#
2296     // invalidate printing area, if height of last line changes
2297     const SwTwips mnOldHeightOfLastLine( mnHeightOfLastLine );
2298     // <--
2299     // determine output device
2300     ViewShell* pVsh = getRootFrm()->GetCurrShell();
2301     ASSERT( pVsh, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no ViewShell" );
2302     // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
2303     // There could be no <ViewShell> instance in the case of loading a binary
2304     // StarOffice file format containing an embedded Writer document.
2305     if ( !pVsh )
2306     {
2307         return;
2308     }
2309     OutputDevice* pOut = pVsh->GetOut();
2310     const IDocumentSettingAccess* pIDSA = GetTxtNode()->getIDocumentSettingAccess();
2311     if ( !pVsh->GetViewOptions()->getBrowseMode() ||
2312           pVsh->GetViewOptions()->IsPrtFormat() )
2313     {
2314         pOut = GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
2315     }
2316     ASSERT( pOut, "<SwTxtFrm::_GetHeightOfLastLineForPropLineSpacing()> - no OutputDevice" );
2317     // --> OD 2007-07-02 #i78921# - make code robust, according to provided patch
2318     if ( !pOut )
2319     {
2320         return;
2321     }
2322     // <--
2323 
2324     // determine height of last line
2325 
2326     if ( _bUseFont || pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING ) )
2327     {
2328         // former determination of last line height for proprotional line
2329         // spacing - take height of font set at the paragraph
2330         SwFont aFont( GetAttrSet(), pIDSA );
2331 
2332         // Wir muessen dafuer sorgen, dass am OutputDevice der Font
2333         // korrekt restauriert wird, sonst droht ein Last!=Owner.
2334         if ( pLastFont )
2335         {
2336             SwFntObj *pOldFont = pLastFont;
2337             pLastFont = NULL;
2338             aFont.SetFntChg( sal_True );
2339             aFont.ChgPhysFnt( pVsh, *pOut );
2340             mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2341             pLastFont->Unlock();
2342             pLastFont = pOldFont;
2343             pLastFont->SetDevFont( pVsh, *pOut );
2344         }
2345         else
2346         {
2347             Font aOldFont = pOut->GetFont();
2348             aFont.SetFntChg( sal_True );
2349             aFont.ChgPhysFnt( pVsh, *pOut );
2350             mnHeightOfLastLine = aFont.GetHeight( pVsh, *pOut );
2351             pLastFont->Unlock();
2352             pLastFont = NULL;
2353             pOut->SetFont( aOldFont );
2354         }
2355     }
2356     else
2357     {
2358         // new determination of last line height - take actually height of last line
2359         // --> OD 2008-05-06 #i89000#
2360         // assure same results, if paragraph is undersized
2361         if ( IsUndersized() )
2362         {
2363             mnHeightOfLastLine = 0;
2364         }
2365         else
2366         {
2367             bool bCalcHeightOfLastLine = true;
2368             if ( !HasPara() )
2369             {
2370                 if ( IsEmpty() )
2371                 {
2372                     mnHeightOfLastLine = EmptyHeight();
2373                     bCalcHeightOfLastLine = false;
2374                 }
2375             }
2376 
2377             if ( bCalcHeightOfLastLine )
2378             {
2379                 ASSERT( HasPara(),
2380                         "<SwTxtFrm::_CalcHeightOfLastLine()> - missing paragraph portions." );
2381                 const SwLineLayout* pLineLayout = GetPara();
2382                 while ( pLineLayout && pLineLayout->GetNext() )
2383                 {
2384                     // iteration to last line
2385                     pLineLayout = pLineLayout->GetNext();
2386                 }
2387                 if ( pLineLayout )
2388                 {
2389                     SwTwips nAscent, nDescent, nDummy1, nDummy2;
2390                     // --> OD 2005-05-20 #i47162# - suppress consideration of
2391                     // fly content portions and the line portion.
2392                     pLineLayout->MaxAscentDescent( nAscent, nDescent,
2393                                                    nDummy1, nDummy2,
2394                                                    0, true );
2395                     // <--
2396                     // --> OD 2006-11-22 #i71281#
2397                     // Suppress wrong invalidation of printing area, if method is
2398                     // called recursive.
2399                     // Thus, member <mnHeightOfLastLine> is only set directly, if
2400                     // no recursive call is needed.
2401     //                mnHeightOfLastLine = nAscent + nDescent;
2402                     const SwTwips nNewHeightOfLastLine = nAscent + nDescent;
2403                     // --> OD 2005-05-20 #i47162# - if last line only contains
2404                     // fly content portions, <mnHeightOfLastLine> is zero.
2405                     // In this case determine height of last line by the font
2406                     if ( nNewHeightOfLastLine == 0 )
2407                     {
2408                         _CalcHeightOfLastLine( true );
2409                     }
2410                     else
2411                     {
2412                         mnHeightOfLastLine = nNewHeightOfLastLine;
2413                     }
2414                     // <--
2415                     // <--
2416                 }
2417             }
2418         }
2419         // <--
2420     }
2421     // --> OD 2006-11-13 #i71281#
2422     // invalidate printing area, if height of last line changes
2423     if ( mnHeightOfLastLine != mnOldHeightOfLastLine )
2424     {
2425         InvalidatePrt();
2426     }
2427     // <--
2428 }
2429 
2430 /*************************************************************************
2431  *                      SwTxtFrm::GetLineSpace()
2432  *************************************************************************/
2433 // OD 07.01.2004 #i11859# - change return data type
2434 //      add default parameter <_bNoPropLineSpacing> to control, if the
2435 //      value of a proportional line spacing is returned or not
2436 // OD 07.01.2004 - trying to describe purpose of method:
2437 //      Method returns the value of the inter line spacing for a text frame.
2438 //      Such a value exists for proportional line spacings ("1,5 Lines",
2439 //      "Double", "Proportional" and for leading line spacing ("Leading").
2440 //      By parameter <_bNoPropLineSpace> (default value false) it can be
2441 //      controlled, if the value of a proportional line spacing is returned.
GetLineSpace(const bool _bNoPropLineSpace) const2442 long SwTxtFrm::GetLineSpace( const bool _bNoPropLineSpace ) const
2443 {
2444     long nRet = 0;
2445 
2446     const SwAttrSet* pSet = GetAttrSet();
2447     const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
2448 
2449     switch( rSpace.GetInterLineSpaceRule() )
2450     {
2451         case SVX_INTER_LINE_SPACE_PROP:
2452         {
2453             // OD 07.01.2004 #i11859#
2454             if ( _bNoPropLineSpace )
2455             {
2456                 break;
2457             }
2458 
2459             // OD 2004-03-17 #i11860# - use method <GetHeightOfLastLine()>
2460             nRet = GetHeightOfLastLine();
2461 
2462             long nTmp = nRet;
2463             nTmp *= rSpace.GetPropLineSpace();
2464             nTmp /= 100;
2465             nTmp -= nRet;
2466             if ( nTmp > 0 )
2467                 nRet = nTmp;
2468             else
2469                 nRet = 0;
2470         }
2471             break;
2472         case SVX_INTER_LINE_SPACE_FIX:
2473         {
2474             if ( rSpace.GetInterLineSpace() > 0 )
2475                 nRet = rSpace.GetInterLineSpace();
2476         }
2477             break;
2478         default:
2479             break;
2480     }
2481     return nRet;
2482 }
2483 
2484 /*************************************************************************
2485  *                      SwTxtFrm::FirstLineHeight()
2486  *************************************************************************/
2487 
FirstLineHeight() const2488 KSHORT SwTxtFrm::FirstLineHeight() const
2489 {
2490     if ( !HasPara() )
2491     {
2492         if( IsEmpty() && IsValid() )
2493             return IsVertical() ? (KSHORT)Prt().Width() : (KSHORT)Prt().Height();
2494         return KSHRT_MAX;
2495     }
2496     const SwParaPortion *pPara = GetPara();
2497     if ( !pPara )
2498         return KSHRT_MAX;
2499 
2500     return pPara->Height();
2501 }
2502 
GetLineCount(xub_StrLen nPos)2503 MSHORT SwTxtFrm::GetLineCount( xub_StrLen nPos )
2504 {
2505     MSHORT nRet = 0;
2506     SwTxtFrm *pFrm = this;
2507     do
2508     {
2509         pFrm->GetFormatted();
2510         if( !pFrm->HasPara() )
2511             break;
2512         SwTxtSizeInfo aInf( pFrm );
2513         SwTxtMargin aLine( pFrm, &aInf );
2514         if( STRING_LEN == nPos )
2515             aLine.Bottom();
2516         else
2517             aLine.CharToLine( nPos );
2518         nRet = nRet + aLine.GetLineNr();
2519         pFrm = pFrm->GetFollow();
2520     } while ( pFrm && pFrm->GetOfst() <= nPos );
2521     return nRet;
2522 }
2523 
ChgThisLines()2524 void SwTxtFrm::ChgThisLines()
2525 {
2526     //not necassary to format here (GerFormatted etc.), because we have to come from there!
2527 
2528     sal_uLong nNew = 0;
2529     const SwLineNumberInfo &rInf = GetNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo();
2530     if ( GetTxt().Len() && HasPara() )
2531     {
2532         SwTxtSizeInfo aInf( this );
2533         SwTxtMargin aLine( this, &aInf );
2534         if ( rInf.IsCountBlankLines() )
2535         {
2536             aLine.Bottom();
2537             nNew = (sal_uLong)aLine.GetLineNr();
2538         }
2539         else
2540         {
2541             do
2542             {
2543                 if( aLine.GetCurr()->HasCntnt() )
2544                     ++nNew;
2545             } while ( aLine.NextLine() );
2546         }
2547     }
2548     else if ( rInf.IsCountBlankLines() )
2549         nNew = 1;
2550 
2551     if ( nNew != nThisLines )
2552     {
2553         if ( !IsInTab() && GetAttrSet()->GetLineNumber().IsCount() )
2554         {
2555             nAllLines -= nThisLines;
2556             nThisLines = nNew;
2557             nAllLines  += nThisLines;
2558             SwFrm *pNxt = GetNextCntntFrm();
2559             while( pNxt && pNxt->IsInTab() )
2560             {
2561                 if( 0 != (pNxt = pNxt->FindTabFrm()) )
2562                     pNxt = pNxt->FindNextCnt();
2563             }
2564             if( pNxt )
2565                 pNxt->InvalidateLineNum();
2566 
2567             //Extend repaint to the bottom.
2568             if ( HasPara() )
2569             {
2570                 SwRepaint *pRepaint = GetPara()->GetRepaint();
2571                 pRepaint->Bottom( Max( pRepaint->Bottom(),
2572                                        Frm().Top()+Prt().Bottom()));
2573             }
2574         }
2575         else //Paragraphs which are not counted should not manipulate the AllLines.
2576             nThisLines = nNew;
2577     }
2578 
2579     //mba: invalidating is not necessary; if mongolian script has a problem, it should be fixed at the ritgh place
2580     //with invalidating we probably get too much flickering
2581     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
2582     //Ugly. How can we hack if better?
2583     //InvalidatePage();
2584 }
2585 
2586 
RecalcAllLines()2587 void SwTxtFrm::RecalcAllLines()
2588 {
2589     ValidateLineNum();
2590 
2591     const SwAttrSet *pAttrSet = GetAttrSet();
2592 
2593     if ( !IsInTab() )
2594     {
2595         const sal_uLong nOld = GetAllLines();
2596         const SwFmtLineNumber &rLineNum = pAttrSet->GetLineNumber();
2597         sal_uLong nNewNum;
2598         const bool bRestart = GetTxtNode()->getIDocumentLineNumberAccess()->GetLineNumberInfo().IsRestartEachPage();
2599 
2600         if ( !IsFollow() && rLineNum.GetStartValue() && rLineNum.IsCount() )
2601             nNewNum = rLineNum.GetStartValue() - 1;
2602         //If it is a follow or not has not be considered if it is a restart at each page; the
2603         //restart should also take affekt at follows.
2604         else if ( bRestart && FindPageFrm()->FindFirstBodyCntnt() == this )
2605         {
2606             nNewNum = 0;
2607         }
2608         else
2609         {
2610             SwCntntFrm *pPrv = GetPrevCntntFrm();
2611             while ( pPrv &&
2612                     (pPrv->IsInTab() || pPrv->IsInDocBody() != IsInDocBody()) )
2613                 pPrv = pPrv->GetPrevCntntFrm();
2614 
2615             // --> FME 2007-06-22 #i78254# Restart line numbering at page change:
2616             // First body content may be in table!
2617             if ( bRestart && pPrv && pPrv->FindPageFrm() != FindPageFrm() )
2618                 pPrv = 0;
2619             // <--
2620 
2621             nNewNum = pPrv ? ((SwTxtFrm*)pPrv)->GetAllLines() : 0;
2622         }
2623         if ( rLineNum.IsCount() )
2624             nNewNum += GetThisLines();
2625 
2626         if ( nOld != nNewNum )
2627         {
2628             nAllLines = nNewNum;
2629             SwCntntFrm *pNxt = GetNextCntntFrm();
2630             while ( pNxt &&
2631                     (pNxt->IsInTab() || pNxt->IsInDocBody() != IsInDocBody()) )
2632                 pNxt = pNxt->GetNextCntntFrm();
2633             if ( pNxt )
2634             {
2635                 if ( pNxt->GetUpper() != GetUpper() )
2636                     pNxt->InvalidateLineNum();
2637                 else
2638                     pNxt->_InvalidateLineNum();
2639             }
2640         }
2641     }
2642 }
2643 
VisitPortions(SwPortionHandler & rPH) const2644 void SwTxtFrm::VisitPortions( SwPortionHandler& rPH ) const
2645 {
2646     const SwParaPortion* pPara = GetPara();
2647 
2648     if( pPara )
2649     {
2650         if ( IsFollow() )
2651             rPH.Skip( GetOfst() );
2652 
2653         const SwLineLayout* pLine = pPara;
2654         while ( pLine )
2655         {
2656             const SwLinePortion* pPor = pLine->GetFirstPortion();
2657             while ( pPor )
2658             {
2659                 pPor->HandlePortion( rPH );
2660                 pPor = pPor->GetPortion();
2661             }
2662 
2663             rPH.LineBreak();
2664             pLine = pLine->GetNext();
2665         }
2666     }
2667 
2668     rPH.Finish();
2669 }
2670 
2671 
2672 /*************************************************************************
2673  *                      SwTxtFrm::GetScriptInfo()
2674  *************************************************************************/
2675 
GetScriptInfo() const2676 const SwScriptInfo* SwTxtFrm::GetScriptInfo() const
2677 {
2678     const SwParaPortion* pPara = GetPara();
2679     return pPara ? &pPara->GetScriptInfo() : 0;
2680 }
2681 
2682 /*************************************************************************
2683  *                      lcl_CalcFlyBasePos()
2684  * Helper function for SwTxtFrm::CalcBasePosForFly()
2685  *************************************************************************/
2686 
lcl_CalcFlyBasePos(const SwTxtFrm & rFrm,SwRect aFlyRect,SwTxtFly & rTxtFly)2687 SwTwips lcl_CalcFlyBasePos( const SwTxtFrm& rFrm, SwRect aFlyRect,
2688                             SwTxtFly& rTxtFly )
2689 {
2690     SWRECTFN( (&rFrm) )
2691     SwTwips nRet = rFrm.IsRightToLeft() ?
2692                    (rFrm.Frm().*fnRect->fnGetRight)() :
2693                    (rFrm.Frm().*fnRect->fnGetLeft)();
2694 
2695     do
2696     {
2697         SwRect aRect = rTxtFly.GetFrm( aFlyRect );
2698         if ( 0 != (aRect.*fnRect->fnGetWidth)() )
2699         {
2700             if ( rFrm.IsRightToLeft() )
2701             {
2702                 if ( (aRect.*fnRect->fnGetRight)() -
2703                      (aFlyRect.*fnRect->fnGetRight)() >= 0 )
2704                 {
2705                     (aFlyRect.*fnRect->fnSetRight)(
2706                         (aRect.*fnRect->fnGetLeft)() );
2707                     nRet = (aRect.*fnRect->fnGetLeft)();
2708                 }
2709                 else
2710                     break;
2711             }
2712             else
2713             {
2714                 if ( (aFlyRect.*fnRect->fnGetLeft)() -
2715                      (aRect.*fnRect->fnGetLeft)() >= 0 )
2716                 {
2717                     (aFlyRect.*fnRect->fnSetLeft)(
2718                         (aRect.*fnRect->fnGetRight)() + 1 );
2719                     nRet = (aRect.*fnRect->fnGetRight)();
2720                 }
2721                 else
2722                     break;
2723             }
2724         }
2725         else
2726             break;
2727     }
2728     while ( (aFlyRect.*fnRect->fnGetWidth)() > 0 );
2729 
2730     return nRet;
2731 }
2732 
2733 /*************************************************************************
2734  *                      SwTxtFrm::CalcBasePosForFly()
2735  *************************************************************************/
2736 
CalcBaseOfstForFly()2737 void SwTxtFrm::CalcBaseOfstForFly()
2738 {
2739     ASSERT( !IsVertical() || !IsSwapped(),
2740             "SwTxtFrm::CalcBasePosForFly with swapped frame!" )
2741 
2742     const SwNode* pNode = GetTxtNode();
2743     if ( !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_FLY_OFFSETS) )
2744         return;
2745 
2746     SWRECTFN( this )
2747 
2748     SwRect aFlyRect( Frm().Pos() + Prt().Pos(), Prt().SSize() );
2749 
2750     // Get first 'real' line and adjust position and height of line rectangle
2751     // OD 08.09.2003 #110978#, #108749#, #110354# - correct behaviour,
2752     // if no 'real' line exists (empty paragraph with and without a dummy portion)
2753     {
2754         SwTwips nTop = (aFlyRect.*fnRect->fnGetTop)();
2755         const SwLineLayout* pLay = GetPara();
2756         SwTwips nLineHeight = 200;
2757         while( pLay && pLay->IsDummy() && pLay->GetNext() )
2758         {
2759             nTop += pLay->Height();
2760             pLay = pLay->GetNext();
2761         }
2762         if ( pLay )
2763         {
2764             nLineHeight = pLay->Height();
2765         }
2766         (aFlyRect.*fnRect->fnSetTopAndHeight)( nTop, nLineHeight );
2767     }
2768 
2769     SwTxtFly aTxtFly( this );
2770     aTxtFly.SetIgnoreCurrentFrame( sal_True );
2771     aTxtFly.SetIgnoreContour( sal_True );
2772     // --> OD 2004-12-17 #118809# - ignore objects in page header|footer for
2773     // text frames not in page header|footer
2774     aTxtFly.SetIgnoreObjsInHeaderFooter( sal_True );
2775     // <--
2776     SwTwips nRet1 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
2777     aTxtFly.SetIgnoreCurrentFrame( sal_False );
2778     SwTwips nRet2 = lcl_CalcFlyBasePos( *this, aFlyRect, aTxtFly );
2779 
2780     // make values relative to frame start position
2781     SwTwips nLeft = IsRightToLeft() ?
2782                     (Frm().*fnRect->fnGetRight)() :
2783                     (Frm().*fnRect->fnGetLeft)();
2784 
2785     mnFlyAnchorOfst = nRet1 - nLeft;
2786     mnFlyAnchorOfstNoWrap = nRet2 - nLeft;
2787 }
2788 
2789 /* repaint all text frames of the given text node */
repaintTextFrames(const SwTxtNode & rNode)2790 void SwTxtFrm::repaintTextFrames( const SwTxtNode& rNode )
2791 {
2792     SwIterator<SwTxtFrm,SwTxtNode> aIter( rNode );
2793     for( const SwTxtFrm *pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
2794     {
2795         SwRect aRec( pFrm->PaintArea() );
2796         const SwRootFrm *pRootFrm = pFrm->getRootFrm();
2797         ViewShell *pCurShell = pRootFrm ? pRootFrm->GetCurrShell() : NULL;
2798         if( pCurShell )
2799             pCurShell->InvalidateWindows( aRec );
2800     }
2801 }
2802 
2803