Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / layout / ftnfrm.cxx
blob00c5db65a27d84adc614444473bef47988990d73
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <libxml/xmlwriter.h>
22 #include <txtftn.hxx>
23 #include <fmtftn.hxx>
24 #include <ftnidx.hxx>
25 #include <pagefrm.hxx>
26 #include <colfrm.hxx>
27 #include <rootfrm.hxx>
28 #include <frmtool.hxx>
29 #include <ftnfrm.hxx>
30 #include <txtfrm.hxx>
31 #include <tabfrm.hxx>
32 #include <pagedesc.hxx>
33 #include <ftninfo.hxx>
34 #include <sectfrm.hxx>
35 #include <objectformatter.hxx>
36 #include <viewopt.hxx>
37 #include <calbck.hxx>
38 #include <ndindex.hxx>
39 #include <pam.hxx>
40 #include <ndtxt.hxx>
41 #include <osl/diagnose.h>
42 #include <sal/log.hxx>
43 #include <IDocumentSettingAccess.hxx>
45 #define ENDNOTE 0x80000000
47 /// Search the position of an attribute in the FootnoteArray at the document,
48 /// because all footnotes are located there, ordered by their index.
49 static sal_uLong lcl_FindFootnotePos( const SwDoc *pDoc, const SwTextFootnote *pAttr )
51 const SwFootnoteIdxs &rFootnoteIdxs = pDoc->GetFootnoteIdxs();
53 SwTextFootnote* pBla = const_cast<SwTextFootnote*>(pAttr);
54 SwFootnoteIdxs::const_iterator it = rFootnoteIdxs.find( pBla );
55 if ( it != rFootnoteIdxs.end() )
57 sal_uLong nRet = it - rFootnoteIdxs.begin();
58 if( pAttr->GetFootnote().IsEndNote() )
59 return nRet + ENDNOTE;
60 return nRet;
62 OSL_ENSURE( !pDoc, "FootnotePos not found." );
63 return 0;
66 bool SwFootnoteFrame::operator<( const SwTextFootnote* pTextFootnote ) const
68 const SwDoc* pDoc = GetFormat()->GetDoc();
69 OSL_ENSURE( pDoc, "SwFootnoteFrame: Missing doc!" );
70 return lcl_FindFootnotePos( pDoc, GetAttr() ) <
71 lcl_FindFootnotePos( pDoc, pTextFootnote );
76 |* bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* pBoss, SwPageFrame* pPage)
77 |* sets pBoss on the next SwFootnoteBossFrame, which can either be a column
78 |* or a page (without columns). If the page changes meanwhile,
79 |* pPage contains the new page and this function returns true.
81 |*/
83 static bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* &rpBoss, SwPageFrame* &rpPage,
84 bool bDontLeave )
86 if( rpBoss->IsColumnFrame() )
88 if( rpBoss->GetNext() )
90 rpBoss = static_cast<SwFootnoteBossFrame*>(rpBoss->GetNext()); //next column
91 return false;
93 if( rpBoss->IsInSct() )
95 SwSectionFrame* pSct = rpBoss->FindSctFrame()->GetFollow();
96 if( pSct )
98 OSL_ENSURE( pSct->Lower() && pSct->Lower()->IsColumnFrame(),
99 "Where's the column?" );
100 rpBoss = static_cast<SwColumnFrame*>(pSct->Lower());
101 SwPageFrame* pOld = rpPage;
102 rpPage = pSct->FindPageFrame();
103 return pOld != rpPage;
105 else if( bDontLeave )
107 rpPage = nullptr;
108 rpBoss = nullptr;
109 return false;
113 rpPage = static_cast<SwPageFrame*>(rpPage->GetNext()); // next page
114 rpBoss = rpPage;
115 if( rpPage )
117 SwLayoutFrame* pBody = rpPage->FindBodyCont();
118 if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
119 rpBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower()); // first column
121 return true;
124 /// @returns column number if pBoss is a column, otherwise 0.
125 static sal_uInt16 lcl_ColumnNum( const SwFrame* pBoss )
127 sal_uInt16 nRet = 0;
128 if( !pBoss->IsColumnFrame() )
129 return 0;
130 const SwFrame* pCol;
131 if( pBoss->IsInSct() )
133 pCol = pBoss->GetUpper()->FindColFrame();
134 if( pBoss->GetNext() || pBoss->GetPrev() )
136 while( pBoss )
138 ++nRet; // Section columns
139 pBoss = pBoss->GetPrev();
143 else
144 pCol = pBoss;
145 while( pCol )
147 nRet += 256; // Page columns
148 pCol = pCol->GetPrev();
150 return nRet;
153 SwFootnoteContFrame::SwFootnoteContFrame( SwFrameFormat *pFormat, SwFrame* pSib ):
154 SwLayoutFrame( pFormat, pSib )
156 mnFrameType = SwFrameType::FtnCont;
159 SwFootnoteFrame* SwFootnoteContFrame::AddChained(bool bAppend, SwFrame* pThis, bool bDefaultFormat)
161 SwFootnoteFrame *pOld = pThis->FindFootnoteFrame();
162 SwFrameFormat *pFormat = pOld->GetFormat();
163 if (bDefaultFormat)
164 pFormat = pFormat->GetDoc()->GetDfltFrameFormat();
166 SwFootnoteFrame *pNew = new SwFootnoteFrame(pFormat, pOld, pOld->GetRef(), pOld->GetAttr());
168 if (bAppend)
170 if (pOld->GetFollow())
172 pNew->SetFollow(pOld->GetFollow());
173 pOld->GetFollow()->SetMaster(pNew);
175 pOld->SetFollow(pNew);
176 pNew->SetMaster(pOld);
178 else
180 if (pOld->GetMaster())
182 pNew->SetMaster(pOld->GetMaster());
183 pOld->GetMaster()->SetFollow(pNew);
185 pNew->SetFollow(pOld);
186 pOld->SetMaster(pNew);
189 return pNew;
192 // lcl_Undersize(..) walks over a SwFrame and its contents
193 // and returns the sum of all requested TextFrame magnifications.
195 static tools::Long lcl_Undersize( const SwFrame* pFrame )
197 tools::Long nRet = 0;
198 SwRectFnSet aRectFnSet(pFrame);
199 if( pFrame->IsTextFrame() )
201 if( static_cast<const SwTextFrame*>(pFrame)->IsUndersized() )
203 // Does this TextFrame would like to be a little bit bigger?
204 nRet = static_cast<const SwTextFrame*>(pFrame)->GetParHeight() -
205 aRectFnSet.GetHeight(pFrame->getFramePrintArea());
206 if( nRet < 0 )
207 nRet = 0;
210 else if( pFrame->IsLayoutFrame() )
212 const SwFrame* pNxt = static_cast<const SwLayoutFrame*>(pFrame)->Lower();
213 while( pNxt )
215 nRet += lcl_Undersize( pNxt );
216 pNxt = pNxt->GetNext();
219 return nRet;
222 namespace sw {
224 SwTwips FootnoteSeparatorHeight(SwPageFootnoteInfo const& rInf)
226 return rInf.GetTopDist() + rInf.GetBottomDist() + rInf.GetLineWidth();
229 } // namespace sw
231 /// "format" the frame (Fixsize is not set here).
232 void SwFootnoteContFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs * )
234 // calculate total border, only one distance to the top
235 const SwPageFrame* pPage = FindPageFrame();
236 const SwPageFootnoteInfo &rInf = pPage->GetPageDesc()->GetFootnoteInfo();
237 const SwTwips nBorder = sw::FootnoteSeparatorHeight(rInf);
238 SwRectFnSet aRectFnSet(this);
240 if ( !isFramePrintAreaValid() )
242 setFramePrintAreaValid(true);
243 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
245 aRectFnSet.SetTop( aPrt, nBorder );
246 aRectFnSet.SetWidth( aPrt, aRectFnSet.GetWidth(getFrameArea()) );
247 aRectFnSet.SetHeight(aPrt, aRectFnSet.GetHeight(getFrameArea()) - nBorder );
249 if( aRectFnSet.GetHeight(aPrt) < 0 && !pPage->IsFootnotePage() )
251 setFrameAreaSizeValid(false);
255 if ( isFrameAreaSizeValid() )
256 return;
258 bool bGrow = pPage->IsFootnotePage();
259 if( bGrow )
261 const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
262 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
263 bGrow = false;
265 if( bGrow )
266 Grow( LONG_MAX );
267 else
269 // VarSize is determined based on the content plus the borders
270 SwTwips nRemaining = 0;
271 SwFrame *pFrame = m_pLower;
272 while ( pFrame )
273 { // lcl_Undersize(..) respects (recursively) TextFrames, which
274 // would like to be bigger. They are created especially in
275 // columnized borders, if these do not have their maximum
276 // size yet.
277 nRemaining += aRectFnSet.GetHeight(pFrame->getFrameArea()) + lcl_Undersize( pFrame );
278 pFrame = pFrame->GetNext();
280 // add the own border
281 nRemaining += nBorder;
283 SwTwips nDiff;
284 if( IsInSct() )
286 nDiff = -aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()) );
287 if( nDiff > 0 )
289 if( nDiff > aRectFnSet.GetHeight(getFrameArea()) )
291 nDiff = aRectFnSet.GetHeight(getFrameArea());
294 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
295 aRectFnSet.AddBottom( aFrm, -nDiff );
296 aRectFnSet.AddHeight( aFrm, -nDiff );
299 nDiff = aRectFnSet.GetHeight(getFrameArea()) - nRemaining;
300 if ( nDiff > 0 )
301 Shrink( nDiff );
302 else if ( nDiff < 0 )
304 Grow( -nDiff );
305 // It may happen that there is less space available,
306 // than what the border needs - the size of the PrtArea
307 // will then be negative.
308 SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
309 if( nPrtHeight < 0 )
311 const SwTwips nTmpDiff = std::max( SwTwips(aRectFnSet.GetTop(getFramePrintArea())), -nPrtHeight );
312 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
313 aRectFnSet.SubTop( aPrt, nTmpDiff );
318 setFrameAreaSizeValid(true);
321 SwTwips SwFootnoteContFrame::GrowFrame( SwTwips nDist, bool bTst, bool )
323 // No check if FixSize since FootnoteContainer are variable up to their max. height.
324 // If the max. height is LONG_MAX, take as much space as needed.
325 // If the page is a special footnote page, take also as much as possible.
326 assert(GetUpper() && GetUpper()->IsFootnoteBossFrame());
328 SwRectFnSet aRectFnSet(this);
329 if( aRectFnSet.GetHeight(getFrameArea()) > 0 &&
330 nDist > ( LONG_MAX - aRectFnSet.GetHeight(getFrameArea()) ) )
331 nDist = LONG_MAX - aRectFnSet.GetHeight(getFrameArea());
333 SwFootnoteBossFrame *pBoss = static_cast<SwFootnoteBossFrame*>(GetUpper());
334 if( IsInSct() )
336 SwSectionFrame* pSect = FindSctFrame();
337 OSL_ENSURE( pSect, "GrowFrame: Missing SectFrame" );
338 // In a section, which has to maximize, a footnotecontainer is allowed
339 // to grow, when the section can't grow anymore.
340 if( !bTst && !pSect->IsColLocked() &&
341 pSect->ToMaximize( false ) && pSect->Growable() )
343 pSect->InvalidateSize();
344 return 0;
347 const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
348 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
349 SwPageFrame *pPage = pBoss->FindPageFrame();
350 if ( bBrowseMode || !pPage->IsFootnotePage() )
352 if ( pBoss->GetMaxFootnoteHeight() != LONG_MAX )
354 nDist = std::min( nDist,
355 SwTwips(pBoss->GetMaxFootnoteHeight() - aRectFnSet.GetHeight(getFrameArea())) );
356 if ( nDist <= 0 )
357 return 0;
359 // FootnoteBoss also influences the max value
360 if( !IsInSct() )
362 const SwTwips nMax = pBoss->GetVarSpace();
363 if ( nDist > nMax )
364 nDist = nMax;
365 if ( nDist <= 0 )
366 return 0;
369 else if( nDist > aRectFnSet.GetHeight(GetPrev()->getFrameArea()) )
370 // do not use more space than the body has
371 nDist = aRectFnSet.GetHeight(GetPrev()->getFrameArea());
373 tools::Long nAvail = 0;
374 if ( bBrowseMode )
376 nAvail = GetUpper()->getFramePrintArea().Height();
377 const SwFrame *pAvail = GetUpper()->Lower();
379 { nAvail -= pAvail->getFrameArea().Height();
380 pAvail = pAvail->GetNext();
381 } while ( pAvail );
382 if ( nAvail > nDist )
383 nAvail = nDist;
386 if ( !bTst )
388 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
389 aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nDist );
391 if( IsVertical() && !IsVertLR() )
393 aFrm.Pos().AdjustX( -nDist );
396 tools::Long nGrow = nDist - nAvail,
397 nReal = 0;
398 if ( nGrow > 0 )
400 SwNeighbourAdjust nAdjust = pBoss->NeighbourhoodAdjustment();
401 if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
402 nReal = AdjustNeighbourhood( nGrow, bTst );
403 else
405 if( SwNeighbourAdjust::GrowAdjust == nAdjust )
407 SwFrame* pFootnote = Lower();
408 if( pFootnote )
410 while( pFootnote->GetNext() )
411 pFootnote = pFootnote->GetNext();
412 if( static_cast<SwFootnoteFrame*>(pFootnote)->GetAttr()->GetFootnote().IsEndNote() )
414 nReal = AdjustNeighbourhood( nGrow, bTst );
415 nAdjust = SwNeighbourAdjust::GrowShrink; // no more AdjustNeighbourhood
419 nReal += pBoss->Grow( nGrow - nReal, bTst );
420 if( ( SwNeighbourAdjust::GrowAdjust == nAdjust || SwNeighbourAdjust::AdjustGrow == nAdjust )
421 && nReal < nGrow )
422 nReal += AdjustNeighbourhood( nGrow - nReal, bTst );
426 nReal += nAvail;
428 if ( !bTst )
430 if ( nReal != nDist )
432 nDist -= nReal;
434 // We can only respect the boundless wish so much
435 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
436 aFrm.AddHeight( -nDist );
438 if( IsVertical() && !IsVertLR() )
440 aFrm.Pos().AdjustX(nDist );
444 // growing happens upwards, so successors to not need to be invalidated
445 if( nReal )
447 InvalidateSize_();
448 InvalidatePos_();
449 InvalidatePage( pPage );
452 return nReal;
455 SwTwips SwFootnoteContFrame::ShrinkFrame( SwTwips nDiff, bool bTst, bool bInfo )
457 SwPageFrame *pPage = FindPageFrame();
458 bool bShrink = false;
459 if ( pPage )
461 if( !pPage->IsFootnotePage() )
462 bShrink = true;
463 else
465 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
466 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
467 bShrink = true;
470 if( bShrink )
472 SwTwips nRet = SwLayoutFrame::ShrinkFrame( nDiff, bTst, bInfo );
473 if( IsInSct() && !bTst )
474 FindSctFrame()->InvalidateNextPos();
475 if ( !bTst && nRet )
477 InvalidatePos_();
478 InvalidatePage( pPage );
480 return nRet;
482 return 0;
485 SwFootnoteFrame::SwFootnoteFrame( SwFrameFormat *pFormat, SwFrame* pSib, SwContentFrame *pCnt, SwTextFootnote *pAt ):
486 SwLayoutFrame( pFormat, pSib ),
487 mpFollow( nullptr ),
488 mpMaster( nullptr ),
489 mpReference( pCnt ),
490 mpAttribute( pAt ),
491 mbBackMoveLocked( false ),
492 // #i49383#
493 mbUnlockPosOfLowerObjs( true )
495 mnFrameType = SwFrameType::Ftn;
498 void SwFootnoteFrame::InvalidateNxtFootnoteCnts( SwPageFrame const *pPage )
500 if ( !GetNext() )
501 return;
503 SwFrame *pCnt = static_cast<SwLayoutFrame*>(GetNext())->ContainsAny();
504 if( !pCnt )
505 return;
507 pCnt->InvalidatePage( pPage );
508 pCnt->InvalidatePrt_();
510 { pCnt->InvalidatePos_();
511 if( pCnt->IsSctFrame() )
513 SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
514 if( pTmp )
515 pTmp->InvalidatePos_();
517 pCnt->GetUpper()->InvalidateSize_();
518 pCnt = pCnt->FindNext();
519 } while ( pCnt && GetUpper()->IsAnLower( pCnt ) );
522 bool SwFootnoteFrame::IsDeleteForbidden() const
524 if (SwLayoutFrame::IsDeleteForbidden())
525 return true;
526 // needs to be in sync with the ::Cut logic
527 const SwLayoutFrame *pUp = GetUpper();
528 if (pUp)
530 if (GetPrev())
531 return false;
533 // The last footnote takes its container along if it
534 // is deleted. Cut would put pUp->Lower() to the value
535 // of GetNext(), so if there is no GetNext then
536 // Cut would delete pUp. If that condition is true
537 // here then check if the container is delete-forbidden
538 return !GetNext() && pUp->IsDeleteForbidden();
540 return false;
543 void SwFootnoteFrame::Cut()
545 if ( GetNext() )
546 GetNext()->InvalidatePos();
547 else if ( GetPrev() )
548 GetPrev()->SetRetouche();
550 // first move then shrink Upper
551 SwLayoutFrame *pUp = GetUpper();
553 // correct chaining
554 SwFootnoteFrame *pFootnote = this;
555 if ( pFootnote->GetFollow() )
556 pFootnote->GetFollow()->SetMaster( pFootnote->GetMaster() );
557 if ( pFootnote->GetMaster() )
558 pFootnote->GetMaster()->SetFollow( pFootnote->GetFollow() );
559 pFootnote->SetFollow( nullptr );
560 pFootnote->SetMaster( nullptr );
562 // cut all connections
563 RemoveFromLayout();
565 if ( !pUp )
566 return;
568 // The last footnote takes its container along
569 if (!pUp->Lower())
571 SwPageFrame *pPage = pUp->FindPageFrame();
572 if ( pPage )
574 SwLayoutFrame *pBody = pPage->FindBodyCont();
575 if( pBody && !pBody->ContainsContent() )
576 pPage->getRootFrame()->SetSuperfluous();
578 SwSectionFrame* pSect = pUp->FindSctFrame();
579 pUp->Cut();
580 SwFrame::DestroyFrame(pUp);
581 // If the last footnote container was removed from a column
582 // section without a Follow, then this section can be shrunk.
583 if( pSect && !pSect->ToMaximize( false ) && !pSect->IsColLocked() )
584 pSect->InvalidateSize_();
586 else
587 { if ( getFrameArea().Height() )
588 pUp->Shrink( getFrameArea().Height() );
589 pUp->SetCompletePaint();
590 pUp->InvalidatePage();
594 void SwFootnoteFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
596 OSL_ENSURE( pParent, "no parent in Paste." );
597 OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
598 OSL_ENSURE( pParent != this, "I am my own parent." );
599 OSL_ENSURE( pSibling != this, "I am my own sibling." );
600 OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
601 "I am still somewhere registered." );
603 // insert into tree structure
604 InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
606 SwRectFnSet aRectFnSet(this);
607 if( aRectFnSet.GetWidth(getFrameArea())!=aRectFnSet.GetWidth(pParent->getFramePrintArea()) )
608 InvalidateSize_();
609 InvalidatePos_();
610 if (SwFrame *const pContent = ContainsContent())
611 { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
612 pContent->InvalidatePrt_();
614 SwPageFrame *pPage = FindPageFrame();
615 InvalidatePage( pPage );
616 if (SwFootnoteFrame *const pNext = static_cast<SwFootnoteFrame *>(GetNext()))
618 pNext->InvalidatePos_();
619 if (SwFrame *const pContent = pNext->ContainsContent())
620 { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
621 pContent->InvalidatePrt_();
624 if( aRectFnSet.GetHeight(getFrameArea()) )
625 pParent->Grow( aRectFnSet.GetHeight(getFrameArea()) );
627 // If the predecessor is the master and/or the successor is the Follow,
628 // then take their content and destroy them.
629 if ( GetPrev() && GetPrev() == GetMaster() )
631 OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetPrev()->GetLower() ),
632 "Footnote without content?" );
633 SwFlowFrame::CastFlowFrame( GetPrev()->GetLower())->
634 MoveSubTree( this, GetLower() );
635 SwFrame *pDel = GetPrev();
636 assert(pDel != this);
637 pDel->Cut();
638 SwFrame::DestroyFrame(pDel);
640 if ( GetNext() && GetNext() == GetFollow() )
642 OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetNext()->GetLower() ),
643 "Footnote without content?" );
644 SwFlowFrame::CastFlowFrame( GetNext()->GetLower() )->MoveSubTree( this );
645 SwFrame *pDel = GetNext();
646 assert(pDel != this);
647 pDel->Cut();
648 SwFrame::DestroyFrame(pDel);
650 #if OSL_DEBUG_LEVEL > 0
651 SwDoc *pDoc = GetFormat()->GetDoc();
652 if ( GetPrev() )
654 OSL_ENSURE( lcl_FindFootnotePos( pDoc, static_cast<SwFootnoteFrame*>(GetPrev())->GetAttr() ) <=
655 lcl_FindFootnotePos( pDoc, GetAttr() ), "Prev is not FootnotePrev" );
657 if ( GetNext() )
659 OSL_ENSURE( lcl_FindFootnotePos( pDoc, GetAttr() ) <=
660 lcl_FindFootnotePos( pDoc, static_cast<SwFootnoteFrame*>(GetNext())->GetAttr() ),
661 "Next is not FootnoteNext" );
663 #endif
664 InvalidateNxtFootnoteCnts( pPage );
667 /// Return the next layout leaf in that the frame can be moved.
668 /// New pages will only be created if specified by the parameter.
669 SwLayoutFrame *SwFrame::GetNextFootnoteLeaf( MakePageType eMakePage )
671 SwFootnoteBossFrame *pOldBoss = FindFootnoteBossFrame();
672 SwPageFrame* pOldPage = pOldBoss->FindPageFrame();
673 SwPageFrame* pPage;
674 SwFootnoteBossFrame *pBoss = pOldBoss->IsColumnFrame() ?
675 static_cast<SwFootnoteBossFrame*>(pOldBoss->GetNext()) : nullptr; // next column, if existing
676 if( pBoss )
677 pPage = nullptr;
678 else
680 if( pOldBoss->GetUpper()->IsSctFrame() )
681 { // this can only be in a column area
682 SwLayoutFrame* pNxt = pOldBoss->GetNextSctLeaf( eMakePage );
683 if( pNxt )
685 OSL_ENSURE( pNxt->IsColBodyFrame(), "GetNextFootnoteLeaf: Funny Leaf" );
686 pBoss = static_cast<SwFootnoteBossFrame*>(pNxt->GetUpper());
687 pPage = pBoss->FindPageFrame();
689 else
690 return nullptr;
692 else
694 // next page
695 pPage = static_cast<SwPageFrame*>(pOldPage->GetNext());
696 // skip empty pages
697 if( pPage && pPage->IsEmptyPage() )
698 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
699 pBoss = pPage;
702 // What do we have until here?
703 // pBoss != NULL, pPage==NULL => pBoss is the next column on the same page
704 // pBoss != NULL, pPage!=NULL => pBoss and pPage are the following page (empty pages skipped)
705 // pBoss == NULL => pPage == NULL, so there are no following pages
707 // If the footnote has already a Follow we do not need to search.
708 // However, if there are unwanted empty columns/pages between Footnote and Follow,
709 // create another Follow on the next best column/page and the rest will sort itself out.
710 SwFootnoteFrame *pFootnote = FindFootnoteFrame();
711 if ( pFootnote && pFootnote->GetFollow() )
713 SwFootnoteBossFrame* pTmpBoss = pFootnote->GetFollow()->FindFootnoteBossFrame();
714 // Following cases will be handled:
715 // 1. both "FootnoteBoss"es are neighboring columns/pages
716 // 2. the new one is the first column of a neighboring page
717 // 3. the new one is the first column in a section of the next page
718 while( pTmpBoss != pBoss && pTmpBoss && !pTmpBoss->GetPrev() )
719 pTmpBoss = pTmpBoss->GetUpper()->FindFootnoteBossFrame();
720 if( pTmpBoss == pBoss )
721 return pFootnote->GetFollow();
724 // If no pBoss could be found or it is a "wrong" page, we need a new page.
725 if ( !pBoss || ( pPage && pPage->IsEndNotePage() && !pOldPage->IsEndNotePage() ) )
727 if ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT )
729 pBoss = InsertPage( pOldPage, pOldPage->IsFootnotePage() );
730 static_cast<SwPageFrame*>(pBoss)->SetEndNotePage( pOldPage->IsEndNotePage() );
732 else
733 return nullptr;
735 if( pBoss->IsPageFrame() )
737 // If this page has columns, then go to the first one
738 SwLayoutFrame* pLay = pBoss->FindBodyCont();
739 if( pLay && pLay->Lower() && pLay->Lower()->IsColumnFrame() )
740 pBoss = static_cast<SwFootnoteBossFrame*>(pLay->Lower());
742 // found column/page - add myself
743 SwFootnoteContFrame *pCont = pBoss->FindFootnoteCont();
744 if ( !pCont && pBoss->GetMaxFootnoteHeight() &&
745 ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) )
746 pCont = pBoss->MakeFootnoteCont();
747 return pCont;
750 /// Get the preceding layout leaf in that the frame can be moved.
751 SwLayoutFrame *SwFrame::GetPrevFootnoteLeaf( MakePageType eMakeFootnote )
753 // The predecessor of a footnote is (if possible)
754 // the master of the chain of the footnote.
755 SwFootnoteFrame *pFootnote = FindFootnoteFrame();
756 SwLayoutFrame *pRet = pFootnote->GetMaster();
758 SwFootnoteBossFrame* pOldBoss = FindFootnoteBossFrame();
759 SwPageFrame *pOldPage = pOldBoss->FindPageFrame();
761 if ( !pOldBoss->GetPrev() && !pOldPage->GetPrev() )
762 return pRet; // there is neither a predecessor column nor page
764 if ( !pRet )
766 bool bEndn = pFootnote->GetAttr()->GetFootnote().IsEndNote();
767 SwFrame* pTmpRef = nullptr;
768 const IDocumentSettingAccess& rSettings
769 = pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
770 if( bEndn && pFootnote->IsInSct() )
772 SwSectionFrame* pSect = pFootnote->FindSctFrame();
773 if( pSect->IsEndnAtEnd() )
774 // Endnotes at the end of the section.
775 pTmpRef = pSect->FindLastContent( SwFindMode::LastCnt );
777 else if (bEndn && rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
779 // Endnotes at the end of the document.
780 SwPageFrame* pPage = getRootFrame()->GetLastPage();
781 assert(pPage);
782 SwFrame* pPrevPage = pPage->GetPrev();
783 if (pPrevPage)
785 // Have a last but one page, use that since we try to get a preceding frame.
786 assert(pPrevPage->IsPageFrame());
787 pPage = static_cast<SwPageFrame*>(pPrevPage);
789 pTmpRef = pPage->FindLastBodyContent();
791 if( !pTmpRef )
792 // Endnotes on a separate page.
793 pTmpRef = pFootnote->GetRef();
794 SwFootnoteBossFrame* pStop = pTmpRef->FindFootnoteBossFrame( !bEndn );
796 const sal_uInt16 nNum = pStop->GetPhyPageNum();
798 // Do not leave the corresponding page if the footnote should
799 // be shown at the document ending or the footnote is an endnote.
800 const bool bEndNote = pOldPage->IsEndNotePage();
801 const bool bFootnoteEndDoc = pOldPage->IsFootnotePage();
802 SwFootnoteBossFrame* pNxtBoss = pOldBoss;
803 SwSectionFrame *pSect = pNxtBoss->GetUpper()->IsSctFrame() ?
804 static_cast<SwSectionFrame*>(pNxtBoss->GetUpper()) : nullptr;
808 if( pNxtBoss->IsColumnFrame() && pNxtBoss->GetPrev() )
809 pNxtBoss = static_cast<SwFootnoteBossFrame*>(pNxtBoss->GetPrev()); // one column backwards
810 else // one page backwards
812 SwLayoutFrame* pBody = nullptr;
813 if( pSect )
815 if( pSect->IsFootnoteLock() )
817 if( pNxtBoss == pOldBoss )
818 return nullptr;
819 pStop = pNxtBoss;
821 else
823 pSect = pSect->FindMaster();
824 if( !pSect || !pSect->Lower() )
825 return nullptr;
826 OSL_ENSURE( pSect->Lower()->IsColumnFrame(),
827 "GetPrevFootnoteLeaf: Where's the column?" );
828 pNxtBoss = static_cast<SwFootnoteBossFrame*>(pSect->Lower());
829 pBody = pSect;
832 else
834 SwPageFrame* pPage = static_cast<SwPageFrame*>(pNxtBoss->FindPageFrame()->GetPrev());
835 if( !pPage || pPage->GetPhyPageNum() < nNum ||
836 bEndNote != pPage->IsEndNotePage() || bFootnoteEndDoc != pPage->IsFootnotePage() )
837 return nullptr; // no further pages found
838 pNxtBoss = pPage;
839 pBody = pPage->FindBodyCont();
841 // We have the previous page, we might need to find the last column of it
842 if( pBody )
844 if ( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
846 pNxtBoss = static_cast<SwFootnoteBossFrame*>(pBody->GetLastLower());
850 SwFootnoteContFrame *pCont = pNxtBoss->FindFootnoteCont();
851 if ( pCont )
853 pRet = pCont;
854 break;
856 if ( pStop == pNxtBoss )
858 // Reached the column/page of the reference.
859 // Try to add a container and paste our content.
860 if ( eMakeFootnote == MAKEPAGE_FTN && pNxtBoss->GetMaxFootnoteHeight() )
861 pRet = pNxtBoss->MakeFootnoteCont();
862 break;
864 } while( !pRet );
866 if ( pRet )
868 const SwFootnoteBossFrame* pNewBoss = pRet->FindFootnoteBossFrame();
869 bool bJump = false;
870 if( pOldBoss->IsColumnFrame() && pOldBoss->GetPrev() ) // a previous column exists
871 bJump = pOldBoss->GetPrev() != static_cast<SwFrame const *>(pNewBoss); // did we chose it?
872 else if( pNewBoss->IsColumnFrame() && pNewBoss->GetNext() )
873 bJump = true; // there is another column after the boss (not the old boss)
874 else
876 // Will be reached only if old and new boss are both either pages or the last (new)
877 // or first (old) column of a page. In this case, check if pages were skipped.
878 const sal_uInt16 nDiff = pOldPage->GetPhyPageNum() - pRet->FindPageFrame()->GetPhyPageNum();
879 if ( nDiff > 2 ||
880 (nDiff > 1 && !static_cast<SwPageFrame*>(pOldPage->GetPrev())->IsEmptyPage()) )
881 bJump = true;
883 if( bJump )
884 SwFlowFrame::SetMoveBwdJump( true );
886 return pRet;
889 bool SwFrame::IsFootnoteAllowed() const
891 if ( !IsInDocBody() )
892 return false;
894 if ( IsInTab() )
896 // no footnotes in repeated headlines
897 const SwTabFrame *pTab = const_cast<SwFrame*>(this)->ImplFindTabFrame();
898 assert(pTab);
899 if ( pTab->IsFollow() )
900 return !pTab->IsInHeadline( *this );
902 return true;
905 void SwRootFrame::UpdateFootnoteNums()
907 // page numbering only if set at the document
908 if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum == FTNNUM_PAGE )
910 SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
911 while ( pPage && !pPage->IsFootnotePage() )
913 pPage->UpdateFootnoteNum();
914 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
919 /// remove all footnotes (not the references) and all footnote pages
920 void sw_RemoveFootnotes( SwFootnoteBossFrame* pBoss, bool bPageOnly, bool bEndNotes )
924 SwFootnoteContFrame *pCont = pBoss->FindFootnoteCont();
925 if ( pCont )
927 SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
928 assert(pFootnote);
929 if ( bPageOnly )
930 while ( pFootnote->GetMaster() )
931 pFootnote = pFootnote->GetMaster();
934 SwFootnoteFrame *pNxt = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
935 if ( !pFootnote->GetAttr()->GetFootnote().IsEndNote() ||
936 bEndNotes )
938 pFootnote->GetRef()->Prepare( PrepareHint::FootnoteInvalidation, static_cast<void*>(pFootnote->GetAttr()) );
939 if ( bPageOnly && !pNxt )
940 pNxt = pFootnote->GetFollow();
941 pFootnote->Cut();
942 SwFrame::DestroyFrame(pFootnote);
944 pFootnote = pNxt;
946 } while ( pFootnote );
948 if( !pBoss->IsInSct() )
950 // A sectionframe with the Footnote/EndnAtEnd-flags may contain
951 // foot/endnotes. If the last lower frame of the bodyframe is
952 // a multicolumned sectionframe, it may contain footnotes, too.
953 SwLayoutFrame* pBody = pBoss->FindBodyCont();
954 if( pBody && pBody->Lower() )
956 SwFrame* pLow = pBody->Lower();
957 while (pLow)
959 if( pLow->IsSctFrame() && ( !pLow->GetNext() ||
960 static_cast<SwSectionFrame*>(pLow)->IsAnyNoteAtEnd() ) &&
961 static_cast<SwSectionFrame*>(pLow)->Lower() &&
962 static_cast<SwSectionFrame*>(pLow)->Lower()->IsColumnFrame() )
963 sw_RemoveFootnotes( static_cast<SwColumnFrame*>(static_cast<SwSectionFrame*>(pLow)->Lower()),
964 bPageOnly, bEndNotes );
965 pLow = pLow->GetNext();
969 // is there another column?
970 pBoss = pBoss->IsColumnFrame() ? static_cast<SwColumnFrame*>(pBoss->GetNext()) : nullptr;
971 } while( pBoss );
974 void SwRootFrame::RemoveFootnotes( SwPageFrame *pPage, bool bPageOnly, bool bEndNotes )
976 if ( !pPage )
977 pPage = static_cast<SwPageFrame*>(Lower());
980 { // On columned pages we have to clean up in all columns
981 SwFootnoteBossFrame* pBoss;
982 SwLayoutFrame* pBody = pPage->FindBodyCont();
983 if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
984 pBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower()); // the first column
985 else
986 pBoss = pPage; // no columns
987 sw_RemoveFootnotes( pBoss, bPageOnly, bEndNotes );
988 if ( !bPageOnly )
990 if ( pPage->IsFootnotePage() &&
991 (!pPage->IsEndNotePage() || bEndNotes) )
993 SwFrame *pDel = pPage;
994 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
995 pDel->Cut();
996 SwFrame::DestroyFrame(pDel);
998 else
999 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1001 else
1002 break;
1004 } while ( pPage );
1007 /// Change the page template of the footnote pages
1008 void SwRootFrame::CheckFootnotePageDescs( bool bEndNote )
1010 SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
1011 while ( pPage && !pPage->IsFootnotePage() )
1012 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1013 while ( pPage && pPage->IsEndNotePage() != bEndNote )
1014 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1016 if ( pPage )
1017 SwFrame::CheckPageDescs( pPage, false );
1020 /** Insert a footnote container
1022 * A footnote container is always placed directly behind the body text.
1024 * The frame format (FrameFormat) is always the default frame format.
1026 * @return footnote container frame
1028 SwFootnoteContFrame *SwFootnoteBossFrame::MakeFootnoteCont()
1030 SAL_WARN_IF(FindFootnoteCont(), "sw.core", "footnote container exists already");
1032 SwFootnoteContFrame *pNew = new SwFootnoteContFrame( GetFormat()->GetDoc()->GetDfltFrameFormat(), this );
1033 SwLayoutFrame *pLay = FindBodyCont();
1034 pNew->Paste( this, pLay->GetNext() );
1035 return pNew;
1038 SwFootnoteContFrame *SwFootnoteBossFrame::FindFootnoteCont()
1040 SwFrame *pFrame = Lower();
1041 while( pFrame && !pFrame->IsFootnoteContFrame() )
1042 pFrame = pFrame->GetNext();
1044 #if OSL_DEBUG_LEVEL > 0
1045 if ( pFrame )
1047 SwFrame *pFootnote = pFrame->GetLower();
1048 assert(pFootnote);
1049 while ( pFootnote )
1051 assert(pFootnote->IsFootnoteFrame() && "Neighbor of footnote must be a footnote");
1052 pFootnote = pFootnote->GetNext();
1055 #endif
1057 return static_cast<SwFootnoteContFrame*>(pFrame);
1060 /// Search the next available footnote container.
1061 SwFootnoteContFrame *SwFootnoteBossFrame::FindNearestFootnoteCont( bool bDontLeave )
1063 SwFootnoteContFrame *pCont = nullptr;
1064 if ( !GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
1066 pCont = FindFootnoteCont();
1067 if ( !pCont )
1069 SwPageFrame *pPage = FindPageFrame();
1070 SwFootnoteBossFrame* pBoss = this;
1071 bool bEndNote = pPage->IsEndNotePage();
1074 bool bChgPage = lcl_NextFootnoteBoss( pBoss, pPage, bDontLeave );
1075 // Found another boss? When changing pages, also the endnote flag must match.
1076 if( pBoss && ( !bChgPage || pPage->IsEndNotePage() == bEndNote ) )
1077 pCont = pBoss->FindFootnoteCont();
1078 } while ( !pCont && pPage );
1081 return pCont;
1084 SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote()
1086 // search for the nearest footnote container
1087 SwFootnoteContFrame *pCont = FindNearestFootnoteCont();
1088 if ( !pCont )
1089 return nullptr;
1091 // Starting from the first footnote, search the first
1092 // footnote that is referenced by the current column/page
1094 SwFootnoteFrame *pRet = static_cast<SwFootnoteFrame*>(pCont->Lower());
1095 const sal_uInt16 nRefNum = FindPageFrame()->GetPhyPageNum();
1096 const sal_uInt16 nRefCol = lcl_ColumnNum( this );
1097 sal_uInt16 nPgNum, nColNum; // page number, column number
1098 SwFootnoteBossFrame* pBoss;
1099 SwPageFrame* pPage;
1100 if( pRet )
1102 pBoss = pRet->GetRef()->FindFootnoteBossFrame();
1103 OSL_ENSURE( pBoss, "FindFirstFootnote: No boss found" );
1104 if( !pBoss )
1105 return nullptr; // ?There must be a bug, but no GPF
1106 pPage = pBoss->FindPageFrame();
1107 nPgNum = pPage->GetPhyPageNum();
1108 if ( nPgNum == nRefNum )
1110 nColNum = lcl_ColumnNum( pBoss );
1111 if( nColNum == nRefCol )
1112 return pRet; // found
1113 else if( nColNum > nRefCol )
1114 return nullptr; // at least one column too far
1116 else if ( nPgNum > nRefNum )
1117 return nullptr; // at least one column too far
1119 else
1120 return nullptr;
1121 // Done if Ref is on a subsequent page or on the same page in a subsequent column
1125 while ( pRet->GetFollow() )
1126 pRet = pRet->GetFollow();
1128 SwFootnoteFrame *pNxt = static_cast<SwFootnoteFrame*>(pRet->GetNext());
1129 if ( !pNxt )
1131 pBoss = pRet->FindFootnoteBossFrame();
1132 pPage = pBoss->FindPageFrame();
1133 lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss
1134 pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr;
1135 if ( pCont )
1136 pNxt = static_cast<SwFootnoteFrame*>(pCont->Lower());
1138 if ( pNxt )
1140 pRet = pNxt;
1141 pBoss = pRet->GetRef()->FindFootnoteBossFrame();
1142 pPage = pBoss->FindPageFrame();
1143 nPgNum = pPage->GetPhyPageNum();
1144 if ( nPgNum == nRefNum )
1146 nColNum = lcl_ColumnNum( pBoss );
1147 if( nColNum == nRefCol )
1148 break; // found
1149 else if( nColNum > nRefCol )
1150 pRet = nullptr; // at least one column too far
1152 else if ( nPgNum > nRefNum )
1153 pRet = nullptr; // at least a page too far
1155 else
1156 pRet = nullptr; // there is none
1157 } while( pRet );
1158 return pRet;
1161 /// Get the first footnote of a given content
1162 const SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote( SwContentFrame const *pCnt ) const
1164 const SwFootnoteFrame *pRet = const_cast<SwFootnoteBossFrame*>(this)->FindFirstFootnote();
1165 if ( pRet )
1167 const sal_uInt16 nColNum = lcl_ColumnNum( this );
1168 const sal_uInt16 nPageNum = GetPhyPageNum();
1169 while ( pRet && (pRet->GetRef() != pCnt) )
1171 while ( pRet->GetFollow() )
1172 pRet = pRet->GetFollow();
1174 if ( pRet->GetNext() )
1175 pRet = static_cast<const SwFootnoteFrame*>(pRet->GetNext());
1176 else
1177 { SwFootnoteBossFrame *pBoss = const_cast<SwFootnoteBossFrame*>(pRet->FindFootnoteBossFrame());
1178 SwPageFrame *pPage = pBoss->FindPageFrame();
1179 lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss
1180 SwFootnoteContFrame *pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr;
1181 pRet = pCont ? static_cast<SwFootnoteFrame*>(pCont->Lower()) : nullptr;
1183 if ( pRet )
1185 const SwFootnoteBossFrame* pBoss = pRet->GetRef()->FindFootnoteBossFrame();
1186 if( !pBoss || pBoss->GetPhyPageNum() != nPageNum ||
1187 nColNum != lcl_ColumnNum( pBoss ) )
1188 pRet = nullptr;
1192 return pRet;
1195 void SwFootnoteBossFrame::ResetFootnote( const SwFootnoteFrame *pCheck )
1197 // Destroy the incarnations of footnotes to an attribute, if they don't
1198 // belong to pAssumed
1199 OSL_ENSURE( !pCheck->GetMaster(), "given master is not a Master." );
1201 SwNodeIndex aIdx( *pCheck->GetAttr()->GetStartNode(), 1 );
1202 SwContentNode *pNd = aIdx.GetNode().GetContentNode();
1203 if ( !pNd )
1204 pNd = pCheck->GetFormat()->GetDoc()->
1205 GetNodes().GoNextSection( &aIdx, true, false );
1206 SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
1207 SwFrame* pFrame = aIter.First();
1208 while( pFrame )
1210 if( pFrame->getRootFrame() == pCheck->getRootFrame() )
1212 SwFrame *pTmp = pFrame->GetUpper();
1213 while ( pTmp && !pTmp->IsFootnoteFrame() )
1214 pTmp = pTmp->GetUpper();
1216 SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pTmp);
1217 while ( pFootnote && pFootnote->GetMaster() )
1218 pFootnote = pFootnote->GetMaster();
1219 if ( pFootnote != pCheck )
1221 while (pFootnote && !pFootnote->IsDeleteForbidden())
1223 SwFootnoteFrame *pNxt = pFootnote->GetFollow();
1224 pFootnote->Cut();
1225 SwFrame::DestroyFrame(pFootnote);
1226 pFootnote = pNxt;
1231 pFrame = aIter.Next();
1235 void SwFootnoteBossFrame::InsertFootnote( SwFootnoteFrame* pNew )
1237 // Place the footnote in front of the footnote whose attribute
1238 // is in front of the new one (get position via the Doc).
1239 // If there is no footnote in this footnote-boss yet, create a new container.
1240 // If there is a container but no footnote for this footnote-boss yet, place
1241 // the footnote behind the last footnote of the closest previous column/page.
1243 ResetFootnote( pNew );
1244 SwFootnoteFrame *pSibling = FindFirstFootnote();
1245 bool bDontLeave = false;
1247 // Ok, a sibling has been found, but is the sibling in an acceptable
1248 // environment?
1249 if( IsInSct() )
1251 SwSectionFrame* pMySect = ImplFindSctFrame();
1252 bool bEndnt = pNew->GetAttr()->GetFootnote().IsEndNote();
1253 if( bEndnt )
1255 const SwSectionFormat* pEndFormat = pMySect->GetEndSectFormat();
1256 bDontLeave = nullptr != pEndFormat;
1257 if( pSibling )
1259 if( pEndFormat )
1261 if( !pSibling->IsInSct() ||
1262 !pSibling->ImplFindSctFrame()->IsDescendantFrom( pEndFormat ) )
1263 pSibling = nullptr;
1265 else if( pSibling->IsInSct() )
1266 pSibling = nullptr;
1269 else
1271 bDontLeave = pMySect->IsFootnoteAtEnd();
1272 if( pSibling )
1274 if( pMySect->IsFootnoteAtEnd() )
1276 if( !pSibling->IsInSct() ||
1277 !pMySect->IsAnFollow( pSibling->ImplFindSctFrame() ) )
1278 pSibling = nullptr;
1280 else if( pSibling->IsInSct() )
1281 pSibling = nullptr;
1286 if( pSibling && pSibling->FindPageFrame()->IsEndNotePage() !=
1287 FindPageFrame()->IsEndNotePage() )
1288 pSibling = nullptr;
1290 // use the Doc to find out the position
1291 SwDoc *pDoc = GetFormat()->GetDoc();
1292 const sal_uLong nStPos = ::lcl_FindFootnotePos( pDoc, pNew->GetAttr() );
1294 sal_uLong nCmpPos = 0;
1295 sal_uLong nLastPos = 0;
1296 SwFootnoteContFrame *pParent = nullptr;
1297 if( pSibling )
1299 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1300 if( nCmpPos > nStPos )
1301 pSibling = nullptr;
1304 if ( !pSibling )
1305 { pParent = FindFootnoteCont();
1306 if ( !pParent )
1308 // There is no footnote container yet. Before creating one, keep in mind that
1309 // there might exist another following footnote that must be placed before the
1310 // new inserted one e.g. because it was divided over multiple pages etc.
1311 pParent = FindNearestFootnoteCont( bDontLeave );
1312 if ( pParent )
1314 SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pParent->Lower());
1315 if ( pFootnote )
1318 nCmpPos = ::lcl_FindFootnotePos( pDoc, pFootnote->GetAttr() );
1319 if ( nCmpPos > nStPos )
1320 pParent = nullptr;
1322 else
1323 pParent = nullptr;
1326 if ( !pParent )
1327 // here, we are sure that we can create a footnote container
1328 pParent = MakeFootnoteCont();
1329 else
1331 // Based on the first footnote below the Parent, search for the first footnote whose
1332 // index is after the index of the newly inserted, to place the new one correctly
1333 pSibling = static_cast<SwFootnoteFrame*>(pParent->Lower());
1334 if ( !pSibling )
1336 OSL_ENSURE( false, "Could not find space for footnote.");
1337 return;
1339 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1341 SwFootnoteBossFrame *pNxtB; // remember the last one to not
1342 SwFootnoteFrame *pLastSib = nullptr; // go too far.
1344 while ( pSibling && nCmpPos <= nStPos )
1346 pLastSib = pSibling; // potential candidate
1347 nLastPos = nCmpPos;
1349 while ( pSibling->GetFollow() )
1350 pSibling = pSibling->GetFollow();
1352 if ( pSibling->GetNext() )
1354 pSibling = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
1355 OSL_ENSURE( !pSibling->GetMaster() || ( ENDNOTE > nStPos &&
1356 pSibling->GetAttr()->GetFootnote().IsEndNote() ),
1357 "InsertFootnote: Master expected I" );
1359 else
1361 pNxtB = pSibling->FindFootnoteBossFrame();
1362 SwPageFrame *pSibPage = pNxtB->FindPageFrame();
1363 bool bEndNote = pSibPage->IsEndNotePage();
1364 bool bChgPage = lcl_NextFootnoteBoss( pNxtB, pSibPage, bDontLeave );
1365 // When changing pages, also the endnote flag must match.
1366 SwFootnoteContFrame *pCont = pNxtB && ( !bChgPage ||
1367 pSibPage->IsEndNotePage() == bEndNote )
1368 ? pNxtB->FindNearestFootnoteCont( bDontLeave ) : nullptr;
1369 if( pCont )
1370 pSibling = static_cast<SwFootnoteFrame*>(pCont->Lower());
1371 else // no further FootnoteContainer, insert after pSibling
1372 break;
1374 if ( pSibling )
1376 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1377 OSL_ENSURE( nCmpPos > nLastPos, "InsertFootnote: Order of FootnoteFrame's buggy" );
1380 // pLastSib is the last footnote before the new one and
1381 // pSibling is empty or the first one after the new one
1382 if ( pSibling && pLastSib && (pSibling != pLastSib) )
1384 // too far?
1385 if ( nCmpPos > nStPos )
1386 pSibling = pLastSib;
1388 else if ( !pSibling )
1390 // Last chance: Take the last footnote of the parent.
1391 // Special case that happens e.g. when moving paragraphs with multiple footnotes.
1392 // To keep the order, use the parent of the last inspected footnote.
1393 pSibling = pLastSib;
1394 while( pSibling->GetFollow() )
1395 pSibling = pSibling->GetFollow();
1396 OSL_ENSURE( !pSibling->GetNext(), "InsertFootnote: Who's that guy?" );
1400 else
1402 // First footnote of the column/page found. Now search from there for the first one on the
1403 // same column/page whose index is after the given one. The last one found is the predecessor.
1404 SwFootnoteBossFrame* pBoss = pNew->GetRef()->FindFootnoteBossFrame(
1405 !pNew->GetAttr()->GetFootnote().IsEndNote() );
1406 sal_uInt16 nRefNum = pBoss->GetPhyPageNum(); // page number of the new footnote
1407 sal_uInt16 nRefCol = lcl_ColumnNum( pBoss ); // column number of the new footnote
1408 bool bEnd = false;
1409 SwFootnoteFrame *pLastSib = nullptr;
1410 while ( pSibling && !bEnd && (nCmpPos <= nStPos) )
1412 pLastSib = pSibling;
1413 nLastPos = nCmpPos;
1415 while ( pSibling->GetFollow() )
1416 pSibling = pSibling->GetFollow();
1418 SwFootnoteFrame *pFoll = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
1419 if ( pFoll )
1421 pBoss = pSibling->GetRef()->FindFootnoteBossFrame( !pSibling->
1422 GetAttr()->GetFootnote().IsEndNote() );
1423 sal_uInt16 nTmpRef;
1424 if( nStPos >= ENDNOTE ||
1425 (nTmpRef = pBoss->GetPhyPageNum()) < nRefNum ||
1426 ( nTmpRef == nRefNum && lcl_ColumnNum( pBoss ) <= nRefCol ))
1427 pSibling = pFoll;
1428 else
1429 bEnd = true;
1431 else
1433 SwFootnoteBossFrame* pNxtB = pSibling->FindFootnoteBossFrame();
1434 SwPageFrame *pSibPage = pNxtB->FindPageFrame();
1435 bool bEndNote = pSibPage->IsEndNotePage();
1436 bool bChgPage = lcl_NextFootnoteBoss( pNxtB, pSibPage, bDontLeave );
1437 // When changing pages, also the endnote flag must match.
1438 SwFootnoteContFrame *pCont = pNxtB && ( !bChgPage ||
1439 pSibPage->IsEndNotePage() == bEndNote )
1440 ? pNxtB->FindNearestFootnoteCont( bDontLeave ) : nullptr;
1441 if ( pCont )
1442 pSibling = static_cast<SwFootnoteFrame*>(pCont->Lower());
1443 else
1444 bEnd = true;
1446 if ( !bEnd && pSibling )
1447 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1448 if (pSibling && (pSibling != pLastSib))
1450 // too far?
1451 if ( (nLastPos < nCmpPos) && (nCmpPos > nStPos) )
1453 pSibling = pLastSib;
1454 bEnd = true;
1459 if ( pSibling )
1461 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1462 if ( nCmpPos < nStPos )
1464 while ( pSibling->GetFollow() )
1465 pSibling = pSibling->GetFollow();
1466 pParent = static_cast<SwFootnoteContFrame*>(pSibling->GetUpper());
1467 pSibling = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
1469 else
1471 if( pSibling->GetMaster() )
1473 if( ENDNOTE > nCmpPos || nStPos >= ENDNOTE )
1475 OSL_FAIL( "InsertFootnote: Master expected II" );
1477 pSibling = pSibling->GetMaster();
1478 while ( pSibling->GetMaster() );
1481 pParent = static_cast<SwFootnoteContFrame*>(pSibling->GetUpper());
1484 OSL_ENSURE( pParent, "paste in space?" );
1485 pNew->Paste( pParent, pSibling );
1488 static SwPageFrame* lcl_GetApproximateFootnotePage(const bool bEnd, const SwPageFrame* pPage,
1489 const SwDoc *pDoc, const SwTextFootnote *pAttr)
1491 // We can at least search the approximately correct page
1492 // to ensure that we will finish in finite time even if
1493 // hundreds of footnotes exist.
1494 const SwPageFrame *pNxt = static_cast<const SwPageFrame*>(pPage->GetNext());
1495 const sal_uLong nStPos = ::lcl_FindFootnotePos(pDoc, pAttr);
1496 while (pNxt && (bEnd ? pNxt->IsEndNotePage() : pNxt->IsFootnotePage() && !pNxt->IsEndNotePage()))
1498 const SwFootnoteContFrame *pCont = pNxt->FindFootnoteCont();
1499 if (pCont && pCont->Lower())
1501 OSL_ENSURE( pCont->Lower()->IsFootnoteFrame(), "no footnote in the container" );
1502 if (nStPos > ::lcl_FindFootnotePos(pDoc,
1503 static_cast<const SwFootnoteFrame*>(pCont->Lower())->GetAttr()))
1505 pPage = pNxt;
1506 pNxt = static_cast<const SwPageFrame*>(pPage->GetNext());
1507 continue;
1510 break;
1512 return const_cast<SwPageFrame*>(pPage);
1515 void SwFootnoteBossFrame::AppendFootnote( SwContentFrame *pRef, SwTextFootnote *pAttr )
1517 // If the footnote already exists, do nothing.
1518 if ( FindFootnote( pRef, pAttr ) )
1519 return;
1521 // If footnotes are inserted at the end of the document,
1522 // we only need to search from the relevant page on.
1523 // If there is none yet, we need to create one.
1524 // If it is an Endnote, we need to search for or create an
1525 // Endnote page.
1526 SwDoc *pDoc = GetFormat()->GetDoc();
1527 SwFootnoteBossFrame *pBoss = this;
1528 SwPageFrame *pPage = FindPageFrame();
1529 SwPageFrame *pMyPage = pPage;
1530 bool bChgPage = false;
1531 const bool bEnd = pAttr->GetFootnote().IsEndNote();
1532 if (bEnd)
1534 const IDocumentSettingAccess& rSettings = *pAttr->GetTextNode().getIDocumentSettingAccess();
1535 if( GetUpper()->IsSctFrame() &&
1536 static_cast<SwSectionFrame*>(GetUpper())->IsEndnAtEnd() )
1538 // Endnotes at the end of the section.
1539 SwFrame* pLast =
1540 static_cast<SwSectionFrame*>(GetUpper())->FindLastContent( SwFindMode::EndNote );
1541 if( pLast )
1543 pBoss = pLast->FindFootnoteBossFrame();
1544 pPage = pBoss->FindPageFrame();
1547 else if (rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
1549 // Endnotes at the end of the document.
1550 pBoss = getRootFrame()->GetLastPage();
1551 pPage = pBoss->FindPageFrame();
1553 else
1555 // Endnotes on a separate page.
1556 while ( pPage->GetNext() && !pPage->IsEndNotePage() )
1558 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1559 bChgPage = true;
1561 if ( !pPage->IsEndNotePage() )
1563 SwPageDesc *pDesc = pDoc->GetEndNoteInfo().GetPageDesc( *pDoc );
1564 pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
1565 !pPage->OnRightPage(), false, false, true, nullptr );
1566 pPage->SetEndNotePage( true );
1567 bChgPage = true;
1569 else
1570 pPage = lcl_GetApproximateFootnotePage(true, pPage, pDoc, pAttr);
1573 else if( FTNPOS_CHAPTER == pDoc->GetFootnoteInfo().m_ePos && ( !GetUpper()->
1574 IsSctFrame() || !static_cast<SwSectionFrame*>(GetUpper())->IsFootnoteAtEnd() ) )
1576 while ( pPage->GetNext() && !pPage->IsFootnotePage() &&
1577 !static_cast<SwPageFrame*>(pPage->GetNext())->IsEndNotePage() )
1579 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1580 bChgPage = true;
1583 if ( !pPage->IsFootnotePage() )
1585 SwPageDesc *pDesc = pDoc->GetFootnoteInfo().GetPageDesc( *pDoc );
1586 pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
1587 !pPage->OnRightPage(), false, false, true, pPage->GetNext() );
1588 bChgPage = true;
1590 else
1591 pPage = lcl_GetApproximateFootnotePage(false, pPage, pDoc, pAttr);
1594 // For now, create a footnote and the corresponding content frames
1595 if ( !pAttr->GetStartNode() )
1597 OSL_ENSURE( false, "no footnote content." );
1598 return;
1601 // If there is already a footnote content on the column/page,
1602 // another one cannot be created in a column area.
1603 if( pBoss->IsInSct() && pBoss->IsColumnFrame() && !pPage->IsFootnotePage() )
1605 SwSectionFrame* pSct = pBoss->FindSctFrame();
1606 if( bEnd ? !pSct->IsEndnAtEnd() : !pSct->IsFootnoteAtEnd() )
1608 SwFootnoteContFrame* pFootnoteCont = pSct->FindFootnoteBossFrame(!bEnd)->FindFootnoteCont();
1609 if( pFootnoteCont )
1611 SwFootnoteFrame* pTmp = static_cast<SwFootnoteFrame*>(pFootnoteCont->Lower());
1612 if( bEnd )
1613 while( pTmp && !pTmp->GetAttr()->GetFootnote().IsEndNote() )
1614 pTmp = static_cast<SwFootnoteFrame*>(pTmp->GetNext());
1615 if( pTmp && *pTmp < pAttr )
1616 return;
1621 SwFootnoteFrame *pNew = new SwFootnoteFrame( pDoc->GetDfltFrameFormat(), this, pRef, pAttr );
1623 SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
1624 ::InsertCnt_( pNew, pDoc, aIdx.GetIndex() );
1626 // If the page was changed or newly created,
1627 // we need to place ourselves in the first column
1628 if( bChgPage )
1630 SwLayoutFrame* pBody = pPage->FindBodyCont();
1631 OSL_ENSURE( pBody, "AppendFootnote: NoPageBody?" );
1632 if( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
1633 pBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower());
1634 else
1635 pBoss = pPage; // page if no columns exist
1637 pBoss->InsertFootnote( pNew );
1638 if ( pNew->GetUpper() ) // inserted or not?
1640 ::RegistFlys( pNew->FindPageFrame(), pNew );
1641 SwSectionFrame* pSect = FindSctFrame();
1642 // The content of a FootnoteContainer in a (column) section only need to be calculated
1643 // if the section stretches already to the bottom edge of the Upper.
1644 if( pSect && !pSect->IsJoinLocked() && ( bEnd ? !pSect->IsEndnAtEnd() :
1645 !pSect->IsFootnoteAtEnd() ) && pSect->Growable() )
1646 pSect->InvalidateSize();
1647 else
1649 // #i49383# - disable unlock of position of
1650 // lower objects during format of footnote content.
1651 const bool bOldFootnoteFrameLocked( pNew->IsColLocked() );
1652 pNew->ColLock();
1653 pNew->KeepLockPosOfLowerObjs();
1654 // #i57914# - adjust fix #i49383#
1655 SwContentFrame *pCnt = pNew->ContainsContent();
1656 while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
1658 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
1659 // #i49383# - format anchored objects
1660 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
1662 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
1663 *(pCnt->FindPageFrame()) ) )
1665 // restart format with first content
1666 pCnt = pNew->ContainsContent();
1667 continue;
1670 pCnt = pCnt->FindNextCnt();
1672 // #i49383#
1673 if ( !bOldFootnoteFrameLocked )
1675 pNew->ColUnlock();
1677 // #i57914# - adjust fix #i49383#
1678 // enable lock of lower object position before format of footnote frame.
1679 pNew->UnlockPosOfLowerObjs();
1680 pNew->Calc(getRootFrame()->GetCurrShell()->GetOut());
1681 // #i57914# - adjust fix #i49383#
1682 if ( !bOldFootnoteFrameLocked && !pNew->GetLower() &&
1683 !pNew->IsColLocked() && !pNew->IsBackMoveLocked() &&
1684 !pNew->IsDeleteForbidden() )
1686 pNew->Cut();
1687 SwFrame::DestroyFrame(pNew);
1690 pMyPage->UpdateFootnoteNum();
1692 else
1693 SwFrame::DestroyFrame(pNew);
1696 SwFootnoteFrame *SwFootnoteBossFrame::FindFootnote( const SwContentFrame *pRef, const SwTextFootnote *pAttr )
1698 // the easiest and savest way goes via the attribute
1699 OSL_ENSURE( pAttr->GetStartNode(), "FootnoteAtr without StartNode." );
1700 SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
1701 SwContentNode *pNd = aIdx.GetNode().GetContentNode();
1702 if ( !pNd )
1703 pNd = pRef->GetAttrSet()->GetDoc()->
1704 GetNodes().GoNextSection( &aIdx, true, false );
1705 if ( !pNd )
1706 return nullptr;
1707 SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
1708 SwFrame* pFrame = aIter.First();
1709 if( pFrame )
1712 pFrame = pFrame->GetUpper();
1713 // #i28500#, #i27243# Due to the endnode collector, there are
1714 // SwFootnoteFrames, which are not in the layout. Therefore the
1715 // bInfFootnote flags are not set correctly, and a cell of FindFootnoteFrame
1716 // would return 0. Therefore we better call ImplFindFootnoteFrame().
1717 SwFootnoteFrame *pFootnote = pFrame->ImplFindFootnoteFrame();
1718 if ( pFootnote && pFootnote->GetRef() == pRef )
1720 // The following condition becomes true, if the whole
1721 // footnotecontent is a section. While no frames exist,
1722 // the HiddenFlag of the section is set, this causes
1723 // the GoNextSection-function leaves the footnote.
1724 if( pFootnote->GetAttr() != pAttr )
1725 return nullptr;
1726 while ( pFootnote && pFootnote->GetMaster() )
1727 pFootnote = pFootnote->GetMaster();
1728 return pFootnote;
1731 } while ( nullptr != (pFrame = aIter.Next()) );
1733 return nullptr;
1736 bool SwFootnoteBossFrame::RemoveFootnote(
1737 const SwContentFrame *const pRef, const SwTextFootnote *const pAttr,
1738 bool bPrep )
1740 bool ret(false);
1741 SwFootnoteFrame *pFootnote = FindFootnote( pRef, pAttr );
1742 if( pFootnote )
1744 ret = true;
1747 SwFootnoteFrame *pFoll = pFootnote->GetFollow();
1748 pFootnote->Cut();
1749 SwFrame::DestroyFrame(pFootnote);
1750 pFootnote = pFoll;
1751 } while ( pFootnote );
1752 if( bPrep && pRef->IsFollow() )
1754 OSL_ENSURE( pRef->IsTextFrame(), "NoTextFrame has Footnote?" );
1755 SwTextFrame* pMaster = pRef->FindMaster();
1756 if( !pMaster->IsLocked() )
1757 pMaster->Prepare( PrepareHint::FootnoteInvalidationGone );
1760 FindPageFrame()->UpdateFootnoteNum();
1761 return ret;
1764 void SwFootnoteBossFrame::ChangeFootnoteRef( const SwContentFrame *pOld, const SwTextFootnote *pAttr,
1765 SwContentFrame *pNew )
1767 SwFootnoteFrame *pFootnote = FindFootnote( pOld, pAttr );
1768 while ( pFootnote )
1770 pFootnote->SetRef( pNew );
1771 pFootnote = pFootnote->GetFollow();
1775 /// OD 03.04.2003 #108446# - add parameter <_bCollectOnlyPreviousFootnotes> in
1776 /// order to control, if only footnotes, which are positioned before the
1777 /// footnote boss frame <this> have to be collected.
1778 void SwFootnoteBossFrame::CollectFootnotes( const SwContentFrame* _pRef,
1779 SwFootnoteBossFrame* _pOld,
1780 SwFootnoteFrames& _rFootnoteArr,
1781 const bool _bCollectOnlyPreviousFootnotes )
1783 SwFootnoteFrame *pFootnote = _pOld->FindFirstFootnote();
1784 while( !pFootnote )
1786 if( _pOld->IsColumnFrame() )
1788 // visit columns
1789 while ( !pFootnote && _pOld->GetPrev() )
1791 // Still no problem if no footnote was found yet. The loop is needed to pick up
1792 // following rows in tables. In all other cases it might correct bad contexts.
1793 _pOld = static_cast<SwFootnoteBossFrame*>(_pOld->GetPrev());
1794 pFootnote = _pOld->FindFirstFootnote();
1797 if( !pFootnote )
1799 // previous page
1800 SwPageFrame* pPg;
1801 for ( SwFrame* pTmp = _pOld;
1802 nullptr != ( pPg = static_cast<SwPageFrame*>(pTmp->FindPageFrame()->GetPrev()))
1803 && pPg->IsEmptyPage() ;
1806 pTmp = pPg;
1808 if( !pPg )
1809 return;
1811 SwLayoutFrame* pBody = pPg->FindBodyCont();
1812 if( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
1814 // multiple columns on one page => search last column
1815 _pOld = static_cast<SwFootnoteBossFrame*>(pBody->GetLastLower());
1817 else
1818 _pOld = pPg; // single column page
1819 pFootnote = _pOld->FindFirstFootnote();
1823 CollectFootnotes_(_pRef, pFootnote, _rFootnoteArr, _bCollectOnlyPreviousFootnotes ? this : nullptr);
1826 static void FootnoteInArr( SwFootnoteFrames& rFootnoteArr, SwFootnoteFrame* pFootnote )
1828 if ( rFootnoteArr.end() == std::find( rFootnoteArr.begin(), rFootnoteArr.end(), pFootnote ) )
1829 rFootnoteArr.push_back( pFootnote );
1832 void SwFootnoteBossFrame::CollectFootnotes_( const SwContentFrame* _pRef,
1833 SwFootnoteFrame* _pFootnote,
1834 SwFootnoteFrames& _rFootnoteArr,
1835 const SwFootnoteBossFrame* _pRefFootnoteBossFrame)
1837 // Collect all footnotes referenced by pRef (attribute by attribute), combine them
1838 // (the content might be divided over multiple pages) and cut them.
1840 // For robustness, we do not log the corresponding footnotes here. If a footnote
1841 // is touched twice, there might be a crash. This allows this function here to
1842 // also handle corrupt layouts in some degrees (without loops or even crashes).
1843 SwFootnoteFrames aNotFootnoteArr;
1845 // here we have a footnote placed in front of the first one of the reference
1846 OSL_ENSURE( !_pFootnote->GetMaster() || _pFootnote->GetRef() != _pRef, "move FollowFootnote?" );
1847 while ( _pFootnote->GetMaster() )
1848 _pFootnote = _pFootnote->GetMaster();
1850 bool bFound = false;
1854 // Search for the next footnote in this column/page so that
1855 // we do not start from zero again after cutting one footnote.
1856 SwFootnoteFrame *pNxtFootnote = _pFootnote;
1857 while ( pNxtFootnote->GetFollow() )
1858 pNxtFootnote = pNxtFootnote->GetFollow();
1859 pNxtFootnote = static_cast<SwFootnoteFrame*>(pNxtFootnote->GetNext());
1861 if ( !pNxtFootnote )
1863 SwFootnoteBossFrame* pBoss = _pFootnote->FindFootnoteBossFrame();
1864 SwPageFrame* pPage = pBoss->FindPageFrame();
1867 lcl_NextFootnoteBoss( pBoss, pPage, false );
1868 if( pBoss )
1870 SwLayoutFrame* pCont = pBoss->FindFootnoteCont();
1871 if( pCont )
1873 pNxtFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
1874 if( pNxtFootnote )
1876 while( pNxtFootnote->GetMaster() )
1877 pNxtFootnote = pNxtFootnote->GetMaster();
1878 if( pNxtFootnote == _pFootnote )
1879 pNxtFootnote = nullptr;
1883 } while( !pNxtFootnote && pBoss );
1885 else if( !pNxtFootnote->GetAttr()->GetFootnote().IsEndNote() )
1887 OSL_ENSURE( !pNxtFootnote->GetMaster(), "_CollectFootnote: Master expected" );
1888 while ( pNxtFootnote->GetMaster() )
1889 pNxtFootnote = pNxtFootnote->GetMaster();
1891 if ( pNxtFootnote == _pFootnote )
1893 OSL_FAIL( "_CollectFootnote: Vicious circle" );
1894 pNxtFootnote = nullptr;
1897 // OD 03.04.2003 #108446# - determine, if found footnote has to be collected.
1898 bool bCollectFoundFootnote = false;
1899 // Ignore endnotes which are on a separate endnote page.
1900 bool bEndNote = _pFootnote->GetAttr()->GetFootnote().IsEndNote();
1901 const IDocumentSettingAccess& rSettings
1902 = _pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
1903 bool bContinuousEndnotes = rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
1904 if (_pFootnote->GetRef() == _pRef && (!bEndNote || bContinuousEndnotes))
1906 if (_pRefFootnoteBossFrame)
1908 SwFootnoteBossFrame* pBossOfFoundFootnote = _pFootnote->FindFootnoteBossFrame( true );
1909 OSL_ENSURE( pBossOfFoundFootnote,
1910 "<SwFootnoteBossFrame::CollectFootnotes_(..)> - footnote boss frame of found footnote frame missing.\nWrong layout!" );
1911 if ( !pBossOfFoundFootnote || // don't crash, if no footnote boss is found.
1912 pBossOfFoundFootnote->IsBefore( _pRefFootnoteBossFrame )
1915 bCollectFoundFootnote = true;
1918 else
1920 bCollectFoundFootnote = true;
1924 if ( bCollectFoundFootnote )
1926 OSL_ENSURE( !_pFootnote->GetMaster(), "move FollowFootnote?" );
1927 SwFootnoteFrame *pNxt = _pFootnote->GetFollow();
1928 while ( pNxt )
1930 SwFrame *pCnt = pNxt->ContainsAny();
1931 if ( pCnt )
1933 // destroy the follow on the way as it is empty
1935 { SwFrame *pNxtCnt = pCnt->GetNext();
1936 pCnt->Cut();
1937 pCnt->Paste( _pFootnote );
1938 pCnt = pNxtCnt;
1939 } while ( pCnt );
1941 else
1943 OSL_ENSURE( !pNxt, "footnote without content?" );
1944 pNxt->Cut();
1945 SwFrame::DestroyFrame(pNxt);
1947 pNxt = _pFootnote->GetFollow();
1949 _pFootnote->Cut();
1950 FootnoteInArr( _rFootnoteArr, _pFootnote );
1951 bFound = true;
1953 else
1955 FootnoteInArr( aNotFootnoteArr, _pFootnote );
1956 if( bFound )
1957 break;
1959 if ( pNxtFootnote &&
1960 _rFootnoteArr.end() == std::find( _rFootnoteArr.begin(), _rFootnoteArr.end(), pNxtFootnote ) &&
1961 aNotFootnoteArr.end() == std::find( aNotFootnoteArr.begin(), aNotFootnoteArr.end(), pNxtFootnote ) )
1962 _pFootnote = pNxtFootnote;
1963 else
1964 break;
1966 while ( _pFootnote );
1969 void SwFootnoteBossFrame::MoveFootnotes_( SwFootnoteFrames &rFootnoteArr, bool bCalc )
1971 // All footnotes referenced by pRef need to be moved
1972 // to a new position (based on the new column/page)
1973 const sal_uInt16 nMyNum = FindPageFrame()->GetPhyPageNum();
1974 const sal_uInt16 nMyCol = lcl_ColumnNum( this );
1975 SwRectFnSet aRectFnSet(this);
1977 // #i21478# - keep last inserted footnote in order to
1978 // format the content of the following one.
1979 SwFootnoteFrame* pLastInsertedFootnote = nullptr;
1980 for (SwFootnoteFrame* pFootnote : rFootnoteArr)
1982 SwFootnoteBossFrame* pRefBoss(pFootnote->GetRef()->FindFootnoteBossFrame(
1983 !pFootnote->GetAttr()->GetFootnote().IsEndNote()));
1984 if( pRefBoss != this )
1986 const sal_uInt16 nRefNum = pRefBoss->FindPageFrame()->GetPhyPageNum();
1987 const sal_uInt16 nRefCol = lcl_ColumnNum( this );
1988 if( nRefNum < nMyNum || ( nRefNum == nMyNum && nRefCol <= nMyCol ) )
1989 pRefBoss = this;
1991 pRefBoss->InsertFootnote( pFootnote );
1993 if ( pFootnote->GetUpper() ) // robust, e.g. with duplicates
1995 // First condense the content so that footnote frames that do not fit on the page
1996 // do not do too much harm (Loop 66312). So, the footnote content first grows as
1997 // soon as the content gets formatted and it is sure that it fits on the page.
1998 SwFrame *pCnt = pFootnote->ContainsAny();
1999 while( pCnt )
2001 if( pCnt->IsLayoutFrame() )
2003 SwFrame* pTmp = static_cast<SwLayoutFrame*>(pCnt)->ContainsAny();
2004 while( pTmp && static_cast<SwLayoutFrame*>(pCnt)->IsAnLower( pTmp ) )
2006 pTmp->Prepare( PrepareHint::FootnoteMove );
2008 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pTmp);
2009 aRectFnSet.SetHeight(aFrm, 0);
2011 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pTmp);
2012 aRectFnSet.SetHeight(aPrt, 0);
2014 pTmp = pTmp->FindNext();
2017 else
2019 pCnt->Prepare( PrepareHint::FootnoteMove );
2022 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pCnt);
2023 aRectFnSet.SetHeight(aFrm, 0);
2025 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pCnt);
2026 aRectFnSet.SetHeight(aPrt, 0);
2028 pCnt = pCnt->GetNext();
2032 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFootnote);
2033 aRectFnSet.SetHeight(aFrm, 0);
2037 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pFootnote);
2038 aRectFnSet.SetHeight(aPrt, 0);
2041 pFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
2042 pFootnote->GetUpper()->Calc(getRootFrame()->GetCurrShell()->GetOut());
2044 if( bCalc )
2046 SwTextFootnote *pAttr = pFootnote->GetAttr();
2047 pCnt = pFootnote->ContainsAny();
2048 bool bUnlock = !pFootnote->IsBackMoveLocked();
2049 pFootnote->LockBackMove();
2051 // #i49383# - disable unlock of position of
2052 // lower objects during format of footnote content.
2053 pFootnote->KeepLockPosOfLowerObjs();
2054 // #i57914# - adjust fix #i49383#
2056 while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
2058 pCnt->InvalidatePos_();
2059 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
2060 // #i49383# - format anchored objects
2061 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
2063 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
2064 *(pCnt->FindPageFrame()) ) )
2066 // restart format with first content
2067 pCnt = pFootnote->ContainsAny();
2068 continue;
2071 if( pCnt->IsSctFrame() )
2073 // If the area is not empty, iterate also over the content
2074 SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
2075 if( pTmp )
2076 pCnt = pTmp;
2077 else
2078 pCnt = pCnt->FindNext();
2080 else
2081 pCnt = pCnt->FindNext();
2083 if( bUnlock )
2085 pFootnote->UnlockBackMove();
2086 if( !pFootnote->ContainsAny() && !pFootnote->IsColLocked() )
2088 pFootnote->Cut();
2089 SwFrame::DestroyFrame(pFootnote);
2090 // #i21478#
2091 pFootnote = nullptr;
2094 // #i49383#
2095 if ( pFootnote )
2097 // #i57914# - adjust fix #i49383#
2098 // enable lock of lower object position before format of footnote frame.
2099 pFootnote->UnlockPosOfLowerObjs();
2100 pFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
2104 else
2106 OSL_ENSURE( !pFootnote->GetMaster() && !pFootnote->GetFollow(),
2107 "DelFootnote and Master/Follow?" );
2108 SwFrame::DestroyFrame(pFootnote);
2109 // #i21478#
2110 pFootnote = nullptr;
2113 // #i21478#
2114 if ( pFootnote )
2116 pLastInsertedFootnote = pFootnote;
2120 // #i21478# - format content of footnote following
2121 // the new inserted ones.
2122 if ( !(bCalc && pLastInsertedFootnote) )
2123 return;
2125 if ( !pLastInsertedFootnote->GetNext() )
2126 return;
2128 SwFootnoteFrame* pNextFootnote = static_cast<SwFootnoteFrame*>(pLastInsertedFootnote->GetNext());
2129 SwTextFootnote* pAttr = pNextFootnote->GetAttr();
2130 SwFrame* pCnt = pNextFootnote->ContainsAny();
2132 bool bUnlock = !pNextFootnote->IsBackMoveLocked();
2133 pNextFootnote->LockBackMove();
2134 // #i49383# - disable unlock of position of
2135 // lower objects during format of footnote content.
2136 pNextFootnote->KeepLockPosOfLowerObjs();
2137 // #i57914# - adjust fix #i49383#
2139 while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
2141 pCnt->InvalidatePos_();
2142 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
2143 // #i49383# - format anchored objects
2144 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
2146 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
2147 *(pCnt->FindPageFrame()) ) )
2149 // restart format with first content
2150 pCnt = pNextFootnote->ContainsAny();
2151 continue;
2154 if( pCnt->IsSctFrame() )
2156 // If the area is not empty, iterate also over the content
2157 SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
2158 if( pTmp )
2159 pCnt = pTmp;
2160 else
2161 pCnt = pCnt->FindNext();
2163 else
2164 pCnt = pCnt->FindNext();
2166 if( bUnlock )
2168 pNextFootnote->UnlockBackMove();
2170 // #i49383#
2171 // #i57914# - adjust fix #i49383#
2172 // enable lock of lower object position before format of footnote frame.
2173 pNextFootnote->UnlockPosOfLowerObjs();
2174 pNextFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
2177 void SwFootnoteBossFrame::MoveFootnotes( const SwContentFrame *pSrc, SwContentFrame *pDest,
2178 SwTextFootnote const *pAttr )
2180 if( ( GetFormat()->GetDoc()->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER &&
2181 (!GetUpper()->IsSctFrame() || !static_cast<SwSectionFrame*>(GetUpper())->IsFootnoteAtEnd()))
2182 || pAttr->GetFootnote().IsEndNote() )
2183 return;
2185 OSL_ENSURE( this == pSrc->FindFootnoteBossFrame( true ),
2186 "SwPageFrame::MoveFootnotes: source frame isn't on that FootnoteBoss" );
2188 SwFootnoteFrame *pFootnote = FindFirstFootnote();
2189 if( !pFootnote )
2190 return;
2192 ChangeFootnoteRef( pSrc, pAttr, pDest );
2193 SwFootnoteBossFrame *pDestBoss = pDest->FindFootnoteBossFrame( true );
2194 OSL_ENSURE( pDestBoss, "+SwPageFrame::MoveFootnotes: no destination boss" );
2195 if( !pDestBoss ) // robust
2196 return;
2198 SwFootnoteFrames aFootnoteArr;
2199 SwFootnoteBossFrame::CollectFootnotes_(pDest, pFootnote, aFootnoteArr, nullptr);
2200 if ( aFootnoteArr.empty() )
2201 return;
2203 pDestBoss->MoveFootnotes_( aFootnoteArr, true );
2204 SwPageFrame* pSrcPage = FindPageFrame();
2205 SwPageFrame* pDestPage = pDestBoss->FindPageFrame();
2206 // update FootnoteNum only at page change
2207 if( pSrcPage != pDestPage )
2209 if( pSrcPage->GetPhyPageNum() > pDestPage->GetPhyPageNum() )
2210 pSrcPage->UpdateFootnoteNum();
2211 pDestPage->UpdateFootnoteNum();
2215 void SwFootnoteBossFrame::RearrangeFootnotes( const SwTwips nDeadLine, const bool bLock,
2216 const SwTextFootnote *pAttr )
2218 // Format all footnotes of a column/page so that they might change the column/page.
2220 SwSaveFootnoteHeight aSave( this, nDeadLine );
2221 SwFootnoteFrame *pFootnote = FindFirstFootnote();
2222 if( pFootnote && pFootnote->GetPrev() && bLock )
2224 SwFootnoteFrame* pFirst = static_cast<SwFootnoteFrame*>(pFootnote->GetUpper()->Lower());
2225 SwFrame* pContent = pFirst->ContainsAny();
2226 if( pContent )
2228 bool bUnlock = !pFirst->IsBackMoveLocked();
2229 pFirst->LockBackMove();
2230 pFirst->Calc(getRootFrame()->GetCurrShell()->GetOut());
2231 pContent->Calc(getRootFrame()->GetCurrShell()->GetOut());
2232 // #i49383# - format anchored objects
2233 if ( pContent->IsTextFrame() && pContent->isFrameAreaDefinitionValid() )
2235 SwObjectFormatter::FormatObjsAtFrame( *pContent,
2236 *(pContent->FindPageFrame()) );
2238 if( bUnlock )
2239 pFirst->UnlockBackMove();
2241 pFootnote = FindFirstFootnote();
2243 SwDoc *pDoc = GetFormat()->GetDoc();
2244 const sal_uLong nFootnotePos = pAttr ? ::lcl_FindFootnotePos( pDoc, pAttr ) : 0;
2245 SwFrame *pCnt = pFootnote ? pFootnote->ContainsAny() : nullptr;
2246 if ( !pCnt )
2247 return;
2249 bool bMore = true;
2250 bool bStart = pAttr == nullptr; // If no attribute is given, process all
2251 // #i49383# - disable unlock of position of
2252 // lower objects during format of footnote and footnote content.
2253 SwFootnoteFrame* pLastFootnoteFrame( nullptr );
2254 // footnote frame needs to be locked, if <bLock> isn't set.
2255 bool bUnlockLastFootnoteFrame( false );
2258 if( !bStart )
2259 bStart = ::lcl_FindFootnotePos( pDoc, pCnt->FindFootnoteFrame()->GetAttr() )
2260 == nFootnotePos;
2261 if( bStart )
2263 pCnt->InvalidatePos_();
2264 pCnt->InvalidateSize_();
2265 pCnt->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
2266 SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
2267 // #i49383#
2268 if ( pFootnoteFrame != pLastFootnoteFrame )
2270 if ( pLastFootnoteFrame )
2272 if ( !bLock && bUnlockLastFootnoteFrame )
2274 pLastFootnoteFrame->ColUnlock();
2276 // #i57914# - adjust fix #i49383#
2277 // enable lock of lower object position before format of footnote frame.
2278 pLastFootnoteFrame->UnlockPosOfLowerObjs();
2279 pLastFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
2280 if ( !bLock && bUnlockLastFootnoteFrame &&
2281 !pLastFootnoteFrame->GetLower() &&
2282 !pLastFootnoteFrame->IsColLocked() &&
2283 !pLastFootnoteFrame->IsBackMoveLocked() &&
2284 !pLastFootnoteFrame->IsDeleteForbidden() )
2286 pLastFootnoteFrame->Cut();
2287 SwFrame::DestroyFrame(pLastFootnoteFrame);
2288 pLastFootnoteFrame = nullptr;
2291 if ( !bLock )
2293 bUnlockLastFootnoteFrame = !pFootnoteFrame->IsColLocked();
2294 pFootnoteFrame->ColLock();
2296 pFootnoteFrame->KeepLockPosOfLowerObjs();
2297 pLastFootnoteFrame = pFootnoteFrame;
2299 // OD 30.10.2002 #97265# - invalidate position of footnote
2300 // frame, if it's below its footnote container, in order to
2301 // assure its correct position, probably calculating its previous
2302 // footnote frames.
2304 SwRectFnSet aRectFnSet(this);
2305 SwFrame* pFootnoteContFrame = pFootnoteFrame->GetUpper();
2306 if ( aRectFnSet.TopDist(pFootnoteFrame->getFrameArea(), aRectFnSet.GetPrtBottom(*pFootnoteContFrame)) > 0 )
2308 pFootnoteFrame->InvalidatePos_();
2311 if ( bLock )
2313 bool bUnlock = !pFootnoteFrame->IsBackMoveLocked();
2314 pFootnoteFrame->LockBackMove();
2315 pFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
2316 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
2317 // #i49383# - format anchored objects
2318 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
2320 SwFrameDeleteGuard aDeleteGuard(pFootnote);
2321 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
2322 *(pCnt->FindPageFrame()) ) )
2324 // restart format with first content
2325 pCnt = pFootnote ? pFootnote->ContainsAny() : nullptr;
2326 if (!pCnt)
2327 bMore = false;
2328 continue;
2331 if( bUnlock )
2333 pFootnoteFrame->UnlockBackMove();
2334 if( !pFootnoteFrame->Lower() &&
2335 !pFootnoteFrame->IsColLocked() )
2337 // #i49383#
2338 OSL_ENSURE( pLastFootnoteFrame == pFootnoteFrame,
2339 "<SwFootnoteBossFrame::RearrangeFootnotes(..)> - <pLastFootnoteFrame> != <pFootnoteFrame>" );
2340 pLastFootnoteFrame = nullptr;
2341 pFootnoteFrame->Cut();
2342 SwFrame::DestroyFrame(pFootnoteFrame);
2343 if (pFootnote == pFootnoteFrame)
2344 pFootnote = nullptr;
2348 else
2350 pFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
2351 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
2352 // #i49383# - format anchored objects
2353 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
2355 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
2356 *(pCnt->FindPageFrame()) ) )
2358 // restart format with first content
2359 pCnt = pFootnote->ContainsAny();
2360 continue;
2365 SwSectionFrame *pDel = nullptr;
2366 if( pCnt->IsSctFrame() )
2368 SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
2369 if( pTmp )
2371 pCnt = pTmp;
2372 continue;
2374 pDel = static_cast<SwSectionFrame*>(pCnt);
2376 if ( pCnt->GetNext() )
2377 pCnt = pCnt->GetNext();
2378 else
2380 pCnt = pCnt->FindNext();
2381 if ( pCnt )
2383 SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
2384 if( pFootnoteFrame->GetRef()->FindFootnoteBossFrame(
2385 pFootnoteFrame->GetAttr()->GetFootnote().IsEndNote() ) != this )
2386 bMore = false;
2388 else
2389 bMore = false;
2391 if( pDel )
2393 bool bUnlockLastFootnoteFrameGuard = pLastFootnoteFrame && !pLastFootnoteFrame->IsColLocked();
2394 if (bUnlockLastFootnoteFrameGuard)
2395 pLastFootnoteFrame->ColLock();
2396 pDel->Cut();
2397 if (bUnlockLastFootnoteFrameGuard)
2398 pLastFootnoteFrame->ColUnlock();
2399 SwFrame::DestroyFrame(pDel);
2401 if ( bMore )
2403 // Go not further than to the provided footnote (if given)
2404 if ( pAttr &&
2405 (::lcl_FindFootnotePos( pDoc,
2406 pCnt->FindFootnoteFrame()->GetAttr()) > nFootnotePos ) )
2407 bMore = false;
2409 } while ( bMore );
2410 // #i49383#
2411 if ( !pLastFootnoteFrame )
2412 return;
2414 if ( !bLock && bUnlockLastFootnoteFrame )
2416 pLastFootnoteFrame->ColUnlock();
2418 // #i57914# - adjust fix #i49383#
2419 // enable lock of lower object position before format of footnote frame.
2420 pLastFootnoteFrame->UnlockPosOfLowerObjs();
2421 pLastFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
2422 if ( !bLock && bUnlockLastFootnoteFrame &&
2423 !pLastFootnoteFrame->GetLower() &&
2424 !pLastFootnoteFrame->IsColLocked() &&
2425 !pLastFootnoteFrame->IsBackMoveLocked() &&
2426 !pLastFootnoteFrame->IsDeleteForbidden() )
2428 pLastFootnoteFrame->Cut();
2429 SwFrame::DestroyFrame(pLastFootnoteFrame);
2433 void SwPageFrame::UpdateFootnoteNum()
2435 // page numbering only if set at the document
2436 if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum != FTNNUM_PAGE )
2437 return;
2439 SwLayoutFrame* pBody = FindBodyCont();
2440 if( !pBody || !pBody->Lower() )
2441 return;
2443 SwContentFrame* pContent = pBody->ContainsContent();
2444 sal_uInt16 nNum = 0;
2446 while( pContent && pContent->FindPageFrame() == this )
2448 if( static_cast<SwTextFrame*>(pContent)->HasFootnote() )
2450 SwFootnoteBossFrame* pBoss = pContent->FindFootnoteBossFrame( true );
2451 if( pBoss->GetUpper()->IsSctFrame() &&
2452 static_cast<SwSectionFrame*>(pBoss->GetUpper())->IsOwnFootnoteNum() )
2453 pContent = static_cast<SwSectionFrame*>(pBoss->GetUpper())->FindLastContent();
2454 else
2456 SwFootnoteFrame* pFootnote = const_cast<SwFootnoteFrame*>(pBoss->FindFirstFootnote( pContent ));
2457 while( pFootnote )
2459 SwTextFootnote* pTextFootnote = pFootnote->GetAttr();
2460 if( !pTextFootnote->GetFootnote().IsEndNote() &&
2461 pTextFootnote->GetFootnote().GetNumStr().isEmpty() &&
2462 !pFootnote->GetMaster())
2464 // sw_redlinehide: the layout can only keep one number
2465 // up to date; depending on its setting, this is either
2466 // the non-hidden or the hidden number; the other
2467 // number will simply be preserved as-is (so in case
2468 // there are 2 layouts, maybe both can be updated...)
2469 ++nNum;
2470 sal_uInt16 const nOldNum(pTextFootnote->GetFootnote().GetNumber());
2471 sal_uInt16 const nOldNumRLHidden(pTextFootnote->GetFootnote().GetNumberRLHidden());
2472 if (getRootFrame()->IsHideRedlines())
2474 if (nNum != nOldNumRLHidden)
2476 pTextFootnote->SetNumber(nOldNum, nNum, OUString());
2479 else
2481 if (nNum != nOldNum)
2483 pTextFootnote->SetNumber(nNum, nOldNumRLHidden, OUString());
2487 if ( pFootnote->GetNext() )
2488 pFootnote = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
2489 else
2491 SwFootnoteBossFrame* pTmpBoss = pFootnote->FindFootnoteBossFrame( true );
2492 if( pTmpBoss )
2494 SwPageFrame* pPage = pTmpBoss->FindPageFrame();
2495 pFootnote = nullptr;
2496 lcl_NextFootnoteBoss( pTmpBoss, pPage, false );
2497 SwFootnoteContFrame *pCont = pTmpBoss ? pTmpBoss->FindNearestFootnoteCont() : nullptr;
2498 if ( pCont )
2499 pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
2502 if( pFootnote && pFootnote->GetRef() != pContent )
2503 pFootnote = nullptr;
2507 pContent = pContent->FindNextCnt();
2511 void SwFootnoteBossFrame::SetFootnoteDeadLine( const SwTwips nDeadLine )
2513 SwFrame *pBody = FindBodyCont();
2514 pBody->Calc(getRootFrame()->GetCurrShell()->GetOut());
2516 SwFrame *pCont = FindFootnoteCont();
2517 const SwTwips nMax = m_nMaxFootnoteHeight;// current should exceed MaxHeight
2518 SwRectFnSet aRectFnSet(this);
2519 if ( pCont )
2521 pCont->Calc(getRootFrame()->GetCurrShell()->GetOut());
2522 m_nMaxFootnoteHeight = -aRectFnSet.BottomDist( pCont->getFrameArea(), nDeadLine );
2524 else
2525 m_nMaxFootnoteHeight = -aRectFnSet.BottomDist( pBody->getFrameArea(), nDeadLine );
2527 const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
2528 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
2529 m_nMaxFootnoteHeight += pBody->Grow( LONG_MAX, true );
2530 if ( IsInSct() )
2531 m_nMaxFootnoteHeight += FindSctFrame()->Grow( LONG_MAX, true );
2533 if ( m_nMaxFootnoteHeight < 0 )
2534 m_nMaxFootnoteHeight = 0;
2535 if ( nMax != LONG_MAX && m_nMaxFootnoteHeight > nMax )
2536 m_nMaxFootnoteHeight = nMax;
2539 SwTwips SwFootnoteBossFrame::GetVarSpace() const
2541 // To not fall below 20% of the page height
2542 // (in contrast to MSOffice where footnotes can fill a whole column/page)
2544 const SwPageFrame* pPg = FindPageFrame();
2545 OSL_ENSURE( pPg || IsInSct(), "Footnote lost page" );
2547 const SwFrame *pBody = FindBodyCont();
2548 SwTwips nRet;
2549 if( pBody )
2551 SwRectFnSet aRectFnSet(this);
2552 if( IsInSct() )
2554 nRet = 0;
2555 SwTwips nTmp = aRectFnSet.YDiff( aRectFnSet.GetPrtTop(*pBody),
2556 aRectFnSet.GetTop(getFrameArea()) );
2557 const SwSectionFrame* pSect = FindSctFrame();
2558 // Endnotes in a ftncontainer causes a deadline:
2559 // the bottom of the last contentfrm
2560 if( pSect->IsEndnAtEnd() ) // endnotes allowed?
2562 OSL_ENSURE( !Lower() || !Lower()->GetNext() || Lower()->GetNext()->
2563 IsFootnoteContFrame(), "FootnoteContainer expected" );
2564 const SwFootnoteContFrame* pCont = Lower() ?
2565 static_cast<const SwFootnoteContFrame*>(Lower()->GetNext()) : nullptr;
2566 if( pCont )
2568 const SwFootnoteFrame* pFootnote = static_cast<const SwFootnoteFrame*>(pCont->Lower());
2569 while( pFootnote)
2571 if( pFootnote->GetAttr()->GetFootnote().IsEndNote() )
2572 { // endnote found
2573 const SwFrame* pFrame = static_cast<const SwLayoutFrame*>(Lower())->Lower();
2574 if( pFrame )
2576 while( pFrame->GetNext() )
2577 pFrame = pFrame->GetNext(); // last cntntfrm
2578 nTmp += aRectFnSet.YDiff(
2579 aRectFnSet.GetTop(getFrameArea()),
2580 aRectFnSet.GetBottom(pFrame->getFrameArea()) );
2582 break;
2584 pFootnote = static_cast<const SwFootnoteFrame*>(pFootnote->GetNext());
2588 if( nTmp < nRet )
2589 nRet = nTmp;
2591 else
2592 nRet = - aRectFnSet.GetHeight(pPg->getFramePrintArea())/5;
2593 nRet += aRectFnSet.GetHeight(pBody->getFrameArea());
2594 if( nRet < 0 )
2595 nRet = 0;
2597 else
2598 nRet = 0;
2599 if ( IsPageFrame() )
2601 const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
2602 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
2603 nRet += BROWSE_HEIGHT - getFrameArea().Height();
2605 return nRet;
2608 /** Obtain if pFrame's size adjustment should be processed
2610 * For a page frame of columns directly below the page AdjustNeighbourhood() needs
2611 * to be called, or Grow()/ Shrink() for frame columns respectively.
2613 * A column section is special, since if there is a footnote container in a column
2614 * and those footnotes are not collected, it is handled like a page frame.
2616 * @see AdjustNeighbourhood()
2617 * @see Grow()
2618 * @see Shrink()
2620 SwNeighbourAdjust SwFootnoteBossFrame::NeighbourhoodAdjustment_() const
2622 SwNeighbourAdjust nRet = SwNeighbourAdjust::OnlyAdjust;
2623 if( GetUpper() && !GetUpper()->IsPageBodyFrame() )
2625 // column sections need grow/shrink
2626 if( GetUpper()->IsFlyFrame() )
2627 nRet = SwNeighbourAdjust::GrowShrink;
2628 else
2630 OSL_ENSURE( GetUpper()->IsSctFrame(), "NeighbourhoodAdjustment: Unexpected Upper" );
2631 if( !GetNext() && !GetPrev() )
2632 nRet = SwNeighbourAdjust::GrowAdjust; // section with a single column (FootnoteAtEnd)
2633 else
2635 const SwFrame* pTmp = Lower();
2636 OSL_ENSURE( pTmp, "NeighbourhoodAdjustment: Missing Lower()" );
2637 if( !pTmp->GetNext() )
2638 nRet = SwNeighbourAdjust::GrowShrink;
2639 else if( !GetUpper()->IsColLocked() )
2640 nRet = SwNeighbourAdjust::AdjustGrow;
2641 OSL_ENSURE( !pTmp->GetNext() || pTmp->GetNext()->IsFootnoteContFrame(),
2642 "NeighbourhoodAdjustment: Who's that guy?" );
2646 return nRet;
2649 void SwPageFrame::SetColMaxFootnoteHeight()
2651 SwLayoutFrame *pBody = FindBodyCont();
2652 if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
2654 SwColumnFrame* pCol = static_cast<SwColumnFrame*>(pBody->Lower());
2657 pCol->SetMaxFootnoteHeight( GetMaxFootnoteHeight() );
2658 pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
2659 } while ( pCol );
2663 bool SwLayoutFrame::MoveLowerFootnotes( SwContentFrame *pStart, SwFootnoteBossFrame *pOldBoss,
2664 SwFootnoteBossFrame *pNewBoss, const bool bFootnoteNums )
2666 SwDoc *pDoc = GetFormat()->GetDoc();
2667 if ( pDoc->GetFootnoteIdxs().empty() )
2668 return false;
2669 if( pDoc->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER &&
2670 ( !IsInSct() || !FindSctFrame()->IsFootnoteAtEnd() ) )
2671 return true;
2673 if ( !pNewBoss )
2674 pNewBoss = FindFootnoteBossFrame( true );
2675 if ( pNewBoss == pOldBoss )
2676 return false;
2678 bool bMoved = false;
2679 if( !pStart )
2680 pStart = ContainsContent();
2682 SwFootnoteFrames aFootnoteArr;
2684 while ( IsAnLower( pStart ) )
2686 if ( static_cast<SwTextFrame*>(pStart)->HasFootnote() )
2688 // OD 03.04.2003 #108446# - To avoid unnecessary moves of footnotes
2689 // use new parameter <_bCollectOnlyPreviousFootnote> (4th parameter of
2690 // method <SwFootnoteBossFrame::CollectFootnote(..)>) to control, that only
2691 // footnotes have to be collected, that are positioned before the
2692 // new dedicated footnote boss frame.
2693 pNewBoss->CollectFootnotes( pStart, pOldBoss, aFootnoteArr, true );
2695 pStart = pStart->GetNextContentFrame();
2698 OSL_ENSURE( pOldBoss->IsInSct() == pNewBoss->IsInSct(),
2699 "MoveLowerFootnotes: Section confusion" );
2700 std::unique_ptr<SwFootnoteFrames> pFootnoteArr;
2701 SwLayoutFrame* pNewChief = nullptr;
2702 SwLayoutFrame* pOldChief = nullptr;
2704 bool bFoundCandidate = false;
2705 if (pStart && pOldBoss->IsInSct())
2707 pOldChief = pOldBoss->FindSctFrame();
2708 pNewChief = pNewBoss->FindSctFrame();
2709 bFoundCandidate = pOldChief != pNewChief;
2712 if (bFoundCandidate)
2714 pFootnoteArr.reset(new SwFootnoteFrames);
2715 pOldChief = pOldBoss->FindFootnoteBossFrame( true );
2716 pNewChief = pNewBoss->FindFootnoteBossFrame( true );
2717 while( pOldChief->IsAnLower( pStart ) )
2719 if ( static_cast<SwTextFrame*>(pStart)->HasFootnote() )
2720 static_cast<SwFootnoteBossFrame*>(pNewChief)->CollectFootnotes( pStart,
2721 pOldBoss, *pFootnoteArr );
2722 pStart = pStart->GetNextContentFrame();
2724 if( pFootnoteArr->empty() )
2726 pFootnoteArr.reset();
2729 else
2730 pFootnoteArr = nullptr;
2732 if ( !aFootnoteArr.empty() || pFootnoteArr )
2734 if( !aFootnoteArr.empty() )
2735 pNewBoss->MoveFootnotes_( aFootnoteArr, true );
2736 if( pFootnoteArr )
2738 assert(pNewChief);
2739 static_cast<SwFootnoteBossFrame*>(pNewChief)->MoveFootnotes_( *pFootnoteArr, true );
2740 pFootnoteArr.reset();
2742 bMoved = true;
2744 // update FootnoteNum only at page change
2745 if ( bFootnoteNums )
2747 SwPageFrame* pOldPage = pOldBoss->FindPageFrame();
2748 SwPageFrame* pNewPage =pNewBoss->FindPageFrame();
2749 if( pOldPage != pNewPage )
2751 pOldPage->UpdateFootnoteNum();
2752 pNewPage->UpdateFootnoteNum();
2756 return bMoved;
2759 /// Return value guarantees that a new page was not created. See SwFlowFrame::MoveFwd.
2760 bool SwContentFrame::MoveFootnoteCntFwd( bool bMakePage, SwFootnoteBossFrame *pOldBoss )
2762 OSL_ENSURE( IsInFootnote(), "no footnote." );
2763 SwLayoutFrame *pFootnote = FindFootnoteFrame();
2765 // The first paragraph in the first footnote in the first column in the
2766 // sectionfrm at the top of the page has not to move forward, if the
2767 // columnbody is empty.
2768 if( pOldBoss->IsInSct() && !pOldBoss->GetIndPrev() && !GetIndPrev() &&
2769 !pFootnote->GetPrev() )
2771 SwLayoutFrame* pBody = pOldBoss->FindBodyCont();
2772 if( !pBody || !pBody->Lower() )
2773 return true;
2776 //fix(9538): if the footnote has neighbors behind itself, remove them temporarily
2777 SwLayoutFrame *pNxt = static_cast<SwLayoutFrame*>(pFootnote->GetNext());
2778 SwLayoutFrame *pLst = nullptr;
2779 while ( pNxt )
2781 while ( pNxt->GetNext() )
2782 pNxt = static_cast<SwLayoutFrame*>(pNxt->GetNext());
2783 if ( pNxt == pLst )
2784 pNxt = nullptr;
2785 else
2786 { pLst = pNxt;
2787 SwContentFrame *pCnt = pNxt->ContainsContent();
2788 if( pCnt )
2789 pCnt->MoveFootnoteCntFwd( true, pOldBoss );
2790 pNxt = static_cast<SwLayoutFrame*>(pFootnote->GetNext());
2794 bool bSamePage = true;
2795 SwLayoutFrame *pNewUpper =
2796 GetLeaf( bMakePage ? MAKEPAGE_INSERT : MAKEPAGE_NONE, true );
2798 if ( pNewUpper )
2800 SwFootnoteBossFrame * const pNewBoss = pNewUpper->FindFootnoteBossFrame();
2801 // Are we changing the column/page?
2802 bool bSameBoss = pNewBoss == pOldBoss;
2803 if ( !bSameBoss )
2805 bSamePage = pOldBoss->FindPageFrame() == pNewBoss->FindPageFrame(); // page change?
2806 pNewUpper->Calc(getRootFrame()->GetCurrShell()->GetOut());
2809 // The layout leaf of the footnote is either a footnote container or a footnote.
2810 // If it is a footnote and it has the same footnote reference like the old Upper,
2811 // then move the content inside of it.
2812 // If it is a container or the reference differs, create a new footnote and add
2813 // it into the container.
2814 // Create also a SectionFrame if currently in an area inside a footnote.
2815 SwFootnoteFrame* pTmpFootnote = pNewUpper->IsFootnoteFrame() ? static_cast<SwFootnoteFrame*>(pNewUpper) : nullptr;
2816 if (!pTmpFootnote)
2818 assert(pNewUpper->IsFootnoteContFrame() && "New Upper not a FootnoteCont");
2819 SwFootnoteContFrame *pCont = static_cast<SwFootnoteContFrame*>(pNewUpper);
2820 pTmpFootnote = SwFootnoteContFrame::AppendChained(this, true);
2821 SwFrame* pNx = pCont->Lower();
2822 if( pNx && pTmpFootnote->GetAttr()->GetFootnote().IsEndNote() )
2823 while(pNx && !static_cast<SwFootnoteFrame*>(pNx)->GetAttr()->GetFootnote().IsEndNote())
2824 pNx = pNx->GetNext();
2825 pTmpFootnote->Paste( pCont, pNx );
2826 pTmpFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
2828 OSL_ENSURE( pTmpFootnote->GetAttr() == FindFootnoteFrame()->GetAttr(), "Wrong Footnote!" );
2829 // areas inside of footnotes get a special treatment
2830 SwLayoutFrame *pNewUp = pTmpFootnote;
2831 if( IsInSct() )
2833 SwSectionFrame* pSect = FindSctFrame();
2834 // area inside of a footnote (or only footnote in an area)?
2835 if( pSect->IsInFootnote() )
2837 if( pTmpFootnote->Lower() && pTmpFootnote->Lower()->IsSctFrame() &&
2838 pSect->GetFollow() == static_cast<SwSectionFrame*>(pTmpFootnote->Lower()) )
2839 pNewUp = static_cast<SwSectionFrame*>(pTmpFootnote->Lower());
2840 else
2842 pNewUp = new SwSectionFrame( *pSect, false );
2843 pNewUp->InsertBefore( pTmpFootnote, pTmpFootnote->Lower() );
2844 static_cast<SwSectionFrame*>(pNewUp)->Init();
2847 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pNewUp);
2848 aFrm.Pos() = pTmpFootnote->getFrameArea().Pos();
2849 aFrm.Pos().AdjustY(1 ); // for notifications
2852 // If the section frame has a successor then the latter needs
2853 // to be moved behind the new Follow of the section frame.
2854 SwFrame* pTmp = pSect->GetNext();
2855 if( pTmp )
2857 SwFlowFrame* pTmpNxt;
2858 if( pTmp->IsContentFrame() )
2859 pTmpNxt = static_cast<SwContentFrame*>(pTmp);
2860 else if( pTmp->IsSctFrame() )
2861 pTmpNxt = static_cast<SwSectionFrame*>(pTmp);
2862 else
2864 OSL_ENSURE( pTmp->IsTabFrame(), "GetNextSctLeaf: Wrong Type" );
2865 pTmpNxt = static_cast<SwTabFrame*>(pTmp);
2867 // we will dereference pNewUp in the following MoveSubTree call
2868 // so it certainly should not be deleted before that
2869 SwFrameDeleteGuard aDeleteGuard(pNewUp);
2870 pTmpNxt->MoveSubTree( pTmpFootnote, pNewUp->GetNext() );
2876 MoveSubTree( pNewUp, pNewUp->Lower() );
2878 if( !bSameBoss )
2879 Prepare( PrepareHint::BossChanged );
2881 return bSamePage;
2884 SwSaveFootnoteHeight::SwSaveFootnoteHeight( SwFootnoteBossFrame *pBs, const SwTwips nDeadLine ) :
2885 aGuard(pBs),
2886 pBoss( pBs ),
2887 nOldHeight( pBs->GetMaxFootnoteHeight() )
2889 pBoss->SetFootnoteDeadLine( nDeadLine );
2890 nNewHeight = pBoss->GetMaxFootnoteHeight();
2893 SwSaveFootnoteHeight::~SwSaveFootnoteHeight()
2895 // If somebody tweaked the deadline meanwhile, we let it happen
2896 if ( nNewHeight == pBoss->GetMaxFootnoteHeight() )
2897 pBoss->m_nMaxFootnoteHeight = nOldHeight;
2900 #ifdef DBG_UTIL
2901 //JP 15.10.2001: in a non pro version test if the attribute has the same
2902 // meaning which his reference is
2904 // Normally, the pRef member and the GetRefFromAttr() result has to be
2905 // identically. Sometimes footnote will be moved from a master to its follow,
2906 // but the GetRef() is called first, so we have to ignore a master/follow
2907 // mismatch.
2909 const SwContentFrame* SwFootnoteFrame::GetRef() const
2911 const SwContentFrame* pRefAttr = GetRefFromAttr();
2912 // check consistency: access to deleted frame?
2913 assert(mpReference == pRefAttr || mpReference->IsAnFollow(pRefAttr)
2914 || pRefAttr->IsAnFollow(mpReference));
2915 (void) pRefAttr;
2916 return mpReference;
2919 SwContentFrame* SwFootnoteFrame::GetRef()
2921 const SwContentFrame* pRefAttr = GetRefFromAttr();
2922 // check consistency: access to deleted frame?
2923 assert(mpReference == pRefAttr || mpReference->IsAnFollow(pRefAttr)
2924 || pRefAttr->IsAnFollow(mpReference));
2925 (void) pRefAttr;
2926 return mpReference;
2928 #endif
2930 const SwContentFrame* SwFootnoteFrame::GetRefFromAttr() const
2932 SwFootnoteFrame* pThis = const_cast<SwFootnoteFrame*>(this);
2933 return pThis->GetRefFromAttr();
2936 SwContentFrame* SwFootnoteFrame::GetRefFromAttr()
2938 assert(mpAttribute && "invalid Attribute");
2939 SwTextNode& rTNd = const_cast<SwTextNode&>(mpAttribute->GetTextNode());
2940 SwPosition aPos( rTNd, mpAttribute->GetStart() );
2941 SwContentFrame* pCFrame = rTNd.getLayoutFrame(getRootFrame(), &aPos);
2942 return pCFrame;
2945 /** search for last content in the current footnote frame
2947 OD 2005-12-02 #i27138#
2949 SwContentFrame* SwFootnoteFrame::FindLastContent()
2951 SwContentFrame* pLastContentFrame( nullptr );
2953 // find last lower, which is a content frame or contains content.
2954 // hidden text frames, empty sections and empty tables have to be skipped.
2955 SwFrame* pLastLowerOfFootnote( GetLower() );
2956 SwFrame* pTmpLastLower( pLastLowerOfFootnote );
2957 while ( pTmpLastLower && pTmpLastLower->GetNext() )
2959 pTmpLastLower = pTmpLastLower->GetNext();
2960 if ( ( pTmpLastLower->IsTextFrame() &&
2961 !static_cast<SwTextFrame*>(pTmpLastLower)->IsHiddenNow() ) ||
2962 ( pTmpLastLower->IsSctFrame() &&
2963 static_cast<SwSectionFrame*>(pTmpLastLower)->GetSection() &&
2964 static_cast<SwSectionFrame*>(pTmpLastLower)->ContainsContent() ) ||
2965 ( pTmpLastLower->IsTabFrame() &&
2966 static_cast<SwTabFrame*>(pTmpLastLower)->ContainsContent() ) )
2968 pLastLowerOfFootnote = pTmpLastLower;
2972 // determine last content frame depending on type of found last lower.
2973 if ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsTabFrame() )
2975 pLastContentFrame = static_cast<SwTabFrame*>(pLastLowerOfFootnote)->FindLastContent();
2977 else if ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsSctFrame() )
2979 pLastContentFrame = static_cast<SwSectionFrame*>(pLastLowerOfFootnote)->FindLastContent();
2981 else
2983 pLastContentFrame = dynamic_cast<SwContentFrame*>(pLastLowerOfFootnote);
2986 return pLastContentFrame;
2989 void SwFootnoteFrame::dumpAsXml(xmlTextWriterPtr writer) const
2991 (void)xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("ftn"));
2992 dumpAsXmlAttributes(writer);
2994 (void)xmlTextWriterStartElement(writer, BAD_CAST("infos"));
2995 dumpInfosAsXml(writer);
2996 (void)xmlTextWriterEndElement(writer);
2997 dumpChildrenAsXml(writer);
2999 (void)xmlTextWriterEndElement(writer);
3002 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */