docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / sw / source / core / layout / ftnfrm.cxx
blob5bb3e3f4623b5e702ad46e3c7939dd1fb942edd4
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>
44 #include <flyfrm.hxx>
45 #include <IDocumentStylePoolAccess.hxx>
46 #include <docsh.hxx>
47 #include <poolfmt.hxx>
48 #include <swfntcch.hxx>
49 #include <wrtsh.hxx>
51 #define ENDNOTE 0x80000000
53 namespace
55 /// Calculates the height of the line that hosts the separator line (the top margin of the
56 /// container), based on the default paragraph style in rDoc.
57 bool FootnoteSeparatorHeightFromParagraph(SwDoc& rDoc, SwTwips& rHeight)
59 const SwTextFormatColl* pDefaultParaFormat
60 = rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD);
61 if (!pDefaultParaFormat)
63 return false;
66 SwViewShell* pSh = rDoc.GetDocShell()->GetWrtShell();
67 if (!pSh)
69 return false;
72 SwFontAccess aFontAccess(pDefaultParaFormat, pSh);
73 SwFont aFont(aFontAccess.Get()->GetFont());
74 OutputDevice& rOut = pSh->GetRefDev();
75 rHeight = aFont.GetHeight(pSh, rOut);
76 return true;
80 /// Search the position of an attribute in the FootnoteArray at the document,
81 /// because all footnotes are located there, ordered by their index.
82 static sal_uInt32 lcl_FindFootnotePos( const SwDoc *pDoc, const SwTextFootnote *pAttr )
84 const SwFootnoteIdxs &rFootnoteIdxs = pDoc->GetFootnoteIdxs();
86 SwTextFootnote* pBla = const_cast<SwTextFootnote*>(pAttr);
87 SwFootnoteIdxs::const_iterator it = rFootnoteIdxs.find( pBla );
88 if ( it != rFootnoteIdxs.end() )
90 sal_uInt32 nRet = it - rFootnoteIdxs.begin();
91 if( pAttr->GetFootnote().IsEndNote() )
92 return nRet + ENDNOTE;
93 return nRet;
95 OSL_ENSURE( !pDoc, "FootnotePos not found." );
96 return 0;
99 bool SwFootnoteFrame::operator<( const SwTextFootnote* pTextFootnote ) const
101 const SwDoc* pDoc = GetFormat()->GetDoc();
102 OSL_ENSURE( pDoc, "SwFootnoteFrame: Missing doc!" );
103 return lcl_FindFootnotePos( pDoc, GetAttr() ) <
104 lcl_FindFootnotePos( pDoc, pTextFootnote );
109 |* bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* pBoss, SwPageFrame* pPage)
110 |* sets pBoss on the next SwFootnoteBossFrame, which can either be a column
111 |* or a page (without columns). If the page changes meanwhile,
112 |* pPage contains the new page and this function returns true.
116 static bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* &rpBoss, SwPageFrame* &rpPage,
117 bool bDontLeave )
119 if( rpBoss->IsColumnFrame() )
121 if( rpBoss->GetNext() )
123 rpBoss = static_cast<SwFootnoteBossFrame*>(rpBoss->GetNext()); //next column
124 return false;
126 if( rpBoss->IsInSct() )
128 SwSectionFrame* pSct = rpBoss->FindSctFrame()->GetFollow();
129 if( pSct )
131 SwFrame* pLower = pSct->Lower();
132 OSL_ENSURE( pLower && pLower->IsColumnFrame(),
133 "Where's the column?" );
134 rpBoss = static_cast<SwColumnFrame*>(pLower);
135 SwPageFrame* pOld = rpPage;
136 rpPage = pSct->FindPageFrame();
137 return pOld != rpPage;
139 else if( bDontLeave )
141 rpPage = nullptr;
142 rpBoss = nullptr;
143 return false;
147 rpPage = static_cast<SwPageFrame*>(rpPage->GetNext()); // next page
148 rpBoss = rpPage;
149 if( rpPage )
151 SwLayoutFrame* pBody = rpPage->FindBodyCont();
152 SwFrame* pLower = pBody ? pBody->Lower() : nullptr;
153 if (pLower && pLower->IsColumnFrame() )
154 rpBoss = static_cast<SwFootnoteBossFrame*>(pLower); // first column
156 return true;
159 /// @returns column number if pBoss is a column, otherwise 0.
160 static sal_uInt16 lcl_ColumnNum( const SwFrame* pBoss )
162 sal_uInt16 nRet = 0;
163 if( !pBoss->IsColumnFrame() )
164 return 0;
165 const SwFrame* pCol;
166 if( pBoss->IsInSct() )
168 pCol = pBoss->GetUpper()->FindColFrame();
169 if( pBoss->GetNext() || pBoss->GetPrev() )
171 while( pBoss )
173 ++nRet; // Section columns
174 pBoss = pBoss->GetPrev();
178 else
179 pCol = pBoss;
180 while( pCol )
182 nRet += 256; // Page columns
183 pCol = pCol->GetPrev();
185 return nRet;
188 SwFootnoteContFrame::SwFootnoteContFrame( SwFrameFormat *pFormat, SwFrame* pSib ):
189 SwLayoutFrame( pFormat, pSib )
191 mnFrameType = SwFrameType::FtnCont;
194 SwFootnoteFrame* SwFootnoteContFrame::AddChained(bool bAppend, SwFrame* pThis, bool bDefaultFormat)
196 SwFootnoteFrame *pOld = pThis->FindFootnoteFrame();
197 SwFrameFormat *pFormat = pOld->GetFormat();
198 if (bDefaultFormat)
199 pFormat = pFormat->GetDoc()->GetDfltFrameFormat();
201 SwFootnoteFrame *pNew = new SwFootnoteFrame(pFormat, pOld, pOld->GetRef(), pOld->GetAttr());
203 if (bAppend)
205 if (pOld->GetFollow())
207 pNew->SetFollow(pOld->GetFollow());
208 pOld->GetFollow()->SetMaster(pNew);
210 pOld->SetFollow(pNew);
211 pNew->SetMaster(pOld);
213 else
215 if (pOld->GetMaster())
217 pNew->SetMaster(pOld->GetMaster());
218 pOld->GetMaster()->SetFollow(pNew);
220 pNew->SetFollow(pOld);
221 pOld->SetMaster(pNew);
224 return pNew;
227 // lcl_Undersize(..) walks over a SwFrame and its contents
228 // and returns the sum of all requested TextFrame magnifications.
230 static tools::Long lcl_Undersize( const SwFrame* pFrame )
232 tools::Long nRet = 0;
233 SwRectFnSet aRectFnSet(pFrame);
234 if( pFrame->IsTextFrame() )
236 if( static_cast<const SwTextFrame*>(pFrame)->IsUndersized() )
238 // Does this TextFrame would like to be a little bit bigger?
239 nRet = static_cast<const SwTextFrame*>(pFrame)->GetParHeight() -
240 aRectFnSet.GetHeight(pFrame->getFramePrintArea());
241 if( nRet < 0 )
242 nRet = 0;
245 else if( pFrame->IsLayoutFrame() )
247 const SwFrame* pNxt = static_cast<const SwLayoutFrame*>(pFrame)->Lower();
248 while( pNxt )
250 nRet += lcl_Undersize( pNxt );
251 pNxt = pNxt->GetNext();
254 return nRet;
257 namespace sw {
259 SwTwips FootnoteSeparatorHeight(SwDoc& rDoc, SwPageFootnoteInfo const& rInf)
261 const IDocumentSettingAccess& rIDSA = rDoc.getIDocumentSettingAccess();
262 if (rIDSA.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
264 // Word style: try to calculate the height from the default para format.
265 SwTwips nHeight{};
266 if (FootnoteSeparatorHeightFromParagraph(rDoc, nHeight))
268 return nHeight;
272 // Writer style: calculate from the page style.
273 return rInf.GetTopDist() + rInf.GetBottomDist() + rInf.GetLineWidth();
276 } // namespace sw
278 /// "format" the frame (Fixsize is not set here).
279 void SwFootnoteContFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs * )
281 // calculate total border, only one distance to the top
282 const SwPageFrame* pPage = FindPageFrame();
283 const SwPageFootnoteInfo &rInf = pPage->GetPageDesc()->GetFootnoteInfo();
284 SwDoc* pDoc = getRootFrame()->GetCurrShell()->GetDoc();
285 const SwTwips nBorder = sw::FootnoteSeparatorHeight(*pDoc, rInf);
286 SwRectFnSet aRectFnSet(this);
288 if ( !isFramePrintAreaValid() )
290 setFramePrintAreaValid(true);
291 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
293 aRectFnSet.SetTop( aPrt, nBorder );
294 aRectFnSet.SetWidth( aPrt, aRectFnSet.GetWidth(getFrameArea()) );
295 aRectFnSet.SetHeight(aPrt, aRectFnSet.GetHeight(getFrameArea()) - nBorder );
297 if( aRectFnSet.GetHeight(aPrt) < 0 && !pPage->IsFootnotePage() )
299 setFrameAreaSizeValid(false);
303 if ( isFrameAreaSizeValid() )
304 return;
306 bool bGrow = pPage->IsFootnotePage();
307 if( bGrow )
309 const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
310 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
311 bGrow = false;
313 if( bGrow )
314 Grow( LONG_MAX );
315 else
317 // VarSize is determined based on the content plus the borders
318 SwTwips nRemaining = 0;
319 SwFrame *pFrame = m_pLower;
320 while ( pFrame )
321 { // lcl_Undersize(..) respects (recursively) TextFrames, which
322 // would like to be bigger. They are created especially in
323 // columnized borders, if these do not have their maximum
324 // size yet.
325 nRemaining += aRectFnSet.GetHeight(pFrame->getFrameArea()) + lcl_Undersize( pFrame );
326 pFrame = pFrame->GetNext();
328 // add the own border
329 nRemaining += nBorder;
331 SwTwips nDiff;
332 if( IsInSct() )
334 nDiff = -aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()) );
335 if( nDiff > 0 )
337 if( nDiff > aRectFnSet.GetHeight(getFrameArea()) )
339 nDiff = aRectFnSet.GetHeight(getFrameArea());
342 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
343 aRectFnSet.AddBottom( aFrm, -nDiff );
344 aRectFnSet.AddHeight( aFrm, -nDiff );
347 nDiff = aRectFnSet.GetHeight(getFrameArea()) - nRemaining;
348 if ( nDiff > 0 )
349 Shrink( nDiff );
350 else if ( nDiff < 0 )
352 Grow( -nDiff );
353 // It may happen that there is less space available,
354 // than what the border needs - the size of the PrtArea
355 // will then be negative.
356 SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
357 if( nPrtHeight < 0 )
359 const SwTwips nTmpDiff = std::max( SwTwips(aRectFnSet.GetTop(getFramePrintArea())), -nPrtHeight );
360 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
361 aRectFnSet.SubTop( aPrt, nTmpDiff );
366 setFrameAreaSizeValid(true);
369 SwTwips SwFootnoteContFrame::GrowFrame(SwTwips nDist, SwResizeLimitReason& reason, bool bTst, bool)
371 // No check if FixSize since FootnoteContainer are variable up to their max. height.
372 // If the max. height is LONG_MAX, take as much space as needed.
373 // If the page is a special footnote page, take also as much as possible.
374 assert(GetUpper() && GetUpper()->IsFootnoteBossFrame());
376 const auto nOrigDist = std::max(nDist, SwTwips(0));
377 reason = SwResizeLimitReason::Unspecified;
379 SwRectFnSet aRectFnSet(this);
380 if( aRectFnSet.GetHeight(getFrameArea()) > 0 &&
381 nDist > ( LONG_MAX - aRectFnSet.GetHeight(getFrameArea()) ) )
382 nDist = LONG_MAX - aRectFnSet.GetHeight(getFrameArea());
384 SwFootnoteBossFrame *pBoss = static_cast<SwFootnoteBossFrame*>(GetUpper());
385 if( IsInSct() )
387 SwSectionFrame* pSect = FindSctFrame();
388 OSL_ENSURE( pSect, "GrowFrame: Missing SectFrame" );
389 // In a section, which has to maximize, a footnotecontainer is allowed
390 // to grow, when the section can't grow anymore.
391 if( !bTst && !pSect->IsColLocked() &&
392 pSect->ToMaximize( false ) && pSect->Growable() )
394 pSect->InvalidateSize();
395 if (nOrigDist)
396 reason = SwResizeLimitReason::FlowToFollow;
397 return 0;
400 const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
401 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
402 SwPageFrame *pPage = pBoss->FindPageFrame();
403 if ( bBrowseMode || !pPage->IsFootnotePage() )
405 if ( pBoss->GetMaxFootnoteHeight() != LONG_MAX )
407 nDist = std::min( nDist,
408 SwTwips(pBoss->GetMaxFootnoteHeight() - aRectFnSet.GetHeight(getFrameArea())) );
409 if ( nDist <= 0 )
411 if (nOrigDist)
412 reason = SwResizeLimitReason::FlowToFollow;
413 return 0;
416 // FootnoteBoss also influences the max value
417 if( !IsInSct() )
419 const SwTwips nMax = pBoss->GetVarSpace();
420 if ( nDist > nMax )
422 nDist = nMax;
423 if (nOrigDist)
424 reason = SwResizeLimitReason::FlowToFollow;
426 if ( nDist <= 0 )
427 return 0;
430 else if( nDist > aRectFnSet.GetHeight(GetPrev()->getFrameArea()) )
432 // do not use more space than the body has
433 nDist = aRectFnSet.GetHeight(GetPrev()->getFrameArea());
434 if (nOrigDist)
435 reason = SwResizeLimitReason::FlowToFollow;
438 tools::Long nAvail = 0;
439 if ( bBrowseMode )
441 nAvail = GetUpper()->getFramePrintArea().Height();
442 const SwFrame *pAvail = GetUpper()->Lower();
444 { nAvail -= pAvail->getFrameArea().Height();
445 pAvail = pAvail->GetNext();
446 } while ( pAvail );
447 if ( nAvail > nDist )
448 nAvail = nDist;
451 if ( !bTst )
453 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
454 aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nDist );
456 if( IsVertical() && !IsVertLR() )
458 aFrm.Pos().AdjustX( -nDist );
461 tools::Long nGrow = nDist - nAvail,
462 nReal = 0;
463 if ( nGrow > 0 )
465 SwNeighbourAdjust nAdjust = pBoss->NeighbourhoodAdjustment();
466 if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
467 nReal = AdjustNeighbourhood( nGrow, bTst );
468 else
470 if( SwNeighbourAdjust::GrowAdjust == nAdjust )
472 SwFrame* pFootnote = Lower();
473 if( pFootnote )
475 while( pFootnote->GetNext() )
476 pFootnote = pFootnote->GetNext();
477 if( static_cast<SwFootnoteFrame*>(pFootnote)->GetAttr()->GetFootnote().IsEndNote() )
479 nReal = AdjustNeighbourhood( nGrow, bTst );
480 nAdjust = SwNeighbourAdjust::GrowShrink; // no more AdjustNeighbourhood
484 nReal += pBoss->Grow(nGrow - nReal, reason, bTst, false);
485 if( ( SwNeighbourAdjust::GrowAdjust == nAdjust || SwNeighbourAdjust::AdjustGrow == nAdjust )
486 && nReal < nGrow )
487 nReal += AdjustNeighbourhood( nGrow - nReal, bTst );
491 nReal += nAvail;
493 if ( !bTst )
495 if ( nReal != nDist )
497 nDist -= nReal;
499 // We can only respect the boundless wish so much
500 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
501 aFrm.AddHeight( -nDist );
503 if( IsVertical() && !IsVertLR() )
505 aFrm.Pos().AdjustX(nDist );
509 // growing happens upwards, so successors to not need to be invalidated
510 if( nReal )
512 InvalidateSize_();
513 InvalidatePos_();
514 InvalidatePage( pPage );
517 if (nOrigDist > nReal && reason == SwResizeLimitReason::Unspecified)
518 reason = SwResizeLimitReason::FlowToFollow;
519 return nReal;
522 SwTwips SwFootnoteContFrame::ShrinkFrame( SwTwips nDiff, bool bTst, bool bInfo )
524 SwPageFrame *pPage = FindPageFrame();
525 bool bShrink = false;
526 if ( pPage )
528 if( !pPage->IsFootnotePage() )
529 bShrink = true;
530 else
532 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
533 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
534 bShrink = true;
537 if( bShrink )
539 SwTwips nRet = SwLayoutFrame::ShrinkFrame( nDiff, bTst, bInfo );
540 if( IsInSct() && !bTst )
541 FindSctFrame()->InvalidateNextPos();
542 if ( !bTst && nRet )
544 InvalidatePos_();
545 InvalidatePage( pPage );
547 return nRet;
549 return 0;
552 SwFootnoteFrame::SwFootnoteFrame( SwFrameFormat *pFormat, SwFrame* pSib, SwContentFrame *pCnt, SwTextFootnote *pAt ):
553 SwLayoutFrame( pFormat, pSib ),
554 mpFollow( nullptr ),
555 mpMaster( nullptr ),
556 mpReference( pCnt ),
557 mpAttribute( pAt ),
558 mbBackMoveLocked( false ),
559 // #i49383#
560 mbUnlockPosOfLowerObjs( true )
562 mnFrameType = SwFrameType::Ftn;
565 void SwFootnoteFrame::InvalidateNxtFootnoteCnts( SwPageFrame const *pPage )
567 if ( !GetNext() )
568 return;
570 SwFrame *pCnt = static_cast<SwLayoutFrame*>(GetNext())->ContainsAny();
571 if( !pCnt )
572 return;
574 pCnt->InvalidatePage( pPage );
575 pCnt->InvalidatePrt_();
577 { pCnt->InvalidatePos_();
578 if( pCnt->IsSctFrame() )
580 SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
581 if( pTmp )
582 pTmp->InvalidatePos_();
584 pCnt->GetUpper()->InvalidateSize_();
585 pCnt = pCnt->FindNext();
586 } while ( pCnt && GetUpper()->IsAnLower( pCnt ) );
589 bool SwFootnoteFrame::IsDeleteForbidden() const
591 if (SwLayoutFrame::IsDeleteForbidden())
592 return true;
593 // needs to be in sync with the ::Cut logic
594 const SwLayoutFrame *pUp = GetUpper();
595 if (pUp)
597 if (GetPrev())
598 return false;
600 // The last footnote takes its container along if it
601 // is deleted. Cut would put pUp->Lower() to the value
602 // of GetNext(), so if there is no GetNext then
603 // Cut would delete pUp. If that condition is true
604 // here then check if the container is delete-forbidden
605 return !GetNext() && pUp->IsDeleteForbidden();
607 return false;
610 void SwFootnoteFrame::Cut()
612 if ( GetNext() )
613 GetNext()->InvalidatePos();
614 else if ( GetPrev() )
615 GetPrev()->SetRetouche();
617 // first move then shrink Upper
618 SwLayoutFrame *pUp = GetUpper();
620 // correct chaining
621 SwFootnoteFrame *pFootnote = this;
622 if ( pFootnote->GetFollow() )
623 pFootnote->GetFollow()->SetMaster( pFootnote->GetMaster() );
624 if ( pFootnote->GetMaster() )
625 pFootnote->GetMaster()->SetFollow( pFootnote->GetFollow() );
626 pFootnote->SetFollow( nullptr );
627 pFootnote->SetMaster( nullptr );
629 // cut all connections
630 RemoveFromLayout();
632 if ( !pUp )
633 return;
635 // The last footnote takes its container along
636 if (!pUp->Lower())
638 SwPageFrame *pPage = pUp->FindPageFrame();
639 if ( pPage )
641 SwLayoutFrame *pBody = pPage->FindBodyCont();
642 if( pBody && !pBody->ContainsContent() )
643 pPage->getRootFrame()->SetSuperfluous();
645 SwSectionFrame* pSect = pUp->FindSctFrame();
646 pUp->Cut();
647 SwFrame::DestroyFrame(pUp);
648 // If the last footnote container was removed from a column
649 // section without a Follow, then this section can be shrunk.
650 if( pSect && !pSect->ToMaximize( false ) && !pSect->IsColLocked() )
651 pSect->InvalidateSize_();
653 else
654 { if ( getFrameArea().Height() )
655 pUp->Shrink( getFrameArea().Height() );
656 pUp->SetCompletePaint();
657 pUp->InvalidatePage();
661 void SwFootnoteFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
663 OSL_ENSURE( pParent, "no parent in Paste." );
664 OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
665 OSL_ENSURE( pParent != this, "I am my own parent." );
666 OSL_ENSURE( pSibling != this, "I am my own sibling." );
667 OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
668 "I am still somewhere registered." );
670 // insert into tree structure
671 InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
673 SwRectFnSet aRectFnSet(this);
674 if( aRectFnSet.GetWidth(getFrameArea())!=aRectFnSet.GetWidth(pParent->getFramePrintArea()) )
675 InvalidateSize_();
676 InvalidatePos_();
677 if (SwFrame *const pContent = ContainsContent())
678 { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
679 pContent->InvalidatePrt_();
681 SwPageFrame *pPage = FindPageFrame();
682 InvalidatePage( pPage );
683 if (SwFootnoteFrame *const pNext = static_cast<SwFootnoteFrame *>(GetNext()))
685 pNext->InvalidatePos_();
686 if (SwFrame *const pContent = pNext->ContainsContent())
687 { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
688 pContent->InvalidatePrt_();
691 if( aRectFnSet.GetHeight(getFrameArea()) )
692 pParent->Grow( aRectFnSet.GetHeight(getFrameArea()) );
694 // If the predecessor is the master and/or the successor is the Follow,
695 // then take their content and destroy them.
696 if ( GetPrev() && GetPrev() == GetMaster() )
698 OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetPrev()->GetLower() ),
699 "Footnote without content?" );
700 SwFlowFrame::CastFlowFrame( GetPrev()->GetLower())->
701 MoveSubTree( this, GetLower() );
702 SwFrame *pDel = GetPrev();
703 assert(pDel != this);
704 pDel->Cut();
705 SwFrame::DestroyFrame(pDel);
707 if ( GetNext() && GetNext() == GetFollow() )
709 OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetNext()->GetLower() ),
710 "Footnote without content?" );
711 SwFlowFrame::CastFlowFrame( GetNext()->GetLower() )->MoveSubTree( this );
712 SwFrame *pDel = GetNext();
713 assert(pDel != this);
714 pDel->Cut();
715 SwFrame::DestroyFrame(pDel);
717 #if OSL_DEBUG_LEVEL > 0
718 SwDoc *pDoc = GetFormat()->GetDoc();
719 if ( GetPrev() )
721 OSL_ENSURE( lcl_FindFootnotePos( pDoc, static_cast<SwFootnoteFrame*>(GetPrev())->GetAttr() ) <=
722 lcl_FindFootnotePos( pDoc, GetAttr() ), "Prev is not FootnotePrev" );
724 if ( GetNext() )
726 OSL_ENSURE( lcl_FindFootnotePos( pDoc, GetAttr() ) <=
727 lcl_FindFootnotePos( pDoc, static_cast<SwFootnoteFrame*>(GetNext())->GetAttr() ),
728 "Next is not FootnoteNext" );
730 #endif
731 InvalidateNxtFootnoteCnts( pPage );
734 /// Return the next layout leaf in that the frame can be moved.
735 /// New pages will only be created if specified by the parameter.
736 SwLayoutFrame *SwFrame::GetNextFootnoteLeaf( MakePageType eMakePage )
738 SwFootnoteBossFrame *pOldBoss = FindFootnoteBossFrame();
739 SwPageFrame* pOldPage = pOldBoss->FindPageFrame();
740 SwPageFrame* pPage;
741 SwFootnoteBossFrame *pBoss = pOldBoss->IsColumnFrame() ?
742 static_cast<SwFootnoteBossFrame*>(pOldBoss->GetNext()) : nullptr; // next column, if existing
743 if( pBoss )
744 pPage = nullptr;
745 else
747 if( pOldBoss->GetUpper()->IsSctFrame() )
748 { // this can only be in a column area
749 SwLayoutFrame* pNxt = pOldBoss->GetNextSctLeaf( eMakePage );
750 if( pNxt )
752 OSL_ENSURE( pNxt->IsColBodyFrame(), "GetNextFootnoteLeaf: Funny Leaf" );
753 pBoss = static_cast<SwFootnoteBossFrame*>(pNxt->GetUpper());
754 pPage = pBoss->FindPageFrame();
756 else
757 return nullptr;
759 else
761 // next page
762 pPage = static_cast<SwPageFrame*>(pOldPage->GetNext());
763 // skip empty pages
764 if( pPage && pPage->IsEmptyPage() )
765 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
766 pBoss = pPage;
769 // What do we have until here?
770 // pBoss != NULL, pPage==NULL => pBoss is the next column on the same page
771 // pBoss != NULL, pPage!=NULL => pBoss and pPage are the following page (empty pages skipped)
772 // pBoss == NULL => pPage == NULL, so there are no following pages
774 // If the footnote has already a Follow we do not need to search.
775 // However, if there are unwanted empty columns/pages between Footnote and Follow,
776 // create another Follow on the next best column/page and the rest will sort itself out.
777 SwFootnoteFrame *pFootnote = FindFootnoteFrame();
778 if ( pFootnote && pFootnote->GetFollow() )
780 SwFootnoteBossFrame* pTmpBoss = pFootnote->GetFollow()->FindFootnoteBossFrame();
781 // Following cases will be handled:
782 // 1. both "FootnoteBoss"es are neighboring columns/pages
783 // 2. the new one is the first column of a neighboring page
784 // 3. the new one is the first column in a section of the next page
785 while( pTmpBoss != pBoss && pTmpBoss && !pTmpBoss->GetPrev() )
786 pTmpBoss = pTmpBoss->GetUpper()->FindFootnoteBossFrame();
787 if( pTmpBoss == pBoss )
788 return pFootnote->GetFollow();
791 // If no pBoss could be found or it is a "wrong" page, we need a new page.
792 if ( !pBoss || ( pPage && pPage->IsEndNotePage() && !pOldPage->IsEndNotePage() ) )
794 if ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT )
796 pBoss = InsertPage( pOldPage, pOldPage->IsFootnotePage() );
797 static_cast<SwPageFrame*>(pBoss)->SetEndNotePage( pOldPage->IsEndNotePage() );
799 else
800 return nullptr;
802 if( pBoss->IsPageFrame() )
804 // If this page has columns, then go to the first one
805 SwLayoutFrame* pLay = pBoss->FindBodyCont();
806 SwFrame* pLower = pLay ? pLay->Lower() : nullptr;
807 if( pLower && pLower->IsColumnFrame() )
808 pBoss = static_cast<SwFootnoteBossFrame*>(pLower);
810 // found column/page - add myself
811 SwFootnoteContFrame *pCont = pBoss->FindFootnoteCont();
812 if ( !pCont && pBoss->GetMaxFootnoteHeight() &&
813 ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) )
814 pCont = pBoss->MakeFootnoteCont();
815 return pCont;
818 /// Get the preceding layout leaf in that the frame can be moved.
819 SwLayoutFrame *SwFrame::GetPrevFootnoteLeaf( MakePageType eMakeFootnote )
821 // The predecessor of a footnote is (if possible)
822 // the master of the chain of the footnote.
823 SwFootnoteFrame *pFootnote = FindFootnoteFrame();
824 SwLayoutFrame *pRet = pFootnote->GetMaster();
826 SwFootnoteBossFrame* pOldBoss = FindFootnoteBossFrame();
827 SwPageFrame *pOldPage = pOldBoss->FindPageFrame();
829 if ( !pOldBoss->GetPrev() && !pOldPage->GetPrev() )
830 return pRet; // there is neither a predecessor column nor page
832 if ( !pRet )
834 bool bEndn = pFootnote->GetAttr()->GetFootnote().IsEndNote();
835 SwFrame* pTmpRef = nullptr;
836 const IDocumentSettingAccess& rSettings
837 = pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
838 bool bContEndnotes = rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
839 if( bEndn && pFootnote->IsInSct() && !bContEndnotes)
841 SwSectionFrame* pSect = pFootnote->FindSctFrame();
842 if( pSect->IsEndnAtEnd() )
843 // Endnotes at the end of the section.
844 pTmpRef = pSect->FindLastContent( SwFindMode::LastCnt );
846 else if (bEndn && bContEndnotes)
848 // Endnotes at the end of the document.
849 pTmpRef = pFootnote->FindFootnoteBossFrame();
851 if( !pTmpRef )
852 // Endnotes on a separate page.
853 pTmpRef = pFootnote->GetRef();
854 SwFootnoteBossFrame* pStop = pTmpRef->FindFootnoteBossFrame( !bEndn );
856 const sal_uInt16 nNum = pStop->GetPhyPageNum();
858 // Do not leave the corresponding page if the footnote should
859 // be shown at the document ending or the footnote is an endnote.
860 const bool bEndNote = pOldPage->IsEndNotePage();
861 const bool bFootnoteEndDoc = pOldPage->IsFootnotePage();
862 SwFootnoteBossFrame* pNxtBoss = pOldBoss;
863 SwSectionFrame *pSect = pNxtBoss->GetUpper()->IsSctFrame() ?
864 static_cast<SwSectionFrame*>(pNxtBoss->GetUpper()) : nullptr;
868 if( pNxtBoss->IsColumnFrame() && pNxtBoss->GetPrev() )
869 pNxtBoss = static_cast<SwFootnoteBossFrame*>(pNxtBoss->GetPrev()); // one column backwards
870 else // one page backwards
872 SwLayoutFrame* pBody = nullptr;
873 if( pSect )
875 if( pSect->IsFootnoteLock() )
877 if( pNxtBoss == pOldBoss )
878 return nullptr;
879 pStop = pNxtBoss;
881 else
883 pSect = pSect->FindMaster();
884 if( !pSect || !pSect->Lower() )
885 return nullptr;
886 OSL_ENSURE( pSect->Lower()->IsColumnFrame(),
887 "GetPrevFootnoteLeaf: Where's the column?" );
888 pNxtBoss = static_cast<SwFootnoteBossFrame*>(pSect->Lower());
889 pBody = pSect;
892 else
894 SwPageFrame* pPage = static_cast<SwPageFrame*>(pNxtBoss->FindPageFrame()->GetPrev());
895 if( !pPage || pPage->GetPhyPageNum() < nNum ||
896 bEndNote != pPage->IsEndNotePage() || bFootnoteEndDoc != pPage->IsFootnotePage() )
897 return nullptr; // no further pages found
898 pNxtBoss = pPage;
899 pBody = pPage->FindBodyCont();
901 // We have the previous page, we might need to find the last column of it
902 if( pBody )
904 SwFrame* pLower = pBody->Lower();
905 if ( pLower && pLower->IsColumnFrame() )
907 pNxtBoss = static_cast<SwFootnoteBossFrame*>(pBody->GetLastLower());
911 SwFootnoteContFrame *pCont = pNxtBoss->FindFootnoteCont();
912 if ( pCont )
914 pRet = pCont;
915 break;
917 if ( pStop == pNxtBoss )
919 // Reached the column/page of the reference.
920 // Try to add a container and paste our content.
921 if ( eMakeFootnote == MAKEPAGE_FTN && pNxtBoss->GetMaxFootnoteHeight() )
922 pRet = pNxtBoss->MakeFootnoteCont();
923 break;
925 } while( !pRet );
927 if ( pRet )
929 const SwFootnoteBossFrame* pNewBoss = pRet->FindFootnoteBossFrame();
930 bool bJump = false;
931 if( pOldBoss->IsColumnFrame() && pOldBoss->GetPrev() ) // a previous column exists
932 bJump = pOldBoss->GetPrev() != static_cast<SwFrame const *>(pNewBoss); // did we chose it?
933 else if( pNewBoss->IsColumnFrame() && pNewBoss->GetNext() )
934 bJump = true; // there is another column after the boss (not the old boss)
935 else
937 // Will be reached only if old and new boss are both either pages or the last (new)
938 // or first (old) column of a page. In this case, check if pages were skipped.
939 const sal_uInt16 nDiff = pOldPage->GetPhyPageNum() - pRet->FindPageFrame()->GetPhyPageNum();
940 if ( nDiff > 2 ||
941 (nDiff > 1 && !static_cast<SwPageFrame*>(pOldPage->GetPrev())->IsEmptyPage()) )
942 bJump = true;
944 if( bJump )
945 SwFlowFrame::SetMoveBwdJump( true );
947 return pRet;
950 bool SwFrame::IsFootnoteAllowed() const
952 bool bSplitFly = false;
953 const SwFlyFrame* pFlyFrame = FindFlyFrame();
954 if (pFlyFrame)
956 // This is a fly. Check if it's a split fly, which is OK to host a footnote.
957 bSplitFly = pFlyFrame->IsFlySplitAllowed();
960 if (!IsInDocBody() && !bSplitFly)
961 return false;
963 if ( IsInTab() )
965 // no footnotes in repeated headlines
966 const SwTabFrame *pTab = const_cast<SwFrame*>(this)->ImplFindTabFrame();
967 assert(pTab);
968 if ( pTab->IsFollow() )
969 return !pTab->IsInHeadline( *this );
971 return true;
974 void SwRootFrame::UpdateFootnoteNums()
976 // page numbering only if set at the document
977 if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum == FTNNUM_PAGE )
979 SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
980 while ( pPage && !pPage->IsFootnotePage() )
982 pPage->UpdateFootnoteNum();
983 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
988 /// remove all footnotes (not the references) and all footnote pages
989 void sw_RemoveFootnotes( SwFootnoteBossFrame* pBoss, bool bPageOnly, bool bEndNotes )
993 SwFootnoteContFrame *pCont = pBoss->FindFootnoteCont();
994 if ( pCont )
996 SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
997 assert(pFootnote);
998 if ( bPageOnly )
999 while ( pFootnote->GetMaster() )
1000 pFootnote = pFootnote->GetMaster();
1003 SwFootnoteFrame *pNxt = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
1004 if ( !pFootnote->GetAttr()->GetFootnote().IsEndNote() ||
1005 bEndNotes )
1007 SwContentFrame* pCF = pFootnote->GetRef();
1008 // it's possible that the contentframe is empty when closing Writer
1009 if (!pCF)
1010 return;
1011 if (!pCF->IsInDtor())
1012 // NOTE: I REPRO'D A CRASH HERE BUT THE DEBUGGER DIDN'T INDICATE
1013 // WHAT THE PROBLEM WAS -- the objects are valid. Happens when
1014 // undoing/redoing rapidly for some time then saving and the crash
1015 // happens on close of LO
1016 pCF->Prepare(PrepareHint::FootnoteInvalidation,
1017 static_cast<void*>(pFootnote->GetAttr()));
1018 if ( bPageOnly && !pNxt )
1019 pNxt = pFootnote->GetFollow();
1020 pFootnote->Cut();
1021 SwFrame::DestroyFrame(pFootnote);
1023 pFootnote = pNxt;
1025 } while ( pFootnote );
1027 if( !pBoss->IsInSct() )
1029 // A sectionframe with the Footnote/EndnAtEnd-flags may contain
1030 // foot/endnotes. If the last lower frame of the bodyframe is
1031 // a multicolumned sectionframe, it may contain footnotes, too.
1032 SwLayoutFrame* pBody = pBoss->FindBodyCont();
1033 if( pBody )
1035 SwFrame* pLow = pBody->Lower();
1036 while (pLow)
1038 if( pLow->IsSctFrame() && ( !pLow->GetNext() ||
1039 static_cast<SwSectionFrame*>(pLow)->IsAnyNoteAtEnd() ) )
1041 SwFrame* pLowerLower = static_cast<SwSectionFrame*>(pLow)->Lower();
1042 if (pLowerLower && pLowerLower->IsColumnFrame() )
1043 sw_RemoveFootnotes( static_cast<SwColumnFrame*>(pLowerLower),
1044 bPageOnly, bEndNotes );
1046 pLow = pLow->GetNext();
1050 // is there another column?
1051 pBoss = pBoss->IsColumnFrame() ? static_cast<SwColumnFrame*>(pBoss->GetNext()) : nullptr;
1052 } while( pBoss );
1055 void SwRootFrame::RemoveFootnotes( SwPageFrame *pPage, bool bPageOnly, bool bEndNotes )
1057 if ( !pPage )
1058 pPage = static_cast<SwPageFrame*>(Lower());
1060 while (pPage)
1061 { // On columned pages we have to clean up in all columns
1062 SwFootnoteBossFrame* pBoss;
1063 SwLayoutFrame* pBody = pPage->FindBodyCont();
1064 SwFrame* pLower = pBody ? pBody->Lower() : nullptr;
1065 if( pLower && pLower->IsColumnFrame() )
1066 pBoss = static_cast<SwFootnoteBossFrame*>(pLower); // the first column
1067 else
1068 pBoss = pPage; // no columns
1069 sw_RemoveFootnotes( pBoss, bPageOnly, bEndNotes );
1070 if ( !bPageOnly )
1072 if ( pPage->IsFootnotePage() &&
1073 (!pPage->IsEndNotePage() || bEndNotes) )
1075 SwFrame *pDel = pPage;
1076 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1077 pDel->Cut();
1078 SwFrame::DestroyFrame(pDel);
1080 else
1081 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1083 else
1084 break;
1089 /// Change the page template of the footnote pages
1090 void SwRootFrame::CheckFootnotePageDescs( bool bEndNote )
1092 SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
1093 while ( pPage && !pPage->IsFootnotePage() )
1094 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1095 while ( pPage && pPage->IsEndNotePage() != bEndNote )
1096 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1098 if ( pPage )
1099 SwFrame::CheckPageDescs( pPage, false );
1102 /** Insert a footnote container
1104 * A footnote container is always placed directly behind the body text.
1106 * The frame format (FrameFormat) is always the default frame format.
1108 * @return footnote container frame
1110 SwFootnoteContFrame *SwFootnoteBossFrame::MakeFootnoteCont()
1112 SAL_WARN_IF(FindFootnoteCont(), "sw.core", "footnote container exists already");
1114 SwFootnoteContFrame *pNew = new SwFootnoteContFrame( GetFormat()->GetDoc()->GetDfltFrameFormat(), this );
1115 SwLayoutFrame *pLay = FindBodyCont();
1116 pNew->Paste( this, pLay->GetNext() );
1117 return pNew;
1120 SwFootnoteContFrame *SwFootnoteBossFrame::FindFootnoteCont()
1122 SwFrame *pFrame = Lower();
1123 while( pFrame && !pFrame->IsFootnoteContFrame() )
1124 pFrame = pFrame->GetNext();
1126 #if OSL_DEBUG_LEVEL > 0
1127 if ( pFrame )
1129 SwFrame *pFootnote = pFrame->GetLower();
1130 assert(pFootnote);
1131 while ( pFootnote )
1133 assert(pFootnote->IsFootnoteFrame() && "Neighbor of footnote must be a footnote");
1134 pFootnote = pFootnote->GetNext();
1137 #endif
1139 return static_cast<SwFootnoteContFrame*>(pFrame);
1142 /// Search the next available footnote container.
1143 SwFootnoteContFrame *SwFootnoteBossFrame::FindNearestFootnoteCont( bool bDontLeave )
1145 SwFootnoteContFrame *pCont = nullptr;
1146 if ( !GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
1148 pCont = FindFootnoteCont();
1149 if ( !pCont )
1151 SwPageFrame *pPage = FindPageFrame();
1152 SwFootnoteBossFrame* pBoss = this;
1153 bool bEndNote = pPage->IsEndNotePage();
1156 bool bChgPage = lcl_NextFootnoteBoss( pBoss, pPage, bDontLeave );
1157 // Found another boss? When changing pages, also the endnote flag must match.
1158 if( pBoss && ( !bChgPage || pPage->IsEndNotePage() == bEndNote ) )
1159 pCont = pBoss->FindFootnoteCont();
1160 } while ( !pCont && pPage );
1163 return pCont;
1166 SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote()
1168 // search for the nearest footnote container
1169 SwFootnoteContFrame *pCont = FindNearestFootnoteCont();
1170 if ( !pCont )
1171 return nullptr;
1173 // Starting from the first footnote, search the first
1174 // footnote that is referenced by the current column/page
1176 SwFootnoteFrame *pRet = static_cast<SwFootnoteFrame*>(pCont->Lower());
1177 const sal_uInt16 nRefNum = FindPageFrame()->GetPhyPageNum();
1178 const sal_uInt16 nRefCol = lcl_ColumnNum( this );
1179 sal_uInt16 nPgNum, nColNum; // page number, column number
1180 SwFootnoteBossFrame* pBoss;
1181 SwPageFrame* pPage;
1182 if( pRet )
1184 pBoss = pRet->GetRef()->FindFootnoteBossFrame();
1185 OSL_ENSURE( pBoss, "FindFirstFootnote: No boss found" );
1186 if( !pBoss )
1187 return nullptr; // ?There must be a bug, but no GPF
1188 pPage = pBoss->FindPageFrame();
1189 // it's possible that there is no page frame when performing an undo operation
1190 if (!pPage)
1191 return nullptr;
1192 nPgNum = pPage->GetPhyPageNum();
1193 if ( nPgNum == nRefNum )
1195 nColNum = lcl_ColumnNum( pBoss );
1196 if( nColNum == nRefCol )
1197 return pRet; // found
1198 else if( nColNum > nRefCol )
1199 return nullptr; // at least one column too far
1201 else if ( nPgNum > nRefNum )
1202 return nullptr; // at least one column too far
1204 else
1205 return nullptr;
1206 // Done if Ref is on a subsequent page or on the same page in a subsequent column
1210 while ( pRet->GetFollow() )
1211 pRet = pRet->GetFollow();
1213 SwFootnoteFrame *pNxt = static_cast<SwFootnoteFrame*>(pRet->GetNext());
1214 if ( !pNxt )
1216 pBoss = pRet->FindFootnoteBossFrame();
1217 // it's possible that there is no boss frame when performing an undo operation
1218 if (!pBoss)
1219 return nullptr;
1220 // it's possible that there is no page frame when performing an undo operation
1221 pPage = pBoss->FindPageFrame();
1222 if (!pPage)
1223 return nullptr;
1224 lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss
1225 pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr;
1226 if ( pCont )
1227 pNxt = static_cast<SwFootnoteFrame*>(pCont->Lower());
1229 if ( pNxt )
1231 pRet = pNxt;
1232 pBoss = pRet->GetRef()->FindFootnoteBossFrame();
1233 // it's possible that there is no boss frame when performing an undo operation
1234 if (!pBoss)
1235 return nullptr;
1236 // it's possible that there is no page frame when performing an undo operation
1237 pPage = pBoss->FindPageFrame();
1238 if (!pPage)
1239 return nullptr;
1240 nPgNum = pPage->GetPhyPageNum();
1241 if ( nPgNum == nRefNum )
1243 nColNum = lcl_ColumnNum( pBoss );
1244 if( nColNum == nRefCol )
1245 break; // found
1246 else if( nColNum > nRefCol )
1247 pRet = nullptr; // at least one column too far
1249 else if ( nPgNum > nRefNum )
1250 pRet = nullptr; // at least a page too far
1252 else
1253 pRet = nullptr; // there is none
1254 } while( pRet );
1255 return pRet;
1258 /// Get the first footnote of a given content
1259 const SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote( SwContentFrame const *pCnt ) const
1261 const SwFootnoteFrame *pRet = const_cast<SwFootnoteBossFrame*>(this)->FindFirstFootnote();
1262 if ( pRet )
1264 const sal_uInt16 nColNum = lcl_ColumnNum( this );
1265 const sal_uInt16 nPageNum = GetPhyPageNum();
1266 while ( pRet && (pRet->GetRef() != pCnt) )
1268 while ( pRet->GetFollow() )
1269 pRet = pRet->GetFollow();
1271 if ( pRet->GetNext() )
1272 pRet = static_cast<const SwFootnoteFrame*>(pRet->GetNext());
1273 else
1274 { SwFootnoteBossFrame *pBoss = const_cast<SwFootnoteBossFrame*>(pRet->FindFootnoteBossFrame());
1275 SwPageFrame *pPage = pBoss->FindPageFrame();
1276 lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss
1277 SwFootnoteContFrame *pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr;
1278 pRet = pCont ? static_cast<SwFootnoteFrame*>(pCont->Lower()) : nullptr;
1280 if ( pRet )
1282 const SwFootnoteBossFrame* pBoss = pRet->GetRef()->FindFootnoteBossFrame();
1283 if( !pBoss || pBoss->GetPhyPageNum() != nPageNum ||
1284 nColNum != lcl_ColumnNum( pBoss ) )
1285 pRet = nullptr;
1289 return pRet;
1292 void SwFootnoteBossFrame::ResetFootnote( const SwFootnoteFrame *pCheck )
1294 // Destroy the incarnations of footnotes to an attribute, if they don't
1295 // belong to pAssumed
1296 OSL_ENSURE( !pCheck->GetMaster(), "given master is not a Master." );
1298 SwNodeIndex aIdx( *pCheck->GetAttr()->GetStartNode(), 1 );
1299 SwContentNode *pNd = aIdx.GetNode().GetContentNode();
1300 if ( !pNd )
1301 pNd = SwNodes::GoNextSection(&aIdx, true, false);
1302 SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
1303 SwFrame* pFrame = aIter.First();
1304 while( pFrame )
1306 if( pFrame->getRootFrame() == pCheck->getRootFrame() )
1308 SwFrame *pTmp = pFrame->GetUpper();
1309 while ( pTmp && !pTmp->IsFootnoteFrame() )
1310 pTmp = pTmp->GetUpper();
1312 SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pTmp);
1313 while ( pFootnote && pFootnote->GetMaster() )
1314 pFootnote = pFootnote->GetMaster();
1315 if ( pFootnote != pCheck )
1317 while (pFootnote && !pFootnote->IsDeleteForbidden())
1319 SwFootnoteFrame *pNxt = pFootnote->GetFollow();
1320 pFootnote->Cut();
1321 SwFrame::DestroyFrame(pFootnote);
1322 pFootnote = pNxt;
1327 pFrame = aIter.Next();
1331 void SwFootnoteBossFrame::InsertFootnote( SwFootnoteFrame* pNew )
1333 // Place the footnote in front of the footnote whose attribute
1334 // is in front of the new one (get position via the Doc).
1335 // If there is no footnote in this footnote-boss yet, create a new container.
1336 // If there is a container but no footnote for this footnote-boss yet, place
1337 // the footnote behind the last footnote of the closest previous column/page.
1339 ResetFootnote( pNew );
1340 SwFootnoteFrame *pSibling = FindFirstFootnote();
1341 bool bDontLeave = false;
1343 // Ok, a sibling has been found, but is the sibling in an acceptable
1344 // environment?
1345 if( IsInSct() )
1347 SwSectionFrame* pMySect = ImplFindSctFrame();
1348 bool bEndnt = pNew->GetAttr()->GetFootnote().IsEndNote();
1349 if( bEndnt )
1351 const SwSectionFormat* pEndFormat = pMySect->GetEndSectFormat();
1352 bDontLeave = nullptr != pEndFormat;
1353 if( pSibling )
1355 if( pEndFormat )
1357 if( !pSibling->IsInSct() ||
1358 !pSibling->ImplFindSctFrame()->IsDescendantFrom( pEndFormat ) )
1359 pSibling = nullptr;
1361 else if( pSibling->IsInSct() )
1362 pSibling = nullptr;
1365 else
1367 bDontLeave = pMySect->IsFootnoteAtEnd();
1368 if( pSibling )
1370 if( pMySect->IsFootnoteAtEnd() )
1372 if( !pSibling->IsInSct() ||
1373 !pMySect->IsAnFollow( pSibling->ImplFindSctFrame() ) )
1374 pSibling = nullptr;
1376 else if( pSibling->IsInSct() )
1377 pSibling = nullptr;
1382 if( pSibling && pSibling->FindPageFrame()->IsEndNotePage() !=
1383 FindPageFrame()->IsEndNotePage() )
1384 pSibling = nullptr;
1386 // use the Doc to find out the position
1387 SwDoc *pDoc = GetFormat()->GetDoc();
1388 const sal_uInt32 nStPos = ::lcl_FindFootnotePos( pDoc, pNew->GetAttr() );
1390 sal_uInt32 nCmpPos = 0;
1391 sal_uInt32 nLastPos = 0;
1392 SwFootnoteContFrame *pParent = nullptr;
1393 if( pSibling )
1395 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1396 if( nCmpPos > nStPos )
1397 pSibling = nullptr;
1400 if ( !pSibling )
1401 { pParent = FindFootnoteCont();
1402 if ( !pParent )
1404 // There is no footnote container yet. Before creating one, keep in mind that
1405 // there might exist another following footnote that must be placed before the
1406 // new inserted one e.g. because it was divided over multiple pages etc.
1407 pParent = FindNearestFootnoteCont( bDontLeave );
1408 if ( pParent )
1410 SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pParent->Lower());
1411 if ( pFootnote )
1414 nCmpPos = ::lcl_FindFootnotePos( pDoc, pFootnote->GetAttr() );
1415 if ( nCmpPos > nStPos )
1416 pParent = nullptr;
1418 else
1419 pParent = nullptr;
1422 if ( !pParent )
1423 // here, we are sure that we can create a footnote container
1424 pParent = MakeFootnoteCont();
1425 else
1427 // Based on the first footnote below the Parent, search for the first footnote whose
1428 // index is after the index of the newly inserted, to place the new one correctly
1429 pSibling = static_cast<SwFootnoteFrame*>(pParent->Lower());
1430 if ( !pSibling )
1432 OSL_ENSURE( false, "Could not find space for footnote.");
1433 return;
1435 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1437 SwFootnoteBossFrame *pNxtB; // remember the last one to not
1438 SwFootnoteFrame *pLastSib = nullptr; // go too far.
1440 while ( pSibling && nCmpPos <= nStPos )
1442 pLastSib = pSibling; // potential candidate
1443 nLastPos = nCmpPos;
1445 while ( pSibling->GetFollow() )
1446 pSibling = pSibling->GetFollow();
1448 if ( pSibling->GetNext() )
1450 pSibling = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
1451 OSL_ENSURE( !pSibling->GetMaster() || ( ENDNOTE > nStPos &&
1452 pSibling->GetAttr()->GetFootnote().IsEndNote() ),
1453 "InsertFootnote: Master expected I" );
1455 else
1457 pNxtB = pSibling->FindFootnoteBossFrame();
1458 SwPageFrame *pSibPage = pNxtB->FindPageFrame();
1459 bool bEndNote = pSibPage->IsEndNotePage();
1460 bool bChgPage = lcl_NextFootnoteBoss( pNxtB, pSibPage, bDontLeave );
1461 // When changing pages, also the endnote flag must match.
1462 SwFootnoteContFrame *pCont = pNxtB && ( !bChgPage ||
1463 pSibPage->IsEndNotePage() == bEndNote )
1464 ? pNxtB->FindNearestFootnoteCont( bDontLeave ) : nullptr;
1465 if( pCont )
1466 pSibling = static_cast<SwFootnoteFrame*>(pCont->Lower());
1467 else // no further FootnoteContainer, insert after pSibling
1468 break;
1470 if ( pSibling )
1472 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1473 OSL_ENSURE( nCmpPos > nLastPos, "InsertFootnote: Order of FootnoteFrame's buggy" );
1476 // pLastSib is the last footnote before the new one and
1477 // pSibling is empty or the first one after the new one
1478 if ( pSibling && pLastSib && (pSibling != pLastSib) )
1480 // too far?
1481 if ( nCmpPos > nStPos )
1482 pSibling = pLastSib;
1484 else if ( !pSibling )
1486 // Last chance: Take the last footnote of the parent.
1487 // Special case that happens e.g. when moving paragraphs with multiple footnotes.
1488 // To keep the order, use the parent of the last inspected footnote.
1489 pSibling = pLastSib;
1490 while( pSibling->GetFollow() )
1491 pSibling = pSibling->GetFollow();
1492 OSL_ENSURE( !pSibling->GetNext(), "InsertFootnote: Who's that guy?" );
1496 else
1498 // First footnote of the column/page found. Now search from there for the first one on the
1499 // same column/page whose index is after the given one. The last one found is the predecessor.
1500 SwFootnoteBossFrame* pBoss = pNew->GetRef()->FindFootnoteBossFrame(
1501 !pNew->GetAttr()->GetFootnote().IsEndNote() );
1502 sal_uInt16 nRefNum = pBoss->GetPhyPageNum(); // page number of the new footnote
1503 sal_uInt16 nRefCol = lcl_ColumnNum( pBoss ); // column number of the new footnote
1504 bool bEnd = false;
1505 SwFootnoteFrame *pLastSib = nullptr;
1506 while ( pSibling && !bEnd && (nCmpPos <= nStPos) )
1508 pLastSib = pSibling;
1509 nLastPos = nCmpPos;
1511 while ( pSibling->GetFollow() )
1512 pSibling = pSibling->GetFollow();
1514 SwFootnoteFrame *pFoll = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
1515 if ( pFoll )
1517 pBoss = pSibling->GetRef()->FindFootnoteBossFrame( !pSibling->
1518 GetAttr()->GetFootnote().IsEndNote() );
1519 sal_uInt16 nTmpRef;
1520 // it's possible pBoss is empty here on an undo/redo operation
1521 if (pBoss && (nStPos >= ENDNOTE ||
1522 (nTmpRef = pBoss->GetPhyPageNum()) < nRefNum ||
1523 ( nTmpRef == nRefNum && lcl_ColumnNum( pBoss ) <= nRefCol )))
1524 pSibling = pFoll;
1525 else
1526 bEnd = true;
1528 else
1530 SwFootnoteBossFrame* pNxtB = pSibling->FindFootnoteBossFrame();
1531 SwPageFrame *pSibPage = pNxtB->FindPageFrame();
1532 bool bEndNote = pSibPage->IsEndNotePage();
1533 bool bChgPage = lcl_NextFootnoteBoss( pNxtB, pSibPage, bDontLeave );
1534 // When changing pages, also the endnote flag must match.
1535 SwFootnoteContFrame *pCont = pNxtB && ( !bChgPage ||
1536 pSibPage->IsEndNotePage() == bEndNote )
1537 ? pNxtB->FindNearestFootnoteCont( bDontLeave ) : nullptr;
1538 if ( pCont )
1539 pSibling = static_cast<SwFootnoteFrame*>(pCont->Lower());
1540 else
1541 bEnd = true;
1543 if ( !bEnd && pSibling )
1544 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1545 if (pSibling && (pSibling != pLastSib))
1547 // too far?
1548 if ( (nLastPos < nCmpPos) && (nCmpPos > nStPos) )
1550 pSibling = pLastSib;
1551 bEnd = true;
1556 if ( pSibling )
1558 nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
1559 if ( nCmpPos < nStPos )
1561 while ( pSibling->GetFollow() )
1562 pSibling = pSibling->GetFollow();
1563 pParent = static_cast<SwFootnoteContFrame*>(pSibling->GetUpper());
1564 pSibling = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
1566 else
1568 if( pSibling->GetMaster() )
1570 if( ENDNOTE > nCmpPos || nStPos >= ENDNOTE )
1572 OSL_FAIL( "InsertFootnote: Master expected II" );
1574 pSibling = pSibling->GetMaster();
1575 while ( pSibling->GetMaster() );
1578 pParent = static_cast<SwFootnoteContFrame*>(pSibling->GetUpper());
1581 OSL_ENSURE( pParent, "paste in space?" );
1582 pNew->Paste( pParent, pSibling );
1585 static SwPageFrame* lcl_GetApproximateFootnotePage(const bool bEnd, const SwPageFrame* pPage,
1586 const SwDoc *pDoc, const SwTextFootnote *pAttr)
1588 // We can at least search the approximately correct page
1589 // to ensure that we will finish in finite time even if
1590 // hundreds of footnotes exist.
1591 const SwPageFrame *pNxt = static_cast<const SwPageFrame*>(pPage->GetNext());
1592 const sal_uInt32 nStPos = ::lcl_FindFootnotePos(pDoc, pAttr);
1593 while (pNxt && (bEnd ? pNxt->IsEndNotePage() : pNxt->IsFootnotePage() && !pNxt->IsEndNotePage()))
1595 const SwFootnoteContFrame *pCont = pNxt->FindFootnoteCont();
1596 const SwFrame* pLower = pCont ? pCont->Lower() : nullptr;
1597 if (pLower)
1599 OSL_ENSURE( pLower->IsFootnoteFrame(), "no footnote in the container" );
1600 if (nStPos > ::lcl_FindFootnotePos(pDoc,
1601 static_cast<const SwFootnoteFrame*>(pLower)->GetAttr()))
1603 pPage = pNxt;
1604 pNxt = static_cast<const SwPageFrame*>(pPage->GetNext());
1605 continue;
1608 break;
1610 return const_cast<SwPageFrame*>(pPage);
1613 void SwFootnoteBossFrame::AppendFootnote( SwContentFrame *pRef, SwTextFootnote *pAttr )
1615 // If the footnote already exists, do nothing.
1616 if ( FindFootnote( pRef, pAttr ) )
1617 return;
1619 // If footnotes are inserted at the end of the document,
1620 // we only need to search from the relevant page on.
1621 // If there is none yet, we need to create one.
1622 // If it is an Endnote, we need to search for or create an
1623 // Endnote page.
1624 SwDoc *pDoc = GetFormat()->GetDoc();
1625 SwFootnoteBossFrame *pBoss = this;
1626 SwPageFrame *pPage = FindPageFrame();
1627 SwPageFrame *pMyPage = pPage;
1628 bool bChgPage = false;
1629 const bool bEnd = pAttr->GetFootnote().IsEndNote();
1630 if (bEnd)
1632 const IDocumentSettingAccess& rSettings = *pAttr->GetTextNode().getIDocumentSettingAccess();
1633 if( GetUpper()->IsSctFrame() &&
1634 static_cast<SwSectionFrame*>(GetUpper())->IsEndnAtEnd() )
1636 // Endnotes at the end of the section.
1637 SwFrame* pLast =
1638 static_cast<SwSectionFrame*>(GetUpper())->FindLastContent( SwFindMode::EndNote );
1639 if( pLast )
1641 pBoss = pLast->FindFootnoteBossFrame();
1642 pPage = pBoss->FindPageFrame();
1645 else if (rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
1647 // Endnotes at the end of the document.
1648 // Find the first page that hosts an endnote section.
1649 SwSectionFrame* pEndnoteSection = pPage->GetEndNoteSection();
1650 while (pPage->GetNext() && !pEndnoteSection)
1652 pPage = pPage->GetNext()->DynCastPageFrame();
1653 pEndnoteSection = pPage->GetEndNoteSection();
1655 // If there are no endnotes sections yet, create one at the end of the document.
1656 // Ignore sections which are already marked for deletion, they don't have an SwSection
1657 // anymore, so not usable for us.
1658 if (!pEndnoteSection || !pEndnoteSection->GetSection())
1660 SwSection* pSwSection = pDoc->GetEndNoteInfo().GetSwSection(*pDoc);
1661 pEndnoteSection = new SwSectionFrame(*pSwSection, pPage);
1662 SwLayoutFrame* pParent = pPage->FindBodyCont();
1663 SwFrame* pBefore = pPage->FindLastBodyContent();
1664 while (pBefore)
1666 // Check if the last content frame is directly under the body frame or there is
1667 // something in-between, e.g. a section frame.
1668 if (pBefore->GetUpper() == pParent)
1670 break;
1673 // If so, insert behind the parent of the content frame, not inside the parent.
1674 pBefore = pBefore->GetUpper();
1676 pEndnoteSection->InsertBehind(pParent, pBefore);
1677 pEndnoteSection->Init();
1678 pEndnoteSection->SetEndNoteSection(true);
1681 SwFrame* pColumnFrame = pEndnoteSection->GetLower();
1682 if (pColumnFrame->IsColumnFrame())
1684 pBoss = static_cast<SwColumnFrame*>(pColumnFrame);
1687 else
1689 // Endnotes on a separate page.
1690 while ( pPage->GetNext() && !pPage->IsEndNotePage() )
1692 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1693 bChgPage = true;
1695 if ( !pPage->IsEndNotePage() )
1697 SwPageDesc *pDesc = pDoc->GetEndNoteInfo().GetPageDesc( *pDoc );
1698 pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
1699 !pPage->OnRightPage(), false, false, true, nullptr );
1700 pPage->SetEndNotePage( true );
1701 bChgPage = true;
1703 else
1704 pPage = lcl_GetApproximateFootnotePage(true, pPage, pDoc, pAttr);
1707 else if( FTNPOS_CHAPTER == pDoc->GetFootnoteInfo().m_ePos && ( !GetUpper()->
1708 IsSctFrame() || !static_cast<SwSectionFrame*>(GetUpper())->IsFootnoteAtEnd() ) )
1710 while ( pPage->GetNext() && !pPage->IsFootnotePage() &&
1711 !static_cast<SwPageFrame*>(pPage->GetNext())->IsEndNotePage() )
1713 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1714 bChgPage = true;
1717 if ( !pPage->IsFootnotePage() )
1719 SwPageDesc *pDesc = pDoc->GetFootnoteInfo().GetPageDesc( *pDoc );
1720 pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
1721 !pPage->OnRightPage(), false, false, true, pPage->GetNext() );
1722 bChgPage = true;
1724 else
1725 pPage = lcl_GetApproximateFootnotePage(false, pPage, pDoc, pAttr);
1728 // For now, create a footnote and the corresponding content frames
1729 if ( !pAttr->GetStartNode() )
1731 OSL_ENSURE( false, "no footnote content." );
1732 return;
1735 // If there is already a footnote content on the column/page,
1736 // another one cannot be created in a column area.
1737 if( pBoss->IsInSct() && pBoss->IsColumnFrame() && !pPage->IsFootnotePage() )
1739 SwSectionFrame* pSct = pBoss->FindSctFrame();
1740 if( bEnd ? !pSct->IsEndnAtEnd() : !pSct->IsFootnoteAtEnd() )
1742 SwFootnoteContFrame* pFootnoteCont = pSct->FindFootnoteBossFrame(!bEnd)->FindFootnoteCont();
1743 if( pFootnoteCont )
1745 SwFootnoteFrame* pTmp = static_cast<SwFootnoteFrame*>(pFootnoteCont->Lower());
1746 if( bEnd )
1747 while( pTmp && !pTmp->GetAttr()->GetFootnote().IsEndNote() )
1748 pTmp = static_cast<SwFootnoteFrame*>(pTmp->GetNext());
1749 if( pTmp && *pTmp < pAttr )
1750 return;
1755 SwFootnoteFrame *pNew = new SwFootnoteFrame( pDoc->GetDfltFrameFormat(), this, pRef, pAttr );
1757 SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
1758 ::InsertCnt_( pNew, pDoc, aIdx.GetIndex() );
1760 // If the page was changed or newly created,
1761 // we need to place ourselves in the first column
1762 if( bChgPage )
1764 SwLayoutFrame* pBody = pPage->FindBodyCont();
1765 OSL_ENSURE( pBody, "AppendFootnote: NoPageBody?" );
1766 if( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
1767 pBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower());
1768 else
1769 pBoss = pPage; // page if no columns exist
1771 pBoss->InsertFootnote( pNew );
1772 if ( pNew->GetUpper() ) // inserted or not?
1774 ::RegistFlys( pNew->FindPageFrame(), pNew );
1775 SwSectionFrame* pSect = FindSctFrame();
1776 // The content of a FootnoteContainer in a (column) section only need to be calculated
1777 // if the section stretches already to the bottom edge of the Upper.
1778 if( pSect && !pSect->IsJoinLocked() && ( bEnd ? !pSect->IsEndnAtEnd() :
1779 !pSect->IsFootnoteAtEnd() ) && pSect->Growable() )
1780 pSect->InvalidateSize();
1781 else
1783 // #i49383# - disable unlock of position of
1784 // lower objects during format of footnote content.
1785 const bool bOldFootnoteFrameLocked( pNew->IsColLocked() );
1786 pNew->ColLock();
1787 pNew->KeepLockPosOfLowerObjs();
1788 // #i57914# - adjust fix #i49383#
1789 SwContentFrame *pCnt = pNew->ContainsContent();
1790 while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
1792 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
1793 // #i49383# - format anchored objects
1794 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
1796 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
1797 *(pCnt->FindPageFrame()) ) )
1799 // restart format with first content
1800 pCnt = pNew->ContainsContent();
1801 continue;
1804 pCnt = pCnt->FindNextCnt();
1806 // #i49383#
1807 if ( !bOldFootnoteFrameLocked )
1809 pNew->ColUnlock();
1811 // #i57914# - adjust fix #i49383#
1812 // enable lock of lower object position before format of footnote frame.
1813 pNew->UnlockPosOfLowerObjs();
1814 pNew->Calc(getRootFrame()->GetCurrShell()->GetOut());
1815 // #i57914# - adjust fix #i49383#
1816 if ( !bOldFootnoteFrameLocked && !pNew->GetLower() &&
1817 !pNew->IsColLocked() && !pNew->IsBackMoveLocked() &&
1818 !pNew->IsDeleteForbidden() )
1820 pNew->Cut();
1821 SwFrame::DestroyFrame(pNew);
1824 pMyPage->UpdateFootnoteNum();
1826 else
1827 SwFrame::DestroyFrame(pNew);
1830 SwFootnoteFrame *SwFootnoteBossFrame::FindFootnote( const SwContentFrame *pRef, const SwTextFootnote *pAttr )
1832 // the easiest and savest way goes via the attribute
1833 OSL_ENSURE( pAttr->GetStartNode(), "FootnoteAtr without StartNode." );
1834 SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
1835 SwContentNode *pNd = aIdx.GetNode().GetContentNode();
1836 if ( !pNd )
1837 pNd = SwNodes::GoNextSection(&aIdx, true, false);
1838 if ( !pNd )
1839 return nullptr;
1840 SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
1841 SwFrame* pFrame = aIter.First();
1842 if( pFrame )
1845 pFrame = pFrame->GetUpper();
1846 // #i28500#, #i27243# Due to the endnode collector, there are
1847 // SwFootnoteFrames, which are not in the layout. Therefore the
1848 // bInfFootnote flags are not set correctly, and a cell of FindFootnoteFrame
1849 // would return 0. Therefore we better call ImplFindFootnoteFrame().
1850 SwFootnoteFrame *pFootnote = pFrame->ImplFindFootnoteFrame();
1851 if ( pFootnote && pFootnote->GetRef() == pRef )
1853 // The following condition becomes true, if the whole
1854 // footnotecontent is a section. While no frames exist,
1855 // the HiddenFlag of the section is set, this causes
1856 // the GoNextSection-function leaves the footnote.
1857 if( pFootnote->GetAttr() != pAttr )
1858 return nullptr;
1859 while ( pFootnote && pFootnote->GetMaster() )
1860 pFootnote = pFootnote->GetMaster();
1861 return pFootnote;
1864 } while ( nullptr != (pFrame = aIter.Next()) );
1866 return nullptr;
1869 bool SwFootnoteBossFrame::RemoveFootnote(
1870 const SwContentFrame *const pRef, const SwTextFootnote *const pAttr,
1871 bool bPrep )
1873 bool ret(false);
1874 SwFootnoteFrame *pFootnote = FindFootnote( pRef, pAttr );
1875 if( pFootnote )
1877 ret = true;
1880 SwFootnoteFrame *pFoll = pFootnote->GetFollow();
1881 pFootnote->Cut();
1882 SwFrame::DestroyFrame(pFootnote);
1883 pFootnote = pFoll;
1884 } while ( pFootnote );
1885 if( bPrep && pRef->IsFollow() )
1887 OSL_ENSURE( pRef->IsTextFrame(), "NoTextFrame has Footnote?" );
1888 SwTextFrame* pMaster = pRef->FindMaster();
1889 if( !pMaster->IsLocked() )
1890 pMaster->Prepare( PrepareHint::FootnoteInvalidationGone );
1893 FindPageFrame()->UpdateFootnoteNum();
1894 return ret;
1897 void SwFootnoteBossFrame::ChangeFootnoteRef( const SwContentFrame *pOld, const SwTextFootnote *pAttr,
1898 SwContentFrame *pNew )
1900 SwFootnoteFrame *pFootnote = FindFootnote( pOld, pAttr );
1901 while ( pFootnote )
1903 pFootnote->SetRef( pNew );
1904 pFootnote = pFootnote->GetFollow();
1908 /// OD 03.04.2003 #108446# - add parameter <_bCollectOnlyPreviousFootnotes> in
1909 /// order to control, if only footnotes, which are positioned before the
1910 /// footnote boss frame <this> have to be collected.
1911 void SwFootnoteBossFrame::CollectFootnotes( const SwContentFrame* _pRef,
1912 SwFootnoteBossFrame* _pOld,
1913 SwFootnoteFrames& _rFootnoteArr,
1914 const bool _bCollectOnlyPreviousFootnotes )
1916 SwFootnoteFrame *pFootnote = _pOld->FindFirstFootnote();
1917 while( !pFootnote )
1919 if( _pOld->IsColumnFrame() )
1921 // visit columns
1922 while ( !pFootnote && _pOld->GetPrev() )
1924 // Still no problem if no footnote was found yet. The loop is needed to pick up
1925 // following rows in tables. In all other cases it might correct bad contexts.
1926 _pOld = static_cast<SwFootnoteBossFrame*>(_pOld->GetPrev());
1927 pFootnote = _pOld->FindFirstFootnote();
1930 if( !pFootnote )
1932 // previous page
1933 SwPageFrame* pPg;
1934 for ( SwFrame* pTmp = _pOld;
1935 nullptr != ( pPg = static_cast<SwPageFrame*>(pTmp->FindPageFrame()->GetPrev()))
1936 && pPg->IsEmptyPage() ;
1939 pTmp = pPg;
1941 if( !pPg )
1942 return;
1944 SwLayoutFrame* pBody = pPg->FindBodyCont();
1945 const SwFrame* pLower = pBody->Lower();
1946 if( pLower && pLower->IsColumnFrame() )
1948 // multiple columns on one page => search last column
1949 _pOld = static_cast<SwFootnoteBossFrame*>(pBody->GetLastLower());
1951 else
1952 _pOld = pPg; // single column page
1953 pFootnote = _pOld->FindFirstFootnote();
1957 CollectFootnotes_(_pRef, pFootnote, _rFootnoteArr, _bCollectOnlyPreviousFootnotes ? this : nullptr);
1960 static void FootnoteInArr( SwFootnoteFrames& rFootnoteArr, SwFootnoteFrame* pFootnote )
1962 if ( rFootnoteArr.end() == std::find( rFootnoteArr.begin(), rFootnoteArr.end(), pFootnote ) )
1963 rFootnoteArr.push_back( pFootnote );
1966 void SwFootnoteBossFrame::CollectFootnotes_( const SwContentFrame* _pRef,
1967 SwFootnoteFrame* _pFootnote,
1968 SwFootnoteFrames& _rFootnoteArr,
1969 const SwFootnoteBossFrame* _pRefFootnoteBossFrame)
1971 // Collect all footnotes referenced by pRef (attribute by attribute), combine them
1972 // (the content might be divided over multiple pages) and cut them.
1974 // For robustness, we do not log the corresponding footnotes here. If a footnote
1975 // is touched twice, there might be a crash. This allows this function here to
1976 // also handle corrupt layouts in some degrees (without loops or even crashes).
1977 SwFootnoteFrames aNotFootnoteArr;
1979 // here we have a footnote placed in front of the first one of the reference
1980 OSL_ENSURE( !_pFootnote->GetMaster() || _pFootnote->GetRef() != _pRef, "move FollowFootnote?" );
1981 while ( _pFootnote->GetMaster() )
1982 _pFootnote = _pFootnote->GetMaster();
1984 bool bFound = false;
1988 // Search for the next footnote in this column/page so that
1989 // we do not start from zero again after cutting one footnote.
1990 SwFootnoteFrame *pNxtFootnote = _pFootnote;
1991 while ( pNxtFootnote->GetFollow() )
1992 pNxtFootnote = pNxtFootnote->GetFollow();
1993 pNxtFootnote = static_cast<SwFootnoteFrame*>(pNxtFootnote->GetNext());
1995 if ( !pNxtFootnote )
1997 SwFootnoteBossFrame* pBoss = _pFootnote->FindFootnoteBossFrame();
1998 SwPageFrame* pPage = pBoss->FindPageFrame();
2001 lcl_NextFootnoteBoss( pBoss, pPage, false );
2002 if( pBoss )
2004 SwLayoutFrame* pCont = pBoss->FindFootnoteCont();
2005 if( pCont )
2007 pNxtFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
2008 if( pNxtFootnote )
2010 while( pNxtFootnote->GetMaster() )
2011 pNxtFootnote = pNxtFootnote->GetMaster();
2012 if( pNxtFootnote == _pFootnote )
2013 pNxtFootnote = nullptr;
2017 } while( !pNxtFootnote && pBoss );
2019 else if( !pNxtFootnote->GetAttr()->GetFootnote().IsEndNote() )
2021 OSL_ENSURE( !pNxtFootnote->GetMaster(), "_CollectFootnote: Master expected" );
2022 while ( pNxtFootnote->GetMaster() )
2023 pNxtFootnote = pNxtFootnote->GetMaster();
2025 if ( pNxtFootnote == _pFootnote )
2027 OSL_FAIL( "_CollectFootnote: Vicious circle" );
2028 pNxtFootnote = nullptr;
2031 // OD 03.04.2003 #108446# - determine, if found footnote has to be collected.
2032 bool bCollectFoundFootnote = false;
2033 // Ignore endnotes which are on a separate endnote page.
2034 bool bEndNote = _pFootnote->GetAttr()->GetFootnote().IsEndNote();
2035 if (_pFootnote->GetRef() == _pRef && !bEndNote)
2037 if (_pRefFootnoteBossFrame)
2039 SwFootnoteBossFrame* pBossOfFoundFootnote = _pFootnote->FindFootnoteBossFrame( true );
2040 OSL_ENSURE( pBossOfFoundFootnote,
2041 "<SwFootnoteBossFrame::CollectFootnotes_(..)> - footnote boss frame of found footnote frame missing.\nWrong layout!" );
2042 if ( !pBossOfFoundFootnote || // don't crash, if no footnote boss is found.
2043 pBossOfFoundFootnote->IsBefore( _pRefFootnoteBossFrame )
2046 bCollectFoundFootnote = true;
2049 else
2051 bCollectFoundFootnote = true;
2055 if ( bCollectFoundFootnote )
2057 OSL_ENSURE( !_pFootnote->GetMaster(), "move FollowFootnote?" );
2058 SwFootnoteFrame *pNxt = _pFootnote->GetFollow();
2059 while ( pNxt )
2061 SwFrame *pCnt = pNxt->ContainsAny();
2062 if ( pCnt )
2064 // destroy the follow on the way as it is empty
2066 { SwFrame *pNxtCnt = pCnt->GetNext();
2067 pCnt->Cut();
2068 pCnt->Paste( _pFootnote );
2069 pCnt = pNxtCnt;
2070 } while ( pCnt );
2072 else
2074 OSL_ENSURE( !pNxt, "footnote without content?" );
2075 pNxt->Cut();
2076 SwFrame::DestroyFrame(pNxt);
2078 pNxt = _pFootnote->GetFollow();
2080 _pFootnote->Cut();
2081 FootnoteInArr( _rFootnoteArr, _pFootnote );
2082 bFound = true;
2084 else
2086 FootnoteInArr( aNotFootnoteArr, _pFootnote );
2087 if( bFound )
2088 break;
2090 if ( pNxtFootnote &&
2091 _rFootnoteArr.end() == std::find( _rFootnoteArr.begin(), _rFootnoteArr.end(), pNxtFootnote ) &&
2092 aNotFootnoteArr.end() == std::find( aNotFootnoteArr.begin(), aNotFootnoteArr.end(), pNxtFootnote ) )
2093 _pFootnote = pNxtFootnote;
2094 else
2095 break;
2097 while ( _pFootnote );
2100 void SwFootnoteBossFrame::MoveFootnotes_( SwFootnoteFrames &rFootnoteArr, bool bCalc )
2102 // All footnotes referenced by pRef need to be moved
2103 // to a new position (based on the new column/page)
2104 const sal_uInt16 nMyNum = FindPageFrame()->GetPhyPageNum();
2105 const sal_uInt16 nMyCol = lcl_ColumnNum( this );
2106 SwRectFnSet aRectFnSet(this);
2108 // #i21478# - keep last inserted footnote in order to
2109 // format the content of the following one.
2110 SwFootnoteFrame* pLastInsertedFootnote = nullptr;
2111 for (SwFootnoteFrame* pFootnote : rFootnoteArr)
2113 SwFootnoteBossFrame* pRefBoss(pFootnote->GetRef()->FindFootnoteBossFrame(
2114 !pFootnote->GetAttr()->GetFootnote().IsEndNote()));
2115 if( pRefBoss != this )
2117 const sal_uInt16 nRefNum = pRefBoss->FindPageFrame()->GetPhyPageNum();
2118 const sal_uInt16 nRefCol = lcl_ColumnNum( this );
2119 if( nRefNum < nMyNum || ( nRefNum == nMyNum && nRefCol <= nMyCol ) )
2120 pRefBoss = this;
2122 pRefBoss->InsertFootnote( pFootnote );
2124 if ( pFootnote->GetUpper() ) // robust, e.g. with duplicates
2126 // First condense the content so that footnote frames that do not fit on the page
2127 // do not do too much harm (Loop 66312). So, the footnote content first grows as
2128 // soon as the content gets formatted and it is sure that it fits on the page.
2129 SwFrame *pCnt = pFootnote->ContainsAny();
2130 while( pCnt )
2132 if( pCnt->IsLayoutFrame() )
2134 SwFrame* pTmp = static_cast<SwLayoutFrame*>(pCnt)->ContainsAny();
2135 while( pTmp && static_cast<SwLayoutFrame*>(pCnt)->IsAnLower( pTmp ) )
2137 pTmp->Prepare( PrepareHint::FootnoteMove );
2139 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pTmp);
2140 aRectFnSet.SetHeight(aFrm, 0);
2142 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pTmp);
2143 aRectFnSet.SetHeight(aPrt, 0);
2145 pTmp = pTmp->FindNext();
2148 else
2150 pCnt->Prepare( PrepareHint::FootnoteMove );
2153 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pCnt);
2154 aRectFnSet.SetHeight(aFrm, 0);
2156 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pCnt);
2157 aRectFnSet.SetHeight(aPrt, 0);
2159 pCnt = pCnt->GetNext();
2163 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFootnote);
2164 aRectFnSet.SetHeight(aFrm, 0);
2168 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pFootnote);
2169 aRectFnSet.SetHeight(aPrt, 0);
2172 pFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
2173 pFootnote->GetUpper()->Calc(getRootFrame()->GetCurrShell()->GetOut());
2175 if( bCalc )
2177 SwTextFootnote *pAttr = pFootnote->GetAttr();
2178 pCnt = pFootnote->ContainsAny();
2179 bool bUnlock = !pFootnote->IsBackMoveLocked();
2180 pFootnote->LockBackMove();
2182 // #i49383# - disable unlock of position of
2183 // lower objects during format of footnote content.
2184 pFootnote->KeepLockPosOfLowerObjs();
2185 // #i57914# - adjust fix #i49383#
2187 while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
2189 pCnt->InvalidatePos_();
2190 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
2191 // #i49383# - format anchored objects
2192 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
2194 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
2195 *(pCnt->FindPageFrame()) ) )
2197 // restart format with first content
2198 pCnt = pFootnote->ContainsAny();
2199 continue;
2202 if( pCnt->IsSctFrame() )
2204 // If the area is not empty, iterate also over the content
2205 SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
2206 if( pTmp )
2207 pCnt = pTmp;
2208 else
2209 pCnt = pCnt->FindNext();
2211 else
2212 pCnt = pCnt->FindNext();
2214 if( bUnlock )
2216 pFootnote->UnlockBackMove();
2217 if( !pFootnote->ContainsAny() && !pFootnote->IsColLocked() )
2219 pFootnote->Cut();
2220 SwFrame::DestroyFrame(pFootnote);
2221 // #i21478#
2222 pFootnote = nullptr;
2225 // #i49383#
2226 if ( pFootnote )
2228 // #i57914# - adjust fix #i49383#
2229 // enable lock of lower object position before format of footnote frame.
2230 pFootnote->UnlockPosOfLowerObjs();
2231 pFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
2235 else
2237 OSL_ENSURE( !pFootnote->GetMaster() && !pFootnote->GetFollow(),
2238 "DelFootnote and Master/Follow?" );
2239 SwFrame::DestroyFrame(pFootnote);
2240 // #i21478#
2241 pFootnote = nullptr;
2244 // #i21478#
2245 if ( pFootnote )
2247 pLastInsertedFootnote = pFootnote;
2251 // #i21478# - format content of footnote following
2252 // the new inserted ones.
2253 if ( !(bCalc && pLastInsertedFootnote) )
2254 return;
2256 if ( !pLastInsertedFootnote->GetNext() )
2257 return;
2259 SwFootnoteFrame* pNextFootnote = static_cast<SwFootnoteFrame*>(pLastInsertedFootnote->GetNext());
2260 SwTextFootnote* pAttr = pNextFootnote->GetAttr();
2261 SwFrame* pCnt = pNextFootnote->ContainsAny();
2263 bool bUnlock = !pNextFootnote->IsBackMoveLocked();
2264 pNextFootnote->LockBackMove();
2265 // #i49383# - disable unlock of position of
2266 // lower objects during format of footnote content.
2267 pNextFootnote->KeepLockPosOfLowerObjs();
2268 // #i57914# - adjust fix #i49383#
2270 while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
2272 pCnt->InvalidatePos_();
2273 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
2274 // #i49383# - format anchored objects
2275 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
2277 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
2278 *(pCnt->FindPageFrame()) ) )
2280 // restart format with first content
2281 pCnt = pNextFootnote->ContainsAny();
2282 continue;
2285 if( pCnt->IsSctFrame() )
2287 // If the area is not empty, iterate also over the content
2288 SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
2289 if( pTmp )
2290 pCnt = pTmp;
2291 else
2292 pCnt = pCnt->FindNext();
2294 else
2295 pCnt = pCnt->FindNext();
2297 if( bUnlock )
2299 pNextFootnote->UnlockBackMove();
2301 // #i49383#
2302 // #i57914# - adjust fix #i49383#
2303 // enable lock of lower object position before format of footnote frame.
2304 pNextFootnote->UnlockPosOfLowerObjs();
2305 pNextFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
2308 void SwFootnoteBossFrame::MoveFootnotes( const SwContentFrame *pSrc, SwContentFrame *pDest,
2309 SwTextFootnote const *pAttr )
2311 if( ( GetFormat()->GetDoc()->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER &&
2312 (!GetUpper()->IsSctFrame() || !static_cast<SwSectionFrame*>(GetUpper())->IsFootnoteAtEnd()))
2313 || pAttr->GetFootnote().IsEndNote() )
2314 return;
2316 OSL_ENSURE( this == pSrc->FindFootnoteBossFrame( true ),
2317 "SwPageFrame::MoveFootnotes: source frame isn't on that FootnoteBoss" );
2319 SwFootnoteFrame *pFootnote = FindFirstFootnote();
2320 if( !pFootnote )
2321 return;
2323 ChangeFootnoteRef( pSrc, pAttr, pDest );
2324 SwFootnoteBossFrame *pDestBoss = pDest->FindFootnoteBossFrame( true );
2325 OSL_ENSURE( pDestBoss, "+SwPageFrame::MoveFootnotes: no destination boss" );
2326 if( !pDestBoss ) // robust
2327 return;
2329 SwFootnoteFrames aFootnoteArr;
2330 SwFootnoteBossFrame::CollectFootnotes_(pDest, pFootnote, aFootnoteArr, nullptr);
2331 if ( aFootnoteArr.empty() )
2332 return;
2334 pDestBoss->MoveFootnotes_( aFootnoteArr, true );
2335 SwPageFrame* pSrcPage = FindPageFrame();
2336 SwPageFrame* pDestPage = pDestBoss->FindPageFrame();
2337 // update FootnoteNum only at page change
2338 if( pSrcPage != pDestPage )
2340 if( pSrcPage->GetPhyPageNum() > pDestPage->GetPhyPageNum() )
2341 pSrcPage->UpdateFootnoteNum();
2342 pDestPage->UpdateFootnoteNum();
2346 void SwFootnoteBossFrame::RearrangeFootnotes( const SwTwips nDeadLine, const bool bLock,
2347 const SwTextFootnote *pAttr )
2349 // Format all footnotes of a column/page so that they might change the column/page.
2351 SwSaveFootnoteHeight aSave( this, nDeadLine );
2352 SwFootnoteFrame *pFootnote = FindFirstFootnote();
2353 if( pFootnote && pFootnote->GetPrev() && bLock )
2355 SwFootnoteFrame* pFirst = static_cast<SwFootnoteFrame*>(pFootnote->GetUpper()->Lower());
2356 SwFrame* pContent = pFirst->ContainsAny();
2357 if( pContent )
2359 bool bUnlock = !pFirst->IsBackMoveLocked();
2360 pFirst->LockBackMove();
2361 pFirst->Calc(getRootFrame()->GetCurrShell()->GetOut());
2362 pContent->Calc(getRootFrame()->GetCurrShell()->GetOut());
2363 // #i49383# - format anchored objects
2364 if ( pContent->IsTextFrame() && pContent->isFrameAreaDefinitionValid() )
2366 SwObjectFormatter::FormatObjsAtFrame( *pContent,
2367 *(pContent->FindPageFrame()) );
2369 if( bUnlock )
2370 pFirst->UnlockBackMove();
2372 pFootnote = FindFirstFootnote();
2374 SwDoc *pDoc = GetFormat()->GetDoc();
2375 const sal_uInt32 nFootnotePos = pAttr ? ::lcl_FindFootnotePos( pDoc, pAttr ) : 0;
2376 SwFrame *pCnt = pFootnote ? pFootnote->ContainsAny() : nullptr;
2377 if ( !pCnt )
2378 return;
2380 bool bMore = true;
2381 bool bStart = pAttr == nullptr; // If no attribute is given, process all
2382 // #i49383# - disable unlock of position of
2383 // lower objects during format of footnote and footnote content.
2384 SwFootnoteFrame* pLastFootnoteFrame( nullptr );
2385 // footnote frame needs to be locked, if <bLock> isn't set.
2386 bool bUnlockLastFootnoteFrame( false );
2389 if( !bStart )
2390 bStart = ::lcl_FindFootnotePos( pDoc, pCnt->FindFootnoteFrame()->GetAttr() )
2391 == nFootnotePos;
2392 if( bStart )
2394 pCnt->InvalidatePos_();
2395 pCnt->InvalidateSize_();
2396 pCnt->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
2397 SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
2398 assert(pFootnoteFrame);
2399 // #i49383#
2400 if ( pFootnoteFrame != pLastFootnoteFrame )
2402 if ( pLastFootnoteFrame )
2404 if ( !bLock && bUnlockLastFootnoteFrame )
2406 pLastFootnoteFrame->ColUnlock();
2408 // #i57914# - adjust fix #i49383#
2409 // enable lock of lower object position before format of footnote frame.
2410 pLastFootnoteFrame->UnlockPosOfLowerObjs();
2411 pLastFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
2412 if ( !bLock && bUnlockLastFootnoteFrame &&
2413 !pLastFootnoteFrame->GetLower() &&
2414 !pLastFootnoteFrame->IsColLocked() &&
2415 !pLastFootnoteFrame->IsBackMoveLocked() &&
2416 !pLastFootnoteFrame->IsDeleteForbidden() )
2418 pLastFootnoteFrame->Cut();
2419 SwFrame::DestroyFrame(pLastFootnoteFrame);
2420 // pLastFootnoteFrame overwritten at end of block
2423 if ( !bLock )
2425 bUnlockLastFootnoteFrame = !pFootnoteFrame->IsColLocked();
2426 pFootnoteFrame->ColLock();
2428 pFootnoteFrame->KeepLockPosOfLowerObjs();
2429 pLastFootnoteFrame = pFootnoteFrame;
2431 // OD 30.10.2002 #97265# - invalidate position of footnote
2432 // frame, if it's below its footnote container, in order to
2433 // assure its correct position, probably calculating its previous
2434 // footnote frames.
2436 SwRectFnSet aRectFnSet(this);
2437 SwFrame* pFootnoteContFrame = pFootnoteFrame->GetUpper();
2438 if ( aRectFnSet.TopDist(pFootnoteFrame->getFrameArea(), aRectFnSet.GetPrtBottom(*pFootnoteContFrame)) > 0 )
2440 pFootnoteFrame->InvalidatePos_();
2443 if ( bLock )
2445 bool bUnlock = !pFootnoteFrame->IsBackMoveLocked();
2446 pFootnoteFrame->LockBackMove();
2447 pFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
2448 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
2449 // #i49383# - format anchored objects
2450 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
2452 SwFrameDeleteGuard aDeleteGuard(pFootnote);
2453 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
2454 *(pCnt->FindPageFrame()) ) )
2456 // restart format with first content
2457 pCnt = pFootnote ? pFootnote->ContainsAny() : nullptr;
2458 if (!pCnt)
2459 bMore = false;
2460 continue;
2463 if( bUnlock )
2465 pFootnoteFrame->UnlockBackMove();
2466 if( !pFootnoteFrame->Lower() &&
2467 !pFootnoteFrame->IsColLocked() )
2469 // #i49383#
2470 OSL_ENSURE( pLastFootnoteFrame == pFootnoteFrame,
2471 "<SwFootnoteBossFrame::RearrangeFootnotes(..)> - <pLastFootnoteFrame> != <pFootnoteFrame>" );
2472 pLastFootnoteFrame = nullptr;
2473 pFootnoteFrame->Cut();
2474 SwFrame::DestroyFrame(pFootnoteFrame);
2475 if (pFootnote == pFootnoteFrame)
2476 pFootnote = nullptr;
2480 else
2482 pFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
2483 pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
2484 // #i49383# - format anchored objects
2485 if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
2487 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
2488 *(pCnt->FindPageFrame()) ) )
2490 // restart format with first content
2491 pCnt = pFootnote->ContainsAny();
2492 continue;
2497 SwSectionFrame *pDel = nullptr;
2498 if( pCnt->IsSctFrame() )
2500 SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
2501 if( pTmp )
2503 pCnt = pTmp;
2504 continue;
2506 pDel = static_cast<SwSectionFrame*>(pCnt);
2508 if ( pCnt->GetNext() )
2509 pCnt = pCnt->GetNext();
2510 else
2512 pCnt = pCnt->FindNext();
2513 if ( pCnt )
2515 SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
2516 if( pFootnoteFrame->GetRef()->FindFootnoteBossFrame(
2517 pFootnoteFrame->GetAttr()->GetFootnote().IsEndNote() ) != this )
2518 bMore = false;
2520 else
2521 bMore = false;
2523 if( pDel )
2525 bool bUnlockLastFootnoteFrameGuard = pLastFootnoteFrame && !pLastFootnoteFrame->IsColLocked();
2526 if (bUnlockLastFootnoteFrameGuard)
2527 pLastFootnoteFrame->ColLock();
2528 pDel->Cut();
2529 if (bUnlockLastFootnoteFrameGuard)
2530 pLastFootnoteFrame->ColUnlock();
2531 SwFrame::DestroyFrame(pDel);
2533 if ( bMore )
2535 // Go not further than to the provided footnote (if given)
2536 if ( pAttr &&
2537 (::lcl_FindFootnotePos( pDoc,
2538 pCnt->FindFootnoteFrame()->GetAttr()) > nFootnotePos ) )
2539 bMore = false;
2541 } while ( bMore );
2542 // #i49383#
2543 if ( !pLastFootnoteFrame )
2544 return;
2546 if ( !bLock && bUnlockLastFootnoteFrame )
2548 pLastFootnoteFrame->ColUnlock();
2550 // #i57914# - adjust fix #i49383#
2551 // enable lock of lower object position before format of footnote frame.
2552 pLastFootnoteFrame->UnlockPosOfLowerObjs();
2553 pLastFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
2554 if ( !bLock && bUnlockLastFootnoteFrame &&
2555 !pLastFootnoteFrame->GetLower() &&
2556 !pLastFootnoteFrame->IsColLocked() &&
2557 !pLastFootnoteFrame->IsBackMoveLocked() &&
2558 !pLastFootnoteFrame->IsDeleteForbidden() )
2560 pLastFootnoteFrame->Cut();
2561 SwFrame::DestroyFrame(pLastFootnoteFrame);
2565 void SwPageFrame::UpdateFootnoteNum()
2567 // page numbering only if set at the document
2568 if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum != FTNNUM_PAGE )
2569 return;
2571 SwLayoutFrame* pBody = FindBodyCont();
2572 if( !pBody || !pBody->Lower() )
2573 return;
2575 SwContentFrame* pContent = pBody->ContainsContent();
2576 sal_uInt16 nNum = 0;
2578 while( pContent && pContent->FindPageFrame() == this )
2580 if( static_cast<SwTextFrame*>(pContent)->HasFootnote() )
2582 SwFootnoteBossFrame* pBoss = pContent->FindFootnoteBossFrame( true );
2583 if( pBoss->GetUpper()->IsSctFrame() &&
2584 static_cast<SwSectionFrame*>(pBoss->GetUpper())->IsOwnFootnoteNum() )
2585 pContent = static_cast<SwSectionFrame*>(pBoss->GetUpper())->FindLastContent();
2586 else
2588 SwFootnoteFrame* pFootnote = const_cast<SwFootnoteFrame*>(pBoss->FindFirstFootnote( pContent ));
2589 while( pFootnote )
2591 SwTextFootnote* pTextFootnote = pFootnote->GetAttr();
2592 if( !pTextFootnote->GetFootnote().IsEndNote() &&
2593 pTextFootnote->GetFootnote().GetNumStr().isEmpty() &&
2594 !pFootnote->GetMaster())
2596 // sw_redlinehide: the layout can only keep one number
2597 // up to date; depending on its setting, this is either
2598 // the non-hidden or the hidden number; the other
2599 // number will simply be preserved as-is (so in case
2600 // there are 2 layouts, maybe both can be updated...)
2601 ++nNum;
2602 sal_uInt16 const nOldNum(pTextFootnote->GetFootnote().GetNumber());
2603 sal_uInt16 const nOldNumRLHidden(pTextFootnote->GetFootnote().GetNumberRLHidden());
2604 if (getRootFrame()->IsHideRedlines())
2606 if (nNum != nOldNumRLHidden)
2608 pTextFootnote->SetNumber(nOldNum, nNum, OUString());
2611 else
2613 if (nNum != nOldNum)
2615 pTextFootnote->SetNumber(nNum, nOldNumRLHidden, OUString());
2619 if ( pFootnote->GetNext() )
2620 pFootnote = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
2621 else
2623 SwFootnoteBossFrame* pTmpBoss = pFootnote->FindFootnoteBossFrame( true );
2624 if( pTmpBoss )
2626 SwPageFrame* pPage = pTmpBoss->FindPageFrame();
2627 pFootnote = nullptr;
2628 lcl_NextFootnoteBoss( pTmpBoss, pPage, false );
2629 SwFootnoteContFrame *pCont = pTmpBoss ? pTmpBoss->FindNearestFootnoteCont() : nullptr;
2630 if ( pCont )
2631 pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
2634 if( pFootnote && pFootnote->GetRef() != pContent )
2635 pFootnote = nullptr;
2639 pContent = pContent->FindNextCnt();
2643 void SwFootnoteBossFrame::SetFootnoteDeadLine( const SwTwips nDeadLine )
2645 SwFrame *pBody = FindBodyCont();
2646 pBody->Calc(getRootFrame()->GetCurrShell()->GetOut());
2648 SwFrame *pCont = FindFootnoteCont();
2649 const SwTwips nMax = m_nMaxFootnoteHeight;// current should exceed MaxHeight
2650 SwRectFnSet aRectFnSet(this);
2651 if ( pCont )
2653 pCont->Calc(getRootFrame()->GetCurrShell()->GetOut());
2654 m_nMaxFootnoteHeight = -aRectFnSet.BottomDist( pCont->getFrameArea(), nDeadLine );
2656 else
2657 m_nMaxFootnoteHeight = -aRectFnSet.BottomDist( pBody->getFrameArea(), nDeadLine );
2659 const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
2660 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
2661 m_nMaxFootnoteHeight += pBody->Grow( LONG_MAX, true );
2662 if ( IsInSct() )
2663 m_nMaxFootnoteHeight += FindSctFrame()->Grow( LONG_MAX, true );
2665 if ( m_nMaxFootnoteHeight < 0 )
2666 m_nMaxFootnoteHeight = 0;
2667 if ( nMax != LONG_MAX && m_nMaxFootnoteHeight > nMax )
2668 m_nMaxFootnoteHeight = nMax;
2671 SwTwips SwFootnoteBossFrame::GetVarSpace() const
2673 // To not fall below 20% of the page height
2674 // (in contrast to MSOffice where footnotes can fill a whole column/page)
2676 const SwPageFrame* pPg = FindPageFrame();
2677 OSL_ENSURE( pPg || IsInSct(), "Footnote lost page" );
2679 const SwFrame *pBody = FindBodyCont();
2680 SwTwips nRet;
2681 if( pBody )
2683 SwRectFnSet aRectFnSet(this);
2684 nRet = aRectFnSet.GetHeight(pBody->getFrameArea());
2685 if( IsInSct() )
2687 SwTwips nTmp = aRectFnSet.YDiff( aRectFnSet.GetPrtTop(*pBody),
2688 aRectFnSet.GetTop(getFrameArea()) );
2689 const SwSectionFrame* pSect = FindSctFrame();
2690 // Endnotes in a ftncontainer causes a deadline:
2691 // the bottom of the last contentfrm
2692 if( pSect->IsEndnAtEnd() ) // endnotes allowed?
2694 const SwFrame* pLower = Lower();
2695 OSL_ENSURE( !pLower || !pLower->GetNext() || pLower->GetNext()->
2696 IsFootnoteContFrame(), "FootnoteContainer expected" );
2697 const SwFootnoteContFrame* pCont = pLower ?
2698 static_cast<const SwFootnoteContFrame*>(pLower->GetNext()) : nullptr;
2699 if( pCont )
2701 const SwFootnoteFrame* pFootnote = static_cast<const SwFootnoteFrame*>(pCont->Lower());
2702 while( pFootnote)
2704 if( pFootnote->GetAttr()->GetFootnote().IsEndNote() )
2705 { // endnote found
2706 const SwFrame* pFrame = static_cast<const SwLayoutFrame*>(pLower)->Lower();
2707 if( pFrame )
2709 while( pFrame->GetNext() )
2710 pFrame = pFrame->GetNext(); // last cntntfrm
2711 nTmp += aRectFnSet.YDiff(
2712 aRectFnSet.GetTop(getFrameArea()),
2713 aRectFnSet.GetBottom(pFrame->getFrameArea()) );
2715 break;
2717 pFootnote = static_cast<const SwFootnoteFrame*>(pFootnote->GetNext());
2721 if( nTmp < 0 )
2722 nRet += nTmp;
2724 else
2726 assert(pPg);
2727 nRet -= aRectFnSet.GetHeight(pPg->getFramePrintArea())/5;
2729 if( nRet < 0 )
2730 nRet = 0;
2732 else
2733 nRet = 0;
2734 if ( IsPageFrame() )
2736 const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
2737 if( pSh && pSh->GetViewOptions()->getBrowseMode() )
2738 nRet += BROWSE_HEIGHT - getFrameArea().Height();
2740 return nRet;
2743 /** Obtain if pFrame's size adjustment should be processed
2745 * For a page frame of columns directly below the page AdjustNeighbourhood() needs
2746 * to be called, or Grow()/ Shrink() for frame columns respectively.
2748 * A column section is special, since if there is a footnote container in a column
2749 * and those footnotes are not collected, it is handled like a page frame.
2751 * @see AdjustNeighbourhood()
2752 * @see Grow()
2753 * @see Shrink()
2755 SwNeighbourAdjust SwFootnoteBossFrame::NeighbourhoodAdjustment_() const
2757 SwNeighbourAdjust nRet = SwNeighbourAdjust::OnlyAdjust;
2758 if( GetUpper() && !GetUpper()->IsPageBodyFrame() )
2760 // column sections need grow/shrink
2761 if( GetUpper()->IsFlyFrame() )
2762 nRet = SwNeighbourAdjust::GrowShrink;
2763 else
2765 OSL_ENSURE( GetUpper()->IsSctFrame(), "NeighbourhoodAdjustment: Unexpected Upper" );
2766 if( !GetNext() && !GetPrev() )
2767 nRet = SwNeighbourAdjust::GrowAdjust; // section with a single column (FootnoteAtEnd)
2768 else
2770 const SwFrame* pTmp = Lower();
2771 assert(pTmp && "NeighbourhoodAdjustment: Missing Lower()");
2772 if( !pTmp->GetNext() )
2773 nRet = SwNeighbourAdjust::GrowShrink;
2774 else if( !GetUpper()->IsColLocked() )
2775 nRet = SwNeighbourAdjust::AdjustGrow;
2776 OSL_ENSURE( !pTmp->GetNext() || pTmp->GetNext()->IsFootnoteContFrame(),
2777 "NeighbourhoodAdjustment: Who's that guy?" );
2781 return nRet;
2784 void SwPageFrame::SetColMaxFootnoteHeight()
2786 SwLayoutFrame *pBody = FindBodyCont();
2787 SwFrame* pLower = pBody ? pBody->Lower() : nullptr;
2788 if( pLower && pLower->IsColumnFrame() )
2790 SwColumnFrame* pCol = static_cast<SwColumnFrame*>(pLower);
2793 pCol->SetMaxFootnoteHeight( GetMaxFootnoteHeight() );
2794 pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
2795 } while ( pCol );
2799 bool SwLayoutFrame::MoveLowerFootnotes( SwContentFrame *pStart, SwFootnoteBossFrame *pOldBoss,
2800 SwFootnoteBossFrame *pNewBoss, const bool bFootnoteNums )
2802 SwDoc *pDoc = GetFormat()->GetDoc();
2803 if ( pDoc->GetFootnoteIdxs().empty() )
2804 return false;
2805 if( pDoc->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER &&
2806 ( !IsInSct() || !FindSctFrame()->IsFootnoteAtEnd() ) )
2807 return true;
2809 if ( !pNewBoss )
2810 pNewBoss = FindFootnoteBossFrame( true );
2811 if ( pNewBoss == pOldBoss )
2812 return false;
2814 bool bMoved = false;
2815 if( !pStart )
2816 pStart = ContainsContent();
2818 SwFootnoteFrames aFootnoteArr;
2820 while ( IsAnLower( pStart ) )
2822 if ( static_cast<SwTextFrame*>(pStart)->HasFootnote() )
2824 // OD 03.04.2003 #108446# - To avoid unnecessary moves of footnotes
2825 // use new parameter <_bCollectOnlyPreviousFootnote> (4th parameter of
2826 // method <SwFootnoteBossFrame::CollectFootnote(..)>) to control, that only
2827 // footnotes have to be collected, that are positioned before the
2828 // new dedicated footnote boss frame.
2829 pNewBoss->CollectFootnotes( pStart, pOldBoss, aFootnoteArr, true );
2831 pStart = pStart->GetNextContentFrame();
2834 OSL_ENSURE( pOldBoss->IsInSct() == pNewBoss->IsInSct(),
2835 "MoveLowerFootnotes: Section confusion" );
2836 std::unique_ptr<SwFootnoteFrames> pFootnoteArr;
2837 SwLayoutFrame* pNewChief = nullptr;
2838 SwLayoutFrame* pOldChief = nullptr;
2840 bool bFoundCandidate = false;
2841 if (pStart && pOldBoss->IsInSct())
2843 pOldChief = pOldBoss->FindSctFrame();
2844 pNewChief = pNewBoss->FindSctFrame();
2845 bFoundCandidate = pOldChief != pNewChief;
2848 if (bFoundCandidate)
2850 pFootnoteArr.reset(new SwFootnoteFrames);
2851 pOldChief = pOldBoss->FindFootnoteBossFrame( true );
2852 pNewChief = pNewBoss->FindFootnoteBossFrame( true );
2853 while( pOldChief->IsAnLower( pStart ) )
2855 if ( static_cast<SwTextFrame*>(pStart)->HasFootnote() )
2856 static_cast<SwFootnoteBossFrame*>(pNewChief)->CollectFootnotes( pStart,
2857 pOldBoss, *pFootnoteArr );
2858 pStart = pStart->GetNextContentFrame();
2860 if( pFootnoteArr->empty() )
2862 pFootnoteArr.reset();
2865 else
2866 pFootnoteArr = nullptr;
2868 if ( !aFootnoteArr.empty() || pFootnoteArr )
2870 if( !aFootnoteArr.empty() )
2871 pNewBoss->MoveFootnotes_( aFootnoteArr, true );
2872 if( pFootnoteArr )
2874 assert(pNewChief);
2875 static_cast<SwFootnoteBossFrame*>(pNewChief)->MoveFootnotes_( *pFootnoteArr, true );
2876 pFootnoteArr.reset();
2878 bMoved = true;
2880 // update FootnoteNum only at page change
2881 if ( bFootnoteNums )
2883 SwPageFrame* pOldPage = pOldBoss->FindPageFrame();
2884 SwPageFrame* pNewPage =pNewBoss->FindPageFrame();
2885 if( pOldPage != pNewPage )
2887 pOldPage->UpdateFootnoteNum();
2888 pNewPage->UpdateFootnoteNum();
2892 return bMoved;
2895 /// Return value guarantees that a new page was not created. See SwFlowFrame::MoveFwd.
2896 bool SwContentFrame::MoveFootnoteCntFwd( bool bMakePage, SwFootnoteBossFrame *pOldBoss )
2898 OSL_ENSURE( IsInFootnote(), "no footnote." );
2899 SwLayoutFrame *pFootnote = FindFootnoteFrame();
2901 // The first paragraph in the first footnote in the first column in the
2902 // sectionfrm at the top of the page has not to move forward, if the
2903 // columnbody is empty.
2904 if( pOldBoss->IsInSct() && !pOldBoss->GetIndPrev() && !GetIndPrev() &&
2905 !pFootnote->GetPrev() )
2907 SwLayoutFrame* pBody = pOldBoss->FindBodyCont();
2908 if( !pBody || !pBody->Lower() )
2909 return true;
2912 //fix(9538): if the footnote has neighbors behind itself, remove them temporarily
2913 SwLayoutFrame *pNxt = static_cast<SwLayoutFrame*>(pFootnote->GetNext());
2914 SwLayoutFrame *pLst = nullptr;
2915 while ( pNxt )
2917 while ( pNxt->GetNext() )
2918 pNxt = static_cast<SwLayoutFrame*>(pNxt->GetNext());
2919 if ( pNxt == pLst )
2920 pNxt = nullptr;
2921 else
2922 { pLst = pNxt;
2923 SwContentFrame *pCnt = pNxt->ContainsContent();
2924 if( pCnt )
2925 pCnt->MoveFootnoteCntFwd( true, pOldBoss );
2926 pNxt = static_cast<SwLayoutFrame*>(pFootnote->GetNext());
2930 bool bSamePage = true;
2931 SwLayoutFrame *pNewUpper =
2932 GetLeaf( bMakePage ? MAKEPAGE_INSERT : MAKEPAGE_NONE, true );
2934 if ( pNewUpper )
2936 SwFootnoteBossFrame * const pNewBoss = pNewUpper->FindFootnoteBossFrame();
2937 // Are we changing the column/page?
2938 bool bSameBoss = pNewBoss == pOldBoss;
2939 if ( !bSameBoss )
2941 bSamePage = pOldBoss->FindPageFrame() == pNewBoss->FindPageFrame(); // page change?
2942 pNewUpper->Calc(getRootFrame()->GetCurrShell()->GetOut());
2945 // The layout leaf of the footnote is either a footnote container or a footnote.
2946 // If it is a footnote and it has the same footnote reference like the old Upper,
2947 // then move the content inside of it.
2948 // If it is a container or the reference differs, create a new footnote and add
2949 // it into the container.
2950 // Create also a SectionFrame if currently in an area inside a footnote.
2951 SwFootnoteFrame* pTmpFootnote = pNewUpper->IsFootnoteFrame() ? static_cast<SwFootnoteFrame*>(pNewUpper) : nullptr;
2952 if (!pTmpFootnote)
2954 assert(pNewUpper->IsFootnoteContFrame() && "New Upper not a FootnoteCont");
2955 SwFootnoteContFrame *pCont = static_cast<SwFootnoteContFrame*>(pNewUpper);
2956 pTmpFootnote = SwFootnoteContFrame::AppendChained(this, true);
2957 SwFrame* pNx = pCont->Lower();
2958 if( pNx && pTmpFootnote->GetAttr()->GetFootnote().IsEndNote() )
2959 while(pNx && !static_cast<SwFootnoteFrame*>(pNx)->GetAttr()->GetFootnote().IsEndNote())
2960 pNx = pNx->GetNext();
2961 pTmpFootnote->Paste( pCont, pNx );
2962 pTmpFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
2964 OSL_ENSURE( pTmpFootnote->GetAttr() == FindFootnoteFrame()->GetAttr(), "Wrong Footnote!" );
2965 // areas inside of footnotes get a special treatment
2966 SwLayoutFrame *pNewUp = pTmpFootnote;
2967 if( IsInSct() )
2969 SwSectionFrame* pSect = FindSctFrame();
2970 // area inside of a footnote (or only footnote in an area)?
2971 if( pSect->IsInFootnote() )
2973 SwFrame* pLower = pTmpFootnote->Lower();
2974 if( pLower && pLower->IsSctFrame() &&
2975 pSect->GetFollow() == static_cast<SwSectionFrame*>(pLower) )
2976 pNewUp = static_cast<SwSectionFrame*>(pLower);
2977 else
2979 pNewUp = new SwSectionFrame( *pSect, false );
2980 pNewUp->InsertBefore( pTmpFootnote, pLower );
2981 static_cast<SwSectionFrame*>(pNewUp)->Init();
2984 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pNewUp);
2985 aFrm.Pos() = pTmpFootnote->getFrameArea().Pos();
2986 aFrm.Pos().AdjustY(1 ); // for notifications
2989 // If the section frame has a successor then the latter needs
2990 // to be moved behind the new Follow of the section frame.
2991 SwFrame* pTmp = pSect->GetNext();
2992 if( pTmp )
2994 SwFlowFrame* pTmpNxt;
2995 if( pTmp->IsContentFrame() )
2996 pTmpNxt = static_cast<SwContentFrame*>(pTmp);
2997 else if( pTmp->IsSctFrame() )
2998 pTmpNxt = static_cast<SwSectionFrame*>(pTmp);
2999 else
3001 OSL_ENSURE( pTmp->IsTabFrame(), "GetNextSctLeaf: Wrong Type" );
3002 pTmpNxt = static_cast<SwTabFrame*>(pTmp);
3004 // we will dereference pNewUp in the following MoveSubTree call
3005 // so it certainly should not be deleted before that
3006 SwFrameDeleteGuard aDeleteGuard(pNewUp);
3007 pTmpNxt->MoveSubTree( pTmpFootnote, pNewUp->GetNext() );
3013 MoveSubTree( pNewUp, pNewUp->Lower() );
3015 if( !bSameBoss )
3016 Prepare( PrepareHint::BossChanged );
3018 return bSamePage;
3021 SwSaveFootnoteHeight::SwSaveFootnoteHeight( SwFootnoteBossFrame *pBs, const SwTwips nDeadLine ) :
3022 aGuard(pBs),
3023 pBoss( pBs ),
3024 nOldHeight( pBs->GetMaxFootnoteHeight() )
3026 pBoss->SetFootnoteDeadLine( nDeadLine );
3027 nNewHeight = pBoss->GetMaxFootnoteHeight();
3030 SwSaveFootnoteHeight::~SwSaveFootnoteHeight()
3032 // If somebody tweaked the deadline meanwhile, we let it happen
3033 if ( nNewHeight == pBoss->GetMaxFootnoteHeight() )
3034 pBoss->m_nMaxFootnoteHeight = nOldHeight;
3037 #ifdef DBG_UTIL
3038 //JP 15.10.2001: in a non pro version test if the attribute has the same
3039 // meaning which his reference is
3041 // Normally, the pRef member and the GetRefFromAttr() result has to be
3042 // identically. Sometimes footnote will be moved from a master to its follow,
3043 // but the GetRef() is called first, so we have to ignore a master/follow
3044 // mismatch.
3046 const SwContentFrame* SwFootnoteFrame::GetRef() const
3048 (void) GetRefFromAttr();
3049 return mpReference;
3052 SwContentFrame* SwFootnoteFrame::GetRef()
3054 (void) GetRefFromAttr();
3055 return mpReference;
3057 #endif
3059 const SwContentFrame* SwFootnoteFrame::GetRefFromAttr() const
3061 SwFootnoteFrame* pThis = const_cast<SwFootnoteFrame*>(this);
3062 return pThis->GetRefFromAttr();
3065 SwContentFrame* SwFootnoteFrame::GetRefFromAttr()
3067 assert(mpAttribute && "invalid Attribute");
3068 SwTextNode& rTNd = const_cast<SwTextNode&>(mpAttribute->GetTextNode());
3069 SwPosition aPos( rTNd, mpAttribute->GetStart() );
3070 SwContentFrame* pCFrame = rTNd.getLayoutFrame(getRootFrame(), &aPos);
3071 return pCFrame;
3074 /** search for last content in the current footnote frame
3076 OD 2005-12-02 #i27138#
3078 SwContentFrame* SwFootnoteFrame::FindLastContent()
3080 SwContentFrame* pLastContentFrame( nullptr );
3082 // find last lower, which is a content frame or contains content.
3083 // hidden text frames, empty sections and empty tables have to be skipped.
3084 SwFrame* pLastLowerOfFootnote( GetLower() );
3085 SwFrame* pTmpLastLower( pLastLowerOfFootnote );
3086 while ( pTmpLastLower && pTmpLastLower->GetNext() )
3088 pTmpLastLower = pTmpLastLower->GetNext();
3089 if (!pTmpLastLower->IsHiddenNow()
3090 && (!pTmpLastLower->IsLayoutFrame()
3091 || static_cast<SwLayoutFrame*>(pTmpLastLower)->ContainsContent()))
3093 pLastLowerOfFootnote = pTmpLastLower;
3097 // determine last content frame depending on type of found last lower.
3098 if ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsTabFrame() )
3100 pLastContentFrame = static_cast<SwTabFrame*>(pLastLowerOfFootnote)->FindLastContent();
3102 else if ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsSctFrame() )
3104 pLastContentFrame = static_cast<SwSectionFrame*>(pLastLowerOfFootnote)->FindLastContent();
3106 else
3108 pLastContentFrame = dynamic_cast<SwContentFrame*>(pLastLowerOfFootnote);
3111 return pLastContentFrame;
3114 void SwFootnoteFrame::dumpAsXml(xmlTextWriterPtr writer) const
3116 (void)xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("ftn"));
3117 dumpAsXmlAttributes(writer);
3119 (void)xmlTextWriterStartElement(writer, BAD_CAST("infos"));
3120 dumpInfosAsXml(writer);
3121 (void)xmlTextWriterEndElement(writer);
3122 dumpChildrenAsXml(writer);
3124 (void)xmlTextWriterEndElement(writer);
3127 void SwFootnoteFrame::dumpAsXmlAttributes(xmlTextWriterPtr writer) const
3129 SwLayoutFrame::dumpAsXmlAttributes(writer);
3131 (void)xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("ref"), "%" SAL_PRIuUINT32, GetRef()->GetFrameId() );
3132 if (GetMaster())
3133 (void)xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("master"), "%" SAL_PRIuUINT32, GetMaster()->GetFrameId() );
3134 if (GetFollow())
3135 (void)xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("follow"), "%" SAL_PRIuUINT32, GetFollow()->GetFrameId() );
3138 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */