xref: /trunk/main/sw/source/core/layout/findfrm.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include "pagefrm.hxx"
33 #include "rootfrm.hxx"
34 #include "cntfrm.hxx"
35 #include "node.hxx"
36 #include "doc.hxx"
37 #include "frmtool.hxx"
38 #include "flyfrm.hxx"
39 #include <frmfmt.hxx>
40 #include <cellfrm.hxx>
41 #include <rowfrm.hxx>
42 #include <swtable.hxx>
43 
44 #include "tabfrm.hxx"
45 #include "sectfrm.hxx"
46 #include "flyfrms.hxx"
47 #include "ftnfrm.hxx"
48 #include "txtftn.hxx"
49 #include "fmtftn.hxx"
50 #include <txtfrm.hxx>   // SwTxtFrm
51 #include <switerator.hxx>
52 
53 /*************************************************************************
54 |*
55 |*  FindBodyCont, FindLastBodyCntnt()
56 |*
57 |*  Beschreibung        Sucht den ersten/letzten CntntFrm im BodyText unterhalb
58 |*      der Seite.
59 |*  Ersterstellung      MA 15. Feb. 93
60 |*  Letzte Aenderung    MA 18. Apr. 94
61 |*
62 |*************************************************************************/
63 SwLayoutFrm *SwFtnBossFrm::FindBodyCont()
64 {
65     SwFrm *pLay = Lower();
66     while ( pLay && !pLay->IsBodyFrm() )
67         pLay = pLay->GetNext();
68     return (SwLayoutFrm*)pLay;
69 }
70 
71 SwCntntFrm *SwPageFrm::FindLastBodyCntnt()
72 {
73     SwCntntFrm *pRet = FindFirstBodyCntnt();
74     SwCntntFrm *pNxt = pRet;
75     while ( pNxt && pNxt->IsInDocBody() && IsAnLower( pNxt ) )
76     {   pRet = pNxt;
77         pNxt = pNxt->FindNextCnt();
78     }
79     return pRet;
80 }
81 
82 /*************************************************************************
83 |*
84 |*  SwLayoutFrm::ContainsCntnt
85 |*
86 |*  Beschreibung            Prueft, ob der Frame irgendwo in seiner
87 |*          untergeordneten Struktur einen oder mehrere CntntFrm's enthaelt;
88 |*          Falls ja wird der erste gefundene CntntFrm zurueckgegeben.
89 |*
90 |*  Ersterstellung      MA 13. May. 92
91 |*  Letzte Aenderung    MA 20. Apr. 94
92 |*
93 |*************************************************************************/
94 
95 const SwCntntFrm *SwLayoutFrm::ContainsCntnt() const
96 {
97     //LayoutBlatt nach unten hin suchen und wenn dieses keinen Inhalt hat
98     //solange die weiteren Blatter abklappern bis Inhalt gefunden oder der
99     //this verlassen wird.
100     //Sections: Cntnt neben Sections wuerde so nicht gefunden (leere Section
101     //direct neben CntntFrm), deshalb muss fuer diese Aufwendiger rekursiv gesucht
102     //werden.
103 
104     const SwLayoutFrm *pLayLeaf = this;
105     do
106     {
107         while ( (!pLayLeaf->IsSctFrm() || pLayLeaf == this ) &&
108                 pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrm() )
109             pLayLeaf = (SwLayoutFrm*)pLayLeaf->Lower();
110 
111         if( pLayLeaf->IsSctFrm() && pLayLeaf != this )
112         {
113             const SwCntntFrm *pCnt = pLayLeaf->ContainsCntnt();
114             if( pCnt )
115                 return pCnt;
116             if( pLayLeaf->GetNext() )
117             {
118                 if( pLayLeaf->GetNext()->IsLayoutFrm() )
119                 {
120                     pLayLeaf = (SwLayoutFrm*)pLayLeaf->GetNext();
121                     continue;
122                 }
123                 else
124                     return (SwCntntFrm*)pLayLeaf->GetNext();
125             }
126         }
127         else if ( pLayLeaf->Lower() )
128             return (SwCntntFrm*)pLayLeaf->Lower();
129 
130         pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
131         if( !IsAnLower( pLayLeaf) )
132             return 0;
133     } while( pLayLeaf );
134     return 0;
135 }
136 
137 /*************************************************************************
138 |*
139 |*  SwLayoutFrm::FirstCell
140 |*
141 |*  Beschreibung    ruft zunaechst ContainsAny auf, um in die innerste Zelle
142 |*                  hineinzukommen. Dort hangelt es sich wieder hoch zum
143 |*                  ersten SwCellFrm, seit es SectionFrms gibt, reicht kein
144 |*                  ContainsCntnt()->GetUpper() mehr...
145 |*  Ersterstellung      AMA 17. Mar. 99
146 |*  Letzte Aenderung    AMA 17. Mar. 99
147 |*
148 |*************************************************************************/
149 
150 const SwCellFrm *SwLayoutFrm::FirstCell() const
151 {
152     const SwFrm* pCnt = ContainsAny();
153     while( pCnt && !pCnt->IsCellFrm() )
154         pCnt = pCnt->GetUpper();
155     return (const SwCellFrm*)pCnt;
156 }
157 
158 /*************************************************************************
159 |*
160 |*  SwLayoutFrm::ContainsAny
161 |*
162 |*  Beschreibung wie ContainsCntnt, nur dass nicht nur CntntFrms, sondern auch
163 |*          Bereiche und Tabellen zurueckgegeben werden.
164 |*  Ersterstellung      AMA 10. Mar. 99
165 |*  Letzte Aenderung    AMA 10. Mar. 99
166 |*
167 |*************************************************************************/
168 
169 // --> OD 2006-02-01 #130797#
170 // New parameter <_bInvestigateFtnForSections> controls investigation of
171 // content of footnotes for sections.
172 const SwFrm *SwLayoutFrm::ContainsAny( const bool _bInvestigateFtnForSections ) const
173 {
174     //LayoutBlatt nach unten hin suchen und wenn dieses keinen Inhalt hat
175     //solange die weiteren Blatter abklappern bis Inhalt gefunden oder der
176     //this verlassen wird.
177     // Oder bis wir einen SectionFrm oder TabFrm gefunden haben
178 
179     const SwLayoutFrm *pLayLeaf = this;
180     // --> OD 2006-02-01 #130797#
181     const bool bNoFtn = IsSctFrm() && !_bInvestigateFtnForSections;
182     // <--
183     do
184     {
185         while ( ( (!pLayLeaf->IsSctFrm() && !pLayLeaf->IsTabFrm())
186                  || pLayLeaf == this ) &&
187                 pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrm() )
188             pLayLeaf = (SwLayoutFrm*)pLayLeaf->Lower();
189 
190         if( ( pLayLeaf->IsTabFrm() || pLayLeaf->IsSctFrm() )
191             && pLayLeaf != this )
192         {
193             // Wir liefern jetzt auch "geloeschte" SectionFrms zurueck,
194             // damit diese beim SaveCntnt und RestoreCntnt mitgepflegt werden.
195             return pLayLeaf;
196         }
197         else if ( pLayLeaf->Lower() )
198             return (SwCntntFrm*)pLayLeaf->Lower();
199 
200         pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
201         if( bNoFtn && pLayLeaf && pLayLeaf->IsInFtn() )
202         {
203             do
204             {
205                 pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
206             } while( pLayLeaf && pLayLeaf->IsInFtn() );
207         }
208         if( !IsAnLower( pLayLeaf) )
209             return 0;
210     } while( pLayLeaf );
211     return 0;
212 }
213 
214 
215 /*************************************************************************
216 |*
217 |*  SwFrm::GetLower()
218 |*
219 |*  Ersterstellung      MA 27. Jul. 92
220 |*  Letzte Aenderung    MA 09. Oct. 97
221 |*
222 |*************************************************************************/
223 const SwFrm* SwFrm::GetLower() const
224 {
225     return IsLayoutFrm() ? ((SwLayoutFrm*)this)->Lower() : 0;
226 }
227 
228 SwFrm* SwFrm::GetLower()
229 {
230     return IsLayoutFrm() ? ((SwLayoutFrm*)this)->Lower() : 0;
231 }
232 
233 /*************************************************************************
234 |*
235 |*  SwLayoutFrm::IsAnLower()
236 |*
237 |*  Ersterstellung      MA 18. Mar. 93
238 |*  Letzte Aenderung    MA 18. Mar. 93
239 |*
240 |*************************************************************************/
241 sal_Bool SwLayoutFrm::IsAnLower( const SwFrm *pAssumed ) const
242 {
243     const SwFrm *pUp = pAssumed;
244     while ( pUp )
245     {
246         if ( pUp == this )
247             return sal_True;
248         if ( pUp->IsFlyFrm() )
249             pUp = ((SwFlyFrm*)pUp)->GetAnchorFrm();
250         else
251             pUp = pUp->GetUpper();
252     }
253     return sal_False;
254 }
255 
256 /** method to check relative position of layout frame to
257     a given layout frame.
258 
259     OD 08.11.2002 - refactoring of pseudo-local method <lcl_Apres(..)> in
260     <txtftn.cxx> for #104840#.
261 
262     @param _aCheckRefLayFrm
263     constant reference of an instance of class <SwLayoutFrm> which
264     is used as the reference for the relative position check.
265 
266     @author OD
267 
268     @return true, if <this> is positioned before the layout frame <p>
269 */
270 bool SwLayoutFrm::IsBefore( const SwLayoutFrm* _pCheckRefLayFrm ) const
271 {
272     ASSERT( !IsRootFrm() , "<IsBefore> called at a <SwRootFrm>.");
273     ASSERT( !_pCheckRefLayFrm->IsRootFrm() , "<IsBefore> called with a <SwRootFrm>.");
274 
275     bool bReturn;
276 
277     // check, if on different pages
278     const SwPageFrm *pMyPage = FindPageFrm();
279     const SwPageFrm *pCheckRefPage = _pCheckRefLayFrm->FindPageFrm();
280     if( pMyPage != pCheckRefPage )
281     {
282         // being on different page as check reference
283         bReturn = pMyPage->GetPhyPageNum() < pCheckRefPage->GetPhyPageNum();
284     }
285     else
286     {
287         // being on same page as check reference
288         // --> search my supreme parent <pUp>, which doesn't contain check reference.
289         const SwLayoutFrm* pUp = this;
290         while ( pUp->GetUpper() &&
291                 !pUp->GetUpper()->IsAnLower( _pCheckRefLayFrm )
292               )
293             pUp = pUp->GetUpper();
294         if( !pUp->GetUpper() )
295         {
296             // can occur, if <this> is a fly frm
297             bReturn = false;
298         }
299         else
300         {
301             // travel through the next's of <pUp> and check if one of these
302             // contain the check reference.
303             SwLayoutFrm* pUpNext = (SwLayoutFrm*)pUp->GetNext();
304             while ( pUpNext &&
305                     !pUpNext->IsAnLower( _pCheckRefLayFrm ) )
306             {
307                 pUpNext = (SwLayoutFrm*)pUpNext->GetNext();
308             }
309             bReturn = pUpNext != 0;
310         }
311     }
312 
313     return bReturn;
314 }
315 
316 //
317 // Local helper functions for GetNextLayoutLeaf
318 //
319 
320 const SwFrm* lcl_FindLayoutFrame( const SwFrm* pFrm, bool bNext )
321 {
322     const SwFrm* pRet = 0;
323     if ( pFrm->IsFlyFrm() )
324         pRet = bNext ? ((SwFlyFrm*)pFrm)->GetNextLink() : ((SwFlyFrm*)pFrm)->GetPrevLink();
325     else
326         pRet = bNext ? pFrm->GetNext() : pFrm->GetPrev();
327 
328     return pRet;
329 }
330 
331 const SwFrm* lcl_GetLower( const SwFrm* pFrm, bool bFwd )
332 {
333     if ( !pFrm->IsLayoutFrm() )
334         return 0;
335 
336     return bFwd ?
337            static_cast<const SwLayoutFrm*>(pFrm)->Lower() :
338            static_cast<const SwLayoutFrm*>(pFrm)->GetLastLower();
339 }
340 
341 /*************************************************************************
342 |*
343 |*  SwFrm::ImplGetNextLayoutLeaf
344 |*
345 |* Finds the next layout leaf. This is a layout frame, which does not
346  * have a lower which is a LayoutFrame. That means, pLower can be 0 or a
347  * content frame.
348  *
349  * However, pLower may be a TabFrm
350  *
351 |*************************************************************************/
352 
353 const SwLayoutFrm *SwFrm::ImplGetNextLayoutLeaf( bool bFwd ) const
354 {
355     const SwFrm       *pFrm = this;
356     const SwLayoutFrm *pLayoutFrm = 0;
357     const SwFrm       *p = 0;
358     bool bGoingUp = !bFwd;          // false for forward, true for backward
359     do {
360 
361          bool bGoingFwdOrBwd = false, bGoingDown = false;
362 
363          bGoingDown = ( !bGoingUp && ( 0 != (p = lcl_GetLower( pFrm, bFwd ) ) ) );
364          if ( !bGoingDown )
365          {
366              // I cannot go down, because either I'm currently going up or
367              // because the is no lower.
368              // I'll try to go forward:
369              bGoingFwdOrBwd = (0 != (p = lcl_FindLayoutFrame( pFrm, bFwd ) ) );
370              if ( !bGoingFwdOrBwd )
371              {
372                  // I cannot go forward, because there is no next frame.
373                  // I'll try to go up:
374                  bGoingUp = (0 != (p = pFrm->GetUpper() ) );
375                  if ( !bGoingUp )
376                  {
377                     // I cannot go up, because there is no upper frame.
378                     return 0;
379                  }
380              }
381          }
382 
383         // If I could not go down or forward, I'll have to go up
384         bGoingUp = !bGoingFwdOrBwd && !bGoingDown;
385 
386         pFrm = p;
387         p = lcl_GetLower( pFrm, true );
388 
389     } while( ( p && !p->IsFlowFrm() ) ||
390              pFrm == this ||
391              0 == ( pLayoutFrm = pFrm->IsLayoutFrm() ? (SwLayoutFrm*)pFrm : 0 ) ||
392              pLayoutFrm->IsAnLower( this ) );
393 
394     return pLayoutFrm;
395 }
396 
397 
398 
399 /*************************************************************************
400 |*
401 |*    SwFrm::ImplGetNextCntntFrm( bool )
402 |*
403 |*      Rueckwaertswandern im Baum: Den untergeordneten Frm greifen,
404 |*      wenn es einen gibt und nicht gerade zuvor um eine Ebene
405 |*      aufgestiegen wurde (das wuerde zu einem endlosen Auf und Ab
406 |*      fuehren!). Damit wird sichergestellt, dass beim
407 |*      Rueckwaertswandern alle Unterbaeume durchsucht werden. Wenn
408 |*      abgestiegen wurde, wird zuerst an das Ende der Kette gegangen,
409 |*      weil im weiteren ja vom letzten Frm innerhalb eines anderen
410 |*      Frms rueckwaerts gegangen wird.
411 |*      Vorwaetzwander funktioniert analog.
412 |*
413 |*    Ersterstellung    ??
414 |*    Letzte Aenderung  MA 30. Oct. 97
415 |*
416 |*************************************************************************/
417 
418 // Achtung: Fixes in ImplGetNextCntntFrm() muessen moeglicherweise auch in
419 // die weiter oben stehende Methode lcl_NextFrm(..) eingepflegt werden
420 const SwCntntFrm* SwCntntFrm::ImplGetNextCntntFrm( bool bFwd ) const
421 {
422     const SwFrm *pFrm = this;
423     // #100926#
424     SwCntntFrm *pCntntFrm = 0;
425     sal_Bool bGoingUp = sal_False;
426     do {
427         const SwFrm *p = 0;
428         sal_Bool bGoingFwdOrBwd = sal_False, bGoingDown = sal_False;
429 
430         bGoingDown = ( !bGoingUp && ( 0 != ( p = lcl_GetLower( pFrm, true ) ) ) );
431         if ( !bGoingDown )
432         {
433             bGoingFwdOrBwd = ( 0 != ( p = lcl_FindLayoutFrame( pFrm, bFwd ) ) );
434             if ( !bGoingFwdOrBwd )
435             {
436                 bGoingUp = ( 0 != ( p = pFrm->GetUpper() ) );
437                 if ( !bGoingUp )
438                 {
439                     return 0;
440                 }
441             }
442         }
443 
444         bGoingUp = !(bGoingFwdOrBwd || bGoingDown);
445 
446         if ( !bFwd )
447         {
448             if( bGoingDown && p )
449                 while ( p->GetNext() )
450                     p = p->GetNext();
451         }
452 
453         pFrm = p;
454     } while ( 0 == (pCntntFrm = (pFrm->IsCntntFrm() ? (SwCntntFrm*)pFrm:0) ));
455 
456     return pCntntFrm;
457 }
458 
459 
460 
461 
462 /*************************************************************************
463 |*
464 |*  SwFrm::FindRootFrm(), FindTabFrm(), FindFtnFrm(), FindFlyFrm(),
465 |*         FindPageFrm(), FindColFrm()
466 |*
467 |*  Ersterstellung      ??
468 |*  Letzte Aenderung    MA 05. Sep. 93
469 |*
470 |*************************************************************************/
471 SwPageFrm* SwFrm::FindPageFrm()
472 {
473     SwFrm *pRet = this;
474     while ( pRet && !pRet->IsPageFrm() )
475     {
476         if ( pRet->GetUpper() )
477             pRet = pRet->GetUpper();
478         else if ( pRet->IsFlyFrm() )
479         {
480             // --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
481             if ( static_cast<SwFlyFrm*>(pRet)->GetPageFrm() )
482                 pRet = static_cast<SwFlyFrm*>(pRet)->GetPageFrm();
483             else
484                 pRet = static_cast<SwFlyFrm*>(pRet)->AnchorFrm();
485         }
486         else
487             return 0;
488     }
489     return (SwPageFrm*)pRet;
490 }
491 
492 SwFtnBossFrm* SwFrm::FindFtnBossFrm( sal_Bool bFootnotes )
493 {
494     SwFrm *pRet = this;
495     // Innerhalb einer Tabelle gibt es keine Fussnotenbosse, auch spaltige
496     // Bereiche enthalten dort keine Fussnotentexte
497     if( pRet->IsInTab() )
498         pRet = pRet->FindTabFrm();
499     while ( pRet && !pRet->IsFtnBossFrm() )
500     {
501         if ( pRet->GetUpper() )
502             pRet = pRet->GetUpper();
503         else if ( pRet->IsFlyFrm() )
504         {
505             // --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
506             if ( static_cast<SwFlyFrm*>(pRet)->GetPageFrm() )
507                 pRet = static_cast<SwFlyFrm*>(pRet)->GetPageFrm();
508             else
509                 pRet = static_cast<SwFlyFrm*>(pRet)->AnchorFrm();
510         }
511         else
512             return 0;
513     }
514     if( bFootnotes && pRet && pRet->IsColumnFrm() &&
515         !pRet->GetNext() && !pRet->GetPrev() )
516     {
517         SwSectionFrm* pSct = pRet->FindSctFrm();
518         ASSERT( pSct, "FindFtnBossFrm: Single column outside section?" );
519         if( !pSct->IsFtnAtEnd() )
520             return pSct->FindFtnBossFrm( sal_True );
521     }
522     return (SwFtnBossFrm*)pRet;
523 }
524 
525 SwTabFrm* SwFrm::ImplFindTabFrm()
526 {
527     SwFrm *pRet = this;
528     while ( !pRet->IsTabFrm() )
529     {
530         pRet = pRet->GetUpper();
531         if ( !pRet )
532             return 0;
533     }
534     return (SwTabFrm*)pRet;
535 }
536 
537 SwSectionFrm* SwFrm::ImplFindSctFrm()
538 {
539     SwFrm *pRet = this;
540     while ( !pRet->IsSctFrm() )
541     {
542         pRet = pRet->GetUpper();
543         if ( !pRet )
544             return 0;
545     }
546     return (SwSectionFrm*)pRet;
547 }
548 
549 SwFtnFrm *SwFrm::ImplFindFtnFrm()
550 {
551     SwFrm *pRet = this;
552     while ( !pRet->IsFtnFrm() )
553     {
554         pRet = pRet->GetUpper();
555         if ( !pRet )
556             return 0;
557     }
558     return (SwFtnFrm*)pRet;
559 }
560 
561 SwFlyFrm *SwFrm::ImplFindFlyFrm()
562 {
563     const SwFrm *pRet = this;
564     do
565     {
566         if ( pRet->IsFlyFrm() )
567             return (SwFlyFrm*)pRet;
568         else
569             pRet = pRet->GetUpper();
570     } while ( pRet );
571     return 0;
572 }
573 
574 SwFrm *SwFrm::FindColFrm()
575 {
576     SwFrm *pFrm = this;
577     do
578     {   pFrm = pFrm->GetUpper();
579     } while ( pFrm && !pFrm->IsColumnFrm() );
580     return pFrm;
581 }
582 
583 SwFrm* SwFrm::FindFooterOrHeader()
584 {
585     SwFrm* pRet = this;
586     do
587     {   if ( pRet->GetType() & 0x0018 ) //Header und Footer
588             return pRet;
589         else if ( pRet->GetUpper() )
590             pRet = pRet->GetUpper();
591         else if ( pRet->IsFlyFrm() )
592             pRet = ((SwFlyFrm*)pRet)->AnchorFrm();
593         else
594             return 0;
595     } while ( pRet );
596     return pRet;
597 }
598 
599 const SwFtnFrm* SwFtnContFrm::FindFootNote() const
600 {
601     const SwFtnFrm* pRet = (SwFtnFrm*)Lower();
602     if( pRet && !pRet->GetAttr()->GetFtn().IsEndNote() )
603         return pRet;
604     return NULL;
605 }
606 
607 const SwPageFrm* SwRootFrm::GetPageAtPos( const Point& rPt, const Size* pSize, bool bExtend ) const
608 {
609     const SwPageFrm* pRet = 0;
610 
611     SwRect aRect;
612     if ( pSize )
613     {
614         aRect.Pos()  = rPt;
615         aRect.SSize() = *pSize;
616     }
617 
618     const SwFrm* pPage = Lower();
619 
620     if ( !bExtend )
621     {
622         if( !Frm().IsInside( rPt ) )
623             return 0;
624 
625         // skip pages above point:
626         while( pPage && rPt.Y() > pPage->Frm().Bottom() )
627             pPage = pPage->GetNext();
628     }
629 
630     ASSERT( GetPageNum() <= maPageRects.size(), "number of pages differes from page rect array size" )
631     sal_uInt16 nPageIdx = 0;
632 
633     while ( pPage && !pRet )
634     {
635         const SwRect& rBoundRect = bExtend ? maPageRects[ nPageIdx++ ] : pPage->Frm();
636 
637         if ( (!pSize && rBoundRect.IsInside(rPt)) ||
638               (pSize && rBoundRect.IsOver(aRect)) )
639         {
640             pRet = static_cast<const SwPageFrm*>(pPage);
641         }
642 
643         pPage = pPage->GetNext();
644     }
645 
646     return pRet;
647 }
648 
649 /*************************************************************************
650 |*
651 |*  SwFrmFrm::GetAttrSet()
652 |*
653 |*  Ersterstellung      MA 02. Aug. 93
654 |*  Letzte Aenderung    MA 02. Aug. 93
655 |*
656 |*************************************************************************/
657 const SwAttrSet* SwFrm::GetAttrSet() const
658 {
659     if ( IsCntntFrm() )
660         return &((const SwCntntFrm*)this)->GetNode()->GetSwAttrSet();
661     else
662         return &((const SwLayoutFrm*)this)->GetFmt()->GetAttrSet();
663 }
664 
665 /*************************************************************************
666 |*
667 |*  SwFrm::_FindNext(), _FindPrev(), InvalidateNextPos()
668 |*         _FindNextCnt() geht in Tabellen und Bereiche hineinund liefert
669 |*         nur SwCntntFrms.
670 |*
671 |*  Beschreibung        Invalidiert die Position des Naechsten Frames.
672 |*      Dies ist der direkte Nachfolger, oder bei CntntFrm's der naechste
673 |*      CntntFrm der im gleichen Fluss liegt wie ich:
674 |*      - Body,
675 |*      - Fussnoten,
676 |*      - Bei Kopf-/Fussbereichen ist die Benachrichtigung nur innerhalb des
677 |*        Bereiches weiterzuleiten.
678 |*      - dito fuer Flys.
679 |*      - Cntnts in Tabs halten sich ausschliesslich innerhalb ihrer Zelle
680 |*        auf.
681 |*      - Tabellen verhalten sich prinzipiell analog zu den Cntnts
682 |*      - Bereiche ebenfalls
683 |*  Ersterstellung      AK 14-Feb-1991
684 |*  Letzte Aenderung    AMA 10. Mar. 99
685 |*
686 |*************************************************************************/
687 
688 // Diese Hilfsfunktion ist ein Aequivalent zur ImplGetNextCntntFrm()-Methode,
689 // sie liefert allerdings neben ContentFrames auch TabFrms und SectionFrms.
690 SwFrm* lcl_NextFrm( SwFrm* pFrm )
691 {
692     SwFrm *pRet = 0;
693     sal_Bool bGoingUp = sal_False;
694     do {
695         SwFrm *p = 0;
696 
697         sal_Bool bGoingFwd = sal_False;
698         sal_Bool bGoingDown = (!bGoingUp && ( 0 != (p = pFrm->IsLayoutFrm() ? ((SwLayoutFrm*)pFrm)->Lower() : 0)));
699 
700         if( !bGoingDown )
701         {
702             bGoingFwd = (0 != (p = ( pFrm->IsFlyFrm() ? ((SwFlyFrm*)pFrm)->GetNextLink() : pFrm->GetNext())));
703             if ( !bGoingFwd )
704             {
705                 bGoingUp = (0 != (p = pFrm->GetUpper()));
706                 if ( !bGoingUp )
707                 {
708                     return 0;
709                 }
710             }
711         }
712         bGoingUp = !(bGoingFwd || bGoingDown);
713         pFrm = p;
714     } while ( 0 == (pRet = ( ( pFrm->IsCntntFrm() || ( !bGoingUp &&
715             ( pFrm->IsTabFrm() || pFrm->IsSctFrm() ) ) )? pFrm : 0 ) ) );
716     return pRet;
717 }
718 
719 SwFrm *SwFrm::_FindNext()
720 {
721     sal_Bool bIgnoreTab = sal_False;
722     SwFrm *pThis = this;
723 
724     if ( IsTabFrm() )
725     {
726         //Der letzte Cntnt der Tabelle wird
727         //gegriffen und dessen Nachfolger geliefert. Um die Spezialbeh.
728         //Fuer Tabellen (s.u.) auszuschalten wird bIgnoreTab gesetzt.
729         if ( ((SwTabFrm*)this)->GetFollow() )
730             return ((SwTabFrm*)this)->GetFollow();
731 
732         pThis = ((SwTabFrm*)this)->FindLastCntnt();
733         if ( !pThis )
734             pThis = this;
735         bIgnoreTab = sal_True;
736     }
737     else if ( IsSctFrm() )
738     {
739         //Der letzte Cntnt des Bereichs wird gegriffen und dessen Nachfolger
740         // geliefert.
741         if ( ((SwSectionFrm*)this)->GetFollow() )
742             return ((SwSectionFrm*)this)->GetFollow();
743 
744         pThis = ((SwSectionFrm*)this)->FindLastCntnt();
745         if ( !pThis )
746             pThis = this;
747     }
748     else if ( IsCntntFrm() )
749     {
750         if( ((SwCntntFrm*)this)->GetFollow() )
751             return ((SwCntntFrm*)this)->GetFollow();
752     }
753     else if ( IsRowFrm() )
754     {
755         SwFrm* pMyUpper = GetUpper();
756         if ( pMyUpper->IsTabFrm() && ((SwTabFrm*)pMyUpper)->GetFollow() )
757             return ((SwTabFrm*)pMyUpper)->GetFollow()->GetLower();
758         else return NULL;
759     }
760     else
761         return NULL;
762 
763     SwFrm* pRet = NULL;
764     const sal_Bool bFtn  = pThis->IsInFtn();
765     if ( !bIgnoreTab && pThis->IsInTab() )
766     {
767         SwLayoutFrm *pUp = pThis->GetUpper();
768         while ( !pUp->IsCellFrm() )
769             pUp = pUp->GetUpper();
770         ASSERT( pUp, "Cntnt in Tabelle aber nicht in Zelle." );
771         SwFrm* pNxt = ((SwCellFrm*)pUp)->GetFollowCell();
772         if ( pNxt )
773             pNxt = ((SwCellFrm*)pNxt)->ContainsCntnt();
774         if ( !pNxt )
775         {
776             pNxt = lcl_NextFrm( pThis );
777             if ( pUp->IsAnLower( pNxt ) )
778                 pRet = pNxt;
779         }
780         else
781             pRet = pNxt;
782     }
783     else
784     {
785         const sal_Bool bBody = pThis->IsInDocBody();
786         SwFrm *pNxtCnt = lcl_NextFrm( pThis );
787         if ( pNxtCnt )
788         {
789             if ( bBody || bFtn )
790             {
791                 while ( pNxtCnt )
792                 {
793                     // OD 02.04.2003 #108446# - check for endnote, only if found
794                     // next content isn't contained in a section, that collect its
795                     // endnotes at its end.
796                     bool bEndn = IsInSct() && !IsSctFrm() &&
797                                  ( !pNxtCnt->IsInSct() ||
798                                    !pNxtCnt->FindSctFrm()->IsEndnAtEnd()
799                                  );
800                     if ( ( bBody && pNxtCnt->IsInDocBody() ) ||
801                          ( pNxtCnt->IsInFtn() &&
802                            ( bFtn ||
803                              ( bEndn && pNxtCnt->FindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
804                            )
805                          )
806                        )
807                     {
808                         pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm()
809                                                     : (SwFrm*)pNxtCnt;
810                         break;
811                     }
812                     pNxtCnt = lcl_NextFrm( pNxtCnt );
813                 }
814             }
815             else if ( pThis->IsInFly() )
816             {
817                 pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm()
818                                             : (SwFrm*)pNxtCnt;
819             }
820             else    //Fuss-/oder Kopfbereich
821             {
822                 const SwFrm *pUp = pThis->GetUpper();
823                 const SwFrm *pCntUp = pNxtCnt->GetUpper();
824                 while ( pUp && pUp->GetUpper() &&
825                         !pUp->IsHeaderFrm() && !pUp->IsFooterFrm() )
826                     pUp = pUp->GetUpper();
827                 while ( pCntUp && pCntUp->GetUpper() &&
828                         !pCntUp->IsHeaderFrm() && !pCntUp->IsFooterFrm() )
829                     pCntUp = pCntUp->GetUpper();
830                 if ( pCntUp == pUp )
831                 {
832                     pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm()
833                                                 : (SwFrm*)pNxtCnt;
834                 }
835             }
836         }
837     }
838     if( pRet && pRet->IsInSct() )
839     {
840         SwSectionFrm* pSct = pRet->FindSctFrm();
841         //Fussnoten in spaltigen Rahmen duerfen nicht den Bereich
842         //liefern, der die Fussnoten umfasst
843         if( !pSct->IsAnLower( this ) &&
844             (!bFtn || pSct->IsInFtn() ) )
845             return pSct;
846     }
847     return pRet;
848 }
849 
850 // --> OD 2005-12-01 #i27138# - add parameter <_bInSameFtn>
851 SwCntntFrm *SwFrm::_FindNextCnt( const bool _bInSameFtn )
852 {
853     SwFrm *pThis = this;
854 
855     if ( IsTabFrm() )
856     {
857         if ( ((SwTabFrm*)this)->GetFollow() )
858         {
859             pThis = ((SwTabFrm*)this)->GetFollow()->ContainsCntnt();
860             if( pThis )
861                 return (SwCntntFrm*)pThis;
862         }
863         pThis = ((SwTabFrm*)this)->FindLastCntnt();
864         if ( !pThis )
865             return 0;
866     }
867     else if ( IsSctFrm() )
868     {
869         if ( ((SwSectionFrm*)this)->GetFollow() )
870         {
871             pThis = ((SwSectionFrm*)this)->GetFollow()->ContainsCntnt();
872             if( pThis )
873                 return (SwCntntFrm*)pThis;
874         }
875         pThis = ((SwSectionFrm*)this)->FindLastCntnt();
876         if ( !pThis )
877             return 0;
878     }
879     else if ( IsCntntFrm() && ((SwCntntFrm*)this)->GetFollow() )
880         return ((SwCntntFrm*)this)->GetFollow();
881 
882     if ( pThis->IsCntntFrm() )
883     {
884         const sal_Bool bBody = pThis->IsInDocBody();
885         const sal_Bool bFtn  = pThis->IsInFtn();
886         SwCntntFrm *pNxtCnt = ((SwCntntFrm*)pThis)->GetNextCntntFrm();
887         if ( pNxtCnt )
888         {
889             // --> OD 2005-12-01 #i27138#
890             if ( bBody || ( bFtn && !_bInSameFtn ) )
891             // <--
892             {
893                 // handling for environments 'footnotes' and 'document body frames':
894                 while ( pNxtCnt )
895                 {
896                     if ( (bBody && pNxtCnt->IsInDocBody()) ||
897                          (bFtn  && pNxtCnt->IsInFtn()) )
898                         return pNxtCnt;
899                     pNxtCnt = pNxtCnt->GetNextCntntFrm();
900                 }
901             }
902             // --> OD 2005-12-01 #i27138#
903             else if ( bFtn && _bInSameFtn )
904             {
905                 // handling for environments 'each footnote':
906                 // Assure that found next content frame belongs to the same footnotes
907                 const SwFtnFrm* pFtnFrmOfNext( pNxtCnt->FindFtnFrm() );
908                 const SwFtnFrm* pFtnFrmOfCurr( pThis->FindFtnFrm() );
909                 ASSERT( pFtnFrmOfCurr,
910                         "<SwFrm::_FindNextCnt() - unknown layout situation: current frame has to have an upper footnote frame." );
911                 if ( pFtnFrmOfNext == pFtnFrmOfCurr )
912                 {
913                     return pNxtCnt;
914                 }
915                 else if ( pFtnFrmOfCurr->GetFollow() )
916                 {
917                     // next content frame has to be the first content frame
918                     // in the follow footnote, which contains a content frame.
919                     SwFtnFrm* pFollowFtnFrmOfCurr(
920                                         const_cast<SwFtnFrm*>(pFtnFrmOfCurr) );
921                     pNxtCnt = 0L;
922                     do {
923                         pFollowFtnFrmOfCurr = pFollowFtnFrmOfCurr->GetFollow();
924                         pNxtCnt = pFollowFtnFrmOfCurr->ContainsCntnt();
925                     } while ( !pNxtCnt && pFollowFtnFrmOfCurr->GetFollow() );
926                     return pNxtCnt;
927                 }
928                 else
929                 {
930                     // current content frame is the last content frame in the
931                     // footnote - no next content frame exists.
932                     return 0L;
933                 }
934             }
935             // <--
936             else if ( pThis->IsInFly() )
937                 // handling for environments 'unlinked fly frame' and
938                 // 'group of linked fly frames':
939                 return pNxtCnt;
940             else
941             {
942                 // handling for environments 'page header' and 'page footer':
943                 const SwFrm *pUp = pThis->GetUpper();
944                 const SwFrm *pCntUp = pNxtCnt->GetUpper();
945                 while ( pUp && pUp->GetUpper() &&
946                         !pUp->IsHeaderFrm() && !pUp->IsFooterFrm() )
947                     pUp = pUp->GetUpper();
948                 while ( pCntUp && pCntUp->GetUpper() &&
949                         !pCntUp->IsHeaderFrm() && !pCntUp->IsFooterFrm() )
950                     pCntUp = pCntUp->GetUpper();
951                 if ( pCntUp == pUp )
952                     return pNxtCnt;
953             }
954         }
955     }
956     return 0;
957 }
958 
959 /** method to determine previous content frame in the same environment
960     for a flow frame (content frame, table frame, section frame)
961 
962     OD 2005-11-30 #i27138#
963 
964     @author OD
965 */
966 SwCntntFrm* SwFrm::_FindPrevCnt( const bool _bInSameFtn )
967 {
968     if ( !IsFlowFrm() )
969     {
970         // nothing to do, if current frame isn't a flow frame.
971         return 0L;
972     }
973 
974     SwCntntFrm* pPrevCntntFrm( 0L );
975 
976     // Because method <SwCntntFrm::GetPrevCntntFrm()> is used to travel
977     // through the layout, a content frame, at which the travel starts, is needed.
978     SwCntntFrm* pCurrCntntFrm = dynamic_cast<SwCntntFrm*>(this);
979 
980     // perform shortcut, if current frame is a follow, and
981     // determine <pCurrCntntFrm>, if current frame is a table or section frame
982     if ( pCurrCntntFrm && pCurrCntntFrm->IsFollow() )
983     {
984         // previous content frame is its master content frame
985         pPrevCntntFrm = pCurrCntntFrm->FindMaster();
986     }
987     else if ( IsTabFrm() )
988     {
989         SwTabFrm* pTabFrm( static_cast<SwTabFrm*>(this) );
990         if ( pTabFrm->IsFollow() )
991         {
992             // previous content frame is the last content of its master table frame
993             pPrevCntntFrm = pTabFrm->FindMaster()->FindLastCntnt();
994         }
995         else
996         {
997             // start content frame for the search is the first content frame of
998             // the table frame.
999             pCurrCntntFrm = pTabFrm->ContainsCntnt();
1000         }
1001     }
1002     else if ( IsSctFrm() )
1003     {
1004         SwSectionFrm* pSectFrm( static_cast<SwSectionFrm*>(this) );
1005         if ( pSectFrm->IsFollow() )
1006         {
1007             // previous content frame is the last content of its master section frame
1008             pPrevCntntFrm = pSectFrm->FindMaster()->FindLastCntnt();
1009         }
1010         else
1011         {
1012             // start content frame for the search is the first content frame of
1013             // the section frame.
1014             pCurrCntntFrm = pSectFrm->ContainsCntnt();
1015         }
1016     }
1017 
1018     // search for next content frame, depending on the environment, in which
1019     // the current frame is in.
1020     if ( !pPrevCntntFrm && pCurrCntntFrm )
1021     {
1022         pPrevCntntFrm = pCurrCntntFrm->GetPrevCntntFrm();
1023         if ( pPrevCntntFrm )
1024         {
1025             if ( pCurrCntntFrm->IsInFly() )
1026             {
1027                 // handling for environments 'unlinked fly frame' and
1028                 // 'group of linked fly frames':
1029                 // Nothing to do, <pPrevCntntFrm> is the one
1030             }
1031             else
1032             {
1033                 const bool bInDocBody = pCurrCntntFrm->IsInDocBody();
1034                 const bool bInFtn  = pCurrCntntFrm->IsInFtn();
1035                 if ( bInDocBody || ( bInFtn && !_bInSameFtn ) )
1036                 {
1037                     // handling for environments 'footnotes' and 'document body frames':
1038                     // Assure that found previous frame is also in one of these
1039                     // environments. Otherwise, travel further
1040                     while ( pPrevCntntFrm )
1041                     {
1042                         if ( ( bInDocBody && pPrevCntntFrm->IsInDocBody() ) ||
1043                              ( bInFtn && pPrevCntntFrm->IsInFtn() ) )
1044                         {
1045                             break;
1046                         }
1047                         pPrevCntntFrm = pPrevCntntFrm->GetPrevCntntFrm();
1048                     }
1049                 }
1050                 else if ( bInFtn && _bInSameFtn )
1051                 {
1052                     // handling for environments 'each footnote':
1053                     // Assure that found next content frame belongs to the same footnotes
1054                     const SwFtnFrm* pFtnFrmOfPrev( pPrevCntntFrm->FindFtnFrm() );
1055                     const SwFtnFrm* pFtnFrmOfCurr( pCurrCntntFrm->FindFtnFrm() );
1056                     if ( pFtnFrmOfPrev != pFtnFrmOfCurr )
1057                     {
1058                         if ( pFtnFrmOfCurr->GetMaster() )
1059                         {
1060                             SwFtnFrm* pMasterFtnFrmOfCurr(
1061                                         const_cast<SwFtnFrm*>(pFtnFrmOfCurr) );
1062                             pPrevCntntFrm = 0L;
1063                             // --> OD 2007-07-05 #146872#
1064                             // correct wrong loop-condition
1065                             do {
1066                                 pMasterFtnFrmOfCurr = pMasterFtnFrmOfCurr->GetMaster();
1067                                 pPrevCntntFrm = pMasterFtnFrmOfCurr->FindLastCntnt();
1068                             } while ( !pPrevCntntFrm &&
1069                                       pMasterFtnFrmOfCurr->GetMaster() );
1070                             // <--
1071                         }
1072                         else
1073                         {
1074                             // current content frame is the first content in the
1075                             // footnote - no previous content exists.
1076                             pPrevCntntFrm = 0L;;
1077                         }
1078                     }
1079                 }
1080                 else
1081                 {
1082                     // handling for environments 'page header' and 'page footer':
1083                     // Assure that found previous frame is also in the same
1084                     // page header respectively page footer as <pCurrCntntFrm>
1085                     // Note: At this point its clear, that <pCurrCntntFrm> has
1086                     //       to be inside a page header or page footer and that
1087                     //       neither <pCurrCntntFrm> nor <pPrevCntntFrm> are
1088                     //       inside a fly frame.
1089                     //       Thus, method <FindFooterOrHeader()> can be used.
1090                     ASSERT( pCurrCntntFrm->FindFooterOrHeader(),
1091                             "<SwFrm::_FindPrevCnt()> - unknown layout situation: current frame should be in page header or page footer" );
1092                     ASSERT( !pPrevCntntFrm->IsInFly(),
1093                             "<SwFrm::_FindPrevCnt()> - unknown layout situation: found previous frame should *not* be inside a fly frame." );
1094                     if ( pPrevCntntFrm->FindFooterOrHeader() !=
1095                                             pCurrCntntFrm->FindFooterOrHeader() )
1096                     {
1097                         pPrevCntntFrm = 0L;
1098                     }
1099                 }
1100             }
1101         }
1102     }
1103 
1104     return pPrevCntntFrm;
1105 }
1106 
1107 SwFrm *SwFrm::_FindPrev()
1108 {
1109     sal_Bool bIgnoreTab = sal_False;
1110     SwFrm *pThis = this;
1111 
1112     if ( IsTabFrm() )
1113     {
1114         //Der erste Cntnt der Tabelle wird
1115         //gegriffen und dessen Vorgaenger geliefert. Um die Spezialbeh.
1116         //Fuer Tabellen (s.u.) auszuschalten wird bIgnoreTab gesetzt.
1117         if ( ((SwTabFrm*)this)->IsFollow() )
1118             return ((SwTabFrm*)this)->FindMaster();
1119         else
1120             pThis = ((SwTabFrm*)this)->ContainsCntnt();
1121         bIgnoreTab = sal_True;
1122     }
1123 
1124     if ( pThis && pThis->IsCntntFrm() )
1125     {
1126         SwCntntFrm *pPrvCnt = ((SwCntntFrm*)pThis)->GetPrevCntntFrm();
1127         if( !pPrvCnt )
1128             return 0;
1129         if ( !bIgnoreTab && pThis->IsInTab() )
1130         {
1131             SwLayoutFrm *pUp = pThis->GetUpper();
1132             while ( !pUp->IsCellFrm() )
1133                 pUp = pUp->GetUpper();
1134             ASSERT( pUp, "Cntnt in Tabelle aber nicht in Zelle." );
1135             if ( pUp->IsAnLower( pPrvCnt ) )
1136                 return pPrvCnt;
1137         }
1138         else
1139         {
1140             SwFrm* pRet;
1141             const sal_Bool bBody = pThis->IsInDocBody();
1142             const sal_Bool bFtn  = bBody ? sal_False : pThis->IsInFtn();
1143             if ( bBody || bFtn )
1144             {
1145                 while ( pPrvCnt )
1146                 {
1147                     if ( (bBody && pPrvCnt->IsInDocBody()) ||
1148                             (bFtn   && pPrvCnt->IsInFtn()) )
1149                     {
1150                         pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm()
1151                                                   : (SwFrm*)pPrvCnt;
1152                         return pRet;
1153                     }
1154                     pPrvCnt = pPrvCnt->GetPrevCntntFrm();
1155                 }
1156             }
1157             else if ( pThis->IsInFly() )
1158             {
1159                 pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm()
1160                                             : (SwFrm*)pPrvCnt;
1161                 return pRet;
1162             }
1163             else    //Fuss-/oder Kopfbereich oder Fly
1164             {
1165                 const SwFrm *pUp = pThis->GetUpper();
1166                 const SwFrm *pCntUp = pPrvCnt->GetUpper();
1167                 while ( pUp && pUp->GetUpper() &&
1168                         !pUp->IsHeaderFrm() && !pUp->IsFooterFrm() )
1169                     pUp = pUp->GetUpper();
1170                 while ( pCntUp && pCntUp->GetUpper() )
1171                     pCntUp = pCntUp->GetUpper();
1172                 if ( pCntUp == pUp )
1173                 {
1174                     pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm()
1175                                                 : (SwFrm*)pPrvCnt;
1176                     return pRet;
1177                 }
1178             }
1179         }
1180     }
1181     return 0;
1182 }
1183 
1184 void SwFrm::ImplInvalidateNextPos( sal_Bool bNoFtn )
1185 {
1186     SwFrm *pFrm;
1187     if ( 0 != (pFrm = _FindNext()) )
1188     {
1189         if( pFrm->IsSctFrm() )
1190         {
1191             while( pFrm && pFrm->IsSctFrm() )
1192             {
1193                 if( ((SwSectionFrm*)pFrm)->GetSection() )
1194                 {
1195                     SwFrm* pTmp = ((SwSectionFrm*)pFrm)->ContainsAny();
1196                     if( pTmp )
1197                         pTmp->InvalidatePos();
1198                     else if( !bNoFtn )
1199                         ((SwSectionFrm*)pFrm)->InvalidateFtnPos();
1200                     if( !IsInSct() || FindSctFrm()->GetFollow() != pFrm )
1201                         pFrm->InvalidatePos();
1202                     return;
1203                 }
1204                 pFrm = pFrm->FindNext();
1205             }
1206             if( pFrm )
1207             {
1208                 if ( pFrm->IsSctFrm())
1209                 { // Damit der Inhalt eines Bereichs die Chance erhaelt,
1210                   // die Seite zu wechseln, muss er ebenfalls invalidiert werden.
1211                     SwFrm* pTmp = ((SwSectionFrm*)pFrm)->ContainsAny();
1212                     if( pTmp )
1213                         pTmp->InvalidatePos();
1214                     if( !IsInSct() || FindSctFrm()->GetFollow() != pFrm )
1215                         pFrm->InvalidatePos();
1216                 }
1217                 else
1218                     pFrm->InvalidatePos();
1219             }
1220         }
1221         else
1222             pFrm->InvalidatePos();
1223     }
1224 }
1225 
1226 /** method to invalidate printing area of next frame
1227 
1228     OD 09.01.2004 #i11859#
1229 
1230     @author OD
1231 
1232     FME 2004-04-19 #i27145# Moved function from SwTxtFrm to SwFrm
1233 */
1234 void SwFrm::InvalidateNextPrtArea()
1235 {
1236     // determine next frame
1237     SwFrm* pNextFrm = FindNext();
1238     // skip empty section frames and hidden text frames
1239     {
1240         while ( pNextFrm &&
1241                 ( ( pNextFrm->IsSctFrm() &&
1242                     !static_cast<SwSectionFrm*>(pNextFrm)->GetSection() ) ||
1243                   ( pNextFrm->IsTxtFrm() &&
1244                     static_cast<SwTxtFrm*>(pNextFrm)->IsHiddenNow() ) ) )
1245         {
1246             pNextFrm = pNextFrm->FindNext();
1247         }
1248     }
1249 
1250     // Invalidate printing area of found next frame
1251     if ( pNextFrm )
1252     {
1253         if ( pNextFrm->IsSctFrm() )
1254         {
1255             // Invalidate printing area of found section frame, if
1256             // (1) this text frame isn't in a section OR
1257             // (2) found section frame isn't a follow of the section frame this
1258             //     text frame is in.
1259             if ( !IsInSct() || FindSctFrm()->GetFollow() != pNextFrm )
1260             {
1261                 pNextFrm->InvalidatePrt();
1262             }
1263 
1264             // Invalidate printing area of first content in found section.
1265             SwFrm* pFstCntntOfSctFrm =
1266                     static_cast<SwSectionFrm*>(pNextFrm)->ContainsAny();
1267             if ( pFstCntntOfSctFrm )
1268             {
1269                 pFstCntntOfSctFrm->InvalidatePrt();
1270             }
1271         }
1272         else
1273         {
1274             pNextFrm->InvalidatePrt();
1275         }
1276     }
1277 }
1278 
1279 /*************************************************************************
1280 |*
1281 |*    lcl_IsInColSect()
1282 |*      liefert nur sal_True, wenn der Frame _direkt_ in einem spaltigen Bereich steht,
1283 |*      nicht etwa, wenn er in einer Tabelle steht, die in einem spaltigen Bereich ist.
1284 |*
1285 |*************************************************************************/
1286 
1287 sal_Bool lcl_IsInColSct( const SwFrm *pUp )
1288 {
1289     sal_Bool bRet = sal_False;
1290     while( pUp )
1291     {
1292         if( pUp->IsColumnFrm() )
1293             bRet = sal_True;
1294         else if( pUp->IsSctFrm() )
1295             return bRet;
1296         else if( pUp->IsTabFrm() )
1297             return sal_False;
1298         pUp = pUp->GetUpper();
1299     }
1300     return sal_False;
1301 }
1302 
1303 /*************************************************************************
1304 |*
1305 |*    SwFrm::IsMoveable();
1306 |*
1307 |*    Ersterstellung    MA 09. Mar. 93
1308 |*    Letzte Aenderung  MA 05. May. 95
1309 |*
1310 |*************************************************************************/
1311 /** determine, if frame is moveable in given environment
1312 
1313     OD 08.08.2003 #110978#
1314     method replaced 'old' method <sal_Bool IsMoveable() const>.
1315     Determines, if frame is moveable in given environment. if no environment
1316     is given (parameter _pLayoutFrm == 0L), the movability in the actual
1317     environment (<this->GetUpper()) is checked.
1318 
1319     @author OD
1320 */
1321 
1322 bool SwFrm::IsMoveable( const SwLayoutFrm* _pLayoutFrm ) const
1323 {
1324     bool bRetVal = false;
1325 
1326     if ( !_pLayoutFrm )
1327     {
1328         _pLayoutFrm = GetUpper();
1329     }
1330 
1331     if ( _pLayoutFrm && IsFlowFrm() )
1332     {
1333         if ( _pLayoutFrm->IsInSct() && lcl_IsInColSct( _pLayoutFrm ) )
1334         {
1335             bRetVal = true;
1336         }
1337         else if ( _pLayoutFrm->IsInFly() ||
1338                   _pLayoutFrm->IsInDocBody() ||
1339                   _pLayoutFrm->IsInFtn() )
1340         {
1341             if ( _pLayoutFrm->IsInTab() && !IsTabFrm() &&
1342                  ( !IsCntntFrm() || !const_cast<SwFrm*>(this)->GetNextCellLeaf( MAKEPAGE_NONE ) ) )
1343             {
1344                 bRetVal = false;
1345             }
1346             else
1347             {
1348                 if ( _pLayoutFrm->IsInFly() )
1349                 {
1350                     // if fly frame has a follow (next linked fly frame),
1351                     // frame is moveable.
1352                     if ( const_cast<SwLayoutFrm*>(_pLayoutFrm)->FindFlyFrm()->GetNextLink() )
1353                     {
1354                         bRetVal = true;
1355                     }
1356                     else
1357                     {
1358                         // if environment is columned, frame is moveable, if
1359                         // it isn't in last column.
1360                         // search for column frame
1361                         const SwFrm* pCol = _pLayoutFrm;
1362                         while ( pCol && !pCol->IsColumnFrm() )
1363                         {
1364                             pCol = pCol->GetUpper();
1365                         }
1366                         // frame is moveable, if found column frame isn't last one.
1367                         if ( pCol && pCol->GetNext() )
1368                         {
1369                             bRetVal = true;
1370                         }
1371                     }
1372                 }
1373                 else
1374                 {
1375                     bRetVal = true;
1376                 }
1377             }
1378         }
1379     }
1380 
1381     return bRetVal;
1382 }
1383 
1384 /*************************************************************************
1385 |*
1386 |*    SwFrm::SetInfFlags();
1387 |*
1388 |*    Ersterstellung    MA 05. Apr. 94
1389 |*    Letzte Aenderung  MA 05. Apr. 94
1390 |*
1391 |*************************************************************************/
1392 void SwFrm::SetInfFlags()
1393 {
1394     if ( !IsFlyFrm() && !GetUpper() ) //noch nicht gepastet, keine Informationen
1395         return;                       //lieferbar
1396 
1397     bInfInvalid = bInfBody = bInfTab = bInfFly = bInfFtn = bInfSct = sal_False;
1398 
1399     SwFrm *pFrm = this;
1400     if( IsFtnContFrm() )
1401         bInfFtn = sal_True;
1402     do
1403     {   // bInfBody wird nur am Seitenbody, nicht im ColumnBody gesetzt
1404         if ( pFrm->IsBodyFrm() && !bInfFtn && pFrm->GetUpper()
1405              && pFrm->GetUpper()->IsPageFrm() )
1406             bInfBody = sal_True;
1407         else if ( pFrm->IsTabFrm() || pFrm->IsCellFrm() )
1408         {
1409             bInfTab = sal_True;
1410         }
1411         else if ( pFrm->IsFlyFrm() )
1412             bInfFly = sal_True;
1413         else if ( pFrm->IsSctFrm() )
1414             bInfSct = sal_True;
1415         else if ( pFrm->IsFtnFrm() )
1416             bInfFtn = sal_True;
1417 
1418         pFrm = pFrm->GetUpper();
1419 
1420     } while ( pFrm && !pFrm->IsPageFrm() ); //Oberhalb der Seite kommt nix
1421 }
1422 
1423 /*-----------------22.8.2001 14:30------------------
1424  * SwFrm::SetDirFlags( sal_Bool )
1425  * actualizes the vertical or the righttoleft-flags.
1426  * If the property is derived, it's from the upper or (for fly frames) from
1427  * the anchor. Otherwise we've to call a virtual method to check the property.
1428  * --------------------------------------------------*/
1429 
1430 void SwFrm::SetDirFlags( sal_Bool bVert )
1431 {
1432     if( bVert )
1433     {
1434         // OD 2004-01-21 #114969# - if derived, valid vertical flag only if
1435         // vertical flag of upper/anchor is valid.
1436         if( bDerivedVert )
1437         {
1438             const SwFrm* pAsk = IsFlyFrm() ?
1439                           ((SwFlyFrm*)this)->GetAnchorFrm() : GetUpper();
1440 
1441             ASSERT( pAsk != this, "Autsch! Stack overflow is about to happen" )
1442 
1443             if( pAsk )
1444             {
1445                 bVertical = pAsk->IsVertical() ? 1 : 0;
1446                 bReverse  = pAsk->IsReverse()  ? 1 : 0;
1447 
1448                 bVertLR  = pAsk->IsVertLR() ? 1 : 0;
1449                 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
1450                 if ( !pAsk->bInvalidVert )
1451                     bInvalidVert = sal_False;
1452             }
1453         }
1454         else
1455             CheckDirection( bVert );
1456     }
1457     else
1458     {
1459         sal_Bool bInv = 0;
1460         if( !bDerivedR2L ) // CheckDirection is able to set bDerivedR2L!
1461             CheckDirection( bVert );
1462         if( bDerivedR2L )
1463         {
1464             const SwFrm* pAsk = IsFlyFrm() ?
1465                           ((SwFlyFrm*)this)->GetAnchorFrm() : GetUpper();
1466 
1467             ASSERT( pAsk != this, "Autsch! Stack overflow is about to happen" )
1468 
1469             if( pAsk )
1470                 bRightToLeft = pAsk->IsRightToLeft() ? 1 : 0;
1471             if( !pAsk || pAsk->bInvalidR2L )
1472                 bInv = bInvalidR2L;
1473         }
1474         bInvalidR2L = bInv;
1475     }
1476 }
1477 
1478 SwLayoutFrm* SwFrm::GetNextCellLeaf( MakePageType )
1479 {
1480     SwFrm* pTmpFrm = this;
1481     while ( !pTmpFrm->IsCellFrm() )
1482         pTmpFrm = pTmpFrm->GetUpper();
1483 
1484     ASSERT( pTmpFrm, "SwFrm::GetNextCellLeaf() without cell" )
1485     return ((SwCellFrm*)pTmpFrm)->GetFollowCell();
1486 }
1487 
1488 SwLayoutFrm* SwFrm::GetPrevCellLeaf( MakePageType )
1489 {
1490     SwFrm* pTmpFrm = this;
1491     while ( !pTmpFrm->IsCellFrm() )
1492         pTmpFrm = pTmpFrm->GetUpper();
1493 
1494     ASSERT( pTmpFrm, "SwFrm::GetNextPreviousLeaf() without cell" )
1495     return ((SwCellFrm*)pTmpFrm)->GetPreviousCell();
1496 }
1497 
1498 SwCellFrm* lcl_FindCorrespondingCellFrm( const SwRowFrm& rOrigRow,
1499                                          const SwCellFrm& rOrigCell,
1500                                          const SwRowFrm& rCorrRow,
1501                                          bool bInFollow )
1502 {
1503     SwCellFrm* pRet = NULL;
1504     SwCellFrm* pCell = (SwCellFrm*)rOrigRow.Lower();
1505     SwCellFrm* pCorrCell = (SwCellFrm*)rCorrRow.Lower();
1506 
1507     while ( pCell != &rOrigCell && !pCell->IsAnLower( &rOrigCell ) )
1508     {
1509         pCell = (SwCellFrm*)pCell->GetNext();
1510         pCorrCell = (SwCellFrm*)pCorrCell->GetNext();
1511     }
1512 
1513     ASSERT( pCell && pCorrCell, "lcl_FindCorrespondingCellFrm does not work" )
1514 
1515     if ( pCell != &rOrigCell )
1516     {
1517         // rOrigCell must be a lower of pCell. We need to recurse into the rows:
1518         ASSERT( pCell->Lower() && pCell->Lower()->IsRowFrm(),
1519                 "lcl_FindCorrespondingCellFrm does not work" )
1520 
1521         SwRowFrm* pRow = (SwRowFrm*)pCell->Lower();
1522         while ( !pRow->IsAnLower( &rOrigCell ) )
1523             pRow = (SwRowFrm*)pRow->GetNext();
1524 
1525         SwRowFrm* pCorrRow = 0;
1526         if ( bInFollow )
1527             pCorrRow = pRow->GetFollowRow();
1528         else
1529         {
1530             SwRowFrm* pTmpRow = static_cast<SwRowFrm*>(pCorrCell->GetLastLower());
1531 
1532             if ( pTmpRow && pTmpRow->GetFollowRow() == pRow )
1533                 pCorrRow = pTmpRow;
1534         }
1535 
1536         if ( pCorrRow )
1537             pRet = lcl_FindCorrespondingCellFrm( *pRow, rOrigCell, *pCorrRow, bInFollow );
1538     }
1539     else
1540         pRet = pCorrCell;
1541 
1542     return pRet;
1543 }
1544 
1545 // VERSION OF GetFollowCell() that assumes that we always have a follow flow line:
1546 SwCellFrm* SwCellFrm::GetFollowCell() const
1547 {
1548     SwCellFrm* pRet = NULL;
1549 
1550     // NEW TABLES
1551     // Covered cells do not have follow cells!
1552     const long nRowSpan = GetLayoutRowSpan();
1553     if ( nRowSpan < 1 )
1554         return NULL;
1555 
1556     // find most upper row frame
1557     const SwFrm* pRow = GetUpper();
1558     while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
1559         pRow = pRow->GetUpper();
1560 
1561     if ( !pRow )
1562         return NULL;
1563 
1564     const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>( pRow->GetUpper() );
1565     if ( !pRow || !pTabFrm->GetFollow() || !pTabFrm->HasFollowFlowLine() )
1566         return NULL;
1567 
1568     const SwCellFrm* pThisCell = this;
1569 
1570     // Get last cell of the current table frame that belongs to the rowspan:
1571     if ( nRowSpan > 1 )
1572     {
1573         // optimization: Will end of row span be in last row or exceed row?
1574         long nMax = 0;
1575         while ( pRow->GetNext() && ++nMax < nRowSpan )
1576             pRow = pRow->GetNext();
1577 
1578         if ( !pRow->GetNext() )
1579         {
1580             pThisCell = &pThisCell->FindStartEndOfRowSpanCell( false, true );
1581             pRow = pThisCell->GetUpper();
1582         }
1583     }
1584 
1585     const SwRowFrm* pFollowRow = NULL;
1586     if ( !pRow->GetNext() &&
1587          NULL != ( pFollowRow = pRow->IsInSplitTableRow() ) &&
1588          ( !pFollowRow->IsRowSpanLine() || nRowSpan > 1 ) )
1589          pRet = lcl_FindCorrespondingCellFrm( *((SwRowFrm*)pRow), *pThisCell, *pFollowRow, true );
1590 
1591     return pRet;
1592 }
1593 
1594 // VERSION OF GetPreviousCell() THAT ASSUMES THAT WE ALWAYS HAVE A FFL
1595 SwCellFrm* SwCellFrm::GetPreviousCell() const
1596 {
1597     SwCellFrm* pRet = NULL;
1598 
1599     // NEW TABLES
1600     // Covered cells do not have previous cells!
1601     if ( GetLayoutRowSpan() < 1 )
1602         return NULL;
1603 
1604     // find most upper row frame
1605     const SwFrm* pRow = GetUpper();
1606     while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
1607         pRow = pRow->GetUpper();
1608 
1609     ASSERT( pRow->GetUpper() && pRow->GetUpper()->IsTabFrm(), "GetPreviousCell without Table" );
1610 
1611     SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper();
1612 
1613     if ( pTab->IsFollow() )
1614     {
1615         const SwFrm* pTmp = pTab->GetFirstNonHeadlineRow();
1616         const bool bIsInFirstLine = ( pTmp == pRow );
1617 
1618         if ( bIsInFirstLine )
1619         {
1620             SwTabFrm *pMaster = (SwTabFrm*)pTab->FindMaster();
1621             if ( pMaster && pMaster->HasFollowFlowLine() )
1622             {
1623                 SwRowFrm* pMasterRow = static_cast<SwRowFrm*>(pMaster->GetLastLower());
1624                 if ( pMasterRow )
1625                     pRet = lcl_FindCorrespondingCellFrm( *((SwRowFrm*)pRow), *this, *pMasterRow, false );
1626                 if ( pRet && pRet->GetTabBox()->getRowSpan() < 1 )
1627                     pRet = &const_cast<SwCellFrm&>(pRet->FindStartEndOfRowSpanCell( true, true ));
1628             }
1629         }
1630     }
1631 
1632     return pRet;
1633 }
1634 
1635 // --> NEW TABLES
1636 const SwCellFrm& SwCellFrm::FindStartEndOfRowSpanCell( bool bStart, bool bCurrentTableOnly ) const
1637 {
1638     const SwCellFrm* pRet = 0;
1639 
1640     const SwTabFrm* pTableFrm = dynamic_cast<const SwTabFrm*>(GetUpper()->GetUpper());
1641 
1642     if ( !bStart && pTableFrm->IsFollow() && pTableFrm->IsInHeadline( *this ) )
1643         return *this;
1644 
1645     ASSERT( pTableFrm &&
1646             (  bStart && GetTabBox()->getRowSpan() < 1 ||
1647               !bStart && GetLayoutRowSpan() > 1 ),
1648             "SwCellFrm::FindStartRowSpanCell: No rowspan, no table, no cookies" )
1649 
1650     if ( pTableFrm )
1651     {
1652         const SwTable* pTable = pTableFrm->GetTable();
1653 
1654         sal_uInt16 nMax = USHRT_MAX;
1655         if ( bCurrentTableOnly )
1656         {
1657             const SwFrm* pCurrentRow = GetUpper();
1658             const bool bDoNotEnterHeadline = bStart && pTableFrm->IsFollow() &&
1659                                         !pTableFrm->IsInHeadline( *pCurrentRow );
1660 
1661             // check how many rows we are allowed to go up or down until we reach the end of
1662             // the current table frame:
1663             nMax = 0;
1664             while ( bStart ? pCurrentRow->GetPrev() : pCurrentRow->GetNext() )
1665             {
1666                 if ( bStart )
1667                 {
1668                     // do not enter a repeated headline:
1669                     if ( bDoNotEnterHeadline && pTableFrm->IsFollow() &&
1670                          pTableFrm->IsInHeadline( *pCurrentRow->GetPrev() ) )
1671                         break;
1672 
1673                     pCurrentRow = pCurrentRow->GetPrev();
1674                 }
1675                 else
1676                     pCurrentRow = pCurrentRow->GetNext();
1677 
1678                 ++nMax;
1679             }
1680         }
1681 
1682         // By passing the nMax value for Find*OfRowSpan (in case of bCurrentTableOnly
1683         // is set) we assure that we find a rMasterBox that has a SwCellFrm in
1684         // the current table frame:
1685         const SwTableBox& rMasterBox = bStart ?
1686                                        GetTabBox()->FindStartOfRowSpan( *pTable, nMax ) :
1687                                        GetTabBox()->FindEndOfRowSpan( *pTable, nMax );
1688 
1689         SwIterator<SwCellFrm,SwFmt> aIter( *rMasterBox.GetFrmFmt() );
1690 
1691         for ( SwCellFrm* pMasterCell = aIter.First(); pMasterCell; pMasterCell = aIter.Next() )
1692         {
1693             if ( pMasterCell->GetTabBox() == &rMasterBox )
1694             {
1695                 const SwTabFrm* pMasterTable = static_cast<const SwTabFrm*>(pMasterCell->GetUpper()->GetUpper());
1696 
1697                 if ( bCurrentTableOnly )
1698                 {
1699                     if ( pMasterTable == pTableFrm )
1700                     {
1701                         pRet = pMasterCell;
1702                         break;
1703                     }
1704                 }
1705                 else
1706                 {
1707                     if ( pMasterTable == pTableFrm ||
1708                          (  (bStart && pMasterTable->IsAnFollow(pTableFrm)) ||
1709                            (!bStart && pTableFrm->IsAnFollow(pMasterTable)) ) )
1710                     {
1711                         pRet = pMasterCell;
1712                         break;
1713                     }
1714                 }
1715             }
1716         }
1717     }
1718 
1719     ASSERT( pRet, "SwCellFrm::FindStartRowSpanCell: No result" )
1720 
1721     return *pRet;
1722 }
1723 // <-- NEW TABLES
1724 
1725 const SwRowFrm* SwFrm::IsInSplitTableRow() const
1726 {
1727     ASSERT( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" )
1728 
1729     const SwFrm* pRow = this;
1730 
1731     // find most upper row frame
1732     while( pRow && ( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) )
1733         pRow = pRow->GetUpper();
1734 
1735     if ( !pRow ) return NULL;
1736 
1737     ASSERT( pRow->GetUpper()->IsTabFrm(), "Confusion in table layout" )
1738 
1739     const SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper();
1740     // --> OD 2006-06-28 #b6443897#
1741     // If most upper row frame is a headline row, the current frame
1742     // can't be in a splitted table row. Thus, add corresponding condition.
1743     if ( pRow->GetNext() ||
1744          pTab->GetTable()->IsHeadline(
1745                     *(static_cast<const SwRowFrm*>(pRow)->GetTabLine()) ) ||
1746          !pTab->HasFollowFlowLine() ||
1747          !pTab->GetFollow() )
1748         return NULL;
1749     // <--
1750 
1751     // skip headline
1752     const SwRowFrm* pFollowRow = pTab->GetFollow()->GetFirstNonHeadlineRow();
1753 
1754     ASSERT( pFollowRow, "SwFrm::IsInSplitTableRow() does not work" )
1755 
1756     return pFollowRow;
1757 }
1758 
1759 const SwRowFrm* SwFrm::IsInFollowFlowRow() const
1760 {
1761     ASSERT( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" )
1762 
1763     // find most upper row frame
1764     const SwFrm* pRow = this;
1765     while( pRow && ( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) )
1766         pRow = pRow->GetUpper();
1767 
1768     if ( !pRow ) return NULL;
1769 
1770     ASSERT( pRow->GetUpper()->IsTabFrm(), "Confusion in table layout" )
1771 
1772     const SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper();
1773 
1774     const SwTabFrm* pMaster = pTab->IsFollow() ? pTab->FindMaster() : 0;
1775 
1776     if ( !pMaster || !pMaster->HasFollowFlowLine() )
1777         return NULL;
1778 
1779     const SwFrm* pTmp = pTab->GetFirstNonHeadlineRow();
1780     const bool bIsInFirstLine = ( pTmp == pRow );
1781 
1782     if ( !bIsInFirstLine )
1783         return NULL;
1784 
1785     const SwRowFrm* pMasterRow = static_cast<const SwRowFrm*>(pMaster->GetLastLower());
1786     return pMasterRow;
1787 }
1788 
1789 bool SwFrm::IsInBalancedSection() const
1790 {
1791     bool bRet = false;
1792 
1793     if ( IsInSct() )
1794     {
1795         const SwSectionFrm* pSectionFrm = FindSctFrm();
1796         if ( pSectionFrm )
1797             bRet = pSectionFrm->IsBalancedSection();
1798     }
1799     return bRet;
1800 }
1801 
1802 /*
1803  * SwLayoutFrm::GetLastLower()
1804  */
1805 const SwFrm* SwLayoutFrm::GetLastLower() const
1806 {
1807     const SwFrm* pRet = Lower();
1808     if ( !pRet )
1809         return 0;
1810     while ( pRet->GetNext() )
1811         pRet = pRet->GetNext();
1812     return pRet;
1813 }
1814