xref: /trunk/main/sw/source/core/layout/ftnfrm.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 <txtftn.hxx>
33 #include <fmtftn.hxx>
34 #include <ftnidx.hxx>
35 #include <pagefrm.hxx>
36 #include <colfrm.hxx>
37 #include <rootfrm.hxx>
38 #include <cntfrm.hxx>
39 #include <doc.hxx>
40 #include <ndtxt.hxx>
41 #include <frmtool.hxx>
42 #include <swtable.hxx>
43 #include <ftnfrm.hxx>
44 #include <txtfrm.hxx>
45 #include <tabfrm.hxx>
46 #include <pagedesc.hxx>
47 #include <ftninfo.hxx>
48 #include <ndindex.hxx>
49 #include <sectfrm.hxx>
50 #include <pam.hxx>
51 #include <objectformatter.hxx>
52 #include "viewopt.hxx"
53 #include "viewsh.hxx"
54 #include <switerator.hxx>
55 
56 /*************************************************************************
57 |*
58 |*  lcl_FindFtnPos()        Sucht die Position des Attributes im FtnArray am
59 |*      Dokument, dort stehen die Fussnoten gluecklicherweise nach ihrem
60 |*      Index sortiert.
61 |*
62 |*************************************************************************/
63 
64 #define ENDNOTE 0x80000000
65 
66 sal_uLong MA_FASTCALL lcl_FindFtnPos( const SwDoc *pDoc, const SwTxtFtn *pAttr )
67 {
68     const SwFtnIdxs &rFtnIdxs = pDoc->GetFtnIdxs();
69 
70 #ifdef MA_DEBUG
71     //Wenn das Array nicht stimmt haben wir ein Problem, denn viele
72     //Ftn-Functions bauen auf dem Array auf.
73     for ( sal_uInt16 k = 0; k+1 < rFtnIdxs.Count(); ++k )
74     {
75         SwIndex aIdx1(&pDoc->GetNodes());
76         SwIndex aIdx2(&pDoc->GetNodes());
77         rFtnIdxs[k]->pFtn->  GetTxtNode().GetIndex(aIdx1);
78         rFtnIdxs[k+1]->pFtn->GetTxtNode().GetIndex(aIdx2);
79         if ( aIdx1.GetIndex() > aIdx2.GetIndex() )
80         {
81             ASSERT( !rFtnIdxs.Count(), "FtnIdxs not up to date" );
82         }
83         else if ( aIdx1.GetIndex() == aIdx2.GetIndex() )
84         {
85             SwTxtFtn *p1 = rFtnIdxs[k];
86             SwTxtFtn *p2 = rFtnIdxs[k+1];
87             ASSERT( *p1->GetStart() < *p2->GetStart(),
88                     "FtnIdxs not up to date" );
89         }
90     }
91 #endif
92 
93     sal_uInt16 nRet;
94     SwTxtFtnPtr pBla = (SwTxtFtn*)pAttr;
95     if ( rFtnIdxs.Seek_Entry( pBla, &nRet ) )
96     {
97         if( pAttr->GetFtn().IsEndNote() )
98             return sal_uLong(nRet) + ENDNOTE;
99         return nRet;
100     }
101     ASSERT( !pDoc, "FtnPos not found." );
102     return 0;
103 }
104 
105 sal_Bool SwFtnFrm::operator<( const SwTxtFtn* pTxtFtn ) const
106 {
107     const SwDoc* pDoc = GetFmt()->GetDoc();
108     ASSERT( pDoc, "SwFtnFrm: Missing doc!" );
109     return lcl_FindFtnPos( pDoc, GetAttr() ) <
110            lcl_FindFtnPos( pDoc, pTxtFtn );
111 }
112 
113 /*************************************************************************
114 |*
115 |*  sal_Bool lcl_NextFtnBoss( SwFtnBossFrm* pBoss, SwPageFrm* pPage)
116 |*  setzt pBoss auf den naechsten SwFtnBossFrm, das kann entweder eine Spalte
117 |*  oder eine Seite (ohne Spalten) sein. Wenn die Seite dabei gewechselt wird
118 |*  enthaelt pPage die neue Seite und die Funktion liefert sal_True.
119 |*
120 |*************************************************************************/
121 
122 sal_Bool lcl_NextFtnBoss( SwFtnBossFrm* &rpBoss, SwPageFrm* &rpPage,
123     sal_Bool bDontLeave )
124 {
125     if( rpBoss->IsColumnFrm() )
126     {
127         if( rpBoss->GetNext() )
128         {
129             rpBoss = (SwFtnBossFrm*)rpBoss->GetNext(); //naechste Spalte
130             return sal_False;
131         }
132         if( rpBoss->IsInSct() )
133         {
134             SwSectionFrm* pSct = rpBoss->FindSctFrm()->GetFollow();
135             if( pSct )
136             {
137                 ASSERT( pSct->Lower() && pSct->Lower()->IsColumnFrm(),
138                         "Where's the column?" );
139                 rpBoss = (SwColumnFrm*)pSct->Lower();
140                 SwPageFrm* pOld = rpPage;
141                 rpPage = pSct->FindPageFrm();
142                 return pOld != rpPage;
143             }
144             else if( bDontLeave )
145             {
146                 rpPage = NULL;
147                 rpBoss = NULL;
148                 return sal_False;
149             }
150         }
151     }
152     rpPage = (SwPageFrm*)rpPage->GetNext(); // naechste Seite
153     rpBoss = rpPage;
154     if( rpPage )
155     {
156         SwLayoutFrm* pBody = rpPage->FindBodyCont();
157         if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() )
158             rpBoss = (SwFtnBossFrm*)pBody->Lower(); // erste Spalte
159     }
160     return sal_True;
161 }
162 
163 /*************************************************************************
164 |*
165 |*  sal_uInt16 lcl_ColumnNum( SwFrm* pBoss )
166 |*  liefert die Spaltennummer, wenn pBoss eine Spalte ist,
167 |*  sonst eine Null (bei Seiten).
168 |*
169 |*************************************************************************/
170 
171 sal_uInt16 lcl_ColumnNum( const SwFrm* pBoss )
172 {
173     sal_uInt16 nRet = 0;
174     if( !pBoss->IsColumnFrm() )
175         return 0;
176     const SwFrm* pCol;
177     if( pBoss->IsInSct() )
178     {
179         pCol = pBoss->GetUpper()->FindColFrm();
180         if( pBoss->GetNext() || pBoss->GetPrev() )
181         {
182             while( pBoss )
183             {
184                 ++nRet;                     // Section columns
185                 pBoss = pBoss->GetPrev();
186             }
187         }
188     }
189     else
190         pCol = pBoss;
191     while( pCol )
192     {
193         nRet += 256;                    // Page columns
194         pCol = pCol->GetPrev();
195     }
196     return nRet;
197 }
198 
199 /*************************************************************************
200 |*
201 |*  SwFtnContFrm::SwFtnContFrm()
202 |*
203 |*************************************************************************/
204 
205 
206 SwFtnContFrm::SwFtnContFrm( SwFrmFmt *pFmt, SwFrm* pSib ):
207     SwLayoutFrm( pFmt, pSib )
208 {
209     nType = FRMC_FTNCONT;
210 }
211 
212 
213 // lcl_Undersize(..) klappert einen SwFrm und dessen Inneres ab
214 // und liefert die Summe aller TxtFrm-Vergroesserungswuensche
215 
216 long lcl_Undersize( const SwFrm* pFrm )
217 {
218     long nRet = 0;
219     SWRECTFN( pFrm )
220     if( pFrm->IsTxtFrm() )
221     {
222         if( ((SwTxtFrm*)pFrm)->IsUndersized() )
223         {
224             // Dieser TxtFrm waere gern ein bisschen groesser
225             nRet = ((SwTxtFrm*)pFrm)->GetParHeight() -
226                     (pFrm->Prt().*fnRect->fnGetHeight)();
227             if( nRet < 0 )
228                 nRet = 0;
229         }
230     }
231     else if( pFrm->IsLayoutFrm() )
232     {
233         const SwFrm* pNxt = ((SwLayoutFrm*)pFrm)->Lower();
234         while( pNxt )
235         {
236             nRet += lcl_Undersize( pNxt );
237             pNxt = pNxt->GetNext();
238         }
239     }
240     return nRet;
241 }
242 
243 /*************************************************************************
244 |*
245 |*  SwFtnContFrm::Format()
246 |*
247 |*  Beschreibung:       "Formatiert" den Frame;
248 |*                      Die Fixsize wird hier nicht eingestellt.
249 |*
250 |*************************************************************************/
251 
252 
253 void SwFtnContFrm::Format( const SwBorderAttrs * )
254 {
255     //GesamtBorder ermitteln, es gibt nur einen Abstand nach oben.
256     const SwPageFrm* pPage = FindPageFrm();
257     const SwPageFtnInfo &rInf = pPage->GetPageDesc()->GetFtnInfo();
258     const SwTwips nBorder = rInf.GetTopDist() + rInf.GetBottomDist() +
259                             rInf.GetLineWidth();
260     SWRECTFN( this )
261     if ( !bValidPrtArea )
262     {
263         bValidPrtArea = sal_True;
264         (Prt().*fnRect->fnSetTop)( nBorder );
265         (Prt().*fnRect->fnSetWidth)( (Frm().*fnRect->fnGetWidth)() );
266         (Prt().*fnRect->fnSetHeight)((Frm().*fnRect->fnGetHeight)() - nBorder );
267         if( (Prt().*fnRect->fnGetHeight)() < 0 && !pPage->IsFtnPage() )
268             bValidSize = sal_False;
269     }
270 
271     if ( !bValidSize )
272     {
273         bool bGrow = pPage->IsFtnPage();
274         if( bGrow )
275         {
276             const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
277             if( pSh && pSh->GetViewOptions()->getBrowseMode() )
278                 bGrow = false;
279         }
280         if( bGrow )
281                 Grow( LONG_MAX, sal_False );
282         else
283         {
284             //Die Groesse in der VarSize wird durch den Inhalt plus den
285             //Raendern bestimmt.
286             SwTwips nRemaining = 0;
287             SwFrm *pFrm = pLower;
288             while ( pFrm )
289             {   // lcl_Undersize(..) beruecksichtigt (rekursiv) TxtFrms, die gerne
290                 // groesser waeren. Diese entstehen insbesondere in spaltigen Rahmen,
291                 // wenn diese noch nicht ihre maximale Groesse haben.
292                 nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)()
293                               + lcl_Undersize( pFrm );
294                 pFrm = pFrm->GetNext();
295             }
296             //Jetzt noch den Rand addieren
297             nRemaining += nBorder;
298 
299             SwTwips nDiff;
300             if( IsInSct() )
301             {
302                 nDiff = -(Frm().*fnRect->fnBottomDist)(
303                                         (GetUpper()->*fnRect->fnGetPrtBottom)() );
304                 if( nDiff > 0 )
305                 {
306                     if( nDiff > (Frm().*fnRect->fnGetHeight)() )
307                         nDiff = (Frm().*fnRect->fnGetHeight)();
308                     (Frm().*fnRect->fnAddBottom)( -nDiff );
309                     (Prt().*fnRect->fnAddHeight)( -nDiff );
310                 }
311             }
312             nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining;
313             if ( nDiff > 0 )
314                 Shrink( nDiff );
315             else if ( nDiff < 0 )
316             {
317                 Grow( -nDiff );
318                 //Es kann passieren, dass weniger Platz zur Verfuegung steht,
319                 //als der bereits der Border benoetigt - die Groesse der
320                 //PrtArea wird dann negativ.
321                 SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)();
322                 if( nPrtHeight < 0 )
323                 {
324                     const SwTwips nTmpDiff = Max( (Prt().*fnRect->fnGetTop)(),
325                                                 -nPrtHeight );
326                     (Prt().*fnRect->fnSubTop)( nTmpDiff );
327                 }
328             }
329         }
330         bValidSize = sal_True;
331     }
332 }
333 /*************************************************************************
334 |*
335 |*  SwFtnContFrm::GrowFrm(), ShrinkFrm()
336 |*
337 |*************************************************************************/
338 
339 SwTwips SwFtnContFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool )
340 {
341     //Keine Pruefung ob FixSize oder nicht, die FtnContainer sind immer bis
342     //zur Maximalhoehe variabel.
343     //Wenn die Maximalhoehe LONG_MAX ist, so nehmen wir uns soviel Platz wie eben
344     //moeglich.
345     //Wenn die Seite eine spezielle Fussnotenseite ist, so nehmen wir uns auch
346     //soviel Platz wie eben moeglich.
347 #ifdef DBG_UTIL
348     if ( !GetUpper() || !GetUpper()->IsFtnBossFrm() )
349     {   ASSERT( !this, "Keine FtnBoss." );
350         return 0;
351     }
352 #endif
353 
354     SWRECTFN( this )
355     if( (Frm().*fnRect->fnGetHeight)() > 0 &&
356          nDist > ( LONG_MAX - (Frm().*fnRect->fnGetHeight)() ) )
357         nDist = LONG_MAX - (Frm().*fnRect->fnGetHeight)();
358 
359     SwFtnBossFrm *pBoss = (SwFtnBossFrm*)GetUpper();
360     if( IsInSct() )
361     {
362         SwSectionFrm* pSect = FindSctFrm();
363         ASSERT( pSect, "GrowFrm: Missing SectFrm" );
364         // In a section, which has to maximize, a footnotecontainer is allowed
365         // to grow, when the section can't grow anymore.
366         if( !bTst && !pSect->IsColLocked() &&
367             pSect->ToMaximize( sal_False ) && pSect->Growable() )
368         {
369             pSect->InvalidateSize();
370             return 0;
371         }
372     }
373     const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
374     const sal_Bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
375     SwPageFrm *pPage = pBoss->FindPageFrm();
376     if ( bBrowseMode || !pPage->IsFtnPage() )
377     {
378         if ( pBoss->GetMaxFtnHeight() != LONG_MAX )
379         {
380             nDist = Min( nDist, pBoss->GetMaxFtnHeight()
381                          - (Frm().*fnRect->fnGetHeight)() );
382             if ( nDist <= 0 )
383                 return 0L;
384         }
385         //Der FtnBoss will bezueglich des MaxWerts auch noch mitreden.
386         if( !IsInSct() )
387         {
388             const SwTwips nMax = pBoss->GetVarSpace();
389             if ( nDist > nMax )
390                 nDist = nMax;
391             if ( nDist <= 0 )
392                 return 0L;
393         }
394     }
395     else if( nDist > (GetPrev()->Frm().*fnRect->fnGetHeight)() )
396         //aber mehr als der Body kann koennen und wollen wir nun auch wieder
397         //nicht herausruecken.
398         nDist = (GetPrev()->Frm().*fnRect->fnGetHeight)();
399 
400     long nAvail = 0;
401     if ( bBrowseMode )
402     {
403         nAvail = GetUpper()->Prt().Height();
404         const SwFrm *pAvail = GetUpper()->Lower();
405         do
406         {   nAvail -= pAvail->Frm().Height();
407             pAvail = pAvail->GetNext();
408         } while ( pAvail );
409         if ( nAvail > nDist )
410             nAvail = nDist;
411     }
412 
413     if ( !bTst )
414     {
415         (Frm().*fnRect->fnSetHeight)( (Frm().*fnRect->fnGetHeight)() + nDist );
416         //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
417         if( IsVertical() && !IsVertLR() && !IsReverse() )
418             Frm().Pos().X() -= nDist;
419     }
420     long nGrow = nDist - nAvail,
421          nReal = 0;
422     if ( nGrow > 0 )
423     {
424         sal_uInt8 nAdjust = pBoss->NeighbourhoodAdjustment( this );
425         if( NA_ONLY_ADJUST == nAdjust )
426             nReal = AdjustNeighbourhood( nGrow, bTst );
427         else
428         {
429             if( NA_GROW_ADJUST == nAdjust )
430             {
431                 SwFrm* pFtn = Lower();
432                 if( pFtn )
433                 {
434                     while( pFtn->GetNext() )
435                         pFtn = pFtn->GetNext();
436                     if( ((SwFtnFrm*)pFtn)->GetAttr()->GetFtn().IsEndNote() )
437                     {
438                         nReal = AdjustNeighbourhood( nGrow, bTst );
439                         nAdjust = NA_GROW_SHRINK; // no more AdjustNeighbourhood
440                     }
441                 }
442             }
443             nReal += pBoss->Grow( nGrow - nReal, bTst );
444             if( ( NA_GROW_ADJUST == nAdjust || NA_ADJUST_GROW == nAdjust )
445                   && nReal < nGrow )
446                 nReal += AdjustNeighbourhood( nGrow - nReal, bTst );
447         }
448     }
449 
450     nReal += nAvail;
451 
452     if ( !bTst )
453     {
454         if ( nReal != nDist )
455         {
456             nDist -= nReal;
457             //Den masslosen Wunsch koennen wir leider nur in Grenzen erfuellen.
458             Frm().SSize().Height() -= nDist;
459             //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
460             if( IsVertical() && !IsVertLR() && !IsReverse() )
461                 Frm().Pos().X() += nDist;
462         }
463 
464         //Nachfolger braucht nicht invalidiert werden, denn wir wachsen
465         //immer nach oben.
466         if( nReal )
467         {
468             _InvalidateSize();
469             _InvalidatePos();
470             InvalidatePage( pPage );
471         }
472     }
473     return nReal;
474 }
475 
476 
477 SwTwips SwFtnContFrm::ShrinkFrm( SwTwips nDiff, sal_Bool bTst, sal_Bool bInfo )
478 {
479     SwPageFrm *pPage = FindPageFrm();
480     bool bShrink = false;
481     if ( pPage )
482     {
483         if( !pPage->IsFtnPage() )
484             bShrink = true;
485         else
486         {
487             const ViewShell *pSh = getRootFrm()->GetCurrShell();
488             if( pSh && pSh->GetViewOptions()->getBrowseMode() )
489                 bShrink = true;
490         }
491     }
492     if( bShrink )
493     {
494         SwTwips nRet = SwLayoutFrm::ShrinkFrm( nDiff, bTst, bInfo );
495         if( IsInSct() && !bTst )
496             FindSctFrm()->InvalidateNextPos();
497         if ( !bTst && nRet )
498         {
499             _InvalidatePos();
500             InvalidatePage( pPage );
501         }
502         return nRet;
503     }
504     return 0;
505 }
506 
507 
508 /*************************************************************************
509 |*
510 |*  SwFtnFrm::SwFtnFrm()
511 |*
512 |*************************************************************************/
513 
514 
515 SwFtnFrm::SwFtnFrm( SwFrmFmt *pFmt, SwFrm* pSib, SwCntntFrm *pCnt, SwTxtFtn *pAt ):
516     SwLayoutFrm( pFmt, pSib ),
517     pFollow( 0 ),
518     pMaster( 0 ),
519     pRef( pCnt ),
520     pAttr( pAt ),
521     bBackMoveLocked( sal_False ),
522     // --> OD 2005-08-11 #i49383#
523     mbUnlockPosOfLowerObjs( true )
524     // <--
525 {
526     nType = FRMC_FTN;
527 }
528 
529 /*************************************************************************
530 |*
531 |*  SwFtnFrm::InvalidateNxtFtnCnts()
532 |*
533 |*************************************************************************/
534 
535 
536 void SwFtnFrm::InvalidateNxtFtnCnts( SwPageFrm *pPage )
537 {
538     if ( GetNext() )
539     {
540         SwFrm *pCnt = ((SwLayoutFrm*)GetNext())->ContainsAny();
541         if( pCnt )
542         {
543             pCnt->InvalidatePage( pPage );
544             pCnt->_InvalidatePrt();
545             do
546             {   pCnt->_InvalidatePos();
547                 if( pCnt->IsSctFrm() )
548                 {
549                     SwFrm* pTmp = ((SwSectionFrm*)pCnt)->ContainsAny();
550                     if( pTmp )
551                         pTmp->_InvalidatePos();
552                 }
553                 pCnt->GetUpper()->_InvalidateSize();
554                 pCnt = pCnt->FindNext();
555             } while ( pCnt && GetUpper()->IsAnLower( pCnt ) );
556         }
557     }
558 }
559 
560 #ifdef DBG_UTIL
561 
562 SwTwips SwFtnFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo )
563 {
564 #if OSL_DEBUG_LEVEL > 1
565     static sal_uInt16 nNum = USHRT_MAX;
566     SwTxtFtn* pTxtFtn = GetAttr();
567     if ( pTxtFtn->GetFtn().GetNumber() == nNum )
568     {
569         int bla = 5;
570         (void)bla;
571 
572     }
573 #endif
574     return SwLayoutFrm::GrowFrm( nDist, bTst, bInfo );
575 }
576 
577 
578 SwTwips SwFtnFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo )
579 {
580 #if OSL_DEBUG_LEVEL > 1
581     static sal_uInt16 nNum = USHRT_MAX;
582     if( nNum != USHRT_MAX )
583     {
584         SwTxtFtn* pTxtFtn = GetAttr();
585         if( &pTxtFtn->GetAttr() && pTxtFtn->GetFtn().GetNumber() == nNum )
586         {
587             int bla = 5;
588             (void)bla;
589         }
590     }
591 #endif
592     return SwLayoutFrm::ShrinkFrm( nDist, bTst, bInfo );
593 }
594 #endif
595 
596 /*************************************************************************
597 |*
598 |*  SwFtnFrm::Cut()
599 |*
600 |*************************************************************************/
601 
602 
603 void SwFtnFrm::Cut()
604 {
605     if ( GetNext() )
606         GetNext()->InvalidatePos();
607     else if ( GetPrev() )
608         GetPrev()->SetRetouche();
609 
610     //Erst removen, dann Upper Shrinken.
611     SwLayoutFrm *pUp = GetUpper();
612 
613     //Verkettung korrigieren.
614     SwFtnFrm *pFtn = (SwFtnFrm*)this;
615     if ( pFtn->GetFollow() )
616         pFtn->GetFollow()->SetMaster( pFtn->GetMaster() );
617     if ( pFtn->GetMaster() )
618         pFtn->GetMaster()->SetFollow( pFtn->GetFollow() );
619     pFtn->SetFollow( 0 );
620     pFtn->SetMaster( 0 );
621 
622     // Alle Verbindungen kappen.
623     Remove();
624 
625     if ( pUp )
626     {
627         //Die letzte Fussnote nimmt ihren Container mit.
628         if ( !pUp->Lower() )
629         {
630             SwPageFrm *pPage = pUp->FindPageFrm();
631             if ( pPage )
632             {
633                 SwLayoutFrm *pBody = pPage->FindBodyCont();
634                 if( pBody && !pBody->ContainsCntnt() )
635                     pPage->getRootFrm()->SetSuperfluous();
636             }
637             SwSectionFrm* pSect = pUp->FindSctFrm();
638             pUp->Cut();
639             delete pUp;
640             // Wenn der letzte Fussnotencontainer aus einem spaltigen Bereich verschwindet,
641             // so kann dieser, falls er keinen Follow besitzt, zusammenschrumpfen.
642             if( pSect && !pSect->ToMaximize( sal_False ) && !pSect->IsColLocked() )
643                 pSect->_InvalidateSize();
644         }
645         else
646         {   if ( Frm().Height() )
647                 pUp->Shrink( Frm().Height() );
648             pUp->SetCompletePaint();
649             pUp->InvalidatePage();
650         }
651     }
652 }
653 
654 /*************************************************************************
655 |*
656 |*  SwFtnFrm::Paste()
657 |*
658 |*************************************************************************/
659 
660 
661 void SwFtnFrm::Paste(  SwFrm* pParent, SwFrm* pSibling )
662 {
663     ASSERT( pParent, "Kein Parent fuer Paste." );
664     ASSERT( pParent->IsLayoutFrm(), "Parent ist CntntFrm." );
665     ASSERT( pParent != this, "Bin selbst der Parent." );
666     ASSERT( pSibling != this, "Bin mein eigener Nachbar." );
667     ASSERT( !GetPrev() && !GetNext() && !GetUpper(),
668             "Bin noch irgendwo angemeldet." );
669 
670     //In den Baum einhaengen.
671     InsertBefore( (SwLayoutFrm*)pParent, pSibling );
672 
673     SWRECTFN( this )
674     if( (Frm().*fnRect->fnGetWidth)()!=(pParent->Prt().*fnRect->fnGetWidth)() )
675         _InvalidateSize();
676     _InvalidatePos();
677     SwPageFrm *pPage = FindPageFrm();
678     InvalidatePage( pPage );
679     if ( GetNext() )
680         GetNext()->_InvalidatePos();
681     if( (Frm().*fnRect->fnGetHeight)() )
682         pParent->Grow( (Frm().*fnRect->fnGetHeight)() );
683 
684     //Wenn mein Vorgaenger mein Master ist und/oder wenn mein Nachfolger mein
685     //Follow ist so kann ich deren Inhalt uebernehmen und sie vernichten.
686     if ( GetPrev() && GetPrev() == GetMaster() )
687     {   ASSERT( SwFlowFrm::CastFlowFrm( GetPrev()->GetLower() ),
688                 "Fussnote ohne Inhalt?" );
689         (SwFlowFrm::CastFlowFrm( GetPrev()->GetLower()))->
690             MoveSubTree( this, GetLower() );
691         SwFrm *pDel = GetPrev();
692         pDel->Cut();
693         delete pDel;
694     }
695     if ( GetNext() && GetNext() == GetFollow() )
696     {   ASSERT( SwFlowFrm::CastFlowFrm( GetNext()->GetLower() ),
697                 "Fussnote ohne Inhalt?" );
698         (SwFlowFrm::CastFlowFrm( GetNext()->GetLower()))->MoveSubTree( this );
699         SwFrm *pDel = GetNext();
700         pDel->Cut();
701         delete pDel;
702     }
703 #ifdef DBG_UTIL
704     SwDoc *pDoc = GetFmt()->GetDoc();
705     if ( GetPrev() )
706     {
707         ASSERT( lcl_FindFtnPos( pDoc, ((SwFtnFrm*)GetPrev())->GetAttr() ) <=
708                 lcl_FindFtnPos( pDoc, GetAttr() ), "Prev ist not FtnPrev" );
709     }
710     if ( GetNext() )
711     {
712         ASSERT( lcl_FindFtnPos( pDoc, GetAttr() ) <=
713                 lcl_FindFtnPos( pDoc, ((SwFtnFrm*)GetNext())->GetAttr() ),
714                 "Next is not FtnNext" );
715     }
716 #endif
717     InvalidateNxtFtnCnts( pPage );
718 }
719 
720 /*************************************************************************
721 |*
722 |*  SwFrm::GetNextFtnLeaf()
723 |*
724 |*  Beschreibung        Liefert das naechste LayoutBlatt in den das
725 |*      Frame gemoved werden kann.
726 |*      Neue Seiten werden nur dann erzeugt, wenn der Parameter sal_True ist.
727 |*
728 |*************************************************************************/
729 
730 
731 SwLayoutFrm *SwFrm::GetNextFtnLeaf( MakePageType eMakePage )
732 {
733     SwFtnBossFrm *pOldBoss = FindFtnBossFrm();
734     SwPageFrm* pOldPage = pOldBoss->FindPageFrm();
735     SwPageFrm* pPage;
736     SwFtnBossFrm *pBoss = pOldBoss->IsColumnFrm() ?
737         (SwFtnBossFrm*)pOldBoss->GetNext() : 0; // naechste Spalte, wenn vorhanden
738     if( pBoss )
739         pPage = NULL;
740     else
741     {
742         if( pOldBoss->GetUpper()->IsSctFrm() )
743         {   // Das kann nur in einem spaltigen Bereich sein
744             SwLayoutFrm* pNxt = pOldBoss->GetNextSctLeaf( eMakePage );
745             if( pNxt )
746             {
747                 ASSERT( pNxt->IsColBodyFrm(), "GetNextFtnLeaf: Funny Leaf" );
748                 pBoss = (SwFtnBossFrm*)pNxt->GetUpper();
749                 pPage = pBoss->FindPageFrm();
750             }
751             else
752                 return 0;
753         }
754         else
755         {
756             // naechste Seite
757             pPage = (SwPageFrm*)pOldPage->GetNext();
758             // Leerseiten ueberspringen
759             if( pPage && pPage->IsEmptyPage() )
760                 pPage = (SwPageFrm*)pPage->GetNext();
761             pBoss = pPage;
762         }
763     }
764     // Was haben wir jetzt?
765     // pBoss != NULL, pPage==NULL => pBoss ist die auf der gleichen Seite folgende Spalte
766     // pBoss != NULL, pPage!=NULL => pBoss und pPage sind die folgende Seite (Empty uebersprungen)
767     // pBoss == NULL => pPage == NULL, es gibt keine folgende Seite
768 
769     //Wenn die Fussnote bereits einen Follow hat brauchen wir nicht zu suchen.
770     //Wenn allerdings zwischen Ftn und Follow unerwuenschte Leerseiten/spalten
771     //herumlungern, so legen wir auf der naechstbesten Seite/Spalte einen weiteren
772     //Follow an, der Rest wird sich schon finden.
773     SwFtnFrm *pFtn = FindFtnFrm();
774     if ( pFtn && pFtn->GetFollow() )
775     {
776         SwFtnBossFrm* pTmpBoss = pFtn->GetFollow()->FindFtnBossFrm();
777         // Folgende Faelle werden hier erkannt und akzeptiert
778         // 1. Die FtnBosse sind benachbarte Seiten oder benachbarte Spalten
779         // 2. Der neue ist die erste Spalte der benachbarten Seite
780         // 3. Der neue ist die erste Spalte in einem Bereich in der naechsten Spalte/Seite
781         while( pTmpBoss != pBoss && pTmpBoss && !pTmpBoss->GetPrev() )
782             pTmpBoss = pTmpBoss->GetUpper()->FindFtnBossFrm();
783         if( pTmpBoss == pBoss )
784             return pFtn->GetFollow();
785     }
786 
787     // Wenn wir keinen pBoss gefunden haben oder es sich um eine "falsche" Seite handelt,
788     // muss eine neue Seite her
789     if ( !pBoss || ( pPage && pPage->IsEndNotePage() && !pOldPage->IsEndNotePage() ) )
790     {
791         if ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT )
792         {
793             pBoss = InsertPage( pOldPage, pOldPage->IsFtnPage() );
794             ((SwPageFrm*)pBoss)->SetEndNotePage( pOldPage->IsEndNotePage() );
795         }
796         else
797             return 0;
798     }
799     if( pBoss->IsPageFrm() )
800     {   // Wenn wir auf einer spaltigen Seite gelandet sind,
801         // gehen wir in die erste Spalte
802         SwLayoutFrm* pLay = pBoss->FindBodyCont();
803         if( pLay && pLay->Lower() && pLay->Lower()->IsColumnFrm() )
804             pBoss = (SwFtnBossFrm*)pLay->Lower();
805     }
806     //Seite/Spalte gefunden, da schummeln wir uns doch gleich mal 'rein
807     SwFtnContFrm *pCont = pBoss->FindFtnCont();
808     if ( !pCont && pBoss->GetMaxFtnHeight() &&
809          ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) )
810         pCont = pBoss->MakeFtnCont();
811     return pCont;
812 }
813 
814 /*************************************************************************
815 |*
816 |*  SwFrm::GetPrevFtnLeaf()
817 |*
818 |*  Beschreibung        Liefert das vorhergehende LayoutBlatt in das der
819 |*      Frame gemoved werden kann.
820 |*
821 |*************************************************************************/
822 
823 
824 SwLayoutFrm *SwFrm::GetPrevFtnLeaf( MakePageType eMakeFtn )
825 {
826     //Der Vorgaenger fuer eine Fussnote ist falls moeglich der Master
827     //in der Fussnoteneigenen Verkettung.
828     SwLayoutFrm *pRet = 0;
829     SwFtnFrm *pFtn = FindFtnFrm();
830     pRet = pFtn->GetMaster();
831 
832     SwFtnBossFrm* pOldBoss = FindFtnBossFrm();
833     SwPageFrm *pOldPage = pOldBoss->FindPageFrm();
834 
835     if ( !pOldBoss->GetPrev() && !pOldPage->GetPrev() )
836         return pRet; // es gibt weder eine Spalte noch eine Seite vor uns
837 
838     if ( !pRet )
839     {
840         bool bEndn = pFtn->GetAttr()->GetFtn().IsEndNote();
841         SwFrm* pTmpRef = NULL;
842         if( bEndn && pFtn->IsInSct() )
843         {
844             SwSectionFrm* pSect = pFtn->FindSctFrm();
845             if( pSect->IsEndnAtEnd() )
846                 pTmpRef = pSect->FindLastCntnt( FINDMODE_LASTCNT );
847         }
848         if( !pTmpRef )
849             pTmpRef = pFtn->GetRef();
850         SwFtnBossFrm* pStop = pTmpRef->FindFtnBossFrm( !bEndn );
851 
852         const sal_uInt16 nNum = pStop->GetPhyPageNum();
853 
854         //Wenn die Fussnoten am Dokumentende angezeigt werden, so verlassen wir
855         //die Entsprechenden Seiten nicht.
856         //Selbiges gilt analog fuer die Endnotenseiten.
857         const sal_Bool bEndNote = pOldPage->IsEndNotePage();
858         const sal_Bool bFtnEndDoc = pOldPage->IsFtnPage();
859         SwFtnBossFrm* pNxtBoss = pOldBoss;
860         SwSectionFrm *pSect = pNxtBoss->GetUpper()->IsSctFrm() ?
861                               (SwSectionFrm*)pNxtBoss->GetUpper() : 0;
862 
863         do
864         {
865             if( pNxtBoss->IsColumnFrm() && pNxtBoss->GetPrev() )
866                 pNxtBoss = (SwFtnBossFrm*)pNxtBoss->GetPrev();  // eine Spalte zurueck
867             else                                // oder eine Seite zurueck
868             {
869                 SwLayoutFrm* pBody = 0;
870                 if( pSect )
871                 {
872                     if( pSect->IsFtnLock() )
873                     {
874                         if( pNxtBoss == pOldBoss )
875                             return 0;
876                         pStop = pNxtBoss;
877                     }
878                     else
879                     {
880                         pSect = (SwSectionFrm*)pSect->FindMaster();
881                         if( !pSect || !pSect->Lower() )
882                             return 0;
883                         ASSERT( pSect->Lower()->IsColumnFrm(),
884                                 "GetPrevFtnLeaf: Where's the column?" );
885                         pNxtBoss = (SwFtnBossFrm*)pSect->Lower();
886                         pBody = pSect;
887                     }
888                 }
889                 else
890                 {
891                     SwPageFrm* pPage = (SwPageFrm*)pNxtBoss->FindPageFrm()->GetPrev();
892                     if( !pPage || pPage->GetPhyPageNum() < nNum ||
893                         bEndNote != pPage->IsEndNotePage() || bFtnEndDoc != pPage->IsFtnPage() )
894                         return NULL; // Keine in Frage kommende Seite mehr gefunden
895                     pNxtBoss = pPage;
896                     pBody = pPage->FindBodyCont();
897                 }
898                 // Die vorherige Seite haben wir nun, ggf. sollten wir in die letzte Spalte
899                 // der Seite wechseln
900                 if( pBody )
901                 {
902                     if ( pBody->Lower() && pBody->Lower()->IsColumnFrm() )
903                     {
904                         pNxtBoss = static_cast<SwFtnBossFrm*>(pBody->GetLastLower());
905                     }
906                 }
907             }
908             SwFtnContFrm *pCont = pNxtBoss->FindFtnCont();
909             if ( pCont )
910             {
911                 pRet = pCont;
912                 break;
913             }
914             if ( pStop == pNxtBoss )
915             {   //Die Seite/Spalte auf der sich auch die Referenz tummelt, ist erreicht.
916                 //Wir koennen jetzt probehalber mal einen Container erzeugen und
917                 //uns hineinpasten.
918                 if ( eMakeFtn == MAKEPAGE_FTN && pNxtBoss->GetMaxFtnHeight() )
919                     pRet = pNxtBoss->MakeFtnCont();
920                 break;
921             }
922         } while( !pRet );
923     }
924     if ( pRet )
925     {
926         const SwFtnBossFrm* pNewBoss = pRet->FindFtnBossFrm();
927         sal_Bool bJump = sal_False;
928         if( pOldBoss->IsColumnFrm() && pOldBoss->GetPrev() ) // es gibt eine vorherige Spalte
929             bJump = pOldBoss->GetPrev() != (SwFrm*)pNewBoss;         // sind wir darin gelandet?
930         else if( pNewBoss->IsColumnFrm() && pNewBoss->GetNext() )
931             bJump = sal_True; // es gibt hinter dem neuen Boss noch eine Spalte, die aber nicht
932                           // der alte Boss sein kann, das haben wir ja bereits geprueft.
933         else // hier landen wir nur, wenn neuer und alter Boss entweder Seiten oder letzte (neu)
934         {   // bzw. erste (alt) Spalten einer Seite sind. In diesem Fall muss noch geprueft
935             // werden, ob Seiten ueberspringen wurden.
936             sal_uInt16 nDiff = pOldPage->GetPhyPageNum() - pRet->FindPageFrm()->GetPhyPageNum();
937             if ( nDiff > 2 ||
938                  (nDiff > 1 && !((SwPageFrm*)pOldPage->GetPrev())->IsEmptyPage()) )
939                 bJump = sal_True;
940         }
941         if( bJump )
942             SwFlowFrm::SetMoveBwdJump( sal_True );
943     }
944     return pRet;
945 }
946 
947 /*************************************************************************
948 |*
949 |*  SwFrm::IsFtnAllowed()
950 |*
951 |*************************************************************************/
952 
953 
954 sal_Bool SwFrm::IsFtnAllowed() const
955 {
956     if ( !IsInDocBody() )
957         return sal_False;
958 
959     if ( IsInTab() )
960     {
961         //Keine Ftns in wiederholten Headlines.
962         const SwTabFrm *pTab = ((SwFrm*)this)->ImplFindTabFrm();
963         if ( pTab->IsFollow() )
964             return !pTab->IsInHeadline( *this );
965     }
966     return sal_True;
967 }
968 
969 /*************************************************************************
970 |*
971 |*  SwRootFrm::UpdateFtnNums()
972 |*
973 |*************************************************************************/
974 
975 
976 void SwRootFrm::UpdateFtnNums()
977 {
978     //Seitenweise Numerierung nur wenn es am Dokument so eingestellt ist.
979     if ( GetFmt()->GetDoc()->GetFtnInfo().eNum == FTNNUM_PAGE )
980     {
981         SwPageFrm *pPage = (SwPageFrm*)Lower();
982         while ( pPage && !pPage->IsFtnPage() )
983         {
984             pPage->UpdateFtnNum();
985             pPage = (SwPageFrm*)pPage->GetNext();
986         }
987     }
988 }
989 
990 /*************************************************************************
991 |*
992 |*  RemoveFtns()        Entfernen aller Fussnoten (nicht etwa die Referenzen)
993 |*                      und Entfernen aller Fussnotenseiten.
994 |*
995 |*************************************************************************/
996 
997 void lcl_RemoveFtns( SwFtnBossFrm* pBoss, sal_Bool bPageOnly, sal_Bool bEndNotes )
998 {
999     do
1000     {
1001         SwFtnContFrm *pCont = pBoss->FindFtnCont();
1002         if ( pCont )
1003         {
1004             SwFtnFrm *pFtn = (SwFtnFrm*)pCont->Lower();
1005             ASSERT( pFtn, "FtnCont ohne Ftn." );
1006             if ( bPageOnly )
1007                 while ( pFtn->GetMaster() )
1008                     pFtn = pFtn->GetMaster();
1009             do
1010             {
1011                 SwFtnFrm *pNxt = (SwFtnFrm*)pFtn->GetNext();
1012                 if ( !pFtn->GetAttr()->GetFtn().IsEndNote() ||
1013                         bEndNotes )
1014                 {
1015                     pFtn->GetRef()->Prepare( PREP_FTN, (void*)pFtn->GetAttr() );
1016                     if ( bPageOnly && !pNxt )
1017                         pNxt = pFtn->GetFollow();
1018                     pFtn->Cut();
1019                     delete pFtn;
1020                 }
1021                 pFtn = pNxt;
1022 
1023             } while ( pFtn );
1024         }
1025         if( !pBoss->IsInSct() )
1026         {
1027             // A sectionframe with the Ftn/EndnAtEnd-flags may contain
1028             // foot/endnotes. If the last lower frame of the bodyframe is
1029             // a multicolumned sectionframe, it may contain footnotes, too.
1030             SwLayoutFrm* pBody = pBoss->FindBodyCont();
1031             if( pBody && pBody->Lower() )
1032             {
1033                 SwFrm* pLow = pBody->Lower();
1034                 while( pLow->GetNext() )
1035                 {
1036                     if( pLow->IsSctFrm() && ( !pLow->GetNext() ||
1037                         ((SwSectionFrm*)pLow)->IsAnyNoteAtEnd() ) &&
1038                         ((SwSectionFrm*)pLow)->Lower() &&
1039                         ((SwSectionFrm*)pLow)->Lower()->IsColumnFrm() )
1040                         lcl_RemoveFtns( (SwColumnFrm*)((SwSectionFrm*)pLow)->Lower(),
1041                             bPageOnly, bEndNotes );
1042                     pLow = pLow->GetNext();
1043                 }
1044             }
1045         }
1046         // noch 'ne Spalte?
1047         pBoss = pBoss->IsColumnFrm() ? (SwColumnFrm*)pBoss->GetNext() : NULL;
1048     } while( pBoss );
1049 }
1050 
1051 void SwRootFrm::RemoveFtns( SwPageFrm *pPage, sal_Bool bPageOnly, sal_Bool bEndNotes )
1052 {
1053     if ( !pPage )
1054         pPage = (SwPageFrm*)Lower();
1055 
1056     do
1057     {   // Bei spaltigen Seiten muessen wir in allen Spalten aufraeumen
1058         SwFtnBossFrm* pBoss;
1059         SwLayoutFrm* pBody = pPage->FindBodyCont();
1060         if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() )
1061             pBoss = (SwFtnBossFrm*)pBody->Lower(); // die erste Spalte
1062         else
1063             pBoss = pPage; // keine Spalten
1064         lcl_RemoveFtns( pBoss, bPageOnly, bEndNotes );
1065         if ( !bPageOnly )
1066         {
1067             if ( pPage->IsFtnPage() &&
1068                  (!pPage->IsEndNotePage() || bEndNotes) )
1069             {
1070                 SwFrm *pDel = pPage;
1071                 pPage = (SwPageFrm*)pPage->GetNext();
1072                 pDel->Cut();
1073                 delete pDel;
1074             }
1075             else
1076                 pPage = (SwPageFrm*)pPage->GetNext();
1077         }
1078         else
1079             break;
1080 
1081     } while ( pPage );
1082 }
1083 
1084 /*************************************************************************
1085 |*
1086 |*  SetFtnPageDescs()   Seitenvorlagen der Fussnotenseiten aendern
1087 |*
1088 |*************************************************************************/
1089 
1090 void SwRootFrm::CheckFtnPageDescs( sal_Bool bEndNote )
1091 {
1092     SwPageFrm *pPage = (SwPageFrm*)Lower();
1093     while ( pPage && !pPage->IsFtnPage() )
1094         pPage = (SwPageFrm*)pPage->GetNext();
1095     while ( pPage && pPage->IsEndNotePage() != bEndNote )
1096         pPage = (SwPageFrm*)pPage->GetNext();
1097     if ( pPage )
1098         SwFrm::CheckPageDescs( pPage, sal_False );
1099 }
1100 
1101 
1102 /*************************************************************************
1103 |*
1104 |*  SwFtnBossFrm::MakeFtnCont()
1105 |*
1106 |*************************************************************************/
1107 
1108 
1109 SwFtnContFrm *SwFtnBossFrm::MakeFtnCont()
1110 {
1111     //Einfuegen eines Fussnotencontainers. Der Fussnotencontainer sitzt
1112     //immer direkt hinter dem Bodytext.
1113     //Sein FrmFmt ist immer das DefaultFrmFmt.
1114 
1115 #ifdef DBG_UTIL
1116     if ( FindFtnCont() )
1117     {   ASSERT( !this, "Fussnotencontainer bereits vorhanden." );
1118         return 0;
1119     }
1120 #endif
1121 
1122     SwFtnContFrm *pNew = new SwFtnContFrm( GetFmt()->GetDoc()->GetDfltFrmFmt(), this );
1123     SwLayoutFrm *pLay = FindBodyCont();
1124     pNew->Paste( this, pLay->GetNext() );
1125     return pNew;
1126 }
1127 
1128 /*************************************************************************
1129 |*
1130 |*  SwFtnBossFrm::FindFtnCont()
1131 |*
1132 |*************************************************************************/
1133 
1134 
1135 SwFtnContFrm *SwFtnBossFrm::FindFtnCont()
1136 {
1137     SwFrm *pFrm = Lower();
1138     while( pFrm && !pFrm->IsFtnContFrm() )
1139         pFrm = pFrm->GetNext();
1140 
1141 #ifdef DBG_UTIL
1142     if ( pFrm )
1143     {
1144         SwFrm *pFtn = pFrm->GetLower();
1145         ASSERT( pFtn, "Cont ohne Fussnote." );
1146         while ( pFtn )
1147         {
1148             ASSERT( pFtn->IsFtnFrm(), "Nachbar von Fussnote keine Fussnote." );
1149             pFtn = pFtn->GetNext();
1150         }
1151     }
1152 #endif
1153 
1154     return (SwFtnContFrm*)pFrm;
1155 }
1156 
1157 /*************************************************************************
1158 |*
1159 |*  SwFtnBossFrm::FindNearestFtnCont()  Sucht den naechst greifbaren Fussnotencontainer.
1160 |*
1161 |*************************************************************************/
1162 
1163 SwFtnContFrm *SwFtnBossFrm::FindNearestFtnCont( sal_Bool bDontLeave )
1164 {
1165     SwFtnContFrm *pCont = 0;
1166     if ( GetFmt()->GetDoc()->GetFtnIdxs().Count() )
1167     {
1168         pCont = FindFtnCont();
1169         if ( !pCont )
1170         {
1171             SwPageFrm *pPage = FindPageFrm();
1172             SwFtnBossFrm* pBoss = this;
1173             sal_Bool bEndNote = pPage->IsEndNotePage();
1174             do
1175             {
1176                 sal_Bool bChgPage = lcl_NextFtnBoss( pBoss, pPage, bDontLeave );
1177                 // Haben wir noch einen Boss gefunden? Bei einem Seitenwechsel muss
1178                 // zudem noch das EndNotenFlag uebereinstimmen
1179                 if( pBoss && ( !bChgPage || pPage->IsEndNotePage() == bEndNote ) )
1180                     pCont = pBoss->FindFtnCont();
1181             } while ( !pCont && pPage );
1182         }
1183     }
1184     return pCont;
1185 }
1186 
1187 
1188 /*************************************************************************
1189 |*
1190 |*  SwFtnBossFrm::FindFirstFtn()
1191 |*
1192 |*  Beschreibung        Erste Fussnote des Fussnotenbosses suchen.
1193 |*
1194 |*************************************************************************/
1195 
1196 
1197 SwFtnFrm *SwFtnBossFrm::FindFirstFtn()
1198 {
1199     //Erstmal den naechsten FussnotenContainer suchen.
1200     SwFtnContFrm *pCont = FindNearestFtnCont();
1201     if ( !pCont )
1202         return 0;
1203 
1204     //Ab der ersten Fussnote im Container die erste suchen, die
1205     //von der aktuellen Spalte (bzw. einspaltigen Seite) referenziert wird.
1206 
1207     SwFtnFrm *pRet = (SwFtnFrm*)pCont->Lower();
1208     const sal_uInt16 nRefNum = FindPageFrm()->GetPhyPageNum();
1209     const sal_uInt16 nRefCol = lcl_ColumnNum( this );
1210     sal_uInt16 nPgNum, nColNum; //Seitennummer, Spaltennummer
1211     SwFtnBossFrm* pBoss;
1212     SwPageFrm* pPage;
1213     if( pRet )
1214     {
1215         pBoss = pRet->GetRef()->FindFtnBossFrm();
1216         ASSERT( pBoss, "FindFirstFtn: No boss found" );
1217         if( !pBoss )
1218             return sal_False; // ?There must be a bug, but no GPF
1219         pPage = pBoss->FindPageFrm();
1220         nPgNum = pPage->GetPhyPageNum();
1221         if ( nPgNum == nRefNum )
1222         {
1223             nColNum = lcl_ColumnNum( pBoss );
1224             if( nColNum == nRefCol )
1225                 return pRet; //hat ihn.
1226             else if( nColNum > nRefCol )
1227                 return NULL; //mind. eine Spalte zu weit.
1228         }
1229         else if ( nPgNum > nRefNum )
1230             return NULL;    //mind. eine Seite zu weit.
1231     }
1232     else
1233         return NULL;
1234     // Ende, wenn Ref auf einer spaeteren Seite oder auf der gleichen Seite in einer
1235     // spaeteren Spalte liegt
1236 
1237     do
1238     {
1239         while ( pRet->GetFollow() )
1240             pRet = pRet->GetFollow();
1241 
1242         SwFtnFrm *pNxt = (SwFtnFrm*)pRet->GetNext();
1243         if ( !pNxt )
1244         {
1245             pBoss = pRet->FindFtnBossFrm();
1246             pPage = pBoss->FindPageFrm();
1247             lcl_NextFtnBoss( pBoss, pPage, sal_False ); // naechster FtnBoss
1248             pCont = pBoss ? pBoss->FindNearestFtnCont() : 0;
1249             if ( pCont )
1250                 pNxt = (SwFtnFrm*)pCont->Lower();
1251         }
1252         if ( pNxt )
1253         {
1254             pRet = pNxt;
1255             pBoss = pRet->GetRef()->FindFtnBossFrm();
1256             pPage = pBoss->FindPageFrm();
1257             nPgNum = pPage->GetPhyPageNum();
1258             if ( nPgNum == nRefNum )
1259             {
1260                 nColNum = lcl_ColumnNum( pBoss );
1261                 if( nColNum == nRefCol )
1262                     break; //hat ihn.
1263                 else if( nColNum > nRefCol )
1264                     pRet = 0; //mind. eine Spalte zu weit.
1265             }
1266             else if ( nPgNum > nRefNum )
1267                 pRet = 0;   //mind. eine Seite zu weit.
1268         }
1269         else
1270             pRet = 0;   //Gibt eben keinen.
1271     } while( pRet );
1272     return pRet;
1273 }
1274 
1275 /*************************************************************************
1276 |*
1277 |*  SwFtnBossFrm::FindFirstFtn()
1278 |*
1279 |*  Beschreibunt        Erste Fussnote zum Cnt suchen.
1280 |*
1281 |*************************************************************************/
1282 
1283 
1284 const SwFtnFrm *SwFtnBossFrm::FindFirstFtn( SwCntntFrm *pCnt ) const
1285 {
1286     const SwFtnFrm *pRet = ((SwFtnBossFrm*)this)->FindFirstFtn();
1287     if ( pRet )
1288     {
1289         const sal_uInt16 nColNum = lcl_ColumnNum( this ); //Spaltennummer
1290         const sal_uInt16 nPageNum = GetPhyPageNum();
1291         while ( pRet && (pRet->GetRef() != pCnt) )
1292         {
1293             while ( pRet->GetFollow() )
1294                 pRet = pRet->GetFollow();
1295 
1296             if ( pRet->GetNext() )
1297                 pRet = (const SwFtnFrm*)pRet->GetNext();
1298             else
1299             {   SwFtnBossFrm *pBoss = (SwFtnBossFrm*)pRet->FindFtnBossFrm();
1300                 SwPageFrm *pPage = pBoss->FindPageFrm();
1301                 lcl_NextFtnBoss( pBoss, pPage, sal_False ); // naechster FtnBoss
1302                 SwFtnContFrm *pCont = pBoss ? pBoss->FindNearestFtnCont() : 0;
1303                 pRet = pCont ? (SwFtnFrm*)pCont->Lower() : 0;
1304             }
1305             if ( pRet )
1306             {
1307                 const SwFtnBossFrm* pBoss = pRet->GetRef()->FindFtnBossFrm();
1308                 if( pBoss->GetPhyPageNum() != nPageNum ||
1309                     nColNum != lcl_ColumnNum( pBoss ) )
1310                 pRet = 0;
1311             }
1312         }
1313     }
1314     return pRet;
1315 }
1316 
1317 /*************************************************************************
1318 |*
1319 |*  SwFtnBossFrm::ResetFtn()
1320 |*
1321 |*************************************************************************/
1322 
1323 
1324 void SwFtnBossFrm::ResetFtn( const SwFtnFrm *pCheck )
1325 {
1326     //Vernichten der Inkarnationen von Fussnoten zum Attribut, wenn sie nicht
1327     //zu pAssumed gehoeren.
1328     ASSERT( !pCheck->GetMaster(), "Master not an Master." );
1329 
1330     SwNodeIndex aIdx( *pCheck->GetAttr()->GetStartNode(), 1 );
1331     SwCntntNode *pNd = aIdx.GetNode().GetCntntNode();
1332     if ( !pNd )
1333         pNd = pCheck->GetFmt()->GetDoc()->
1334               GetNodes().GoNextSection( &aIdx, sal_True, sal_False );
1335     SwIterator<SwFrm,SwCntntNode> aIter( *pNd );
1336     SwFrm* pFrm = aIter.First();
1337     while( pFrm )
1338     {
1339             if( pFrm->getRootFrm() == pCheck->getRootFrm() )
1340             {
1341             SwFrm *pTmp = pFrm->GetUpper();
1342             while ( pTmp && !pTmp->IsFtnFrm() )
1343                 pTmp = pTmp->GetUpper();
1344 
1345             SwFtnFrm *pFtn = (SwFtnFrm*)pTmp;
1346             while ( pFtn && pFtn->GetMaster() )
1347                 pFtn = pFtn->GetMaster();
1348             if ( pFtn != pCheck )
1349             {
1350                 while ( pFtn )
1351                 {
1352                     SwFtnFrm *pNxt = pFtn->GetFollow();
1353                     pFtn->Cut();
1354                     delete pFtn;
1355                     pFtn = pNxt;
1356                 }
1357             }
1358         }
1359 
1360         pFrm = aIter.Next();
1361     }
1362 }
1363 
1364 /*************************************************************************
1365 |*
1366 |*  SwFtnBossFrm::InsertFtn()
1367 |*
1368 |*************************************************************************/
1369 
1370 
1371 void SwFtnBossFrm::InsertFtn( SwFtnFrm* pNew )
1372 {
1373 #if (OSL_DEBUG_LEVEL > 1) && defined(DBG_UTIL)
1374     static sal_uInt16 nStop = 0;
1375     if ( nStop == pNew->GetFrmId() )
1376     {
1377         int bla = 5;
1378         (void)bla;
1379     }
1380 #endif
1381     //Die Fussnote haben wir, sie muss jetzt nur noch irgendwo
1382     //hin und zwar vor die Fussnote, deren Attribut vor das
1383     //der neuen zeigt (Position wird ueber das Doc ermittelt)
1384     //Gibt es in diesem Fussnotenboss noch keine Fussnoten, so muss eben ein
1385     //Container erzeugt werden.
1386     //Gibt es bereits einen Container aber noch keine Fussnote zu diesem
1387     //Fussnotenboss, so muss die Fussnote hinter die letzte Fussnote der dichtesten
1388     //Vorseite/spalte.
1389 
1390     ResetFtn( pNew );
1391     SwFtnFrm *pSibling = FindFirstFtn();
1392     sal_Bool bDontLeave = sal_False;
1393 
1394     // Ok, a sibling has been found, but is the sibling in an acceptable
1395     // environment?
1396     if( IsInSct() )
1397     {
1398         SwSectionFrm* pMySect = ImplFindSctFrm();
1399         bool bEndnt = pNew->GetAttr()->GetFtn().IsEndNote();
1400         if( bEndnt )
1401         {
1402             const SwSectionFmt* pEndFmt = pMySect->GetEndSectFmt();
1403             bDontLeave = 0 != pEndFmt;
1404             if( pSibling )
1405             {
1406                 if( pEndFmt )
1407                 {
1408                     if( !pSibling->IsInSct() ||
1409                         !pSibling->ImplFindSctFrm()->IsDescendantFrom( pEndFmt ) )
1410                         pSibling = NULL;
1411                 }
1412                 else if( pSibling->IsInSct() )
1413                     pSibling = NULL;
1414             }
1415         }
1416         else
1417         {
1418             bDontLeave = pMySect->IsFtnAtEnd();
1419             if( pSibling )
1420             {
1421                 if( pMySect->IsFtnAtEnd() )
1422                 {
1423                     if( !pSibling->IsInSct() ||
1424                         !pMySect->IsAnFollow( pSibling->ImplFindSctFrm() ) )
1425                         pSibling = NULL;
1426                 }
1427                 else if( pSibling->IsInSct() )
1428                     pSibling = NULL;
1429             }
1430         }
1431     }
1432 
1433     if( pSibling && pSibling->FindPageFrm()->IsEndNotePage() !=
1434         FindPageFrm()->IsEndNotePage() )
1435         pSibling = NULL;
1436 
1437     //Damit die Position herausgefunden werden kann.
1438     SwDoc *pDoc = GetFmt()->GetDoc();
1439     const sal_uLong nStPos = ::lcl_FindFtnPos( pDoc, pNew->GetAttr() );
1440 
1441     sal_uLong nCmpPos = 0;
1442     sal_uLong nLastPos = 0;
1443     SwFtnContFrm *pParent = 0;
1444     if( pSibling )
1445     {
1446         nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() );
1447         if( nCmpPos > nStPos )
1448             pSibling = NULL;
1449     }
1450 
1451     if ( !pSibling )
1452     {   pParent = FindFtnCont();
1453         if ( !pParent )
1454         {
1455             //Es gibt noch keinen FussnotenContainer, also machen wir einen.
1456             //HAAAAAAAALT! So einfach ist das leider mal wieder nicht: Es kann
1457             //sein, dass irgendeine naechste Fussnote existiert die vor der
1458             //einzufuegenden zu stehen hat, weil z.B. eine Fussnote ueber zig
1459             //Seiten aufgespalten ist usw.
1460             pParent = FindNearestFtnCont( bDontLeave );
1461             if ( pParent )
1462             {
1463                 SwFtnFrm *pFtn = (SwFtnFrm*)pParent->Lower();
1464                 if ( pFtn )
1465                 {
1466 
1467                     nCmpPos = ::lcl_FindFtnPos( pDoc, pFtn->GetAttr() );
1468                     if ( nCmpPos > nStPos )
1469                         pParent = 0;
1470                 }
1471                 else
1472                     pParent = 0;
1473             }
1474         }
1475         if ( !pParent )
1476             //Jetzt kann aber ein Fussnotencontainer gebaut werden.
1477             pParent = MakeFtnCont();
1478         else
1479         {
1480             //Ausgehend von der ersten Fussnote unterhalb des Parents wird die
1481             //erste Fussnote gesucht deren Index hinter dem Index der
1482             //einzufuegenden liegt; vor dieser kann der neue dann gepastet
1483             //werden.
1484             pSibling = (SwFtnFrm*)pParent->Lower();
1485             if ( !pSibling )
1486             {   ASSERT( !this, "Keinen Platz fuer Fussnote gefunden.");
1487                 return;
1488             }
1489             nCmpPos  = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() );
1490 
1491             SwFtnBossFrm *pNxtB = this; //Immer den letzten merken, damit wir nicht
1492             SwFtnFrm  *pLastSib = 0;    //ueber das Ziel hinausschiessen.
1493 
1494             while ( pSibling && nCmpPos <= nStPos )
1495             {
1496                 pLastSib = pSibling; // der kommt schon mal in Frage
1497                 nLastPos = nCmpPos;
1498 
1499                 while ( pSibling->GetFollow() )
1500                     pSibling = pSibling->GetFollow();
1501 
1502                 if ( pSibling->GetNext() )
1503                 {
1504                     pSibling = (SwFtnFrm*)pSibling->GetNext();
1505                     ASSERT( !pSibling->GetMaster() || ( ENDNOTE > nStPos &&
1506                             pSibling->GetAttr()->GetFtn().IsEndNote() ),
1507                             "InsertFtn: Master expected I" );
1508                 }
1509                 else
1510                 {
1511                     pNxtB = pSibling->FindFtnBossFrm();
1512                     SwPageFrm *pSibPage = pNxtB->FindPageFrm();
1513                     sal_Bool bEndNote = pSibPage->IsEndNotePage();
1514                     sal_Bool bChgPage = lcl_NextFtnBoss( pNxtB, pSibPage, bDontLeave );
1515                     // Bei Seitenwechsel muss das EndNoteFlag ueberprueft werden.
1516                     SwFtnContFrm *pCont = pNxtB && ( !bChgPage ||
1517                         pSibPage->IsEndNotePage() == bEndNote )
1518                         ? pNxtB->FindNearestFtnCont( bDontLeave ) : 0;
1519                     if( pCont )
1520                         pSibling = (SwFtnFrm*)pCont->Lower();
1521                     else // kein weiterer FtnContainer, dann werden  wir uns wohl hinter
1522                         break; // pSibling haengen
1523                 }
1524                 if ( pSibling )
1525                 {
1526                     nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() );
1527                     ASSERT( nCmpPos > nLastPos, "InsertFtn: Order of FtnFrm's buggy" );
1528                 }
1529             }
1530             // pLastSib ist jetzt die letzte Fussnote vor uns,
1531             // pSibling leer oder die erste nach uns.
1532             if ( pSibling && pLastSib && (pSibling != pLastSib) )
1533             {   //Sind wir vielleicht bereits ueber das Ziel hinausgeschossen?
1534                 if ( nCmpPos > nStPos )
1535                     pSibling = pLastSib;
1536             }
1537             else if ( !pSibling )
1538             {   //Eine Chance haben wir noch: wir nehmen einfach die letzte
1539                 //Fussnote im Parent. Ein Sonderfall, der z.B. beim
1540                 //zurueckfliessen von Absaetzen mit mehreren Fussnoten
1541                 //vorkommt.
1542                 //Damit wir nicht die Reihenfolge verwuerfeln muessen wir den
1543                 //Parent der letzten Fussnote, die wir an der Hand hatten benutzen.
1544                 pSibling = pLastSib;
1545                 while( pSibling->GetFollow() )
1546                     pSibling = pSibling->GetFollow();
1547                 ASSERT( !pSibling->GetNext(), "InsertFtn: Who's that guy?" );
1548             }
1549         }
1550     }
1551     else
1552     {   //Die erste Fussnote der Spalte/Seite haben wir an der Hand, jetzt ausgehend
1553         //von dieser die erste zur selben Spalte/Seite suchen deren Index hinter
1554         //den uebergebenen zeigt, die letzte, die wir an der Hand hatten, ist
1555         //dann der Vorgaenger.
1556         SwFtnBossFrm* pBoss = pNew->GetRef()->FindFtnBossFrm(
1557             !pNew->GetAttr()->GetFtn().IsEndNote() );
1558         sal_uInt16 nRefNum = pBoss->GetPhyPageNum();    // Die Seiten- und
1559         sal_uInt16 nRefCol = lcl_ColumnNum( pBoss );    // Spaltennummer der neuen Fussnote
1560         sal_Bool bEnd = sal_False;
1561         SwFtnFrm *pLastSib = 0;
1562         while ( pSibling && !bEnd && (nCmpPos <= nStPos) )
1563         {
1564             pLastSib = pSibling;
1565             nLastPos = nCmpPos;
1566 
1567             while ( pSibling->GetFollow() )
1568                 pSibling = pSibling->GetFollow();
1569 
1570             SwFtnFrm *pFoll = (SwFtnFrm*)pSibling->GetNext();
1571             if ( pFoll )
1572             {
1573                 pBoss = pSibling->GetRef()->FindFtnBossFrm( !pSibling->
1574                                             GetAttr()->GetFtn().IsEndNote() );
1575                 sal_uInt16 nTmpRef;
1576                 if( nStPos >= ENDNOTE ||
1577                     (nTmpRef = pBoss->GetPhyPageNum()) < nRefNum ||
1578                     ( nTmpRef == nRefNum && lcl_ColumnNum( pBoss ) <= nRefCol ))
1579                     pSibling = pFoll;
1580                 else
1581                     bEnd = sal_True;
1582             }
1583             else
1584             {
1585                 SwFtnBossFrm* pNxtB = pSibling->FindFtnBossFrm();
1586                 SwPageFrm *pSibPage = pNxtB->FindPageFrm();
1587                 sal_Bool bEndNote = pSibPage->IsEndNotePage();
1588                 sal_Bool bChgPage = lcl_NextFtnBoss( pNxtB, pSibPage, bDontLeave );
1589                 // Bei Seitenwechsel muss das EndNoteFlag ueberprueft werden.
1590                 SwFtnContFrm *pCont = pNxtB && ( !bChgPage ||
1591                     pSibPage->IsEndNotePage() == bEndNote )
1592                     ? pNxtB->FindNearestFtnCont( bDontLeave ) : 0;
1593                 if ( pCont )
1594                     pSibling = (SwFtnFrm*)pCont->Lower();
1595                 else
1596                     bEnd = sal_True;
1597             }
1598             if ( !bEnd && pSibling )
1599                 nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() );
1600             if ( pSibling && pLastSib && (pSibling != pLastSib) )
1601             {   //Sind wir vielleicht bereits ueber das Ziel hinausgeschossen?
1602                 if ( (nLastPos < nCmpPos) && (nCmpPos > nStPos) )
1603                 {
1604                     pSibling = pLastSib;
1605                     bEnd = sal_True;
1606                 }
1607             }
1608         }
1609     }
1610     if ( pSibling )
1611     {
1612         nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() );
1613         if ( nCmpPos < nStPos )
1614         {
1615             while ( pSibling->GetFollow() )
1616                 pSibling = pSibling->GetFollow();
1617             pParent = (SwFtnContFrm*)pSibling->GetUpper();
1618             pSibling = (SwFtnFrm*)pSibling->GetNext();
1619         }
1620         else
1621         {
1622             if( pSibling->GetMaster() )
1623             {
1624                 if( ENDNOTE > nCmpPos || nStPos >= ENDNOTE )
1625                 {
1626                     ASSERT( sal_False, "InsertFtn: Master expected II" );
1627                     do
1628                         pSibling = pSibling->GetMaster();
1629                     while ( pSibling->GetMaster() );
1630                 }
1631             }
1632             pParent = (SwFtnContFrm*)pSibling->GetUpper();
1633         }
1634     }
1635     ASSERT( pParent, "paste in space?" );
1636     pNew->Paste( pParent, pSibling );
1637 }
1638 
1639 /*************************************************************************
1640 |*
1641 |*  SwFtnBossFrm::AppendFtn()
1642 |*
1643 |*************************************************************************/
1644 
1645 
1646 void SwFtnBossFrm::AppendFtn( SwCntntFrm *pRef, SwTxtFtn *pAttr )
1647 {
1648     //Wenn es die Fussnote schon gibt tun wir nix.
1649     if ( FindFtn( pRef, pAttr ) )
1650         return;
1651 
1652     //Wenn Fussnoten am Dokumentende eingestellt sind, so brauchen wir 'eh erst
1653     //ab der entsprechenden Seite zu suchen.
1654     //Wenn es noch keine gibt, muss eben eine erzeugt werden.
1655     //Wenn es sich um eine Endnote handelt, muss eine Endnotenseite gesucht
1656     //bzw. erzeugt werden.
1657     SwDoc *pDoc = GetFmt()->GetDoc();
1658     SwFtnBossFrm *pBoss = this;
1659     SwPageFrm *pPage = FindPageFrm();
1660     SwPageFrm *pMyPage = pPage;
1661     sal_Bool bChgPage = sal_False;
1662     sal_Bool bEnd = sal_False;
1663     if ( pAttr->GetFtn().IsEndNote() )
1664     {
1665         bEnd = sal_True;
1666         if( GetUpper()->IsSctFrm() &&
1667             ((SwSectionFrm*)GetUpper())->IsEndnAtEnd() )
1668         {
1669             SwFrm* pLast =
1670                 ((SwSectionFrm*)GetUpper())->FindLastCntnt( FINDMODE_ENDNOTE );
1671             if( pLast )
1672             {
1673                 pBoss = pLast->FindFtnBossFrm();
1674                 pPage = pBoss->FindPageFrm();
1675             }
1676         }
1677         else
1678         {
1679             while ( pPage->GetNext() && !pPage->IsEndNotePage() )
1680             {
1681                 pPage = (SwPageFrm*)pPage->GetNext();
1682                 bChgPage = sal_True;
1683             }
1684             if ( !pPage->IsEndNotePage() )
1685             {
1686                 SwPageDesc *pDesc = pDoc->GetEndNoteInfo().GetPageDesc( *pDoc );
1687                 pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
1688                         !pPage->OnRightPage(), sal_False, sal_True, 0 );
1689                 pPage->SetEndNotePage( sal_True );
1690                 bChgPage = sal_True;
1691             }
1692             else
1693             {
1694                 //Wir koennen wenigstens schon mal ungefaehr die richtige Seite
1695                 //suchen. Damit stellen wir sicher das wir auch bei hunderten
1696                 //Fussnoten noch in endlicher Zeit fertig werden.
1697                 SwPageFrm *pNxt = (SwPageFrm*)pPage->GetNext();
1698                 const sal_uLong nStPos = ::lcl_FindFtnPos( pDoc, pAttr );
1699                 while ( pNxt && pNxt->IsEndNotePage() )
1700                 {
1701                     SwFtnContFrm *pCont = pNxt->FindFtnCont();
1702                     if ( pCont && pCont->Lower() )
1703                     {
1704                         ASSERT( pCont->Lower()->IsFtnFrm(), "Keine Ftn im Container" );
1705                         if ( nStPos > ::lcl_FindFtnPos( pDoc,
1706                                         ((SwFtnFrm*)pCont->Lower())->GetAttr()))
1707                         {
1708                             pPage = pNxt;
1709                             pNxt = (SwPageFrm*)pPage->GetNext();
1710                             continue;
1711                         }
1712                     }
1713                     break;
1714                 }
1715             }
1716         }
1717     }
1718     else if( FTNPOS_CHAPTER == pDoc->GetFtnInfo().ePos && ( !GetUpper()->
1719              IsSctFrm() || !((SwSectionFrm*)GetUpper())->IsFtnAtEnd() ) )
1720     {
1721         while ( pPage->GetNext() && !pPage->IsFtnPage() &&
1722                 !((SwPageFrm*)pPage->GetNext())->IsEndNotePage() )
1723         {
1724             pPage = (SwPageFrm*)pPage->GetNext();
1725             bChgPage = sal_True;
1726         }
1727 
1728         if ( !pPage->IsFtnPage() )
1729         {
1730             SwPageDesc *pDesc = pDoc->GetFtnInfo().GetPageDesc( *pDoc );
1731             pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
1732                 !pPage->OnRightPage(), sal_False, sal_True, pPage->GetNext() );
1733             bChgPage = sal_True;
1734         }
1735         else
1736         {
1737             //Wir koennen wenigstens schon mal ungefaehr die richtige Seite
1738             //suchen. Damit stellen wir sicher das wir auch bei hunderten
1739             //Fussnoten noch in endlicher Zeit fertig werden.
1740             SwPageFrm *pNxt = (SwPageFrm*)pPage->GetNext();
1741             const sal_uLong nStPos = ::lcl_FindFtnPos( pDoc, pAttr );
1742             while ( pNxt && pNxt->IsFtnPage() && !pNxt->IsEndNotePage() )
1743             {
1744                 SwFtnContFrm *pCont = pNxt->FindFtnCont();
1745                 if ( pCont && pCont->Lower() )
1746                 {
1747                     ASSERT( pCont->Lower()->IsFtnFrm(), "Keine Ftn im Container" );
1748                     if ( nStPos > ::lcl_FindFtnPos( pDoc,
1749                                         ((SwFtnFrm*)pCont->Lower())->GetAttr()))
1750                     {
1751                         pPage = pNxt;
1752                         pNxt = (SwPageFrm*)pPage->GetNext();
1753                         continue;
1754                     }
1755                 }
1756                 break;
1757             }
1758         }
1759     }
1760 
1761     //Erstmal eine Fussnote und die benoetigten CntntFrms anlegen.
1762     if ( !pAttr->GetStartNode() )
1763     {   ASSERT( !this, "Kein Fussnoteninhalt." );
1764         return;
1765     }
1766 
1767     // Wenn es auf der Seite/Spalte bereits einen FtnCont gibt,
1768     // kann in einen spaltigen Bereich keiner erzeugt werden.
1769     if( pBoss->IsInSct() && pBoss->IsColumnFrm() && !pPage->IsFtnPage() )
1770     {
1771         SwSectionFrm* pSct = pBoss->FindSctFrm();
1772         if( bEnd ? !pSct->IsEndnAtEnd() : !pSct->IsFtnAtEnd() )
1773         {
1774             SwFtnContFrm* pFtnCont = pSct->FindFtnBossFrm(!bEnd)->FindFtnCont();
1775             if( pFtnCont )
1776             {
1777                 SwFtnFrm* pTmp = (SwFtnFrm*)pFtnCont->Lower();
1778                 if( bEnd )
1779                     while( pTmp && !pTmp->GetAttr()->GetFtn().IsEndNote() )
1780                         pTmp = (SwFtnFrm*)pTmp->GetNext();
1781                 if( pTmp && *pTmp < pAttr )
1782                     return;
1783             }
1784         }
1785     }
1786 
1787     SwFtnFrm *pNew = new SwFtnFrm( pDoc->GetDfltFrmFmt(), this, pRef, pAttr );
1788     {
1789         SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
1790         ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() );
1791     }
1792     // Wenn die Seite gewechselt (oder gar neu angelegt) wurde,
1793     // muessen wir uns dort in die erste Spalte setzen
1794     if( bChgPage )
1795     {
1796         SwLayoutFrm* pBody = pPage->FindBodyCont();
1797         ASSERT( pBody, "AppendFtn: NoPageBody?" );
1798         if( pBody->Lower() && pBody->Lower()->IsColumnFrm() )
1799             pBoss = (SwFtnBossFrm*)pBody->Lower();
1800         else
1801             pBoss = pPage; // bei nichtspaltigen Seiten auf die Seite selbst
1802     }
1803     pBoss->InsertFtn( pNew );
1804     if ( pNew->GetUpper() )         //Eingesetzt oder nicht?
1805     {
1806         ::RegistFlys( pNew->FindPageFrm(), pNew );
1807         SwSectionFrm* pSect = FindSctFrm();
1808         // Der Inhalt des FtnContainers in einem (spaltigen) Bereich
1809         // braucht nur kalkuliert zu werden,
1810         // wenn der Bereich bereits bis zur Unterkante seines Uppers geht.
1811         if( pSect && !pSect->IsJoinLocked() && ( bEnd ? !pSect->IsEndnAtEnd() :
1812             !pSect->IsFtnAtEnd() ) && pSect->Growable() )
1813             pSect->InvalidateSize();
1814         else
1815         {
1816             // --> OD 2005-05-18 #i49383# - disable unlock of position of
1817             // lower objects during format of footnote content.
1818             const bool bOldFtnFrmLocked( pNew->IsColLocked() );
1819             pNew->ColLock();
1820             pNew->KeepLockPosOfLowerObjs();
1821             // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
1822             // no extra notify for footnote frame
1823 //            SwLayNotify* pFtnFrmNotitfy = new SwLayNotify( pNew );
1824             // <--
1825             SwCntntFrm *pCnt = pNew->ContainsCntnt();
1826             while ( pCnt && pCnt->FindFtnFrm()->GetAttr() == pAttr )
1827             {
1828                 pCnt->Calc();
1829                 // --> OD 2005-05-17 #i49383# - format anchored objects
1830                 if ( pCnt->IsTxtFrm() && pCnt->IsValid() )
1831                 {
1832                     if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt,
1833                                                               *(pCnt->FindPageFrm()) ) )
1834                     {
1835                         // restart format with first content
1836                         pCnt = pNew->ContainsCntnt();
1837                         continue;
1838                     }
1839                 }
1840                 // <--
1841                 pCnt = (SwCntntFrm*)pCnt->FindNextCnt();
1842             }
1843             // --> OD 2005-05-18 #i49383#
1844             if ( !bOldFtnFrmLocked )
1845             {
1846                 pNew->ColUnlock();
1847             }
1848             // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
1849             // enable lock of lower object position before format of footnote frame.
1850             pNew->UnlockPosOfLowerObjs();
1851             // <--
1852             pNew->Calc();
1853             // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
1854             // no extra notify for footnote frame
1855 //            pNew->UnlockPosOfLowerObjs();
1856 //            delete pFtnFrmNotitfy;
1857             // <--
1858             if ( !bOldFtnFrmLocked && !pNew->GetLower() &&
1859                  !pNew->IsColLocked() && !pNew->IsBackMoveLocked() )
1860             {
1861                 pNew->Cut();
1862                 delete pNew;
1863             }
1864             // <--
1865         }
1866         pMyPage->UpdateFtnNum();
1867     }
1868     else
1869         delete pNew;
1870 }
1871 /*************************************************************************
1872 |*
1873 |*  SwFtnBossFrm::FindFtn()
1874 |*
1875 |*************************************************************************/
1876 
1877 
1878 SwFtnFrm *SwFtnBossFrm::FindFtn( const SwCntntFrm *pRef, const SwTxtFtn *pAttr )
1879 {
1880     //Der einfachste und sicherste Weg geht ueber das Attribut.
1881     ASSERT( pAttr->GetStartNode(), "FtnAtr ohne StartNode." );
1882     SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
1883     SwCntntNode *pNd = aIdx.GetNode().GetCntntNode();
1884     if ( !pNd )
1885         pNd = pRef->GetAttrSet()->GetDoc()->
1886               GetNodes().GoNextSection( &aIdx, sal_True, sal_False );
1887     if ( !pNd )
1888         return 0;
1889     SwIterator<SwFrm,SwCntntNode> aIter( *pNd );
1890     SwFrm* pFrm = aIter.First();
1891     if( pFrm )
1892         do
1893         {
1894                 pFrm = pFrm->GetUpper();
1895                 // #i28500#, #i27243# Due to the endnode collector, there are
1896                 // SwFtnFrms, which are not in the layout. Therefore the
1897                 // bInfFtn flags are not set correctly, and a cell of FindFtnFrm
1898                 // would return 0. Therefore we better call ImplFindFtnFrm().
1899                 SwFtnFrm *pFtn = pFrm->ImplFindFtnFrm();
1900                 if ( pFtn && pFtn->GetRef() == pRef )
1901                 {
1902                     // The following condition becomes true, if the whole
1903                     // footnotecontent is a section. While no frames exist,
1904                     // the HiddenFlag of the section is set, this causes
1905                     // the GoNextSection-function leaves the footnote.
1906                     if( pFtn->GetAttr() != pAttr )
1907                         return 0;
1908                     while ( pFtn && pFtn->GetMaster() )
1909                         pFtn = pFtn->GetMaster();
1910                     return pFtn;
1911                 }
1912 
1913         } while ( 0 != (pFrm = aIter.Next()) );
1914 
1915     return 0;
1916 }
1917 /*************************************************************************
1918 |*
1919 |*  SwFtnBossFrm::RemoveFtn()
1920 |*
1921 |*************************************************************************/
1922 
1923 
1924 void SwFtnBossFrm::RemoveFtn( const SwCntntFrm *pRef, const SwTxtFtn *pAttr,
1925                               sal_Bool bPrep )
1926 {
1927     SwFtnFrm *pFtn = FindFtn( pRef, pAttr );
1928     if( pFtn )
1929     {
1930         do
1931         {
1932             SwFtnFrm *pFoll = pFtn->GetFollow();
1933             pFtn->Cut();
1934             delete pFtn;
1935             pFtn = pFoll;
1936         } while ( pFtn );
1937         if( bPrep && pRef->IsFollow() )
1938         {
1939             ASSERT( pRef->IsTxtFrm(), "NoTxtFrm has Footnote?" );
1940             SwTxtFrm* pMaster = (SwTxtFrm*)pRef->FindMaster();
1941             if( !pMaster->IsLocked() )
1942                 pMaster->Prepare( PREP_FTN_GONE );
1943         }
1944     }
1945     FindPageFrm()->UpdateFtnNum();
1946 }
1947 
1948 /*************************************************************************
1949 |*
1950 |*  SwFtnBossFrm::ChangeFtnRef()
1951 |*
1952 |*************************************************************************/
1953 
1954 
1955 void SwFtnBossFrm::ChangeFtnRef( const SwCntntFrm *pOld, const SwTxtFtn *pAttr,
1956                                  SwCntntFrm *pNew )
1957 {
1958     SwFtnFrm *pFtn = FindFtn( pOld, pAttr );
1959     while ( pFtn )
1960     {
1961         pFtn->SetRef( pNew );
1962         pFtn = pFtn->GetFollow();
1963     }
1964 }
1965 
1966 /*************************************************************************
1967 |*
1968 |*  SwFtnBossFrm::CollectFtns()
1969 |*
1970 |*************************************************************************/
1971 
1972 
1973 /// OD 03.04.2003 #108446# - add parameter <_bCollectOnlyPreviousFtns> in
1974 /// order to control, if only footnotes, which are positioned before the
1975 /// footnote boss frame <this> have to be collected.
1976 void SwFtnBossFrm::CollectFtns( const SwCntntFrm* _pRef,
1977                                 SwFtnBossFrm*     _pOld,
1978                                 SvPtrarr&         _rFtnArr,
1979                                 const sal_Bool    _bCollectOnlyPreviousFtns )
1980 {
1981     SwFtnFrm *pFtn = _pOld->FindFirstFtn();
1982     while( !pFtn )
1983     {
1984         if( _pOld->IsColumnFrm() )
1985         {   // Spalten abklappern
1986             while ( !pFtn && _pOld->GetPrev() )
1987             {
1988                 //Wenn wir keine Fussnote gefunden haben, ist noch nicht alles zu
1989                 //spaet. Die Schleife wird beim Aufnehmen von Follow-Zeilen durch
1990                 //Tabellen benoetigt. Fuer alle anderen Faelle ist sie in der Lage
1991                 //'krumme' Verhaeltnisse zu korrigieren.
1992                 _pOld = (SwFtnBossFrm*)_pOld->GetPrev();
1993                 pFtn = _pOld->FindFirstFtn();
1994             }
1995         }
1996         if( !pFtn )
1997         {
1998             //  vorherige Seite
1999             SwPageFrm* pPg;
2000             for ( SwFrm* pTmp = _pOld;
2001                   0 != ( pPg = (SwPageFrm*)pTmp->FindPageFrm()->GetPrev())
2002                     && pPg->IsEmptyPage() ;
2003                 )
2004             {
2005                 pTmp = pPg;
2006             }
2007             if( !pPg )
2008                 return;
2009 
2010             SwLayoutFrm* pBody = pPg->FindBodyCont();
2011             if( pBody->Lower() && pBody->Lower()->IsColumnFrm() )
2012             {
2013                 // mehrspaltige Seite => letzte Spalte suchen
2014                 _pOld = static_cast<SwFtnBossFrm*>(pBody->GetLastLower());
2015             }
2016             else
2017                 _pOld = pPg; // einspaltige Seite
2018             pFtn = _pOld->FindFirstFtn();
2019         }
2020     }
2021     // OD 03.04.2003 #108446# - consider new parameter <_bCollectOnlyPreviousFtns>
2022     SwFtnBossFrm* pRefBossFrm = NULL;
2023     if ( _bCollectOnlyPreviousFtns )
2024     {
2025         pRefBossFrm = this;
2026     }
2027     _CollectFtns( _pRef, pFtn, _rFtnArr, _bCollectOnlyPreviousFtns, pRefBossFrm );
2028 }
2029 
2030 
2031 /*************************************************************************
2032 |*
2033 |*  SwFtnBossFrm::_CollectFtns()
2034 |*
2035 |*************************************************************************/
2036 inline void FtnInArr( SvPtrarr& rFtnArr, SwFtnFrm* pFtn )
2037 {
2038     if ( USHRT_MAX == rFtnArr.GetPos( (VoidPtr)pFtn ) )
2039         rFtnArr.Insert( (VoidPtr)pFtn, rFtnArr.Count() );
2040 }
2041 
2042 /// OD 03.04.2003 #108446# - add parameters <_bCollectOnlyPreviousFtns> and
2043 /// <_pRefFtnBossFrm> in order to control, if only footnotes, which are positioned
2044 /// before the given reference footnote boss frame have to be collected.
2045 /// Note: if parameter <_bCollectOnlyPreviousFtns> is true, then parameter
2046 /// <_pRefFtnBossFrm> have to be referenced to an object.
2047 /// Adjust parameter names.
2048 void SwFtnBossFrm::_CollectFtns( const SwCntntFrm*   _pRef,
2049                                  SwFtnFrm*           _pFtn,
2050                                  SvPtrarr&           _rFtnArr,
2051                                  sal_Bool            _bCollectOnlyPreviousFtns,
2052                                  const SwFtnBossFrm* _pRefFtnBossFrm)
2053 {
2054     // OD 03.04.2003 #108446# - assert, that no reference footnote boss frame
2055     // is set, in spite of the order, that only previous footnotes has to be
2056     // collected.
2057     ASSERT( !_bCollectOnlyPreviousFtns || _pRefFtnBossFrm,
2058             "<SwFtnBossFrm::_CollectFtns(..)> - No reference footnote boss frame for collecting only previous footnotes set.\nCrash will be caused!" );
2059 
2060     //Alle Fussnoten die von pRef referenziert werden nacheinander
2061     //einsammeln (Attribut fuer Attribut), zusammengefuegen
2062     //(der Inhalt zu einem Attribut kann ueber mehrere Seiten verteilt sein)
2063     //und ausschneiden.
2064 
2065     SvPtrarr aNotFtnArr( 20, 20 );  //Zur Robustheit werden hier die nicht
2066                                     //dazugehoerigen Fussnoten eingetragen.
2067                                     //Wenn eine Fussnote zweimal angefasst wird
2068                                     //ists vorbei! So kommt die Funktion auch
2069                                     //noch mit einem kaputten Layout
2070                                     //einigermassen (ohne Schleife und Absturz)
2071                                     //"klar".
2072 
2073     //Hier sollte keiner mit einer Follow-Ftn ankommen, es sei denn er hat
2074     //ernste Absichten (:-)); spricht er kommt mit einer Ftn an die vor der
2075     //ersten der Referenz liegt.
2076     ASSERT( !_pFtn->GetMaster() || _pFtn->GetRef() != _pRef, "FollowFtn moven?" );
2077     while ( _pFtn->GetMaster() )
2078         _pFtn = _pFtn->GetMaster();
2079 
2080     sal_Bool bFound = sal_False;
2081 
2082     while ( _pFtn )
2083     {
2084         //Erstmal die naechste Fussnote der Spalte/Seite suchen, damit wir nicht
2085         //nach dem Cut jeder Fussnote von vorn anfangen muessen.
2086         SwFtnFrm *pNxtFtn = _pFtn;
2087         while ( pNxtFtn->GetFollow() )
2088             pNxtFtn = pNxtFtn->GetFollow();
2089         pNxtFtn = (SwFtnFrm*)pNxtFtn->GetNext();
2090 
2091         if ( !pNxtFtn )
2092         {
2093             SwFtnBossFrm* pBoss = _pFtn->FindFtnBossFrm();
2094             SwPageFrm* pPage = pBoss->FindPageFrm();
2095             do
2096             {
2097                 lcl_NextFtnBoss( pBoss, pPage, sal_False );
2098                 if( pBoss )
2099                 {
2100                     SwLayoutFrm* pCont = pBoss->FindFtnCont();
2101                     if( pCont )
2102                     {
2103                         pNxtFtn = (SwFtnFrm*)pCont->Lower();
2104                         if( pNxtFtn )
2105                         {
2106                             while( pNxtFtn->GetMaster() )
2107                                 pNxtFtn = pNxtFtn->GetMaster();
2108                             if( pNxtFtn == _pFtn )
2109                                 pNxtFtn = NULL;
2110                         }
2111                     }
2112                 }
2113             } while( !pNxtFtn && pBoss );
2114         }
2115         else if( !pNxtFtn->GetAttr()->GetFtn().IsEndNote() )
2116         {   ASSERT( !pNxtFtn->GetMaster(), "_CollectFtn: Master exspected" );
2117             while ( pNxtFtn->GetMaster() )
2118                 pNxtFtn = pNxtFtn->GetMaster();
2119         }
2120         if ( pNxtFtn == _pFtn )
2121         {
2122             ASSERT( sal_False, "_CollectFtn: Devil's circle" );
2123             pNxtFtn = 0;
2124         }
2125 
2126         // OD 03.04.2003 #108446# - determine, if found footnote has to be collected.
2127         sal_Bool bCollectFoundFtn = sal_False;
2128         if ( _pFtn->GetRef() == _pRef && !_pFtn->GetAttr()->GetFtn().IsEndNote() )
2129         {
2130             if ( _bCollectOnlyPreviousFtns )
2131             {
2132                 SwFtnBossFrm* pBossOfFoundFtn = _pFtn->FindFtnBossFrm( sal_True );
2133                 ASSERT( pBossOfFoundFtn,
2134                         "<SwFtnBossFrm::_CollectFtns(..)> - footnote boss frame of found footnote frame missing.\nWrong layout!" );
2135                 if ( !pBossOfFoundFtn ||    // don't crash, if no footnote boss is found.
2136                      pBossOfFoundFtn->IsBefore( _pRefFtnBossFrm )
2137                    )
2138                 {
2139                     bCollectFoundFtn = sal_True;
2140                 }
2141             }
2142             else
2143             {
2144                 bCollectFoundFtn = sal_True;
2145             }
2146         }
2147 
2148         if ( bCollectFoundFtn )
2149         {
2150             ASSERT( !_pFtn->GetMaster(), "FollowFtn moven?" );
2151             SwFtnFrm *pNxt = _pFtn->GetFollow();
2152             while ( pNxt )
2153             {
2154                 SwFrm *pCnt = pNxt->ContainsAny();
2155                 if ( pCnt )
2156                 {   //Unterwegs wird der Follow zerstoert weil er leer wird!
2157                     do
2158                     {   SwFrm *pNxtCnt = pCnt->GetNext();
2159                         pCnt->Cut();
2160                         pCnt->Paste( _pFtn );
2161                         pCnt = pNxtCnt;
2162                     } while ( pCnt );
2163                 }
2164                 else
2165                 {   ASSERT( !pNxt, "Fussnote ohne Inhalt?" );
2166                     pNxt->Cut();
2167                     delete pNxt;
2168                 }
2169                 pNxt = _pFtn->GetFollow();
2170             }
2171             _pFtn->Cut();
2172             FtnInArr( _rFtnArr, _pFtn );
2173             bFound = sal_True;
2174         }
2175         else
2176         {
2177             FtnInArr( aNotFtnArr, _pFtn );
2178             if( bFound )
2179                 break;
2180         }
2181         if ( pNxtFtn &&
2182              USHRT_MAX == _rFtnArr.GetPos( (VoidPtr)pNxtFtn ) &&
2183              USHRT_MAX == aNotFtnArr.GetPos( (VoidPtr)pNxtFtn ) )
2184             _pFtn = pNxtFtn;
2185         else
2186             break;
2187     }
2188 }
2189 
2190 /*************************************************************************
2191 |*
2192 |*  SwFtnBossFrm::_MoveFtns()
2193 |*
2194 |*************************************************************************/
2195 
2196 
2197 void SwFtnBossFrm::_MoveFtns( SvPtrarr &rFtnArr, sal_Bool bCalc )
2198 {
2199     //Alle Fussnoten die von pRef referenziert werden muessen von der
2200     //aktuellen Position, die sich durch die alte Spalte/Seite ergab, auf eine
2201     //neue Position, bestimmt durch die neue Spalte/Seite, gemoved werden.
2202     const sal_uInt16 nMyNum = FindPageFrm()->GetPhyPageNum();
2203     const sal_uInt16 nMyCol = lcl_ColumnNum( this );
2204     SWRECTFN( this )
2205 
2206     // --> OD 2004-06-11 #i21478# - keep last inserted footnote in order to
2207     // format the content of the following one.
2208     SwFtnFrm* pLastInsertedFtn = 0L;
2209     for ( sal_uInt16 i = 0; i < rFtnArr.Count(); ++i )
2210     {
2211         SwFtnFrm *pFtn = (SwFtnFrm*)rFtnArr[i];
2212 
2213         SwFtnBossFrm* pRefBoss = pFtn->GetRef()->FindFtnBossFrm( sal_True );
2214         if( pRefBoss != this )
2215         {
2216             const sal_uInt16 nRefNum = pRefBoss->FindPageFrm()->GetPhyPageNum();
2217             const sal_uInt16 nRefCol = lcl_ColumnNum( this );
2218             if( nRefNum < nMyNum || ( nRefNum == nMyNum && nRefCol <= nMyCol ) )
2219                 pRefBoss = this;
2220         }
2221         pRefBoss->InsertFtn( pFtn );
2222 
2223         if ( pFtn->GetUpper() ) //Robust, z.B. bei doppelten
2224         {
2225             // Damit FtnFrms, die nicht auf die Seite passen, nicht fuer zuviel
2226             // Unruhe sorgen (Loop 66312), wird ihr Inhalt zunaechst zusammengestaucht.
2227             // Damit wird der FtnCont erst gegrowt, wenn der Inhalt formatiert wird
2228             // und feststellt, dass er auf die Seite passt.
2229             SwFrm *pCnt = pFtn->ContainsAny();
2230             while( pCnt )
2231             {
2232                 if( pCnt->IsLayoutFrm() )
2233                 {
2234                     SwFrm* pTmp = ((SwLayoutFrm*)pCnt)->ContainsAny();
2235                     while( pTmp && ((SwLayoutFrm*)pCnt)->IsAnLower( pTmp ) )
2236                     {
2237                         pTmp->Prepare( PREP_MOVEFTN );
2238                         (pTmp->Frm().*fnRect->fnSetHeight)(0);
2239                         (pTmp->Prt().*fnRect->fnSetHeight)(0);
2240                         pTmp = pTmp->FindNext();
2241                     }
2242                 }
2243                 else
2244                     pCnt->Prepare( PREP_MOVEFTN );
2245                 (pCnt->Frm().*fnRect->fnSetHeight)(0);
2246                 (pCnt->Prt().*fnRect->fnSetHeight)(0);
2247                 pCnt = pCnt->GetNext();
2248             }
2249             (pFtn->Frm().*fnRect->fnSetHeight)(0);
2250             (pFtn->Prt().*fnRect->fnSetHeight)(0);
2251             pFtn->Calc();
2252             pFtn->GetUpper()->Calc();
2253 
2254             if( bCalc )
2255             {
2256                 SwTxtFtn *pAttr = pFtn->GetAttr();
2257                 pCnt = pFtn->ContainsAny();
2258                 sal_Bool bUnlock = !pFtn->IsBackMoveLocked();
2259                 pFtn->LockBackMove();
2260 
2261                 // --> OD 2005-05-18 #i49383# - disable unlock of position of
2262                 // lower objects during format of footnote content.
2263                 pFtn->KeepLockPosOfLowerObjs();
2264                 // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2265                 // no extra notify for footnote frame
2266 //                SwLayNotify aFtnFrmNotitfy( pFtn );
2267                 // <--
2268 
2269                 while ( pCnt && pCnt->FindFtnFrm()->GetAttr() == pAttr )
2270                 {
2271                     pCnt->_InvalidatePos();
2272                     pCnt->Calc();
2273                     // --> OD 2005-05-17 #i49383# - format anchored objects
2274                     if ( pCnt->IsTxtFrm() && pCnt->IsValid() )
2275                     {
2276                         if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt,
2277                                                                   *(pCnt->FindPageFrm()) ) )
2278                         {
2279                             // restart format with first content
2280                             pCnt = pFtn->ContainsAny();
2281                             continue;
2282                         }
2283                     }
2284                     // <--
2285                     if( pCnt->IsSctFrm() )
2286                     {   // Wenn es sich um einen nichtleeren Bereich handelt,
2287                         // iterieren wir auch ueber seinen Inhalt
2288                         SwFrm* pTmp = ((SwSectionFrm*)pCnt)->ContainsAny();
2289                         if( pTmp )
2290                             pCnt = pTmp;
2291                         else
2292                             pCnt = pCnt->FindNext();
2293                     }
2294                     else
2295                         pCnt = pCnt->FindNext();
2296                 }
2297                 if( bUnlock )
2298                 {
2299                     pFtn->UnlockBackMove();
2300                     if( !pFtn->ContainsAny() && !pFtn->IsColLocked() )
2301                     {
2302                         pFtn->Cut();
2303                         delete pFtn;
2304                         // --> OD 2004-06-10 #i21478#
2305                         pFtn = 0L;
2306                     }
2307                 }
2308                 // --> OD 2005-05-18 #i49383#
2309                 if ( pFtn )
2310                 {
2311                     // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2312                     // enable lock of lower object position before format of footnote frame.
2313                     pFtn->UnlockPosOfLowerObjs();
2314                     pFtn->Calc();
2315 //                    pFtn->UnlockPosOfLowerObjs();
2316                     // <--
2317                 }
2318                 // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2319                 // no extra notify for footnote frame
2320 //                else
2321 //                {
2322 //                    aFtnFrmNotitfy.FrmDeleted();
2323 //                }
2324                 // <--
2325             }
2326         }
2327         else
2328         {   ASSERT( !pFtn->GetMaster() && !pFtn->GetFollow(),
2329                     "DelFtn und Master/Follow?" );
2330             delete pFtn;
2331             // --> OD 2004-06-10 #i21478#
2332             pFtn = 0L;
2333         }
2334 
2335         // --> OD 2004-06-10 #i21478#
2336         if ( pFtn )
2337         {
2338             pLastInsertedFtn = pFtn;
2339         }
2340     }
2341 
2342     // --> OD 2004-06-10 #i21478# - format content of footnote following
2343     // the new inserted ones.
2344     if ( bCalc && pLastInsertedFtn )
2345     {
2346         if ( pLastInsertedFtn->GetNext() )
2347         {
2348             SwFtnFrm* pNextFtn = static_cast<SwFtnFrm*>(pLastInsertedFtn->GetNext());
2349             SwTxtFtn* pAttr = pNextFtn->GetAttr();
2350             SwFrm* pCnt = pNextFtn->ContainsAny();
2351 
2352             sal_Bool bUnlock = !pNextFtn->IsBackMoveLocked();
2353             pNextFtn->LockBackMove();
2354             // --> OD 2005-05-18 #i49383# - disable unlock of position of
2355             // lower objects during format of footnote content.
2356             pNextFtn->KeepLockPosOfLowerObjs();
2357             // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2358             // no extra notify for footnote frame
2359 //            SwLayNotify aFtnFrmNotitfy( pNextFtn );
2360             // <--
2361 
2362             while ( pCnt && pCnt->FindFtnFrm()->GetAttr() == pAttr )
2363             {
2364                 pCnt->_InvalidatePos();
2365                 pCnt->Calc();
2366                 // --> OD 2005-05-17 #i49383# - format anchored objects
2367                 if ( pCnt->IsTxtFrm() && pCnt->IsValid() )
2368                 {
2369                     if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt,
2370                                                               *(pCnt->FindPageFrm()) ) )
2371                     {
2372                         // restart format with first content
2373                         pCnt = pNextFtn->ContainsAny();
2374                         continue;
2375                     }
2376                 }
2377                 // <--
2378                 if( pCnt->IsSctFrm() )
2379                 {   // Wenn es sich um einen nichtleeren Bereich handelt,
2380                     // iterieren wir auch ueber seinen Inhalt
2381                     SwFrm* pTmp = ((SwSectionFrm*)pCnt)->ContainsAny();
2382                     if( pTmp )
2383                         pCnt = pTmp;
2384                     else
2385                         pCnt = pCnt->FindNext();
2386                 }
2387                 else
2388                     pCnt = pCnt->FindNext();
2389             }
2390             if( bUnlock )
2391             {
2392                 pNextFtn->UnlockBackMove();
2393             }
2394             // --> OD 2005-05-18 #i49383#
2395             // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2396             // enable lock of lower object position before format of footnote frame.
2397             pNextFtn->UnlockPosOfLowerObjs();
2398             pNextFtn->Calc();
2399 //            pNextFtn->UnlockPosOfLowerObjs();
2400             // <--
2401         }
2402     }
2403 }
2404 
2405 /*************************************************************************
2406 |*
2407 |*  SwFtnBossFrm::MoveFtns()
2408 |*
2409 |*************************************************************************/
2410 
2411 
2412 void SwFtnBossFrm::MoveFtns( const SwCntntFrm *pSrc, SwCntntFrm *pDest,
2413                              SwTxtFtn *pAttr )
2414 {
2415     if( ( GetFmt()->GetDoc()->GetFtnInfo().ePos == FTNPOS_CHAPTER &&
2416         (!GetUpper()->IsSctFrm() || !((SwSectionFrm*)GetUpper())->IsFtnAtEnd()))
2417         || pAttr->GetFtn().IsEndNote() )
2418         return;
2419 
2420     ASSERT( this == pSrc->FindFtnBossFrm( sal_True ),
2421             "SwPageFrm::MoveFtns: source frame isn't on that FtnBoss" );
2422 
2423     SwFtnFrm *pFtn = FindFirstFtn();
2424     if( pFtn )
2425     {
2426         ChangeFtnRef( pSrc, pAttr, pDest );
2427         SwFtnBossFrm *pDestBoss = pDest->FindFtnBossFrm( sal_True );
2428         ASSERT( pDestBoss, "+SwPageFrm::MoveFtns: no destination boss" );
2429         if( pDestBoss )     // robust
2430         {
2431             SvPtrarr aFtnArr( 5, 5 );
2432             pDestBoss->_CollectFtns( pDest, pFtn, aFtnArr );
2433             if ( aFtnArr.Count() )
2434             {
2435                 pDestBoss->_MoveFtns( aFtnArr, sal_True );
2436                 SwPageFrm* pSrcPage = FindPageFrm();
2437                 SwPageFrm* pDestPage = pDestBoss->FindPageFrm();
2438                 // Nur beim Seitenwechsel FtnNum Updaten
2439                 if( pSrcPage != pDestPage )
2440                 {
2441                     if( pSrcPage->GetPhyPageNum() > pDestPage->GetPhyPageNum() )
2442                         pSrcPage->UpdateFtnNum();
2443                     pDestPage->UpdateFtnNum();
2444                 }
2445             }
2446         }
2447     }
2448 }
2449 
2450 /*************************************************************************
2451 |*
2452 |*  SwFtnBossFrm::RearrangeFtns()
2453 |*
2454 |*************************************************************************/
2455 
2456 
2457 void SwFtnBossFrm::RearrangeFtns( const SwTwips nDeadLine, const sal_Bool bLock,
2458                                   const SwTxtFtn *pAttr )
2459 {
2460     //Alle Fussnoten der Spalte/Seite dergestalt anformatieren,
2461     //dass sie ggf. die Spalte/Seite wechseln.
2462 
2463     SwSaveFtnHeight aSave( this, nDeadLine );
2464     SwFtnFrm *pFtn = FindFirstFtn();
2465     if( pFtn && pFtn->GetPrev() && bLock )
2466     {
2467         SwFtnFrm* pFirst = (SwFtnFrm*)pFtn->GetUpper()->Lower();
2468         SwFrm* pCntnt = pFirst->ContainsAny();
2469         if( pCntnt )
2470         {
2471             sal_Bool bUnlock = !pFirst->IsBackMoveLocked();
2472             pFirst->LockBackMove();
2473             pFirst->Calc();
2474             pCntnt->Calc();
2475             // --> OD 2005-05-17 #i49383# - format anchored objects
2476             if ( pCntnt->IsTxtFrm() && pCntnt->IsValid() )
2477             {
2478                 SwObjectFormatter::FormatObjsAtFrm( *pCntnt,
2479                                                     *(pCntnt->FindPageFrm()) );
2480             }
2481             // <--
2482             if( bUnlock )
2483                 pFirst->UnlockBackMove();
2484         }
2485         pFtn = FindFirstFtn();
2486     }
2487     SwDoc *pDoc = GetFmt()->GetDoc();
2488     const sal_uLong nFtnPos = pAttr ? ::lcl_FindFtnPos( pDoc, pAttr ) : 0;
2489     SwFrm *pCnt = pFtn ? pFtn->ContainsAny() : 0;
2490     if ( pCnt )
2491     {
2492         sal_Bool bMore = sal_True;
2493         sal_Bool bStart = pAttr == 0; // wenn kein Attribut uebergeben wird, alle bearbeiten
2494         // --> OD 2005-05-18 #i49383# - disable unlock of position of
2495         // lower objects during format of footnote and footnote content.
2496         SwFtnFrm* pLastFtnFrm( 0L );
2497         // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2498         // no extra notify for footnote frame
2499 //        SwLayNotify* pFtnFrmNotify( 0L );
2500         // footnote frame needs to be locked, if <bLock> isn't set.
2501         bool bUnlockLastFtnFrm( false );
2502         // <--
2503         do
2504         {
2505             if( !bStart )
2506                 bStart = ::lcl_FindFtnPos( pDoc, pCnt->FindFtnFrm()->GetAttr() )
2507                          == nFtnPos;
2508             if( bStart )
2509             {
2510                 pCnt->_InvalidatePos();
2511                 pCnt->_InvalidateSize();
2512                 pCnt->Prepare( PREP_ADJUST_FRM );
2513                 SwFtnFrm* pFtnFrm = pCnt->FindFtnFrm();
2514                 // --> OD 2005-05-18 #i49383#
2515                 if ( pFtnFrm != pLastFtnFrm )
2516                 {
2517                     if ( pLastFtnFrm )
2518                     {
2519                         if ( !bLock && bUnlockLastFtnFrm )
2520                         {
2521                             pLastFtnFrm->ColUnlock();
2522                         }
2523                         // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2524                         // enable lock of lower object position before format of footnote frame.
2525                         pLastFtnFrm->UnlockPosOfLowerObjs();
2526                         pLastFtnFrm->Calc();
2527 //                        pLastFtnFrm->UnlockPosOfLowerObjs();
2528                         // no extra notify for footnote frame
2529 //                        delete pFtnFrmNotify;
2530                         // <--
2531                         if ( !bLock && bUnlockLastFtnFrm &&
2532                              !pLastFtnFrm->GetLower() &&
2533                              !pLastFtnFrm->IsColLocked() &&
2534                              !pLastFtnFrm->IsBackMoveLocked() )
2535                         {
2536                             pLastFtnFrm->Cut();
2537                             delete pLastFtnFrm;
2538                             pLastFtnFrm = 0L;
2539                         }
2540                     }
2541                     if ( !bLock )
2542                     {
2543                         bUnlockLastFtnFrm = !pFtnFrm->IsColLocked();
2544                         pFtnFrm->ColLock();
2545                     }
2546                     pFtnFrm->KeepLockPosOfLowerObjs();
2547                     pLastFtnFrm = pFtnFrm;
2548                     // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2549                     // no extra notify for footnote frame
2550 //                    pFtnFrmNotify = new SwLayNotify( pLastFtnFrm );
2551                     // <--
2552                 }
2553                 // <--
2554                 // OD 30.10.2002 #97265# - invalidate position of footnote
2555                 // frame, if it's below its footnote container, in order to
2556                 // assure its correct position, probably calculating its previous
2557                 // footnote frames.
2558                 {
2559                     SWRECTFN( this );
2560                     SwFrm* aFtnContFrm = pFtnFrm->GetUpper();
2561                     if ( (pFtnFrm->Frm().*fnRect->fnTopDist)((aFtnContFrm->*fnRect->fnGetPrtBottom)()) > 0 )
2562                     {
2563                         pFtnFrm->_InvalidatePos();
2564                     }
2565                 }
2566                 if ( bLock )
2567                 {
2568                     sal_Bool bUnlock = !pFtnFrm->IsBackMoveLocked();
2569                     pFtnFrm->LockBackMove();
2570                     pFtnFrm->Calc();
2571                     pCnt->Calc();
2572                     // --> OD 2005-05-17 #i49383# - format anchored objects
2573                     if ( pCnt->IsTxtFrm() && pCnt->IsValid() )
2574                     {
2575                         if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt,
2576                                                                   *(pCnt->FindPageFrm()) ) )
2577                         {
2578                             // restart format with first content
2579                             pCnt = pFtn->ContainsAny();
2580                             continue;
2581                         }
2582                     }
2583                     // <--
2584                     if( bUnlock )
2585                     {
2586                         pFtnFrm->UnlockBackMove();
2587                         if( !pFtnFrm->Lower() &&
2588                             !pFtnFrm->IsColLocked() )
2589                         {
2590                             // --> OD 2005-08-10 #i49383#
2591                             ASSERT( pLastFtnFrm == pFtnFrm,
2592                                     "<SwFtnBossFrm::RearrangeFtns(..)> - <pLastFtnFrm> != <pFtnFrm>" );
2593                             pLastFtnFrm = 0L;
2594                             // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2595                             // no extra notify for footnote frame
2596 //                            pFtnFrmNotify->FrmDeleted();
2597 //                            delete pFtnFrmNotify;
2598                             // <--
2599                             pFtnFrm->Cut();
2600                             delete pFtnFrm;
2601                         }
2602                     }
2603                 }
2604                 else
2605                 {
2606                     pFtnFrm->Calc();
2607                     pCnt->Calc();
2608                     // --> OD 2005-05-17 #i49383# - format anchored objects
2609                     if ( pCnt->IsTxtFrm() && pCnt->IsValid() )
2610                     {
2611                         if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt,
2612                                                                   *(pCnt->FindPageFrm()) ) )
2613                         {
2614                             // restart format with first content
2615                             pCnt = pFtn->ContainsAny();
2616                             continue;
2617                         }
2618                     }
2619                     // <--
2620                 }
2621             }
2622             SwSectionFrm *pDel = NULL;
2623             if( pCnt->IsSctFrm() )
2624             {
2625                 SwFrm* pTmp = ((SwSectionFrm*)pCnt)->ContainsAny();
2626                 if( pTmp )
2627                 {
2628                     pCnt = pTmp;
2629                     continue;
2630                 }
2631                 pDel = (SwSectionFrm*)pCnt;
2632             }
2633             if ( pCnt->GetNext() )
2634                 pCnt = pCnt->GetNext();
2635             else
2636             {
2637                 pCnt = pCnt->FindNext();
2638                 if ( pCnt )
2639                 {
2640                     SwFtnFrm* pFtnFrm = pCnt->FindFtnFrm();
2641                     if( pFtnFrm->GetRef()->FindFtnBossFrm(
2642                         pFtnFrm->GetAttr()->GetFtn().IsEndNote() ) != this )
2643                         bMore = sal_False;
2644                 }
2645                 else
2646                     bMore = sal_False;
2647             }
2648             if( pDel )
2649             {
2650                 pDel->Cut();
2651                 delete pDel;
2652             }
2653             if ( bMore )
2654             {
2655                 //Nicht weiter als bis zur angegebenen Fussnote, falls eine
2656                 //angegeben wurde.
2657                 if ( pAttr &&
2658                      (::lcl_FindFtnPos( pDoc,
2659                                     pCnt->FindFtnFrm()->GetAttr()) > nFtnPos ) )
2660                     bMore = sal_False;
2661             }
2662         } while ( bMore );
2663         // --> OD 2005-05-18 #i49383#
2664         if ( pLastFtnFrm )
2665         {
2666             if ( !bLock && bUnlockLastFtnFrm )
2667             {
2668                 pLastFtnFrm->ColUnlock();
2669             }
2670             // --> OD 2006-02-02 #i57914# - adjust fix #i49383#
2671             // enable lock of lower object position before format of footnote frame.
2672             pLastFtnFrm->UnlockPosOfLowerObjs();
2673             pLastFtnFrm->Calc();
2674 //            pLastFtnFrm->UnlockPosOfLowerObjs();
2675             // no extra notify for footnote frame
2676 //            delete pFtnFrmNotify;
2677             // <--
2678             if ( !bLock && bUnlockLastFtnFrm &&
2679                  !pLastFtnFrm->GetLower() &&
2680                  !pLastFtnFrm->IsColLocked() &&
2681                  !pLastFtnFrm->IsBackMoveLocked() )
2682             {
2683                 pLastFtnFrm->Cut();
2684                 delete pLastFtnFrm;
2685             }
2686         }
2687         // <--
2688     }
2689 }
2690 
2691 /*************************************************************************
2692 |*
2693 |*  SwPageFrm::UpdateFtnNum()
2694 |*
2695 |*************************************************************************/
2696 
2697 void SwPageFrm::UpdateFtnNum()
2698 {
2699     //Seitenweise Numerierung nur wenn es am Dokument so eingestellt ist.
2700     if ( GetFmt()->GetDoc()->GetFtnInfo().eNum != FTNNUM_PAGE )
2701         return;
2702 
2703     SwLayoutFrm* pBody = FindBodyCont();
2704     if( !pBody || !pBody->Lower() )
2705         return;
2706 
2707     SwCntntFrm* pCntnt = pBody->ContainsCntnt();
2708     sal_uInt16 nNum = 0;
2709 
2710     while( pCntnt && pCntnt->FindPageFrm() == this )
2711     {
2712         if( ((SwTxtFrm*)pCntnt)->HasFtn() )
2713         {
2714             SwFtnBossFrm* pBoss = pCntnt->FindFtnBossFrm( sal_True );
2715             if( pBoss->GetUpper()->IsSctFrm() &&
2716                 ((SwSectionFrm*)pBoss->GetUpper())->IsOwnFtnNum() )
2717                 pCntnt = ((SwSectionFrm*)pBoss->GetUpper())->FindLastCntnt();
2718             else
2719             {
2720                 SwFtnFrm* pFtn = (SwFtnFrm*)pBoss->FindFirstFtn( pCntnt );
2721                 while( pFtn )
2722                 {
2723                     SwTxtFtn* pTxtFtn = pFtn->GetAttr();
2724                     if( !pTxtFtn->GetFtn().IsEndNote() &&
2725                         !pTxtFtn->GetFtn().GetNumStr().Len() &&
2726                         !pFtn->GetMaster() &&
2727                         (pTxtFtn->GetFtn().GetNumber() != ++nNum) )
2728                         pTxtFtn->SetNumber( nNum );
2729                     if ( pFtn->GetNext() )
2730                         pFtn = (SwFtnFrm*)pFtn->GetNext();
2731                     else
2732                     {
2733                         SwFtnBossFrm* pTmpBoss = pFtn->FindFtnBossFrm( sal_True );
2734                         SwPageFrm* pPage = pTmpBoss->FindPageFrm();
2735                         pFtn = NULL;
2736                         lcl_NextFtnBoss( pTmpBoss, pPage, sal_False );
2737                         if( pTmpBoss )
2738                         {
2739                             SwFtnContFrm *pCont = pTmpBoss->FindNearestFtnCont();
2740                             if ( pCont )
2741                                 pFtn = (SwFtnFrm*)pCont->Lower();
2742                         }
2743                     }
2744                     if( pFtn && pFtn->GetRef() != pCntnt )
2745                         pFtn = NULL;
2746                 }
2747             }
2748         }
2749         pCntnt = pCntnt->FindNextCnt();
2750     }
2751 }
2752 
2753 /*************************************************************************
2754 |*
2755 |*  SwFtnBossFrm::SetFtnDeadLine()
2756 |*
2757 |*************************************************************************/
2758 
2759 void SwFtnBossFrm::SetFtnDeadLine( const SwTwips nDeadLine )
2760 {
2761     SwFrm *pBody = FindBodyCont();
2762     pBody->Calc();
2763 
2764     SwFrm *pCont = FindFtnCont();
2765     const SwTwips nMax = nMaxFtnHeight;//Aktuelle MaxHeight nicht ueberschreiten.
2766     SWRECTFN( this )
2767     if ( pCont )
2768     {
2769         pCont->Calc();
2770         nMaxFtnHeight = -(pCont->Frm().*fnRect->fnBottomDist)( nDeadLine );
2771     }
2772     else
2773         nMaxFtnHeight = -(pBody->Frm().*fnRect->fnBottomDist)( nDeadLine );
2774 
2775     const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
2776     if( pSh && pSh->GetViewOptions()->getBrowseMode() )
2777         nMaxFtnHeight += pBody->Grow( LONG_MAX, sal_True );
2778     if ( IsInSct() )
2779         nMaxFtnHeight += FindSctFrm()->Grow( LONG_MAX, sal_True );
2780 
2781     if ( nMaxFtnHeight < 0 )
2782         nMaxFtnHeight = 0;
2783     if ( nMax != LONG_MAX && nMaxFtnHeight > nMax )
2784         nMaxFtnHeight = nMax;
2785 }
2786 
2787 /*************************************************************************
2788 |*
2789 |*  SwFtnBossFrm::GetVarSpace()
2790 |*
2791 |*************************************************************************/
2792 SwTwips SwFtnBossFrm::GetVarSpace() const
2793 {
2794     //Fuer Seiten soll ein Wert von 20% der Seitenhoehe nicht unterschritten
2795     //werden (->AMA: was macht MS da?)
2796     //->AMA: Was ist da fuer Bereiche sinnvoll (und kompatibel zu MS ;-)?
2797     //AMA: MS kennt scheinbar kein Begrenzung, die Fussnoten nehmen durchaus
2798     // die ganze Seite/Spalte ein.
2799 
2800     const SwPageFrm* pPg = FindPageFrm();
2801     ASSERT( pPg || IsInSct(), "Footnote lost page" );
2802 
2803     const SwFrm *pBody = FindBodyCont();
2804     SwTwips nRet;
2805     if( pBody )
2806     {
2807         SWRECTFN( this )
2808         if( IsInSct() )
2809         {
2810             nRet = 0;
2811             SwTwips nTmp = (*fnRect->fnYDiff)( (pBody->*fnRect->fnGetPrtTop)(),
2812                                                (Frm().*fnRect->fnGetTop)() );
2813             const SwSectionFrm* pSect = FindSctFrm();
2814             //  Endnotes in a ftncontainer causes a deadline:
2815             // the bottom of the last contentfrm
2816             if( pSect->IsEndnAtEnd() ) // endnotes allowed?
2817             {
2818                 ASSERT( !Lower() || !Lower()->GetNext() || Lower()->GetNext()->
2819                         IsFtnContFrm(), "FtnContainer exspected" );
2820                 const SwFtnContFrm* pCont = Lower() ?
2821                     (SwFtnContFrm*)Lower()->GetNext() : 0;
2822                 if( pCont )
2823                 {
2824                     SwFtnFrm* pFtn = (SwFtnFrm*)pCont->Lower();
2825                     while( pFtn)
2826                     {
2827                         if( pFtn->GetAttr()->GetFtn().IsEndNote() )
2828                         { // endnote found
2829                             SwFrm* pFrm = ((SwLayoutFrm*)Lower())->Lower();
2830                             if( pFrm )
2831                             {
2832                                 while( pFrm->GetNext() )
2833                                     pFrm = pFrm->GetNext(); // last cntntfrm
2834                                 nTmp += (*fnRect->fnYDiff)(
2835                                          (Frm().*fnRect->fnGetTop)(),
2836                                          (pFrm->Frm().*fnRect->fnGetBottom)() );
2837                             }
2838                             break;
2839                         }
2840                         pFtn = (SwFtnFrm*)pFtn->GetNext();
2841                     }
2842                 }
2843             }
2844             if( nTmp < nRet )
2845                 nRet = nTmp;
2846         }
2847         else
2848             nRet = - (pPg->Prt().*fnRect->fnGetHeight)()/5;
2849         nRet += (pBody->Frm().*fnRect->fnGetHeight)();
2850         if( nRet < 0 )
2851             nRet = 0;
2852     }
2853     else
2854         nRet = 0;
2855     if ( IsPageFrm() )
2856     {
2857         const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0;
2858         if( pSh && pSh->GetViewOptions()->getBrowseMode() )
2859         nRet += BROWSE_HEIGHT - Frm().Height();
2860     }
2861     return nRet;
2862 }
2863 
2864 /*************************************************************************
2865 |*
2866 |*  SwFtnBossFrm::NeighbourhoodAdjustment(SwFrm*)
2867 |*
2868 |*  gibt Auskunft, ob die Groessenveraenderung von pFrm von AdjustNeighbourhood(...)
2869 |*  oder von Grow/Shrink(..) verarbeitet werden sollte.
2870 |*  Bei einem PageFrm oder in Spalten direkt unterhalb der Seite muss AdjustNei..
2871 |*  gerufen werden, in Rahmenspalten Grow/Shrink.
2872 |*  Spannend sind die spaltigen Bereiche: Wenn es in der Spalte einen Fussnotencontainer
2873 |*  gibt und die Fussnoten nicht vom Bereich eingesammelt werden, ist ein Adjust..,
2874 |*  ansonsten ein Grow/Shrink notwendig.
2875 |*
2876 |*************************************************************************/
2877 
2878 sal_uInt8 SwFtnBossFrm::_NeighbourhoodAdjustment( const SwFrm* ) const
2879 {
2880     sal_uInt8 nRet = NA_ONLY_ADJUST;
2881     if( GetUpper() && !GetUpper()->IsPageBodyFrm() )
2882     {
2883         // Spaltige Rahmen erfordern Grow/Shrink
2884         if( GetUpper()->IsFlyFrm() )
2885             nRet = NA_GROW_SHRINK;
2886         else
2887         {
2888             ASSERT( GetUpper()->IsSctFrm(), "NeighbourhoodAdjustment: Unexspected Upper" );
2889             if( !GetNext() && !GetPrev() )
2890                 nRet = NA_GROW_ADJUST; // section with a single column (FtnAtEnd)
2891             else
2892             {
2893                 const SwFrm* pTmp = Lower();
2894                 ASSERT( pTmp, "NeighbourhoodAdjustment: Missing Lower()" );
2895                 if( !pTmp->GetNext() )
2896                     nRet = NA_GROW_SHRINK;
2897                 else if( !GetUpper()->IsColLocked() )
2898                     nRet = NA_ADJUST_GROW;
2899                 ASSERT( !pTmp->GetNext() || pTmp->GetNext()->IsFtnContFrm(),
2900                         "NeighbourhoodAdjustment: Who's that guy?" );
2901             }
2902         }
2903     }
2904     return nRet;
2905 }
2906 
2907 /*************************************************************************
2908 |*
2909 |*  SwPageFrm::SetColMaxFtnHeight()
2910 |*
2911 |*************************************************************************/
2912 void SwPageFrm::SetColMaxFtnHeight()
2913 {
2914     SwLayoutFrm *pBody = FindBodyCont();
2915     if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() )
2916     {
2917         SwColumnFrm* pCol = (SwColumnFrm*)pBody->Lower();
2918         do
2919         {
2920             pCol->SetMaxFtnHeight( GetMaxFtnHeight() );
2921             pCol = (SwColumnFrm*)pCol->GetNext();
2922         } while ( pCol );
2923     }
2924 }
2925 
2926 /*************************************************************************
2927 |*
2928 |*  SwLayoutFrm::MoveLowerFtns
2929 |*
2930 |*************************************************************************/
2931 
2932 
2933 sal_Bool SwLayoutFrm::MoveLowerFtns( SwCntntFrm *pStart, SwFtnBossFrm *pOldBoss,
2934                                  SwFtnBossFrm *pNewBoss, const sal_Bool bFtnNums )
2935 {
2936     SwDoc *pDoc = GetFmt()->GetDoc();
2937     if ( !pDoc->GetFtnIdxs().Count() )
2938         return sal_False;
2939     if( pDoc->GetFtnInfo().ePos == FTNPOS_CHAPTER &&
2940         ( !IsInSct() || !FindSctFrm()->IsFtnAtEnd() ) )
2941         return sal_True;
2942 
2943     if ( !pNewBoss )
2944         pNewBoss = FindFtnBossFrm( sal_True );
2945     if ( pNewBoss == pOldBoss )
2946         return sal_False;
2947 
2948     sal_Bool bMoved = sal_False;
2949     if( !pStart )
2950         pStart = ContainsCntnt();
2951 
2952     SvPtrarr aFtnArr( 5, 5 );
2953 
2954     while ( IsAnLower( pStart ) )
2955     {
2956         if ( ((SwTxtFrm*)pStart)->HasFtn() )
2957         {
2958             // OD 03.04.2003 #108446# - To avoid unnecessary moves of footnotes
2959             // use new parameter <_bCollectOnlyPreviousFtn> (4th parameter of
2960             // method <SwFtnBossFrm::CollectFtn(..)>) to control, that only
2961             // footnotes have to be collected, that are positioned before the
2962             // new dedicated footnote boss frame.
2963             pNewBoss->CollectFtns( pStart, pOldBoss, aFtnArr, sal_True );
2964         }
2965         pStart = pStart->GetNextCntntFrm();
2966     }
2967 
2968     ASSERT( pOldBoss->IsInSct() == pNewBoss->IsInSct(),
2969             "MoveLowerFtns: Section confusion" );
2970     SvPtrarr *pFtnArr;
2971     SwLayoutFrm* pNewChief = 0;
2972     SwLayoutFrm* pOldChief = 0;
2973     if( pStart && pOldBoss->IsInSct() && ( pOldChief = pOldBoss->FindSctFrm() )
2974         != ( pNewChief = pNewBoss->FindSctFrm() ) )
2975     {
2976         pFtnArr = new SvPtrarr( 5, 5 );
2977         pOldChief = pOldBoss->FindFtnBossFrm( sal_True );
2978         pNewChief = pNewBoss->FindFtnBossFrm( sal_True );
2979         while( pOldChief->IsAnLower( pStart ) )
2980         {
2981             if ( ((SwTxtFrm*)pStart)->HasFtn() )
2982                 ((SwFtnBossFrm*)pNewChief)->CollectFtns( pStart,
2983                                         (SwFtnBossFrm*)pOldBoss, *pFtnArr );
2984             pStart = pStart->GetNextCntntFrm();
2985         }
2986         if( !pFtnArr->Count() )
2987         {
2988             delete pFtnArr;
2989             pFtnArr = NULL;
2990         }
2991     }
2992     else
2993         pFtnArr = NULL;
2994 
2995     if ( aFtnArr.Count() || pFtnArr )
2996     {
2997         if( aFtnArr.Count() )
2998             pNewBoss->_MoveFtns( aFtnArr, sal_True );
2999         if( pFtnArr )
3000         {
3001             ((SwFtnBossFrm*)pNewChief)->_MoveFtns( *pFtnArr, sal_True );
3002             delete pFtnArr;
3003         }
3004         bMoved = sal_True;
3005 
3006         // Nur bei einem Seitenwechsel muss die FtnNum neu berechnet werden
3007         if ( bFtnNums )
3008         {
3009             SwPageFrm* pOldPage = pOldBoss->FindPageFrm();
3010             SwPageFrm* pNewPage =pNewBoss->FindPageFrm();
3011             if( pOldPage != pNewPage )
3012             {
3013                 pOldPage->UpdateFtnNum();
3014                 pNewPage->UpdateFtnNum();
3015             }
3016         }
3017     }
3018     return bMoved;
3019 }
3020 
3021 /*************************************************************************
3022 |*
3023 |*  SwLayoutFrm::MoveFtnCntFwd()
3024 |*
3025 |*************************************************************************/
3026 
3027 
3028 sal_Bool SwCntntFrm::MoveFtnCntFwd( sal_Bool bMakePage, SwFtnBossFrm *pOldBoss )
3029 {
3030     ASSERT( IsInFtn(), "Keine Ftn." );
3031     SwLayoutFrm *pFtn = FindFtnFrm();
3032 
3033     // The first paragraph in the first footnote in the first column in the
3034     // sectionfrm at the top of the page has not to move forward, if the
3035     // columnbody is empty.
3036     if( pOldBoss->IsInSct() && !pOldBoss->GetIndPrev() && !GetIndPrev() &&
3037         !pFtn->GetPrev() )
3038     {
3039         SwLayoutFrm* pBody = pOldBoss->FindBodyCont();
3040         if( !pBody || !pBody->Lower() )
3041             return sal_True;
3042     }
3043 
3044     //fix(9538): Wenn die Ftn noch Nachbarn hinter sich hat, so muessen
3045     //diese ersteinmal verschwinden.
3046     SwLayoutFrm *pNxt = (SwLayoutFrm*)pFtn->GetNext();
3047     SwLayoutFrm *pLst = 0;
3048     while ( pNxt )
3049     {
3050         while ( pNxt->GetNext() )
3051             pNxt = (SwLayoutFrm*)pNxt->GetNext();
3052         if ( pNxt == pLst )
3053             pNxt = 0;
3054         else
3055         {   pLst = pNxt;
3056             SwCntntFrm *pCnt = pNxt->ContainsCntnt();
3057             if( pCnt )
3058                 pCnt->MoveFtnCntFwd( sal_True, pOldBoss );
3059             pNxt = (SwLayoutFrm*)pFtn->GetNext();
3060         }
3061     }
3062 
3063     sal_Bool bSamePage = sal_True;
3064     SwLayoutFrm *pNewUpper =
3065                 GetLeaf( bMakePage ? MAKEPAGE_INSERT : MAKEPAGE_NONE, sal_True );
3066 
3067     if ( pNewUpper )
3068     {
3069         sal_Bool bSameBoss = sal_True;
3070         SwFtnBossFrm * const pNewBoss = pNewUpper->FindFtnBossFrm();
3071         //Wechseln wir die Spalte/Seite?
3072         if ( sal_False == ( bSameBoss = pNewBoss == pOldBoss ) )
3073         {
3074             bSamePage = pOldBoss->FindPageFrm() == pNewBoss->FindPageFrm(); // Seitenwechsel?
3075             pNewUpper->Calc();
3076         }
3077 
3078         //Das Layoutblatt, dass wir fuer Fussnoten bekommen ist entweder
3079         //ein Fussnotencontainer oder eine Fussnote
3080         //Wenn es eine Fussnote ist, und sie die gleiche Fussnotenreferez
3081         //wie der alte Upper hat, so moven wir uns direkt hinein.
3082         //Ist die Referenz einen andere oder ist es ein Container, so wird
3083         //eine neue Fussnote erzeugt und in den Container gestellt.
3084         // Wenn wir in einem Bereich innerhalb der Fussnote sind, muss
3085         // SectionFrame noch angelegt werden.
3086         SwFtnFrm* pTmpFtn = pNewUpper->IsFtnFrm() ? ((SwFtnFrm*)pNewUpper) : 0;
3087         if( !pTmpFtn )
3088         {
3089             ASSERT( pNewUpper->IsFtnContFrm(), "Neuer Upper kein FtnCont.");
3090             SwFtnContFrm *pCont = (SwFtnContFrm*)pNewUpper;
3091 
3092             //Fussnote erzeugen.
3093             SwFtnFrm *pOld = FindFtnFrm();
3094             pTmpFtn = new SwFtnFrm( pOld->GetFmt()->GetDoc()->GetDfltFrmFmt(),
3095                                     pOld, pOld->GetRef(), pOld->GetAttr() );
3096             //Verkettung der Fussnoten.
3097             if ( pOld->GetFollow() )
3098             {
3099                 pTmpFtn->SetFollow( pOld->GetFollow() );
3100                 pOld->GetFollow()->SetMaster( pTmpFtn );
3101             }
3102             pOld->SetFollow( pTmpFtn );
3103             pTmpFtn->SetMaster( pOld );
3104             SwFrm* pNx = pCont->Lower();
3105             if( pNx && pTmpFtn->GetAttr()->GetFtn().IsEndNote() )
3106                 while(pNx && !((SwFtnFrm*)pNx)->GetAttr()->GetFtn().IsEndNote())
3107                     pNx = pNx->GetNext();
3108             pTmpFtn->Paste( pCont, pNx );
3109             pTmpFtn->Calc();
3110         }
3111         ASSERT( pTmpFtn->GetAttr() == FindFtnFrm()->GetAttr(), "Wrong Footnote!" );
3112         // Bereiche in Fussnoten beduerfen besonderer Behandlung
3113         SwLayoutFrm *pNewUp = pTmpFtn;
3114         if( IsInSct() )
3115         {
3116             SwSectionFrm* pSect = FindSctFrm();
3117             // Bereich in Fussnote (oder nur Fussnote in Bereich)?
3118             if( pSect->IsInFtn() )
3119             {
3120                 if( pTmpFtn->Lower() && pTmpFtn->Lower()->IsSctFrm() &&
3121                     pSect->GetFollow() == (SwSectionFrm*)pTmpFtn->Lower() )
3122                     pNewUp = (SwSectionFrm*)pTmpFtn->Lower();
3123                 else
3124                 {
3125                     pNewUp = new SwSectionFrm( *pSect, sal_False );
3126                     pNewUp->InsertBefore( pTmpFtn, pTmpFtn->Lower() );
3127                     static_cast<SwSectionFrm*>(pNewUp)->Init();
3128                     pNewUp->Frm().Pos() = pTmpFtn->Frm().Pos();
3129                     pNewUp->Frm().Pos().Y() += 1; //wg. Benachrichtigungen.
3130 
3131                     // Wenn unser Bereichsframe einen Nachfolger hat, so muss dieser
3132                     // umgehaengt werden hinter den neuen Follow der Bereichsframes.
3133                     SwFrm* pTmp = pSect->GetNext();
3134                     if( pTmp )
3135                     {
3136                         SwFlowFrm* pTmpNxt;
3137                         if( pTmp->IsCntntFrm() )
3138                             pTmpNxt = (SwCntntFrm*)pTmp;
3139                         else if( pTmp->IsSctFrm() )
3140                             pTmpNxt = (SwSectionFrm*)pTmp;
3141                         else
3142                         {
3143                             ASSERT( pTmp->IsTabFrm(), "GetNextSctLeaf: Wrong Type" );
3144                             pTmpNxt = (SwTabFrm*)pTmp;
3145                         }
3146                         pTmpNxt->MoveSubTree( pTmpFtn, pNewUp->GetNext() );
3147                     }
3148                 }
3149             }
3150         }
3151 
3152         MoveSubTree( pNewUp, pNewUp->Lower() );
3153 
3154         if( !bSameBoss )
3155             Prepare( PREP_BOSS_CHGD );
3156     }
3157     return bSamePage;
3158 }
3159 
3160 /*************************************************************************
3161 |*
3162 |*  class SwSaveFtnHeight
3163 |*
3164 |*************************************************************************/
3165 
3166 
3167 SwSaveFtnHeight::SwSaveFtnHeight( SwFtnBossFrm *pBs, const SwTwips nDeadLine ) :
3168     pBoss( pBs ),
3169     nOldHeight( pBs->GetMaxFtnHeight() )
3170 {
3171     pBoss->SetFtnDeadLine( nDeadLine );
3172     nNewHeight = pBoss->GetMaxFtnHeight();
3173 }
3174 
3175 
3176 
3177 SwSaveFtnHeight::~SwSaveFtnHeight()
3178 {
3179     //Wenn zwischendurch jemand an der DeadLine gedreht hat, so lassen wir
3180     //ihm seinen Spass!
3181     if ( nNewHeight == pBoss->GetMaxFtnHeight() )
3182         pBoss->nMaxFtnHeight = nOldHeight;
3183 }
3184 
3185 
3186 #ifdef DBG_UTIL
3187 //JP 15.10.2001: in a non pro version test if the attribute has the same
3188 //              meaning which his reference is
3189 
3190 // Normally, the pRef member and the GetRefFromAttr() result has to be
3191 // identically. Sometimes footnote will be moved from a master to its follow,
3192 // but the GetRef() is called first, so we have to ignore a master/follow
3193 // mismatch.
3194 
3195 const SwCntntFrm* SwFtnFrm::GetRef() const
3196 {
3197     const SwCntntFrm* pRefAttr = GetRefFromAttr();
3198     ASSERT( pRef == pRefAttr || pRef->IsAnFollow( pRefAttr )
3199             || pRefAttr->IsAnFollow( pRef ),
3200             "access to deleted Frame? pRef != pAttr->GetRef()" );
3201     return pRef;
3202 }
3203 
3204 SwCntntFrm* SwFtnFrm::GetRef()
3205 {
3206     const SwCntntFrm* pRefAttr = GetRefFromAttr();
3207     ASSERT( pRef == pRefAttr || pRef->IsAnFollow( pRefAttr )
3208             || pRefAttr->IsAnFollow( pRef ),
3209             "access to deleted Frame? pRef != pAttr->GetRef()" );
3210     return pRef;
3211 }
3212 
3213 #endif
3214 
3215 const SwCntntFrm* SwFtnFrm::GetRefFromAttr()  const
3216 {
3217     SwFtnFrm* pThis = (SwFtnFrm*)this;
3218     return pThis->GetRefFromAttr();
3219 }
3220 
3221 SwCntntFrm* SwFtnFrm::GetRefFromAttr()
3222 {
3223     ASSERT( pAttr, "invalid Attribute" );
3224     SwTxtNode& rTNd = (SwTxtNode&)pAttr->GetTxtNode();
3225     SwPosition aPos( rTNd, SwIndex( &rTNd, *pAttr->GetStart() ));
3226     SwCntntFrm* pCFrm = rTNd.getLayoutFrm( getRootFrm(), 0, &aPos, sal_False );
3227     return pCFrm;
3228 }
3229 
3230 /** search for last content in the current footnote frame
3231 
3232     OD 2005-12-02 #i27138#
3233 
3234     @author OD
3235 */
3236 SwCntntFrm* SwFtnFrm::FindLastCntnt()
3237 {
3238     SwCntntFrm* pLastCntntFrm( 0L );
3239 
3240     // find last lower, which is a content frame or contains content.
3241     // hidden text frames, empty sections and empty tables have to be skipped.
3242     SwFrm* pLastLowerOfFtn( GetLower() );
3243     SwFrm* pTmpLastLower( pLastLowerOfFtn );
3244     while ( pTmpLastLower && pTmpLastLower->GetNext() )
3245     {
3246         pTmpLastLower = pTmpLastLower->GetNext();
3247         if ( ( pTmpLastLower->IsTxtFrm() &&
3248                !static_cast<SwTxtFrm*>(pTmpLastLower)->IsHiddenNow() ) ||
3249              ( pTmpLastLower->IsSctFrm() &&
3250                static_cast<SwSectionFrm*>(pTmpLastLower)->GetSection() &&
3251                static_cast<SwSectionFrm*>(pTmpLastLower)->ContainsCntnt() ) ||
3252              ( pTmpLastLower->IsTabFrm() &&
3253                static_cast<SwTabFrm*>(pTmpLastLower)->ContainsCntnt() ) )
3254         {
3255             pLastLowerOfFtn = pTmpLastLower;
3256         }
3257     }
3258 
3259     // determine last content frame depending on type of found last lower.
3260     if ( pLastLowerOfFtn && pLastLowerOfFtn->IsTabFrm() )
3261     {
3262         pLastCntntFrm = static_cast<SwTabFrm*>(pLastLowerOfFtn)->FindLastCntnt();
3263     }
3264     else if ( pLastLowerOfFtn && pLastLowerOfFtn->IsSctFrm() )
3265     {
3266         pLastCntntFrm = static_cast<SwSectionFrm*>(pLastLowerOfFtn)->FindLastCntnt();
3267     }
3268     else
3269     {
3270         pLastCntntFrm = dynamic_cast<SwCntntFrm*>(pLastLowerOfFtn);
3271     }
3272 
3273     return pLastCntntFrm;
3274 }
3275 
3276