summaryrefslogtreecommitdiffstats
path: root/sw/source/core/layout/ftnfrm.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sw/source/core/layout/ftnfrm.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/layout/ftnfrm.cxx')
-rw-r--r--sw/source/core/layout/ftnfrm.cxx2987
1 files changed, 2987 insertions, 0 deletions
diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx
new file mode 100644
index 000000000..652436eb4
--- /dev/null
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -0,0 +1,2987 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <txtftn.hxx>
+#include <fmtftn.hxx>
+#include <ftnidx.hxx>
+#include <pagefrm.hxx>
+#include <colfrm.hxx>
+#include <rootfrm.hxx>
+#include <frmtool.hxx>
+#include <ftnfrm.hxx>
+#include <txtfrm.hxx>
+#include <tabfrm.hxx>
+#include <pagedesc.hxx>
+#include <ftninfo.hxx>
+#include <sectfrm.hxx>
+#include <objectformatter.hxx>
+#include <viewopt.hxx>
+#include <calbck.hxx>
+#include <ndindex.hxx>
+#include <pam.hxx>
+#include <ndtxt.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <IDocumentSettingAccess.hxx>
+
+#define ENDNOTE 0x80000000
+
+/// Search the position of an attribute in the FootnoteArray at the document,
+/// because all footnotes are located there, ordered by their index.
+static sal_uLong lcl_FindFootnotePos( const SwDoc *pDoc, const SwTextFootnote *pAttr )
+{
+ const SwFootnoteIdxs &rFootnoteIdxs = pDoc->GetFootnoteIdxs();
+
+ SwTextFootnote* pBla = const_cast<SwTextFootnote*>(pAttr);
+ SwFootnoteIdxs::const_iterator it = rFootnoteIdxs.find( pBla );
+ if ( it != rFootnoteIdxs.end() )
+ {
+ sal_uLong nRet = it - rFootnoteIdxs.begin();
+ if( pAttr->GetFootnote().IsEndNote() )
+ return nRet + ENDNOTE;
+ return nRet;
+ }
+ OSL_ENSURE( !pDoc, "FootnotePos not found." );
+ return 0;
+}
+
+bool SwFootnoteFrame::operator<( const SwTextFootnote* pTextFootnote ) const
+{
+ const SwDoc* pDoc = GetFormat()->GetDoc();
+ OSL_ENSURE( pDoc, "SwFootnoteFrame: Missing doc!" );
+ return lcl_FindFootnotePos( pDoc, GetAttr() ) <
+ lcl_FindFootnotePos( pDoc, pTextFootnote );
+}
+
+/*
+|*
+|* bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* pBoss, SwPageFrame* pPage)
+|* sets pBoss on the next SwFootnoteBossFrame, which can either be a column
+|* or a page (without columns). If the page changes meanwhile,
+|* pPage contains the new page and this function returns true.
+|*
+|*/
+
+static bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* &rpBoss, SwPageFrame* &rpPage,
+ bool bDontLeave )
+{
+ if( rpBoss->IsColumnFrame() )
+ {
+ if( rpBoss->GetNext() )
+ {
+ rpBoss = static_cast<SwFootnoteBossFrame*>(rpBoss->GetNext()); //next column
+ return false;
+ }
+ if( rpBoss->IsInSct() )
+ {
+ SwSectionFrame* pSct = rpBoss->FindSctFrame()->GetFollow();
+ if( pSct )
+ {
+ OSL_ENSURE( pSct->Lower() && pSct->Lower()->IsColumnFrame(),
+ "Where's the column?" );
+ rpBoss = static_cast<SwColumnFrame*>(pSct->Lower());
+ SwPageFrame* pOld = rpPage;
+ rpPage = pSct->FindPageFrame();
+ return pOld != rpPage;
+ }
+ else if( bDontLeave )
+ {
+ rpPage = nullptr;
+ rpBoss = nullptr;
+ return false;
+ }
+ }
+ }
+ rpPage = static_cast<SwPageFrame*>(rpPage->GetNext()); // next page
+ rpBoss = rpPage;
+ if( rpPage )
+ {
+ SwLayoutFrame* pBody = rpPage->FindBodyCont();
+ if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
+ rpBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower()); // first column
+ }
+ return true;
+}
+
+/// @returns column number if pBoss is a column, otherwise 0.
+static sal_uInt16 lcl_ColumnNum( const SwFrame* pBoss )
+{
+ sal_uInt16 nRet = 0;
+ if( !pBoss->IsColumnFrame() )
+ return 0;
+ const SwFrame* pCol;
+ if( pBoss->IsInSct() )
+ {
+ pCol = pBoss->GetUpper()->FindColFrame();
+ if( pBoss->GetNext() || pBoss->GetPrev() )
+ {
+ while( pBoss )
+ {
+ ++nRet; // Section columns
+ pBoss = pBoss->GetPrev();
+ }
+ }
+ }
+ else
+ pCol = pBoss;
+ while( pCol )
+ {
+ nRet += 256; // Page columns
+ pCol = pCol->GetPrev();
+ }
+ return nRet;
+}
+
+SwFootnoteContFrame::SwFootnoteContFrame( SwFrameFormat *pFormat, SwFrame* pSib ):
+ SwLayoutFrame( pFormat, pSib )
+{
+ mnFrameType = SwFrameType::FtnCont;
+}
+
+SwFootnoteFrame* SwFootnoteContFrame::AddChained(bool bAppend, SwFrame* pThis, bool bDefaultFormat)
+{
+ SwFootnoteFrame *pOld = pThis->FindFootnoteFrame();
+ SwFrameFormat *pFormat = pOld->GetFormat();
+ if (bDefaultFormat)
+ pFormat = pFormat->GetDoc()->GetDfltFrameFormat();
+
+ SwFootnoteFrame *pNew = new SwFootnoteFrame(pFormat, pOld, pOld->GetRef(), pOld->GetAttr());
+
+ if (bAppend)
+ {
+ if (pOld->GetFollow())
+ {
+ pNew->SetFollow(pOld->GetFollow());
+ pOld->GetFollow()->SetMaster(pNew);
+ }
+ pOld->SetFollow(pNew);
+ pNew->SetMaster(pOld);
+ }
+ else
+ {
+ if (pOld->GetMaster())
+ {
+ pNew->SetMaster(pOld->GetMaster());
+ pOld->GetMaster()->SetFollow(pNew);
+ }
+ pNew->SetFollow(pOld);
+ pOld->SetMaster(pNew);
+ }
+
+ return pNew;
+}
+
+// lcl_Undersize(..) walks over a SwFrame and its contents
+// and returns the sum of all requested TextFrame magnifications.
+
+static tools::Long lcl_Undersize( const SwFrame* pFrame )
+{
+ tools::Long nRet = 0;
+ SwRectFnSet aRectFnSet(pFrame);
+ if( pFrame->IsTextFrame() )
+ {
+ if( static_cast<const SwTextFrame*>(pFrame)->IsUndersized() )
+ {
+ // Does this TextFrame would like to be a little bit bigger?
+ nRet = static_cast<const SwTextFrame*>(pFrame)->GetParHeight() -
+ aRectFnSet.GetHeight(pFrame->getFramePrintArea());
+ if( nRet < 0 )
+ nRet = 0;
+ }
+ }
+ else if( pFrame->IsLayoutFrame() )
+ {
+ const SwFrame* pNxt = static_cast<const SwLayoutFrame*>(pFrame)->Lower();
+ while( pNxt )
+ {
+ nRet += lcl_Undersize( pNxt );
+ pNxt = pNxt->GetNext();
+ }
+ }
+ return nRet;
+}
+
+namespace sw {
+
+SwTwips FootnoteSeparatorHeight(SwPageFootnoteInfo const& rInf)
+{
+ return rInf.GetTopDist() + rInf.GetBottomDist() + rInf.GetLineWidth();
+}
+
+} // namespace sw
+
+/// "format" the frame (Fixsize is not set here).
+void SwFootnoteContFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs * )
+{
+ // calculate total border, only one distance to the top
+ const SwPageFrame* pPage = FindPageFrame();
+ const SwPageFootnoteInfo &rInf = pPage->GetPageDesc()->GetFootnoteInfo();
+ const SwTwips nBorder = sw::FootnoteSeparatorHeight(rInf);
+ SwRectFnSet aRectFnSet(this);
+
+ if ( !isFramePrintAreaValid() )
+ {
+ setFramePrintAreaValid(true);
+ SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
+
+ aRectFnSet.SetTop( aPrt, nBorder );
+ aRectFnSet.SetWidth( aPrt, aRectFnSet.GetWidth(getFrameArea()) );
+ aRectFnSet.SetHeight(aPrt, aRectFnSet.GetHeight(getFrameArea()) - nBorder );
+
+ if( aRectFnSet.GetHeight(aPrt) < 0 && !pPage->IsFootnotePage() )
+ {
+ setFrameAreaSizeValid(false);
+ }
+ }
+
+ if ( isFrameAreaSizeValid() )
+ return;
+
+ bool bGrow = pPage->IsFootnotePage();
+ if( bGrow )
+ {
+ const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
+ if( pSh && pSh->GetViewOptions()->getBrowseMode() )
+ bGrow = false;
+ }
+ if( bGrow )
+ Grow( LONG_MAX );
+ else
+ {
+ // VarSize is determined based on the content plus the borders
+ SwTwips nRemaining = 0;
+ SwFrame *pFrame = m_pLower;
+ while ( pFrame )
+ { // lcl_Undersize(..) respects (recursively) TextFrames, which
+ // would like to be bigger. They are created especially in
+ // columnized borders, if these do not have their maximum
+ // size yet.
+ nRemaining += aRectFnSet.GetHeight(pFrame->getFrameArea()) + lcl_Undersize( pFrame );
+ pFrame = pFrame->GetNext();
+ }
+ // add the own border
+ nRemaining += nBorder;
+
+ SwTwips nDiff;
+ if( IsInSct() )
+ {
+ nDiff = -aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()) );
+ if( nDiff > 0 )
+ {
+ if( nDiff > aRectFnSet.GetHeight(getFrameArea()) )
+ {
+ nDiff = aRectFnSet.GetHeight(getFrameArea());
+ }
+
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
+ aRectFnSet.AddBottom( aFrm, -nDiff );
+ aRectFnSet.AddHeight( aFrm, -nDiff );
+ }
+ }
+ nDiff = aRectFnSet.GetHeight(getFrameArea()) - nRemaining;
+ if ( nDiff > 0 )
+ Shrink( nDiff );
+ else if ( nDiff < 0 )
+ {
+ Grow( -nDiff );
+ // It may happen that there is less space available,
+ // than what the border needs - the size of the PrtArea
+ // will then be negative.
+ SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
+ if( nPrtHeight < 0 )
+ {
+ const SwTwips nTmpDiff = std::max( SwTwips(aRectFnSet.GetTop(getFramePrintArea())), -nPrtHeight );
+ SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
+ aRectFnSet.SubTop( aPrt, nTmpDiff );
+ }
+ }
+ }
+
+ setFrameAreaSizeValid(true);
+}
+
+SwTwips SwFootnoteContFrame::GrowFrame( SwTwips nDist, bool bTst, bool )
+{
+ // No check if FixSize since FootnoteContainer are variable up to their max. height.
+ // If the max. height is LONG_MAX, take as much space as needed.
+ // If the page is a special footnote page, take also as much as possible.
+ assert(GetUpper() && GetUpper()->IsFootnoteBossFrame());
+
+ SwRectFnSet aRectFnSet(this);
+ if( aRectFnSet.GetHeight(getFrameArea()) > 0 &&
+ nDist > ( LONG_MAX - aRectFnSet.GetHeight(getFrameArea()) ) )
+ nDist = LONG_MAX - aRectFnSet.GetHeight(getFrameArea());
+
+ SwFootnoteBossFrame *pBoss = static_cast<SwFootnoteBossFrame*>(GetUpper());
+ if( IsInSct() )
+ {
+ SwSectionFrame* pSect = FindSctFrame();
+ OSL_ENSURE( pSect, "GrowFrame: Missing SectFrame" );
+ // In a section, which has to maximize, a footnotecontainer is allowed
+ // to grow, when the section can't grow anymore.
+ if( !bTst && !pSect->IsColLocked() &&
+ pSect->ToMaximize( false ) && pSect->Growable() )
+ {
+ pSect->InvalidateSize();
+ return 0;
+ }
+ }
+ const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
+ const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
+ SwPageFrame *pPage = pBoss->FindPageFrame();
+ if ( bBrowseMode || !pPage->IsFootnotePage() )
+ {
+ if ( pBoss->GetMaxFootnoteHeight() != LONG_MAX )
+ {
+ nDist = std::min( nDist,
+ SwTwips(pBoss->GetMaxFootnoteHeight() - aRectFnSet.GetHeight(getFrameArea())) );
+ if ( nDist <= 0 )
+ return 0;
+ }
+ // FootnoteBoss also influences the max value
+ if( !IsInSct() )
+ {
+ const SwTwips nMax = pBoss->GetVarSpace();
+ if ( nDist > nMax )
+ nDist = nMax;
+ if ( nDist <= 0 )
+ return 0;
+ }
+ }
+ else if( nDist > aRectFnSet.GetHeight(GetPrev()->getFrameArea()) )
+ // do not use more space than the body has
+ nDist = aRectFnSet.GetHeight(GetPrev()->getFrameArea());
+
+ tools::Long nAvail = 0;
+ if ( bBrowseMode )
+ {
+ nAvail = GetUpper()->getFramePrintArea().Height();
+ const SwFrame *pAvail = GetUpper()->Lower();
+ do
+ { nAvail -= pAvail->getFrameArea().Height();
+ pAvail = pAvail->GetNext();
+ } while ( pAvail );
+ if ( nAvail > nDist )
+ nAvail = nDist;
+ }
+
+ if ( !bTst )
+ {
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
+ aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nDist );
+
+ if( IsVertical() && !IsVertLR() )
+ {
+ aFrm.Pos().AdjustX( -nDist );
+ }
+ }
+ tools::Long nGrow = nDist - nAvail,
+ nReal = 0;
+ if ( nGrow > 0 )
+ {
+ SwNeighbourAdjust nAdjust = pBoss->NeighbourhoodAdjustment();
+ if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
+ nReal = AdjustNeighbourhood( nGrow, bTst );
+ else
+ {
+ if( SwNeighbourAdjust::GrowAdjust == nAdjust )
+ {
+ SwFrame* pFootnote = Lower();
+ if( pFootnote )
+ {
+ while( pFootnote->GetNext() )
+ pFootnote = pFootnote->GetNext();
+ if( static_cast<SwFootnoteFrame*>(pFootnote)->GetAttr()->GetFootnote().IsEndNote() )
+ {
+ nReal = AdjustNeighbourhood( nGrow, bTst );
+ nAdjust = SwNeighbourAdjust::GrowShrink; // no more AdjustNeighbourhood
+ }
+ }
+ }
+ nReal += pBoss->Grow( nGrow - nReal, bTst );
+ if( ( SwNeighbourAdjust::GrowAdjust == nAdjust || SwNeighbourAdjust::AdjustGrow == nAdjust )
+ && nReal < nGrow )
+ nReal += AdjustNeighbourhood( nGrow - nReal, bTst );
+ }
+ }
+
+ nReal += nAvail;
+
+ if ( !bTst )
+ {
+ if ( nReal != nDist )
+ {
+ nDist -= nReal;
+
+ // We can only respect the boundless wish so much
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
+ aFrm.AddHeight( -nDist );
+
+ if( IsVertical() && !IsVertLR() )
+ {
+ aFrm.Pos().AdjustX(nDist );
+ }
+ }
+
+ // growing happens upwards, so successors to not need to be invalidated
+ if( nReal )
+ {
+ InvalidateSize_();
+ InvalidatePos_();
+ InvalidatePage( pPage );
+ }
+ }
+ return nReal;
+}
+
+SwTwips SwFootnoteContFrame::ShrinkFrame( SwTwips nDiff, bool bTst, bool bInfo )
+{
+ SwPageFrame *pPage = FindPageFrame();
+ bool bShrink = false;
+ if ( pPage )
+ {
+ if( !pPage->IsFootnotePage() )
+ bShrink = true;
+ else
+ {
+ const SwViewShell *pSh = getRootFrame()->GetCurrShell();
+ if( pSh && pSh->GetViewOptions()->getBrowseMode() )
+ bShrink = true;
+ }
+ }
+ if( bShrink )
+ {
+ SwTwips nRet = SwLayoutFrame::ShrinkFrame( nDiff, bTst, bInfo );
+ if( IsInSct() && !bTst )
+ FindSctFrame()->InvalidateNextPos();
+ if ( !bTst && nRet )
+ {
+ InvalidatePos_();
+ InvalidatePage( pPage );
+ }
+ return nRet;
+ }
+ return 0;
+}
+
+SwFootnoteFrame::SwFootnoteFrame( SwFrameFormat *pFormat, SwFrame* pSib, SwContentFrame *pCnt, SwTextFootnote *pAt ):
+ SwLayoutFrame( pFormat, pSib ),
+ mpFollow( nullptr ),
+ mpMaster( nullptr ),
+ mpReference( pCnt ),
+ mpAttribute( pAt ),
+ mbBackMoveLocked( false ),
+ // #i49383#
+ mbUnlockPosOfLowerObjs( true )
+{
+ mnFrameType = SwFrameType::Ftn;
+}
+
+void SwFootnoteFrame::InvalidateNxtFootnoteCnts( SwPageFrame const *pPage )
+{
+ if ( !GetNext() )
+ return;
+
+ SwFrame *pCnt = static_cast<SwLayoutFrame*>(GetNext())->ContainsAny();
+ if( !pCnt )
+ return;
+
+ pCnt->InvalidatePage( pPage );
+ pCnt->InvalidatePrt_();
+ do
+ { pCnt->InvalidatePos_();
+ if( pCnt->IsSctFrame() )
+ {
+ SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
+ if( pTmp )
+ pTmp->InvalidatePos_();
+ }
+ pCnt->GetUpper()->InvalidateSize_();
+ pCnt = pCnt->FindNext();
+ } while ( pCnt && GetUpper()->IsAnLower( pCnt ) );
+}
+
+bool SwFootnoteFrame::IsDeleteForbidden() const
+{
+ if (SwLayoutFrame::IsDeleteForbidden())
+ return true;
+ // needs to be in sync with the ::Cut logic
+ const SwLayoutFrame *pUp = GetUpper();
+ if (pUp)
+ {
+ if (GetPrev())
+ return false;
+
+ // The last footnote takes its container along if it
+ // is deleted. Cut would put pUp->Lower() to the value
+ // of GetNext(), so if there is no GetNext then
+ // Cut would delete pUp. If that condition is true
+ // here then check if the container is delete-forbidden
+ return !GetNext() && pUp->IsDeleteForbidden();
+ }
+ return false;
+}
+
+void SwFootnoteFrame::Cut()
+{
+ if ( GetNext() )
+ GetNext()->InvalidatePos();
+ else if ( GetPrev() )
+ GetPrev()->SetRetouche();
+
+ // first move then shrink Upper
+ SwLayoutFrame *pUp = GetUpper();
+
+ // correct chaining
+ SwFootnoteFrame *pFootnote = this;
+ if ( pFootnote->GetFollow() )
+ pFootnote->GetFollow()->SetMaster( pFootnote->GetMaster() );
+ if ( pFootnote->GetMaster() )
+ pFootnote->GetMaster()->SetFollow( pFootnote->GetFollow() );
+ pFootnote->SetFollow( nullptr );
+ pFootnote->SetMaster( nullptr );
+
+ // cut all connections
+ RemoveFromLayout();
+
+ if ( !pUp )
+ return;
+
+ // The last footnote takes its container along
+ if (!pUp->Lower())
+ {
+ SwPageFrame *pPage = pUp->FindPageFrame();
+ if ( pPage )
+ {
+ SwLayoutFrame *pBody = pPage->FindBodyCont();
+ if( pBody && !pBody->ContainsContent() )
+ pPage->getRootFrame()->SetSuperfluous();
+ }
+ SwSectionFrame* pSect = pUp->FindSctFrame();
+ pUp->Cut();
+ SwFrame::DestroyFrame(pUp);
+ // If the last footnote container was removed from a column
+ // section without a Follow, then this section can be shrunk.
+ if( pSect && !pSect->ToMaximize( false ) && !pSect->IsColLocked() )
+ pSect->InvalidateSize_();
+ }
+ else
+ { if ( getFrameArea().Height() )
+ pUp->Shrink( getFrameArea().Height() );
+ pUp->SetCompletePaint();
+ pUp->InvalidatePage();
+ }
+}
+
+void SwFootnoteFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
+{
+ OSL_ENSURE( pParent, "no parent in Paste." );
+ OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
+ OSL_ENSURE( pParent != this, "I am my own parent." );
+ OSL_ENSURE( pSibling != this, "I am my own sibling." );
+ OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
+ "I am still somewhere registered." );
+
+ // insert into tree structure
+ InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
+
+ SwRectFnSet aRectFnSet(this);
+ if( aRectFnSet.GetWidth(getFrameArea())!=aRectFnSet.GetWidth(pParent->getFramePrintArea()) )
+ InvalidateSize_();
+ InvalidatePos_();
+ if (SwFrame *const pContent = ContainsContent())
+ { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
+ pContent->InvalidatePrt_();
+ }
+ SwPageFrame *pPage = FindPageFrame();
+ InvalidatePage( pPage );
+ if (SwFootnoteFrame *const pNext = static_cast<SwFootnoteFrame *>(GetNext()))
+ {
+ pNext->InvalidatePos_();
+ if (SwFrame *const pContent = pNext->ContainsContent())
+ { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
+ pContent->InvalidatePrt_();
+ }
+ }
+ if( aRectFnSet.GetHeight(getFrameArea()) )
+ pParent->Grow( aRectFnSet.GetHeight(getFrameArea()) );
+
+ // If the predecessor is the master and/or the successor is the Follow,
+ // then take their content and destroy them.
+ if ( GetPrev() && GetPrev() == GetMaster() )
+ {
+ OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetPrev()->GetLower() ),
+ "Footnote without content?" );
+ SwFlowFrame::CastFlowFrame( GetPrev()->GetLower())->
+ MoveSubTree( this, GetLower() );
+ SwFrame *pDel = GetPrev();
+ assert(pDel != this);
+ pDel->Cut();
+ SwFrame::DestroyFrame(pDel);
+ }
+ if ( GetNext() && GetNext() == GetFollow() )
+ {
+ OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetNext()->GetLower() ),
+ "Footnote without content?" );
+ SwFlowFrame::CastFlowFrame( GetNext()->GetLower() )->MoveSubTree( this );
+ SwFrame *pDel = GetNext();
+ assert(pDel != this);
+ pDel->Cut();
+ SwFrame::DestroyFrame(pDel);
+ }
+#if OSL_DEBUG_LEVEL > 0
+ SwDoc *pDoc = GetFormat()->GetDoc();
+ if ( GetPrev() )
+ {
+ OSL_ENSURE( lcl_FindFootnotePos( pDoc, static_cast<SwFootnoteFrame*>(GetPrev())->GetAttr() ) <=
+ lcl_FindFootnotePos( pDoc, GetAttr() ), "Prev is not FootnotePrev" );
+ }
+ if ( GetNext() )
+ {
+ OSL_ENSURE( lcl_FindFootnotePos( pDoc, GetAttr() ) <=
+ lcl_FindFootnotePos( pDoc, static_cast<SwFootnoteFrame*>(GetNext())->GetAttr() ),
+ "Next is not FootnoteNext" );
+ }
+#endif
+ InvalidateNxtFootnoteCnts( pPage );
+}
+
+/// Return the next layout leaf in that the frame can be moved.
+/// New pages will only be created if specified by the parameter.
+SwLayoutFrame *SwFrame::GetNextFootnoteLeaf( MakePageType eMakePage )
+{
+ SwFootnoteBossFrame *pOldBoss = FindFootnoteBossFrame();
+ SwPageFrame* pOldPage = pOldBoss->FindPageFrame();
+ SwPageFrame* pPage;
+ SwFootnoteBossFrame *pBoss = pOldBoss->IsColumnFrame() ?
+ static_cast<SwFootnoteBossFrame*>(pOldBoss->GetNext()) : nullptr; // next column, if existing
+ if( pBoss )
+ pPage = nullptr;
+ else
+ {
+ if( pOldBoss->GetUpper()->IsSctFrame() )
+ { // this can only be in a column area
+ SwLayoutFrame* pNxt = pOldBoss->GetNextSctLeaf( eMakePage );
+ if( pNxt )
+ {
+ OSL_ENSURE( pNxt->IsColBodyFrame(), "GetNextFootnoteLeaf: Funny Leaf" );
+ pBoss = static_cast<SwFootnoteBossFrame*>(pNxt->GetUpper());
+ pPage = pBoss->FindPageFrame();
+ }
+ else
+ return nullptr;
+ }
+ else
+ {
+ // next page
+ pPage = static_cast<SwPageFrame*>(pOldPage->GetNext());
+ // skip empty pages
+ if( pPage && pPage->IsEmptyPage() )
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+ pBoss = pPage;
+ }
+ }
+ // What do we have until here?
+ // pBoss != NULL, pPage==NULL => pBoss is the next column on the same page
+ // pBoss != NULL, pPage!=NULL => pBoss and pPage are the following page (empty pages skipped)
+ // pBoss == NULL => pPage == NULL, so there are no following pages
+
+ // If the footnote has already a Follow we do not need to search.
+ // However, if there are unwanted empty columns/pages between Footnote and Follow,
+ // create another Follow on the next best column/page and the rest will sort itself out.
+ SwFootnoteFrame *pFootnote = FindFootnoteFrame();
+ if ( pFootnote && pFootnote->GetFollow() )
+ {
+ SwFootnoteBossFrame* pTmpBoss = pFootnote->GetFollow()->FindFootnoteBossFrame();
+ // Following cases will be handled:
+ // 1. both "FootnoteBoss"es are neighboring columns/pages
+ // 2. the new one is the first column of a neighboring page
+ // 3. the new one is the first column in a section of the next page
+ while( pTmpBoss != pBoss && pTmpBoss && !pTmpBoss->GetPrev() )
+ pTmpBoss = pTmpBoss->GetUpper()->FindFootnoteBossFrame();
+ if( pTmpBoss == pBoss )
+ return pFootnote->GetFollow();
+ }
+
+ // If no pBoss could be found or it is a "wrong" page, we need a new page.
+ if ( !pBoss || ( pPage && pPage->IsEndNotePage() && !pOldPage->IsEndNotePage() ) )
+ {
+ if ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT )
+ {
+ pBoss = InsertPage( pOldPage, pOldPage->IsFootnotePage() );
+ static_cast<SwPageFrame*>(pBoss)->SetEndNotePage( pOldPage->IsEndNotePage() );
+ }
+ else
+ return nullptr;
+ }
+ if( pBoss->IsPageFrame() )
+ {
+ // If this page has columns, then go to the first one
+ SwLayoutFrame* pLay = pBoss->FindBodyCont();
+ if( pLay && pLay->Lower() && pLay->Lower()->IsColumnFrame() )
+ pBoss = static_cast<SwFootnoteBossFrame*>(pLay->Lower());
+ }
+ // found column/page - add myself
+ SwFootnoteContFrame *pCont = pBoss->FindFootnoteCont();
+ if ( !pCont && pBoss->GetMaxFootnoteHeight() &&
+ ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) )
+ pCont = pBoss->MakeFootnoteCont();
+ return pCont;
+}
+
+/// Get the preceding layout leaf in that the frame can be moved.
+SwLayoutFrame *SwFrame::GetPrevFootnoteLeaf( MakePageType eMakeFootnote )
+{
+ // The predecessor of a footnote is (if possible)
+ // the master of the chain of the footnote.
+ SwFootnoteFrame *pFootnote = FindFootnoteFrame();
+ SwLayoutFrame *pRet = pFootnote->GetMaster();
+
+ SwFootnoteBossFrame* pOldBoss = FindFootnoteBossFrame();
+ SwPageFrame *pOldPage = pOldBoss->FindPageFrame();
+
+ if ( !pOldBoss->GetPrev() && !pOldPage->GetPrev() )
+ return pRet; // there is neither a predecessor column nor page
+
+ if ( !pRet )
+ {
+ bool bEndn = pFootnote->GetAttr()->GetFootnote().IsEndNote();
+ SwFrame* pTmpRef = nullptr;
+ const IDocumentSettingAccess& rSettings
+ = pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
+ if( bEndn && pFootnote->IsInSct() )
+ {
+ SwSectionFrame* pSect = pFootnote->FindSctFrame();
+ if( pSect->IsEndnAtEnd() )
+ // Endnotes at the end of the section.
+ pTmpRef = pSect->FindLastContent( SwFindMode::LastCnt );
+ }
+ else if (bEndn && rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
+ {
+ // Endnotes at the end of the document.
+ SwPageFrame* pPage = getRootFrame()->GetLastPage();
+ assert(pPage);
+ SwFrame* pPrevPage = pPage->GetPrev();
+ if (pPrevPage)
+ {
+ // Have a last but one page, use that since we try to get a preceding frame.
+ assert(pPrevPage->IsPageFrame());
+ pPage = static_cast<SwPageFrame*>(pPrevPage);
+ }
+ pTmpRef = pPage->FindLastBodyContent();
+ }
+ if( !pTmpRef )
+ // Endnotes on a separate page.
+ pTmpRef = pFootnote->GetRef();
+ SwFootnoteBossFrame* pStop = pTmpRef->FindFootnoteBossFrame( !bEndn );
+
+ const sal_uInt16 nNum = pStop->GetPhyPageNum();
+
+ // Do not leave the corresponding page if the footnote should
+ // be shown at the document ending or the footnote is an endnote.
+ const bool bEndNote = pOldPage->IsEndNotePage();
+ const bool bFootnoteEndDoc = pOldPage->IsFootnotePage();
+ SwFootnoteBossFrame* pNxtBoss = pOldBoss;
+ SwSectionFrame *pSect = pNxtBoss->GetUpper()->IsSctFrame() ?
+ static_cast<SwSectionFrame*>(pNxtBoss->GetUpper()) : nullptr;
+
+ do
+ {
+ if( pNxtBoss->IsColumnFrame() && pNxtBoss->GetPrev() )
+ pNxtBoss = static_cast<SwFootnoteBossFrame*>(pNxtBoss->GetPrev()); // one column backwards
+ else // one page backwards
+ {
+ SwLayoutFrame* pBody = nullptr;
+ if( pSect )
+ {
+ if( pSect->IsFootnoteLock() )
+ {
+ if( pNxtBoss == pOldBoss )
+ return nullptr;
+ pStop = pNxtBoss;
+ }
+ else
+ {
+ pSect = pSect->FindMaster();
+ if( !pSect || !pSect->Lower() )
+ return nullptr;
+ OSL_ENSURE( pSect->Lower()->IsColumnFrame(),
+ "GetPrevFootnoteLeaf: Where's the column?" );
+ pNxtBoss = static_cast<SwFootnoteBossFrame*>(pSect->Lower());
+ pBody = pSect;
+ }
+ }
+ else
+ {
+ SwPageFrame* pPage = static_cast<SwPageFrame*>(pNxtBoss->FindPageFrame()->GetPrev());
+ if( !pPage || pPage->GetPhyPageNum() < nNum ||
+ bEndNote != pPage->IsEndNotePage() || bFootnoteEndDoc != pPage->IsFootnotePage() )
+ return nullptr; // no further pages found
+ pNxtBoss = pPage;
+ pBody = pPage->FindBodyCont();
+ }
+ // We have the previous page, we might need to find the last column of it
+ if( pBody )
+ {
+ if ( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
+ {
+ pNxtBoss = static_cast<SwFootnoteBossFrame*>(pBody->GetLastLower());
+ }
+ }
+ }
+ SwFootnoteContFrame *pCont = pNxtBoss->FindFootnoteCont();
+ if ( pCont )
+ {
+ pRet = pCont;
+ break;
+ }
+ if ( pStop == pNxtBoss )
+ {
+ // Reached the column/page of the reference.
+ // Try to add a container and paste our content.
+ if ( eMakeFootnote == MAKEPAGE_FTN && pNxtBoss->GetMaxFootnoteHeight() )
+ pRet = pNxtBoss->MakeFootnoteCont();
+ break;
+ }
+ } while( !pRet );
+ }
+ if ( pRet )
+ {
+ const SwFootnoteBossFrame* pNewBoss = pRet->FindFootnoteBossFrame();
+ bool bJump = false;
+ if( pOldBoss->IsColumnFrame() && pOldBoss->GetPrev() ) // a previous column exists
+ bJump = pOldBoss->GetPrev() != static_cast<SwFrame const *>(pNewBoss); // did we chose it?
+ else if( pNewBoss->IsColumnFrame() && pNewBoss->GetNext() )
+ bJump = true; // there is another column after the boss (not the old boss)
+ else
+ {
+ // Will be reached only if old and new boss are both either pages or the last (new)
+ // or first (old) column of a page. In this case, check if pages were skipped.
+ const sal_uInt16 nDiff = pOldPage->GetPhyPageNum() - pRet->FindPageFrame()->GetPhyPageNum();
+ if ( nDiff > 2 ||
+ (nDiff > 1 && !static_cast<SwPageFrame*>(pOldPage->GetPrev())->IsEmptyPage()) )
+ bJump = true;
+ }
+ if( bJump )
+ SwFlowFrame::SetMoveBwdJump( true );
+ }
+ return pRet;
+}
+
+bool SwFrame::IsFootnoteAllowed() const
+{
+ if ( !IsInDocBody() )
+ return false;
+
+ if ( IsInTab() )
+ {
+ // no footnotes in repeated headlines
+ const SwTabFrame *pTab = const_cast<SwFrame*>(this)->ImplFindTabFrame();
+ assert(pTab);
+ if ( pTab->IsFollow() )
+ return !pTab->IsInHeadline( *this );
+ }
+ return true;
+}
+
+void SwRootFrame::UpdateFootnoteNums()
+{
+ // page numbering only if set at the document
+ if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum == FTNNUM_PAGE )
+ {
+ SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
+ while ( pPage && !pPage->IsFootnotePage() )
+ {
+ pPage->UpdateFootnoteNum();
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+ }
+ }
+}
+
+/// remove all footnotes (not the references) and all footnote pages
+void sw_RemoveFootnotes( SwFootnoteBossFrame* pBoss, bool bPageOnly, bool bEndNotes )
+{
+ do
+ {
+ SwFootnoteContFrame *pCont = pBoss->FindFootnoteCont();
+ if ( pCont )
+ {
+ SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
+ assert(pFootnote);
+ if ( bPageOnly )
+ while ( pFootnote->GetMaster() )
+ pFootnote = pFootnote->GetMaster();
+ do
+ {
+ SwFootnoteFrame *pNxt = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
+ if ( !pFootnote->GetAttr()->GetFootnote().IsEndNote() ||
+ bEndNotes )
+ {
+ pFootnote->GetRef()->Prepare( PrepareHint::FootnoteInvalidation, static_cast<void*>(pFootnote->GetAttr()) );
+ if ( bPageOnly && !pNxt )
+ pNxt = pFootnote->GetFollow();
+ pFootnote->Cut();
+ SwFrame::DestroyFrame(pFootnote);
+ }
+ pFootnote = pNxt;
+
+ } while ( pFootnote );
+ }
+ if( !pBoss->IsInSct() )
+ {
+ // A sectionframe with the Footnote/EndnAtEnd-flags may contain
+ // foot/endnotes. If the last lower frame of the bodyframe is
+ // a multicolumned sectionframe, it may contain footnotes, too.
+ SwLayoutFrame* pBody = pBoss->FindBodyCont();
+ if( pBody && pBody->Lower() )
+ {
+ SwFrame* pLow = pBody->Lower();
+ while (pLow)
+ {
+ if( pLow->IsSctFrame() && ( !pLow->GetNext() ||
+ static_cast<SwSectionFrame*>(pLow)->IsAnyNoteAtEnd() ) &&
+ static_cast<SwSectionFrame*>(pLow)->Lower() &&
+ static_cast<SwSectionFrame*>(pLow)->Lower()->IsColumnFrame() )
+ sw_RemoveFootnotes( static_cast<SwColumnFrame*>(static_cast<SwSectionFrame*>(pLow)->Lower()),
+ bPageOnly, bEndNotes );
+ pLow = pLow->GetNext();
+ }
+ }
+ }
+ // is there another column?
+ pBoss = pBoss->IsColumnFrame() ? static_cast<SwColumnFrame*>(pBoss->GetNext()) : nullptr;
+ } while( pBoss );
+}
+
+void SwRootFrame::RemoveFootnotes( SwPageFrame *pPage, bool bPageOnly, bool bEndNotes )
+{
+ if ( !pPage )
+ pPage = static_cast<SwPageFrame*>(Lower());
+
+ do
+ { // On columned pages we have to clean up in all columns
+ SwFootnoteBossFrame* pBoss;
+ SwLayoutFrame* pBody = pPage->FindBodyCont();
+ if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
+ pBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower()); // the first column
+ else
+ pBoss = pPage; // no columns
+ sw_RemoveFootnotes( pBoss, bPageOnly, bEndNotes );
+ if ( !bPageOnly )
+ {
+ if ( pPage->IsFootnotePage() &&
+ (!pPage->IsEndNotePage() || bEndNotes) )
+ {
+ SwFrame *pDel = pPage;
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+ pDel->Cut();
+ SwFrame::DestroyFrame(pDel);
+ }
+ else
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+ }
+ else
+ break;
+
+ } while ( pPage );
+}
+
+/// Change the page template of the footnote pages
+void SwRootFrame::CheckFootnotePageDescs( bool bEndNote )
+{
+ SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
+ while ( pPage && !pPage->IsFootnotePage() )
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+ while ( pPage && pPage->IsEndNotePage() != bEndNote )
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+
+ if ( pPage )
+ SwFrame::CheckPageDescs( pPage, false );
+}
+
+/** Insert a footnote container
+ *
+ * A footnote container is always placed directly behind the body text.
+ *
+ * The frame format (FrameFormat) is always the default frame format.
+ *
+ * @return footnote container frame
+ */
+SwFootnoteContFrame *SwFootnoteBossFrame::MakeFootnoteCont()
+{
+ SAL_WARN_IF(FindFootnoteCont(), "sw.core", "footnote container exists already");
+
+ SwFootnoteContFrame *pNew = new SwFootnoteContFrame( GetFormat()->GetDoc()->GetDfltFrameFormat(), this );
+ SwLayoutFrame *pLay = FindBodyCont();
+ pNew->Paste( this, pLay->GetNext() );
+ return pNew;
+}
+
+SwFootnoteContFrame *SwFootnoteBossFrame::FindFootnoteCont()
+{
+ SwFrame *pFrame = Lower();
+ while( pFrame && !pFrame->IsFootnoteContFrame() )
+ pFrame = pFrame->GetNext();
+
+#if OSL_DEBUG_LEVEL > 0
+ if ( pFrame )
+ {
+ SwFrame *pFootnote = pFrame->GetLower();
+ assert(pFootnote);
+ while ( pFootnote )
+ {
+ assert(pFootnote->IsFootnoteFrame() && "Neighbor of footnote must be a footnote");
+ pFootnote = pFootnote->GetNext();
+ }
+ }
+#endif
+
+ return static_cast<SwFootnoteContFrame*>(pFrame);
+}
+
+/// Search the next available footnote container.
+SwFootnoteContFrame *SwFootnoteBossFrame::FindNearestFootnoteCont( bool bDontLeave )
+{
+ SwFootnoteContFrame *pCont = nullptr;
+ if ( !GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
+ {
+ pCont = FindFootnoteCont();
+ if ( !pCont )
+ {
+ SwPageFrame *pPage = FindPageFrame();
+ SwFootnoteBossFrame* pBoss = this;
+ bool bEndNote = pPage->IsEndNotePage();
+ do
+ {
+ bool bChgPage = lcl_NextFootnoteBoss( pBoss, pPage, bDontLeave );
+ // Found another boss? When changing pages, also the endnote flag must match.
+ if( pBoss && ( !bChgPage || pPage->IsEndNotePage() == bEndNote ) )
+ pCont = pBoss->FindFootnoteCont();
+ } while ( !pCont && pPage );
+ }
+ }
+ return pCont;
+}
+
+SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote()
+{
+ // search for the nearest footnote container
+ SwFootnoteContFrame *pCont = FindNearestFootnoteCont();
+ if ( !pCont )
+ return nullptr;
+
+ // Starting from the first footnote, search the first
+ // footnote that is referenced by the current column/page
+
+ SwFootnoteFrame *pRet = static_cast<SwFootnoteFrame*>(pCont->Lower());
+ const sal_uInt16 nRefNum = FindPageFrame()->GetPhyPageNum();
+ const sal_uInt16 nRefCol = lcl_ColumnNum( this );
+ sal_uInt16 nPgNum, nColNum; // page number, column number
+ SwFootnoteBossFrame* pBoss;
+ SwPageFrame* pPage;
+ if( pRet )
+ {
+ pBoss = pRet->GetRef()->FindFootnoteBossFrame();
+ OSL_ENSURE( pBoss, "FindFirstFootnote: No boss found" );
+ if( !pBoss )
+ return nullptr; // ?There must be a bug, but no GPF
+ pPage = pBoss->FindPageFrame();
+ nPgNum = pPage->GetPhyPageNum();
+ if ( nPgNum == nRefNum )
+ {
+ nColNum = lcl_ColumnNum( pBoss );
+ if( nColNum == nRefCol )
+ return pRet; // found
+ else if( nColNum > nRefCol )
+ return nullptr; // at least one column too far
+ }
+ else if ( nPgNum > nRefNum )
+ return nullptr; // at least one column too far
+ }
+ else
+ return nullptr;
+ // Done if Ref is on a subsequent page or on the same page in a subsequent column
+
+ do
+ {
+ while ( pRet->GetFollow() )
+ pRet = pRet->GetFollow();
+
+ SwFootnoteFrame *pNxt = static_cast<SwFootnoteFrame*>(pRet->GetNext());
+ if ( !pNxt )
+ {
+ pBoss = pRet->FindFootnoteBossFrame();
+ pPage = pBoss->FindPageFrame();
+ lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss
+ pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr;
+ if ( pCont )
+ pNxt = static_cast<SwFootnoteFrame*>(pCont->Lower());
+ }
+ if ( pNxt )
+ {
+ pRet = pNxt;
+ pBoss = pRet->GetRef()->FindFootnoteBossFrame();
+ pPage = pBoss->FindPageFrame();
+ nPgNum = pPage->GetPhyPageNum();
+ if ( nPgNum == nRefNum )
+ {
+ nColNum = lcl_ColumnNum( pBoss );
+ if( nColNum == nRefCol )
+ break; // found
+ else if( nColNum > nRefCol )
+ pRet = nullptr; // at least one column too far
+ }
+ else if ( nPgNum > nRefNum )
+ pRet = nullptr; // at least a page too far
+ }
+ else
+ pRet = nullptr; // there is none
+ } while( pRet );
+ return pRet;
+}
+
+/// Get the first footnote of a given content
+const SwFootnoteFrame *SwFootnoteBossFrame::FindFirstFootnote( SwContentFrame const *pCnt ) const
+{
+ const SwFootnoteFrame *pRet = const_cast<SwFootnoteBossFrame*>(this)->FindFirstFootnote();
+ if ( pRet )
+ {
+ const sal_uInt16 nColNum = lcl_ColumnNum( this );
+ const sal_uInt16 nPageNum = GetPhyPageNum();
+ while ( pRet && (pRet->GetRef() != pCnt) )
+ {
+ while ( pRet->GetFollow() )
+ pRet = pRet->GetFollow();
+
+ if ( pRet->GetNext() )
+ pRet = static_cast<const SwFootnoteFrame*>(pRet->GetNext());
+ else
+ { SwFootnoteBossFrame *pBoss = const_cast<SwFootnoteBossFrame*>(pRet->FindFootnoteBossFrame());
+ SwPageFrame *pPage = pBoss->FindPageFrame();
+ lcl_NextFootnoteBoss( pBoss, pPage, false ); // next FootnoteBoss
+ SwFootnoteContFrame *pCont = pBoss ? pBoss->FindNearestFootnoteCont() : nullptr;
+ pRet = pCont ? static_cast<SwFootnoteFrame*>(pCont->Lower()) : nullptr;
+ }
+ if ( pRet )
+ {
+ const SwFootnoteBossFrame* pBoss = pRet->GetRef()->FindFootnoteBossFrame();
+ if( pBoss->GetPhyPageNum() != nPageNum ||
+ nColNum != lcl_ColumnNum( pBoss ) )
+ pRet = nullptr;
+ }
+ }
+ }
+ return pRet;
+}
+
+void SwFootnoteBossFrame::ResetFootnote( const SwFootnoteFrame *pCheck )
+{
+ // Destroy the incarnations of footnotes to an attribute, if they don't
+ // belong to pAssumed
+ OSL_ENSURE( !pCheck->GetMaster(), "given master is not a Master." );
+
+ SwNodeIndex aIdx( *pCheck->GetAttr()->GetStartNode(), 1 );
+ SwContentNode *pNd = aIdx.GetNode().GetContentNode();
+ if ( !pNd )
+ pNd = pCheck->GetFormat()->GetDoc()->
+ GetNodes().GoNextSection( &aIdx, true, false );
+ SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
+ SwFrame* pFrame = aIter.First();
+ while( pFrame )
+ {
+ if( pFrame->getRootFrame() == pCheck->getRootFrame() )
+ {
+ SwFrame *pTmp = pFrame->GetUpper();
+ while ( pTmp && !pTmp->IsFootnoteFrame() )
+ pTmp = pTmp->GetUpper();
+
+ SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pTmp);
+ while ( pFootnote && pFootnote->GetMaster() )
+ pFootnote = pFootnote->GetMaster();
+ if ( pFootnote != pCheck )
+ {
+ while (pFootnote && !pFootnote->IsDeleteForbidden())
+ {
+ SwFootnoteFrame *pNxt = pFootnote->GetFollow();
+ pFootnote->Cut();
+ SwFrame::DestroyFrame(pFootnote);
+ pFootnote = pNxt;
+ }
+ }
+ }
+
+ pFrame = aIter.Next();
+ }
+}
+
+void SwFootnoteBossFrame::InsertFootnote( SwFootnoteFrame* pNew )
+{
+ // Place the footnote in front of the footnote whose attribute
+ // is in front of the new one (get position via the Doc).
+ // If there is no footnote in this footnote-boss yet, create a new container.
+ // If there is a container but no footnote for this footnote-boss yet, place
+ // the footnote behind the last footnote of the closest previous column/page.
+
+ ResetFootnote( pNew );
+ SwFootnoteFrame *pSibling = FindFirstFootnote();
+ bool bDontLeave = false;
+
+ // Ok, a sibling has been found, but is the sibling in an acceptable
+ // environment?
+ if( IsInSct() )
+ {
+ SwSectionFrame* pMySect = ImplFindSctFrame();
+ bool bEndnt = pNew->GetAttr()->GetFootnote().IsEndNote();
+ if( bEndnt )
+ {
+ const SwSectionFormat* pEndFormat = pMySect->GetEndSectFormat();
+ bDontLeave = nullptr != pEndFormat;
+ if( pSibling )
+ {
+ if( pEndFormat )
+ {
+ if( !pSibling->IsInSct() ||
+ !pSibling->ImplFindSctFrame()->IsDescendantFrom( pEndFormat ) )
+ pSibling = nullptr;
+ }
+ else if( pSibling->IsInSct() )
+ pSibling = nullptr;
+ }
+ }
+ else
+ {
+ bDontLeave = pMySect->IsFootnoteAtEnd();
+ if( pSibling )
+ {
+ if( pMySect->IsFootnoteAtEnd() )
+ {
+ if( !pSibling->IsInSct() ||
+ !pMySect->IsAnFollow( pSibling->ImplFindSctFrame() ) )
+ pSibling = nullptr;
+ }
+ else if( pSibling->IsInSct() )
+ pSibling = nullptr;
+ }
+ }
+ }
+
+ if( pSibling && pSibling->FindPageFrame()->IsEndNotePage() !=
+ FindPageFrame()->IsEndNotePage() )
+ pSibling = nullptr;
+
+ // use the Doc to find out the position
+ SwDoc *pDoc = GetFormat()->GetDoc();
+ const sal_uLong nStPos = ::lcl_FindFootnotePos( pDoc, pNew->GetAttr() );
+
+ sal_uLong nCmpPos = 0;
+ sal_uLong nLastPos = 0;
+ SwFootnoteContFrame *pParent = nullptr;
+ if( pSibling )
+ {
+ nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
+ if( nCmpPos > nStPos )
+ pSibling = nullptr;
+ }
+
+ if ( !pSibling )
+ { pParent = FindFootnoteCont();
+ if ( !pParent )
+ {
+ // There is no footnote container yet. Before creating one, keep in mind that
+ // there might exist another following footnote that must be placed before the
+ // new inserted one e.g. because it was divided over multiple pages etc.
+ pParent = FindNearestFootnoteCont( bDontLeave );
+ if ( pParent )
+ {
+ SwFootnoteFrame *pFootnote = static_cast<SwFootnoteFrame*>(pParent->Lower());
+ if ( pFootnote )
+ {
+
+ nCmpPos = ::lcl_FindFootnotePos( pDoc, pFootnote->GetAttr() );
+ if ( nCmpPos > nStPos )
+ pParent = nullptr;
+ }
+ else
+ pParent = nullptr;
+ }
+ }
+ if ( !pParent )
+ // here, we are sure that we can create a footnote container
+ pParent = MakeFootnoteCont();
+ else
+ {
+ // Based on the first footnote below the Parent, search for the first footnote whose
+ // index is after the index of the newly inserted, to place the new one correctly
+ pSibling = static_cast<SwFootnoteFrame*>(pParent->Lower());
+ if ( !pSibling )
+ {
+ OSL_ENSURE( false, "Could not find space for footnote.");
+ return;
+ }
+ nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
+
+ SwFootnoteBossFrame *pNxtB; // remember the last one to not
+ SwFootnoteFrame *pLastSib = nullptr; // go too far.
+
+ while ( pSibling && nCmpPos <= nStPos )
+ {
+ pLastSib = pSibling; // potential candidate
+ nLastPos = nCmpPos;
+
+ while ( pSibling->GetFollow() )
+ pSibling = pSibling->GetFollow();
+
+ if ( pSibling->GetNext() )
+ {
+ pSibling = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
+ OSL_ENSURE( !pSibling->GetMaster() || ( ENDNOTE > nStPos &&
+ pSibling->GetAttr()->GetFootnote().IsEndNote() ),
+ "InsertFootnote: Master expected I" );
+ }
+ else
+ {
+ pNxtB = pSibling->FindFootnoteBossFrame();
+ SwPageFrame *pSibPage = pNxtB->FindPageFrame();
+ bool bEndNote = pSibPage->IsEndNotePage();
+ bool bChgPage = lcl_NextFootnoteBoss( pNxtB, pSibPage, bDontLeave );
+ // When changing pages, also the endnote flag must match.
+ SwFootnoteContFrame *pCont = pNxtB && ( !bChgPage ||
+ pSibPage->IsEndNotePage() == bEndNote )
+ ? pNxtB->FindNearestFootnoteCont( bDontLeave ) : nullptr;
+ if( pCont )
+ pSibling = static_cast<SwFootnoteFrame*>(pCont->Lower());
+ else // no further FootnoteContainer, insert after pSibling
+ break;
+ }
+ if ( pSibling )
+ {
+ nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
+ OSL_ENSURE( nCmpPos > nLastPos, "InsertFootnote: Order of FootnoteFrame's buggy" );
+ }
+ }
+ // pLastSib is the last footnote before the new one and
+ // pSibling is empty or the first one after the new one
+ if ( pSibling && pLastSib && (pSibling != pLastSib) )
+ {
+ // too far?
+ if ( nCmpPos > nStPos )
+ pSibling = pLastSib;
+ }
+ else if ( !pSibling )
+ {
+ // Last chance: Take the last footnote of the parent.
+ // Special case that happens e.g. when moving paragraphs with multiple footnotes.
+ // To keep the order, use the parent of the last inspected footnote.
+ pSibling = pLastSib;
+ while( pSibling->GetFollow() )
+ pSibling = pSibling->GetFollow();
+ OSL_ENSURE( !pSibling->GetNext(), "InsertFootnote: Who's that guy?" );
+ }
+ }
+ }
+ else
+ {
+ // First footnote of the column/page found. Now search from there for the first one on the
+ // same column/page whose index is after the given one. The last one found is the predecessor.
+ SwFootnoteBossFrame* pBoss = pNew->GetRef()->FindFootnoteBossFrame(
+ !pNew->GetAttr()->GetFootnote().IsEndNote() );
+ sal_uInt16 nRefNum = pBoss->GetPhyPageNum(); // page number of the new footnote
+ sal_uInt16 nRefCol = lcl_ColumnNum( pBoss ); // column number of the new footnote
+ bool bEnd = false;
+ SwFootnoteFrame *pLastSib = nullptr;
+ while ( pSibling && !bEnd && (nCmpPos <= nStPos) )
+ {
+ pLastSib = pSibling;
+ nLastPos = nCmpPos;
+
+ while ( pSibling->GetFollow() )
+ pSibling = pSibling->GetFollow();
+
+ SwFootnoteFrame *pFoll = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
+ if ( pFoll )
+ {
+ pBoss = pSibling->GetRef()->FindFootnoteBossFrame( !pSibling->
+ GetAttr()->GetFootnote().IsEndNote() );
+ sal_uInt16 nTmpRef;
+ if( nStPos >= ENDNOTE ||
+ (nTmpRef = pBoss->GetPhyPageNum()) < nRefNum ||
+ ( nTmpRef == nRefNum && lcl_ColumnNum( pBoss ) <= nRefCol ))
+ pSibling = pFoll;
+ else
+ bEnd = true;
+ }
+ else
+ {
+ SwFootnoteBossFrame* pNxtB = pSibling->FindFootnoteBossFrame();
+ SwPageFrame *pSibPage = pNxtB->FindPageFrame();
+ bool bEndNote = pSibPage->IsEndNotePage();
+ bool bChgPage = lcl_NextFootnoteBoss( pNxtB, pSibPage, bDontLeave );
+ // When changing pages, also the endnote flag must match.
+ SwFootnoteContFrame *pCont = pNxtB && ( !bChgPage ||
+ pSibPage->IsEndNotePage() == bEndNote )
+ ? pNxtB->FindNearestFootnoteCont( bDontLeave ) : nullptr;
+ if ( pCont )
+ pSibling = static_cast<SwFootnoteFrame*>(pCont->Lower());
+ else
+ bEnd = true;
+ }
+ if ( !bEnd && pSibling )
+ nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
+ if (pSibling && (pSibling != pLastSib))
+ {
+ // too far?
+ if ( (nLastPos < nCmpPos) && (nCmpPos > nStPos) )
+ {
+ pSibling = pLastSib;
+ bEnd = true;
+ }
+ }
+ }
+ }
+ if ( pSibling )
+ {
+ nCmpPos = ::lcl_FindFootnotePos( pDoc, pSibling->GetAttr() );
+ if ( nCmpPos < nStPos )
+ {
+ while ( pSibling->GetFollow() )
+ pSibling = pSibling->GetFollow();
+ pParent = static_cast<SwFootnoteContFrame*>(pSibling->GetUpper());
+ pSibling = static_cast<SwFootnoteFrame*>(pSibling->GetNext());
+ }
+ else
+ {
+ if( pSibling->GetMaster() )
+ {
+ if( ENDNOTE > nCmpPos || nStPos >= ENDNOTE )
+ {
+ OSL_FAIL( "InsertFootnote: Master expected II" );
+ do
+ pSibling = pSibling->GetMaster();
+ while ( pSibling->GetMaster() );
+ }
+ }
+ pParent = static_cast<SwFootnoteContFrame*>(pSibling->GetUpper());
+ }
+ }
+ OSL_ENSURE( pParent, "paste in space?" );
+ pNew->Paste( pParent, pSibling );
+}
+
+static SwPageFrame* lcl_GetApproximateFootnotePage(const bool bEnd, const SwPageFrame* pPage,
+ const SwDoc *pDoc, const SwTextFootnote *pAttr)
+{
+ // We can at least search the approximately correct page
+ // to ensure that we will finish in finite time even if
+ // hundreds of footnotes exist.
+ const SwPageFrame *pNxt = static_cast<const SwPageFrame*>(pPage->GetNext());
+ const sal_uLong nStPos = ::lcl_FindFootnotePos(pDoc, pAttr);
+ while (pNxt && (bEnd ? pNxt->IsEndNotePage() : pNxt->IsFootnotePage() && !pNxt->IsEndNotePage()))
+ {
+ const SwFootnoteContFrame *pCont = pNxt->FindFootnoteCont();
+ if (pCont && pCont->Lower())
+ {
+ OSL_ENSURE( pCont->Lower()->IsFootnoteFrame(), "no footnote in the container" );
+ if (nStPos > ::lcl_FindFootnotePos(pDoc,
+ static_cast<const SwFootnoteFrame*>(pCont->Lower())->GetAttr()))
+ {
+ pPage = pNxt;
+ pNxt = static_cast<const SwPageFrame*>(pPage->GetNext());
+ continue;
+ }
+ }
+ break;
+ }
+ return const_cast<SwPageFrame*>(pPage);
+}
+
+void SwFootnoteBossFrame::AppendFootnote( SwContentFrame *pRef, SwTextFootnote *pAttr )
+{
+ // If the footnote already exists, do nothing.
+ if ( FindFootnote( pRef, pAttr ) )
+ return;
+
+ // If footnotes are inserted at the end of the document,
+ // we only need to search from the relevant page on.
+ // If there is none yet, we need to create one.
+ // If it is an Endnote, we need to search for or create an
+ // Endnote page.
+ SwDoc *pDoc = GetFormat()->GetDoc();
+ SwFootnoteBossFrame *pBoss = this;
+ SwPageFrame *pPage = FindPageFrame();
+ SwPageFrame *pMyPage = pPage;
+ bool bChgPage = false;
+ const bool bEnd = pAttr->GetFootnote().IsEndNote();
+ if (bEnd)
+ {
+ const IDocumentSettingAccess& rSettings = *pAttr->GetTextNode().getIDocumentSettingAccess();
+ if( GetUpper()->IsSctFrame() &&
+ static_cast<SwSectionFrame*>(GetUpper())->IsEndnAtEnd() )
+ {
+ // Endnotes at the end of the section.
+ SwFrame* pLast =
+ static_cast<SwSectionFrame*>(GetUpper())->FindLastContent( SwFindMode::EndNote );
+ if( pLast )
+ {
+ pBoss = pLast->FindFootnoteBossFrame();
+ pPage = pBoss->FindPageFrame();
+ }
+ }
+ else if (rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
+ {
+ // Endnotes at the end of the document.
+ pBoss = getRootFrame()->GetLastPage();
+ pPage = pBoss->FindPageFrame();
+ }
+ else
+ {
+ // Endnotes on a separate page.
+ while ( pPage->GetNext() && !pPage->IsEndNotePage() )
+ {
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+ bChgPage = true;
+ }
+ if ( !pPage->IsEndNotePage() )
+ {
+ SwPageDesc *pDesc = pDoc->GetEndNoteInfo().GetPageDesc( *pDoc );
+ pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
+ !pPage->OnRightPage(), false, false, true, nullptr );
+ pPage->SetEndNotePage( true );
+ bChgPage = true;
+ }
+ else
+ pPage = lcl_GetApproximateFootnotePage(true, pPage, pDoc, pAttr);
+ }
+ }
+ else if( FTNPOS_CHAPTER == pDoc->GetFootnoteInfo().m_ePos && ( !GetUpper()->
+ IsSctFrame() || !static_cast<SwSectionFrame*>(GetUpper())->IsFootnoteAtEnd() ) )
+ {
+ while ( pPage->GetNext() && !pPage->IsFootnotePage() &&
+ !static_cast<SwPageFrame*>(pPage->GetNext())->IsEndNotePage() )
+ {
+ pPage = static_cast<SwPageFrame*>(pPage->GetNext());
+ bChgPage = true;
+ }
+
+ if ( !pPage->IsFootnotePage() )
+ {
+ SwPageDesc *pDesc = pDoc->GetFootnoteInfo().GetPageDesc( *pDoc );
+ pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(),
+ !pPage->OnRightPage(), false, false, true, pPage->GetNext() );
+ bChgPage = true;
+ }
+ else
+ pPage = lcl_GetApproximateFootnotePage(false, pPage, pDoc, pAttr);
+ }
+
+ // For now, create a footnote and the corresponding content frames
+ if ( !pAttr->GetStartNode() )
+ {
+ OSL_ENSURE( false, "no footnote content." );
+ return;
+ }
+
+ // If there is already a footnote content on the column/page,
+ // another one cannot be created in a column area.
+ if( pBoss->IsInSct() && pBoss->IsColumnFrame() && !pPage->IsFootnotePage() )
+ {
+ SwSectionFrame* pSct = pBoss->FindSctFrame();
+ if( bEnd ? !pSct->IsEndnAtEnd() : !pSct->IsFootnoteAtEnd() )
+ {
+ SwFootnoteContFrame* pFootnoteCont = pSct->FindFootnoteBossFrame(!bEnd)->FindFootnoteCont();
+ if( pFootnoteCont )
+ {
+ SwFootnoteFrame* pTmp = static_cast<SwFootnoteFrame*>(pFootnoteCont->Lower());
+ if( bEnd )
+ while( pTmp && !pTmp->GetAttr()->GetFootnote().IsEndNote() )
+ pTmp = static_cast<SwFootnoteFrame*>(pTmp->GetNext());
+ if( pTmp && *pTmp < pAttr )
+ return;
+ }
+ }
+ }
+
+ SwFootnoteFrame *pNew = new SwFootnoteFrame( pDoc->GetDfltFrameFormat(), this, pRef, pAttr );
+ {
+ SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
+ ::InsertCnt_( pNew, pDoc, aIdx.GetIndex() );
+ }
+ // If the page was changed or newly created,
+ // we need to place ourselves in the first column
+ if( bChgPage )
+ {
+ SwLayoutFrame* pBody = pPage->FindBodyCont();
+ OSL_ENSURE( pBody, "AppendFootnote: NoPageBody?" );
+ if( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
+ pBoss = static_cast<SwFootnoteBossFrame*>(pBody->Lower());
+ else
+ pBoss = pPage; // page if no columns exist
+ }
+ pBoss->InsertFootnote( pNew );
+ if ( pNew->GetUpper() ) // inserted or not?
+ {
+ ::RegistFlys( pNew->FindPageFrame(), pNew );
+ SwSectionFrame* pSect = FindSctFrame();
+ // The content of a FootnoteContainer in a (column) section only need to be calculated
+ // if the section stretches already to the bottom edge of the Upper.
+ if( pSect && !pSect->IsJoinLocked() && ( bEnd ? !pSect->IsEndnAtEnd() :
+ !pSect->IsFootnoteAtEnd() ) && pSect->Growable() )
+ pSect->InvalidateSize();
+ else
+ {
+ // #i49383# - disable unlock of position of
+ // lower objects during format of footnote content.
+ const bool bOldFootnoteFrameLocked( pNew->IsColLocked() );
+ pNew->ColLock();
+ pNew->KeepLockPosOfLowerObjs();
+ // #i57914# - adjust fix #i49383#
+ SwContentFrame *pCnt = pNew->ContainsContent();
+ while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
+ {
+ pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ // #i49383# - format anchored objects
+ if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
+ {
+ if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
+ *(pCnt->FindPageFrame()) ) )
+ {
+ // restart format with first content
+ pCnt = pNew->ContainsContent();
+ continue;
+ }
+ }
+ pCnt = pCnt->FindNextCnt();
+ }
+ // #i49383#
+ if ( !bOldFootnoteFrameLocked )
+ {
+ pNew->ColUnlock();
+ }
+ // #i57914# - adjust fix #i49383#
+ // enable lock of lower object position before format of footnote frame.
+ pNew->UnlockPosOfLowerObjs();
+ pNew->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ // #i57914# - adjust fix #i49383#
+ if ( !bOldFootnoteFrameLocked && !pNew->GetLower() &&
+ !pNew->IsColLocked() && !pNew->IsBackMoveLocked() &&
+ !pNew->IsDeleteForbidden() )
+ {
+ pNew->Cut();
+ SwFrame::DestroyFrame(pNew);
+ }
+ }
+ pMyPage->UpdateFootnoteNum();
+ }
+ else
+ SwFrame::DestroyFrame(pNew);
+}
+
+SwFootnoteFrame *SwFootnoteBossFrame::FindFootnote( const SwContentFrame *pRef, const SwTextFootnote *pAttr )
+{
+ // the easiest and savest way goes via the attribute
+ OSL_ENSURE( pAttr->GetStartNode(), "FootnoteAtr without StartNode." );
+ SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
+ SwContentNode *pNd = aIdx.GetNode().GetContentNode();
+ if ( !pNd )
+ pNd = pRef->GetAttrSet()->GetDoc()->
+ GetNodes().GoNextSection( &aIdx, true, false );
+ if ( !pNd )
+ return nullptr;
+ SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
+ SwFrame* pFrame = aIter.First();
+ if( pFrame )
+ do
+ {
+ pFrame = pFrame->GetUpper();
+ // #i28500#, #i27243# Due to the endnode collector, there are
+ // SwFootnoteFrames, which are not in the layout. Therefore the
+ // bInfFootnote flags are not set correctly, and a cell of FindFootnoteFrame
+ // would return 0. Therefore we better call ImplFindFootnoteFrame().
+ SwFootnoteFrame *pFootnote = pFrame->ImplFindFootnoteFrame();
+ if ( pFootnote && pFootnote->GetRef() == pRef )
+ {
+ // The following condition becomes true, if the whole
+ // footnotecontent is a section. While no frames exist,
+ // the HiddenFlag of the section is set, this causes
+ // the GoNextSection-function leaves the footnote.
+ if( pFootnote->GetAttr() != pAttr )
+ return nullptr;
+ while ( pFootnote && pFootnote->GetMaster() )
+ pFootnote = pFootnote->GetMaster();
+ return pFootnote;
+ }
+
+ } while ( nullptr != (pFrame = aIter.Next()) );
+
+ return nullptr;
+}
+
+bool SwFootnoteBossFrame::RemoveFootnote(
+ const SwContentFrame *const pRef, const SwTextFootnote *const pAttr,
+ bool bPrep )
+{
+ bool ret(false);
+ SwFootnoteFrame *pFootnote = FindFootnote( pRef, pAttr );
+ if( pFootnote )
+ {
+ ret = true;
+ do
+ {
+ SwFootnoteFrame *pFoll = pFootnote->GetFollow();
+ pFootnote->Cut();
+ SwFrame::DestroyFrame(pFootnote);
+ pFootnote = pFoll;
+ } while ( pFootnote );
+ if( bPrep && pRef->IsFollow() )
+ {
+ OSL_ENSURE( pRef->IsTextFrame(), "NoTextFrame has Footnote?" );
+ SwTextFrame* pMaster = pRef->FindMaster();
+ if( !pMaster->IsLocked() )
+ pMaster->Prepare( PrepareHint::FootnoteInvalidationGone );
+ }
+ }
+ FindPageFrame()->UpdateFootnoteNum();
+ return ret;
+}
+
+void SwFootnoteBossFrame::ChangeFootnoteRef( const SwContentFrame *pOld, const SwTextFootnote *pAttr,
+ SwContentFrame *pNew )
+{
+ SwFootnoteFrame *pFootnote = FindFootnote( pOld, pAttr );
+ while ( pFootnote )
+ {
+ pFootnote->SetRef( pNew );
+ pFootnote = pFootnote->GetFollow();
+ }
+}
+
+/// OD 03.04.2003 #108446# - add parameter <_bCollectOnlyPreviousFootnotes> in
+/// order to control, if only footnotes, which are positioned before the
+/// footnote boss frame <this> have to be collected.
+void SwFootnoteBossFrame::CollectFootnotes( const SwContentFrame* _pRef,
+ SwFootnoteBossFrame* _pOld,
+ SwFootnoteFrames& _rFootnoteArr,
+ const bool _bCollectOnlyPreviousFootnotes )
+{
+ SwFootnoteFrame *pFootnote = _pOld->FindFirstFootnote();
+ while( !pFootnote )
+ {
+ if( _pOld->IsColumnFrame() )
+ {
+ // visit columns
+ while ( !pFootnote && _pOld->GetPrev() )
+ {
+ // Still no problem if no footnote was found yet. The loop is needed to pick up
+ // following rows in tables. In all other cases it might correct bad contexts.
+ _pOld = static_cast<SwFootnoteBossFrame*>(_pOld->GetPrev());
+ pFootnote = _pOld->FindFirstFootnote();
+ }
+ }
+ if( !pFootnote )
+ {
+ // previous page
+ SwPageFrame* pPg;
+ for ( SwFrame* pTmp = _pOld;
+ nullptr != ( pPg = static_cast<SwPageFrame*>(pTmp->FindPageFrame()->GetPrev()))
+ && pPg->IsEmptyPage() ;
+ )
+ {
+ pTmp = pPg;
+ }
+ if( !pPg )
+ return;
+
+ SwLayoutFrame* pBody = pPg->FindBodyCont();
+ if( pBody->Lower() && pBody->Lower()->IsColumnFrame() )
+ {
+ // multiple columns on one page => search last column
+ _pOld = static_cast<SwFootnoteBossFrame*>(pBody->GetLastLower());
+ }
+ else
+ _pOld = pPg; // single column page
+ pFootnote = _pOld->FindFirstFootnote();
+ }
+ }
+
+ CollectFootnotes_(_pRef, pFootnote, _rFootnoteArr, _bCollectOnlyPreviousFootnotes ? this : nullptr);
+}
+
+static void FootnoteInArr( SwFootnoteFrames& rFootnoteArr, SwFootnoteFrame* pFootnote )
+{
+ if ( rFootnoteArr.end() == std::find( rFootnoteArr.begin(), rFootnoteArr.end(), pFootnote ) )
+ rFootnoteArr.push_back( pFootnote );
+}
+
+void SwFootnoteBossFrame::CollectFootnotes_( const SwContentFrame* _pRef,
+ SwFootnoteFrame* _pFootnote,
+ SwFootnoteFrames& _rFootnoteArr,
+ const SwFootnoteBossFrame* _pRefFootnoteBossFrame)
+{
+ // Collect all footnotes referenced by pRef (attribute by attribute), combine them
+ // (the content might be divided over multiple pages) and cut them.
+
+ // For robustness, we do not log the corresponding footnotes here. If a footnote
+ // is touched twice, there might be a crash. This allows this function here to
+ // also handle corrupt layouts in some degrees (without loops or even crashes).
+ SwFootnoteFrames aNotFootnoteArr;
+
+ // here we have a footnote placed in front of the first one of the reference
+ OSL_ENSURE( !_pFootnote->GetMaster() || _pFootnote->GetRef() != _pRef, "move FollowFootnote?" );
+ while ( _pFootnote->GetMaster() )
+ _pFootnote = _pFootnote->GetMaster();
+
+ bool bFound = false;
+
+ do
+ {
+ // Search for the next footnote in this column/page so that
+ // we do not start from zero again after cutting one footnote.
+ SwFootnoteFrame *pNxtFootnote = _pFootnote;
+ while ( pNxtFootnote->GetFollow() )
+ pNxtFootnote = pNxtFootnote->GetFollow();
+ pNxtFootnote = static_cast<SwFootnoteFrame*>(pNxtFootnote->GetNext());
+
+ if ( !pNxtFootnote )
+ {
+ SwFootnoteBossFrame* pBoss = _pFootnote->FindFootnoteBossFrame();
+ SwPageFrame* pPage = pBoss->FindPageFrame();
+ do
+ {
+ lcl_NextFootnoteBoss( pBoss, pPage, false );
+ if( pBoss )
+ {
+ SwLayoutFrame* pCont = pBoss->FindFootnoteCont();
+ if( pCont )
+ {
+ pNxtFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
+ if( pNxtFootnote )
+ {
+ while( pNxtFootnote->GetMaster() )
+ pNxtFootnote = pNxtFootnote->GetMaster();
+ if( pNxtFootnote == _pFootnote )
+ pNxtFootnote = nullptr;
+ }
+ }
+ }
+ } while( !pNxtFootnote && pBoss );
+ }
+ else if( !pNxtFootnote->GetAttr()->GetFootnote().IsEndNote() )
+ {
+ OSL_ENSURE( !pNxtFootnote->GetMaster(), "_CollectFootnote: Master expected" );
+ while ( pNxtFootnote->GetMaster() )
+ pNxtFootnote = pNxtFootnote->GetMaster();
+ }
+ if ( pNxtFootnote == _pFootnote )
+ {
+ OSL_FAIL( "_CollectFootnote: Vicious circle" );
+ pNxtFootnote = nullptr;
+ }
+
+ // OD 03.04.2003 #108446# - determine, if found footnote has to be collected.
+ bool bCollectFoundFootnote = false;
+ // Ignore endnotes which are on a separate endnote page.
+ bool bEndNote = _pFootnote->GetAttr()->GetFootnote().IsEndNote();
+ const IDocumentSettingAccess& rSettings
+ = _pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
+ bool bContinuousEndnotes = rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
+ if (_pFootnote->GetRef() == _pRef && (!bEndNote || bContinuousEndnotes))
+ {
+ if (_pRefFootnoteBossFrame)
+ {
+ SwFootnoteBossFrame* pBossOfFoundFootnote = _pFootnote->FindFootnoteBossFrame( true );
+ OSL_ENSURE( pBossOfFoundFootnote,
+ "<SwFootnoteBossFrame::CollectFootnotes_(..)> - footnote boss frame of found footnote frame missing.\nWrong layout!" );
+ if ( !pBossOfFoundFootnote || // don't crash, if no footnote boss is found.
+ pBossOfFoundFootnote->IsBefore( _pRefFootnoteBossFrame )
+ )
+ {
+ bCollectFoundFootnote = true;
+ }
+ }
+ else
+ {
+ bCollectFoundFootnote = true;
+ }
+ }
+
+ if ( bCollectFoundFootnote )
+ {
+ OSL_ENSURE( !_pFootnote->GetMaster(), "move FollowFootnote?" );
+ SwFootnoteFrame *pNxt = _pFootnote->GetFollow();
+ while ( pNxt )
+ {
+ SwFrame *pCnt = pNxt->ContainsAny();
+ if ( pCnt )
+ {
+ // destroy the follow on the way as it is empty
+ do
+ { SwFrame *pNxtCnt = pCnt->GetNext();
+ pCnt->Cut();
+ pCnt->Paste( _pFootnote );
+ pCnt = pNxtCnt;
+ } while ( pCnt );
+ }
+ else
+ {
+ OSL_ENSURE( !pNxt, "footnote without content?" );
+ pNxt->Cut();
+ SwFrame::DestroyFrame(pNxt);
+ }
+ pNxt = _pFootnote->GetFollow();
+ }
+ _pFootnote->Cut();
+ FootnoteInArr( _rFootnoteArr, _pFootnote );
+ bFound = true;
+ }
+ else
+ {
+ FootnoteInArr( aNotFootnoteArr, _pFootnote );
+ if( bFound )
+ break;
+ }
+ if ( pNxtFootnote &&
+ _rFootnoteArr.end() == std::find( _rFootnoteArr.begin(), _rFootnoteArr.end(), pNxtFootnote ) &&
+ aNotFootnoteArr.end() == std::find( aNotFootnoteArr.begin(), aNotFootnoteArr.end(), pNxtFootnote ) )
+ _pFootnote = pNxtFootnote;
+ else
+ break;
+ }
+ while ( _pFootnote );
+}
+
+void SwFootnoteBossFrame::MoveFootnotes_( SwFootnoteFrames &rFootnoteArr, bool bCalc )
+{
+ // All footnotes referenced by pRef need to be moved
+ // to a new position (based on the new column/page)
+ const sal_uInt16 nMyNum = FindPageFrame()->GetPhyPageNum();
+ const sal_uInt16 nMyCol = lcl_ColumnNum( this );
+ SwRectFnSet aRectFnSet(this);
+
+ // #i21478# - keep last inserted footnote in order to
+ // format the content of the following one.
+ SwFootnoteFrame* pLastInsertedFootnote = nullptr;
+ for (SwFootnoteFrame* pFootnote : rFootnoteArr)
+ {
+ SwFootnoteBossFrame* pRefBoss(pFootnote->GetRef()->FindFootnoteBossFrame(
+ !pFootnote->GetAttr()->GetFootnote().IsEndNote()));
+ if( pRefBoss != this )
+ {
+ const sal_uInt16 nRefNum = pRefBoss->FindPageFrame()->GetPhyPageNum();
+ const sal_uInt16 nRefCol = lcl_ColumnNum( this );
+ if( nRefNum < nMyNum || ( nRefNum == nMyNum && nRefCol <= nMyCol ) )
+ pRefBoss = this;
+ }
+ pRefBoss->InsertFootnote( pFootnote );
+
+ if ( pFootnote->GetUpper() ) // robust, e.g. with duplicates
+ {
+ // First condense the content so that footnote frames that do not fit on the page
+ // do not do too much harm (Loop 66312). So, the footnote content first grows as
+ // soon as the content gets formatted and it is sure that it fits on the page.
+ SwFrame *pCnt = pFootnote->ContainsAny();
+ while( pCnt )
+ {
+ if( pCnt->IsLayoutFrame() )
+ {
+ SwFrame* pTmp = static_cast<SwLayoutFrame*>(pCnt)->ContainsAny();
+ while( pTmp && static_cast<SwLayoutFrame*>(pCnt)->IsAnLower( pTmp ) )
+ {
+ pTmp->Prepare( PrepareHint::FootnoteMove );
+
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pTmp);
+ aRectFnSet.SetHeight(aFrm, 0);
+
+ SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pTmp);
+ aRectFnSet.SetHeight(aPrt, 0);
+
+ pTmp = pTmp->FindNext();
+ }
+ }
+ else
+ {
+ pCnt->Prepare( PrepareHint::FootnoteMove );
+ }
+
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pCnt);
+ aRectFnSet.SetHeight(aFrm, 0);
+
+ SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pCnt);
+ aRectFnSet.SetHeight(aPrt, 0);
+
+ pCnt = pCnt->GetNext();
+ }
+
+ {
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFootnote);
+ aRectFnSet.SetHeight(aFrm, 0);
+ }
+
+ {
+ SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pFootnote);
+ aRectFnSet.SetHeight(aPrt, 0);
+ }
+
+ pFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ pFootnote->GetUpper()->Calc(getRootFrame()->GetCurrShell()->GetOut());
+
+ if( bCalc )
+ {
+ SwTextFootnote *pAttr = pFootnote->GetAttr();
+ pCnt = pFootnote->ContainsAny();
+ bool bUnlock = !pFootnote->IsBackMoveLocked();
+ pFootnote->LockBackMove();
+
+ // #i49383# - disable unlock of position of
+ // lower objects during format of footnote content.
+ pFootnote->KeepLockPosOfLowerObjs();
+ // #i57914# - adjust fix #i49383#
+
+ while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
+ {
+ pCnt->InvalidatePos_();
+ pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ // #i49383# - format anchored objects
+ if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
+ {
+ if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
+ *(pCnt->FindPageFrame()) ) )
+ {
+ // restart format with first content
+ pCnt = pFootnote->ContainsAny();
+ continue;
+ }
+ }
+ if( pCnt->IsSctFrame() )
+ {
+ // If the area is not empty, iterate also over the content
+ SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
+ if( pTmp )
+ pCnt = pTmp;
+ else
+ pCnt = pCnt->FindNext();
+ }
+ else
+ pCnt = pCnt->FindNext();
+ }
+ if( bUnlock )
+ {
+ pFootnote->UnlockBackMove();
+ if( !pFootnote->ContainsAny() && !pFootnote->IsColLocked() )
+ {
+ pFootnote->Cut();
+ SwFrame::DestroyFrame(pFootnote);
+ // #i21478#
+ pFootnote = nullptr;
+ }
+ }
+ // #i49383#
+ if ( pFootnote )
+ {
+ // #i57914# - adjust fix #i49383#
+ // enable lock of lower object position before format of footnote frame.
+ pFootnote->UnlockPosOfLowerObjs();
+ pFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ }
+ }
+ }
+ else
+ {
+ OSL_ENSURE( !pFootnote->GetMaster() && !pFootnote->GetFollow(),
+ "DelFootnote and Master/Follow?" );
+ SwFrame::DestroyFrame(pFootnote);
+ // #i21478#
+ pFootnote = nullptr;
+ }
+
+ // #i21478#
+ if ( pFootnote )
+ {
+ pLastInsertedFootnote = pFootnote;
+ }
+ }
+
+ // #i21478# - format content of footnote following
+ // the new inserted ones.
+ if ( !(bCalc && pLastInsertedFootnote) )
+ return;
+
+ if ( !pLastInsertedFootnote->GetNext() )
+ return;
+
+ SwFootnoteFrame* pNextFootnote = static_cast<SwFootnoteFrame*>(pLastInsertedFootnote->GetNext());
+ SwTextFootnote* pAttr = pNextFootnote->GetAttr();
+ SwFrame* pCnt = pNextFootnote->ContainsAny();
+
+ bool bUnlock = !pNextFootnote->IsBackMoveLocked();
+ pNextFootnote->LockBackMove();
+ // #i49383# - disable unlock of position of
+ // lower objects during format of footnote content.
+ pNextFootnote->KeepLockPosOfLowerObjs();
+ // #i57914# - adjust fix #i49383#
+
+ while ( pCnt && pCnt->FindFootnoteFrame()->GetAttr() == pAttr )
+ {
+ pCnt->InvalidatePos_();
+ pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ // #i49383# - format anchored objects
+ if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
+ {
+ if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
+ *(pCnt->FindPageFrame()) ) )
+ {
+ // restart format with first content
+ pCnt = pNextFootnote->ContainsAny();
+ continue;
+ }
+ }
+ if( pCnt->IsSctFrame() )
+ {
+ // If the area is not empty, iterate also over the content
+ SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
+ if( pTmp )
+ pCnt = pTmp;
+ else
+ pCnt = pCnt->FindNext();
+ }
+ else
+ pCnt = pCnt->FindNext();
+ }
+ if( bUnlock )
+ {
+ pNextFootnote->UnlockBackMove();
+ }
+ // #i49383#
+ // #i57914# - adjust fix #i49383#
+ // enable lock of lower object position before format of footnote frame.
+ pNextFootnote->UnlockPosOfLowerObjs();
+ pNextFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
+}
+
+void SwFootnoteBossFrame::MoveFootnotes( const SwContentFrame *pSrc, SwContentFrame *pDest,
+ SwTextFootnote const *pAttr )
+{
+ if( ( GetFormat()->GetDoc()->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER &&
+ (!GetUpper()->IsSctFrame() || !static_cast<SwSectionFrame*>(GetUpper())->IsFootnoteAtEnd()))
+ || pAttr->GetFootnote().IsEndNote() )
+ return;
+
+ OSL_ENSURE( this == pSrc->FindFootnoteBossFrame( true ),
+ "SwPageFrame::MoveFootnotes: source frame isn't on that FootnoteBoss" );
+
+ SwFootnoteFrame *pFootnote = FindFirstFootnote();
+ if( !pFootnote )
+ return;
+
+ ChangeFootnoteRef( pSrc, pAttr, pDest );
+ SwFootnoteBossFrame *pDestBoss = pDest->FindFootnoteBossFrame( true );
+ OSL_ENSURE( pDestBoss, "+SwPageFrame::MoveFootnotes: no destination boss" );
+ if( !pDestBoss ) // robust
+ return;
+
+ SwFootnoteFrames aFootnoteArr;
+ SwFootnoteBossFrame::CollectFootnotes_(pDest, pFootnote, aFootnoteArr, nullptr);
+ if ( aFootnoteArr.empty() )
+ return;
+
+ pDestBoss->MoveFootnotes_( aFootnoteArr, true );
+ SwPageFrame* pSrcPage = FindPageFrame();
+ SwPageFrame* pDestPage = pDestBoss->FindPageFrame();
+ // update FootnoteNum only at page change
+ if( pSrcPage != pDestPage )
+ {
+ if( pSrcPage->GetPhyPageNum() > pDestPage->GetPhyPageNum() )
+ pSrcPage->UpdateFootnoteNum();
+ pDestPage->UpdateFootnoteNum();
+ }
+}
+
+void SwFootnoteBossFrame::RearrangeFootnotes( const SwTwips nDeadLine, const bool bLock,
+ const SwTextFootnote *pAttr )
+{
+ // Format all footnotes of a column/page so that they might change the column/page.
+
+ SwSaveFootnoteHeight aSave( this, nDeadLine );
+ SwFootnoteFrame *pFootnote = FindFirstFootnote();
+ if( pFootnote && pFootnote->GetPrev() && bLock )
+ {
+ SwFootnoteFrame* pFirst = static_cast<SwFootnoteFrame*>(pFootnote->GetUpper()->Lower());
+ SwFrame* pContent = pFirst->ContainsAny();
+ if( pContent )
+ {
+ bool bUnlock = !pFirst->IsBackMoveLocked();
+ pFirst->LockBackMove();
+ pFirst->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ pContent->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ // #i49383# - format anchored objects
+ if ( pContent->IsTextFrame() && pContent->isFrameAreaDefinitionValid() )
+ {
+ SwObjectFormatter::FormatObjsAtFrame( *pContent,
+ *(pContent->FindPageFrame()) );
+ }
+ if( bUnlock )
+ pFirst->UnlockBackMove();
+ }
+ pFootnote = FindFirstFootnote();
+ }
+ SwDoc *pDoc = GetFormat()->GetDoc();
+ const sal_uLong nFootnotePos = pAttr ? ::lcl_FindFootnotePos( pDoc, pAttr ) : 0;
+ SwFrame *pCnt = pFootnote ? pFootnote->ContainsAny() : nullptr;
+ if ( !pCnt )
+ return;
+
+ bool bMore = true;
+ bool bStart = pAttr == nullptr; // If no attribute is given, process all
+ // #i49383# - disable unlock of position of
+ // lower objects during format of footnote and footnote content.
+ SwFootnoteFrame* pLastFootnoteFrame( nullptr );
+ // footnote frame needs to be locked, if <bLock> isn't set.
+ bool bUnlockLastFootnoteFrame( false );
+ do
+ {
+ if( !bStart )
+ bStart = ::lcl_FindFootnotePos( pDoc, pCnt->FindFootnoteFrame()->GetAttr() )
+ == nFootnotePos;
+ if( bStart )
+ {
+ pCnt->InvalidatePos_();
+ pCnt->InvalidateSize_();
+ pCnt->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
+ SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
+ // #i49383#
+ if ( pFootnoteFrame != pLastFootnoteFrame )
+ {
+ if ( pLastFootnoteFrame )
+ {
+ if ( !bLock && bUnlockLastFootnoteFrame )
+ {
+ pLastFootnoteFrame->ColUnlock();
+ }
+ // #i57914# - adjust fix #i49383#
+ // enable lock of lower object position before format of footnote frame.
+ pLastFootnoteFrame->UnlockPosOfLowerObjs();
+ pLastFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ if ( !bLock && bUnlockLastFootnoteFrame &&
+ !pLastFootnoteFrame->GetLower() &&
+ !pLastFootnoteFrame->IsColLocked() &&
+ !pLastFootnoteFrame->IsBackMoveLocked() &&
+ !pLastFootnoteFrame->IsDeleteForbidden() )
+ {
+ pLastFootnoteFrame->Cut();
+ SwFrame::DestroyFrame(pLastFootnoteFrame);
+ pLastFootnoteFrame = nullptr;
+ }
+ }
+ if ( !bLock )
+ {
+ bUnlockLastFootnoteFrame = !pFootnoteFrame->IsColLocked();
+ pFootnoteFrame->ColLock();
+ }
+ pFootnoteFrame->KeepLockPosOfLowerObjs();
+ pLastFootnoteFrame = pFootnoteFrame;
+ }
+ // OD 30.10.2002 #97265# - invalidate position of footnote
+ // frame, if it's below its footnote container, in order to
+ // assure its correct position, probably calculating its previous
+ // footnote frames.
+ {
+ SwRectFnSet aRectFnSet(this);
+ SwFrame* pFootnoteContFrame = pFootnoteFrame->GetUpper();
+ if ( aRectFnSet.TopDist(pFootnoteFrame->getFrameArea(), aRectFnSet.GetPrtBottom(*pFootnoteContFrame)) > 0 )
+ {
+ pFootnoteFrame->InvalidatePos_();
+ }
+ }
+ if ( bLock )
+ {
+ bool bUnlock = !pFootnoteFrame->IsBackMoveLocked();
+ pFootnoteFrame->LockBackMove();
+ pFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ // #i49383# - format anchored objects
+ if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
+ {
+ SwFrameDeleteGuard aDeleteGuard(pFootnote);
+ if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
+ *(pCnt->FindPageFrame()) ) )
+ {
+ // restart format with first content
+ pCnt = pFootnote ? pFootnote->ContainsAny() : nullptr;
+ if (!pCnt)
+ bMore = false;
+ continue;
+ }
+ }
+ if( bUnlock )
+ {
+ pFootnoteFrame->UnlockBackMove();
+ if( !pFootnoteFrame->Lower() &&
+ !pFootnoteFrame->IsColLocked() )
+ {
+ // #i49383#
+ OSL_ENSURE( pLastFootnoteFrame == pFootnoteFrame,
+ "<SwFootnoteBossFrame::RearrangeFootnotes(..)> - <pLastFootnoteFrame> != <pFootnoteFrame>" );
+ pLastFootnoteFrame = nullptr;
+ pFootnoteFrame->Cut();
+ SwFrame::DestroyFrame(pFootnoteFrame);
+ if (pFootnote == pFootnoteFrame)
+ pFootnote = nullptr;
+ }
+ }
+ }
+ else
+ {
+ pFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ pCnt->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ // #i49383# - format anchored objects
+ if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
+ {
+ if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
+ *(pCnt->FindPageFrame()) ) )
+ {
+ // restart format with first content
+ pCnt = pFootnote->ContainsAny();
+ continue;
+ }
+ }
+ }
+ }
+ SwSectionFrame *pDel = nullptr;
+ if( pCnt->IsSctFrame() )
+ {
+ SwFrame* pTmp = static_cast<SwSectionFrame*>(pCnt)->ContainsAny();
+ if( pTmp )
+ {
+ pCnt = pTmp;
+ continue;
+ }
+ pDel = static_cast<SwSectionFrame*>(pCnt);
+ }
+ if ( pCnt->GetNext() )
+ pCnt = pCnt->GetNext();
+ else
+ {
+ pCnt = pCnt->FindNext();
+ if ( pCnt )
+ {
+ SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
+ if( pFootnoteFrame->GetRef()->FindFootnoteBossFrame(
+ pFootnoteFrame->GetAttr()->GetFootnote().IsEndNote() ) != this )
+ bMore = false;
+ }
+ else
+ bMore = false;
+ }
+ if( pDel )
+ {
+ bool bUnlockLastFootnoteFrameGuard = pLastFootnoteFrame && !pLastFootnoteFrame->IsColLocked();
+ if (bUnlockLastFootnoteFrameGuard)
+ pLastFootnoteFrame->ColLock();
+ pDel->Cut();
+ if (bUnlockLastFootnoteFrameGuard)
+ pLastFootnoteFrame->ColUnlock();
+ SwFrame::DestroyFrame(pDel);
+ }
+ if ( bMore )
+ {
+ // Go not further than to the provided footnote (if given)
+ if ( pAttr &&
+ (::lcl_FindFootnotePos( pDoc,
+ pCnt->FindFootnoteFrame()->GetAttr()) > nFootnotePos ) )
+ bMore = false;
+ }
+ } while ( bMore );
+ // #i49383#
+ if ( !pLastFootnoteFrame )
+ return;
+
+ if ( !bLock && bUnlockLastFootnoteFrame )
+ {
+ pLastFootnoteFrame->ColUnlock();
+ }
+ // #i57914# - adjust fix #i49383#
+ // enable lock of lower object position before format of footnote frame.
+ pLastFootnoteFrame->UnlockPosOfLowerObjs();
+ pLastFootnoteFrame->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ if ( !bLock && bUnlockLastFootnoteFrame &&
+ !pLastFootnoteFrame->GetLower() &&
+ !pLastFootnoteFrame->IsColLocked() &&
+ !pLastFootnoteFrame->IsBackMoveLocked() &&
+ !pLastFootnoteFrame->IsDeleteForbidden() )
+ {
+ pLastFootnoteFrame->Cut();
+ SwFrame::DestroyFrame(pLastFootnoteFrame);
+ }
+}
+
+void SwPageFrame::UpdateFootnoteNum()
+{
+ // page numbering only if set at the document
+ if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum != FTNNUM_PAGE )
+ return;
+
+ SwLayoutFrame* pBody = FindBodyCont();
+ if( !pBody || !pBody->Lower() )
+ return;
+
+ SwContentFrame* pContent = pBody->ContainsContent();
+ sal_uInt16 nNum = 0;
+
+ while( pContent && pContent->FindPageFrame() == this )
+ {
+ if( static_cast<SwTextFrame*>(pContent)->HasFootnote() )
+ {
+ SwFootnoteBossFrame* pBoss = pContent->FindFootnoteBossFrame( true );
+ if( pBoss->GetUpper()->IsSctFrame() &&
+ static_cast<SwSectionFrame*>(pBoss->GetUpper())->IsOwnFootnoteNum() )
+ pContent = static_cast<SwSectionFrame*>(pBoss->GetUpper())->FindLastContent();
+ else
+ {
+ SwFootnoteFrame* pFootnote = const_cast<SwFootnoteFrame*>(pBoss->FindFirstFootnote( pContent ));
+ while( pFootnote )
+ {
+ SwTextFootnote* pTextFootnote = pFootnote->GetAttr();
+ if( !pTextFootnote->GetFootnote().IsEndNote() &&
+ pTextFootnote->GetFootnote().GetNumStr().isEmpty() &&
+ !pFootnote->GetMaster())
+ {
+ // sw_redlinehide: the layout can only keep one number
+ // up to date; depending on its setting, this is either
+ // the non-hidden or the hidden number; the other
+ // number will simply be preserved as-is (so in case
+ // there are 2 layouts, maybe both can be updated...)
+ ++nNum;
+ sal_uInt16 const nOldNum(pTextFootnote->GetFootnote().GetNumber());
+ sal_uInt16 const nOldNumRLHidden(pTextFootnote->GetFootnote().GetNumberRLHidden());
+ if (getRootFrame()->IsHideRedlines())
+ {
+ if (nNum != nOldNumRLHidden)
+ {
+ pTextFootnote->SetNumber(nOldNum, nNum, OUString());
+ }
+ }
+ else
+ {
+ if (nNum != nOldNum)
+ {
+ pTextFootnote->SetNumber(nNum, nOldNumRLHidden, OUString());
+ }
+ }
+ }
+ if ( pFootnote->GetNext() )
+ pFootnote = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
+ else
+ {
+ SwFootnoteBossFrame* pTmpBoss = pFootnote->FindFootnoteBossFrame( true );
+ if( pTmpBoss )
+ {
+ SwPageFrame* pPage = pTmpBoss->FindPageFrame();
+ pFootnote = nullptr;
+ lcl_NextFootnoteBoss( pTmpBoss, pPage, false );
+ SwFootnoteContFrame *pCont = pTmpBoss ? pTmpBoss->FindNearestFootnoteCont() : nullptr;
+ if ( pCont )
+ pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
+ }
+ }
+ if( pFootnote && pFootnote->GetRef() != pContent )
+ pFootnote = nullptr;
+ }
+ }
+ }
+ pContent = pContent->FindNextCnt();
+ }
+}
+
+void SwFootnoteBossFrame::SetFootnoteDeadLine( const SwTwips nDeadLine )
+{
+ SwFrame *pBody = FindBodyCont();
+ pBody->Calc(getRootFrame()->GetCurrShell()->GetOut());
+
+ SwFrame *pCont = FindFootnoteCont();
+ const SwTwips nMax = m_nMaxFootnoteHeight;// current should exceed MaxHeight
+ SwRectFnSet aRectFnSet(this);
+ if ( pCont )
+ {
+ pCont->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ m_nMaxFootnoteHeight = -aRectFnSet.BottomDist( pCont->getFrameArea(), nDeadLine );
+ }
+ else
+ m_nMaxFootnoteHeight = -aRectFnSet.BottomDist( pBody->getFrameArea(), nDeadLine );
+
+ const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
+ if( pSh && pSh->GetViewOptions()->getBrowseMode() )
+ m_nMaxFootnoteHeight += pBody->Grow( LONG_MAX, true );
+ if ( IsInSct() )
+ m_nMaxFootnoteHeight += FindSctFrame()->Grow( LONG_MAX, true );
+
+ if ( m_nMaxFootnoteHeight < 0 )
+ m_nMaxFootnoteHeight = 0;
+ if ( nMax != LONG_MAX && m_nMaxFootnoteHeight > nMax )
+ m_nMaxFootnoteHeight = nMax;
+}
+
+SwTwips SwFootnoteBossFrame::GetVarSpace() const
+{
+ // To not fall below 20% of the page height
+ // (in contrast to MSOffice where footnotes can fill a whole column/page)
+
+ const SwPageFrame* pPg = FindPageFrame();
+ OSL_ENSURE( pPg || IsInSct(), "Footnote lost page" );
+
+ const SwFrame *pBody = FindBodyCont();
+ SwTwips nRet;
+ if( pBody )
+ {
+ SwRectFnSet aRectFnSet(this);
+ if( IsInSct() )
+ {
+ nRet = 0;
+ SwTwips nTmp = aRectFnSet.YDiff( aRectFnSet.GetPrtTop(*pBody),
+ aRectFnSet.GetTop(getFrameArea()) );
+ const SwSectionFrame* pSect = FindSctFrame();
+ // Endnotes in a ftncontainer causes a deadline:
+ // the bottom of the last contentfrm
+ if( pSect->IsEndnAtEnd() ) // endnotes allowed?
+ {
+ OSL_ENSURE( !Lower() || !Lower()->GetNext() || Lower()->GetNext()->
+ IsFootnoteContFrame(), "FootnoteContainer expected" );
+ const SwFootnoteContFrame* pCont = Lower() ?
+ static_cast<const SwFootnoteContFrame*>(Lower()->GetNext()) : nullptr;
+ if( pCont )
+ {
+ const SwFootnoteFrame* pFootnote = static_cast<const SwFootnoteFrame*>(pCont->Lower());
+ while( pFootnote)
+ {
+ if( pFootnote->GetAttr()->GetFootnote().IsEndNote() )
+ { // endnote found
+ const SwFrame* pFrame = static_cast<const SwLayoutFrame*>(Lower())->Lower();
+ if( pFrame )
+ {
+ while( pFrame->GetNext() )
+ pFrame = pFrame->GetNext(); // last cntntfrm
+ nTmp += aRectFnSet.YDiff(
+ aRectFnSet.GetTop(getFrameArea()),
+ aRectFnSet.GetBottom(pFrame->getFrameArea()) );
+ }
+ break;
+ }
+ pFootnote = static_cast<const SwFootnoteFrame*>(pFootnote->GetNext());
+ }
+ }
+ }
+ if( nTmp < nRet )
+ nRet = nTmp;
+ }
+ else
+ nRet = - aRectFnSet.GetHeight(pPg->getFramePrintArea())/5;
+ nRet += aRectFnSet.GetHeight(pBody->getFrameArea());
+ if( nRet < 0 )
+ nRet = 0;
+ }
+ else
+ nRet = 0;
+ if ( IsPageFrame() )
+ {
+ const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
+ if( pSh && pSh->GetViewOptions()->getBrowseMode() )
+ nRet += BROWSE_HEIGHT - getFrameArea().Height();
+ }
+ return nRet;
+}
+
+/** Obtain if pFrame's size adjustment should be processed
+ *
+ * For a page frame of columns directly below the page AdjustNeighbourhood() needs
+ * to be called, or Grow()/ Shrink() for frame columns respectively.
+ *
+ * A column section is special, since if there is a footnote container in a column
+ * and those footnotes are not collected, it is handled like a page frame.
+ *
+ * @see AdjustNeighbourhood()
+ * @see Grow()
+ * @see Shrink()
+ */
+SwNeighbourAdjust SwFootnoteBossFrame::NeighbourhoodAdjustment_() const
+{
+ SwNeighbourAdjust nRet = SwNeighbourAdjust::OnlyAdjust;
+ if( GetUpper() && !GetUpper()->IsPageBodyFrame() )
+ {
+ // column sections need grow/shrink
+ if( GetUpper()->IsFlyFrame() )
+ nRet = SwNeighbourAdjust::GrowShrink;
+ else
+ {
+ OSL_ENSURE( GetUpper()->IsSctFrame(), "NeighbourhoodAdjustment: Unexpected Upper" );
+ if( !GetNext() && !GetPrev() )
+ nRet = SwNeighbourAdjust::GrowAdjust; // section with a single column (FootnoteAtEnd)
+ else
+ {
+ const SwFrame* pTmp = Lower();
+ OSL_ENSURE( pTmp, "NeighbourhoodAdjustment: Missing Lower()" );
+ if( !pTmp->GetNext() )
+ nRet = SwNeighbourAdjust::GrowShrink;
+ else if( !GetUpper()->IsColLocked() )
+ nRet = SwNeighbourAdjust::AdjustGrow;
+ OSL_ENSURE( !pTmp->GetNext() || pTmp->GetNext()->IsFootnoteContFrame(),
+ "NeighbourhoodAdjustment: Who's that guy?" );
+ }
+ }
+ }
+ return nRet;
+}
+
+void SwPageFrame::SetColMaxFootnoteHeight()
+{
+ SwLayoutFrame *pBody = FindBodyCont();
+ if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
+ {
+ SwColumnFrame* pCol = static_cast<SwColumnFrame*>(pBody->Lower());
+ do
+ {
+ pCol->SetMaxFootnoteHeight( GetMaxFootnoteHeight() );
+ pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
+ } while ( pCol );
+ }
+}
+
+bool SwLayoutFrame::MoveLowerFootnotes( SwContentFrame *pStart, SwFootnoteBossFrame *pOldBoss,
+ SwFootnoteBossFrame *pNewBoss, const bool bFootnoteNums )
+{
+ SwDoc *pDoc = GetFormat()->GetDoc();
+ if ( pDoc->GetFootnoteIdxs().empty() )
+ return false;
+ if( pDoc->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER &&
+ ( !IsInSct() || !FindSctFrame()->IsFootnoteAtEnd() ) )
+ return true;
+
+ if ( !pNewBoss )
+ pNewBoss = FindFootnoteBossFrame( true );
+ if ( pNewBoss == pOldBoss )
+ return false;
+
+ bool bMoved = false;
+ if( !pStart )
+ pStart = ContainsContent();
+
+ SwFootnoteFrames aFootnoteArr;
+
+ while ( IsAnLower( pStart ) )
+ {
+ if ( static_cast<SwTextFrame*>(pStart)->HasFootnote() )
+ {
+ // OD 03.04.2003 #108446# - To avoid unnecessary moves of footnotes
+ // use new parameter <_bCollectOnlyPreviousFootnote> (4th parameter of
+ // method <SwFootnoteBossFrame::CollectFootnote(..)>) to control, that only
+ // footnotes have to be collected, that are positioned before the
+ // new dedicated footnote boss frame.
+ pNewBoss->CollectFootnotes( pStart, pOldBoss, aFootnoteArr, true );
+ }
+ pStart = pStart->GetNextContentFrame();
+ }
+
+ OSL_ENSURE( pOldBoss->IsInSct() == pNewBoss->IsInSct(),
+ "MoveLowerFootnotes: Section confusion" );
+ std::unique_ptr<SwFootnoteFrames> pFootnoteArr;
+ SwLayoutFrame* pNewChief = nullptr;
+ SwLayoutFrame* pOldChief = nullptr;
+
+ bool bFoundCandidate = false;
+ if (pStart && pOldBoss->IsInSct())
+ {
+ pOldChief = pOldBoss->FindSctFrame();
+ pNewChief = pNewBoss->FindSctFrame();
+ bFoundCandidate = pOldChief != pNewChief;
+ }
+
+ if (bFoundCandidate)
+ {
+ pFootnoteArr.reset(new SwFootnoteFrames);
+ pOldChief = pOldBoss->FindFootnoteBossFrame( true );
+ pNewChief = pNewBoss->FindFootnoteBossFrame( true );
+ while( pOldChief->IsAnLower( pStart ) )
+ {
+ if ( static_cast<SwTextFrame*>(pStart)->HasFootnote() )
+ static_cast<SwFootnoteBossFrame*>(pNewChief)->CollectFootnotes( pStart,
+ pOldBoss, *pFootnoteArr );
+ pStart = pStart->GetNextContentFrame();
+ }
+ if( pFootnoteArr->empty() )
+ {
+ pFootnoteArr.reset();
+ }
+ }
+ else
+ pFootnoteArr = nullptr;
+
+ if ( !aFootnoteArr.empty() || pFootnoteArr )
+ {
+ if( !aFootnoteArr.empty() )
+ pNewBoss->MoveFootnotes_( aFootnoteArr, true );
+ if( pFootnoteArr )
+ {
+ assert(pNewChief);
+ static_cast<SwFootnoteBossFrame*>(pNewChief)->MoveFootnotes_( *pFootnoteArr, true );
+ pFootnoteArr.reset();
+ }
+ bMoved = true;
+
+ // update FootnoteNum only at page change
+ if ( bFootnoteNums )
+ {
+ SwPageFrame* pOldPage = pOldBoss->FindPageFrame();
+ SwPageFrame* pNewPage =pNewBoss->FindPageFrame();
+ if( pOldPage != pNewPage )
+ {
+ pOldPage->UpdateFootnoteNum();
+ pNewPage->UpdateFootnoteNum();
+ }
+ }
+ }
+ return bMoved;
+}
+
+/// Return value guarantees that a new page was not created. See SwFlowFrame::MoveFwd.
+bool SwContentFrame::MoveFootnoteCntFwd( bool bMakePage, SwFootnoteBossFrame *pOldBoss )
+{
+ OSL_ENSURE( IsInFootnote(), "no footnote." );
+ SwLayoutFrame *pFootnote = FindFootnoteFrame();
+
+ // The first paragraph in the first footnote in the first column in the
+ // sectionfrm at the top of the page has not to move forward, if the
+ // columnbody is empty.
+ if( pOldBoss->IsInSct() && !pOldBoss->GetIndPrev() && !GetIndPrev() &&
+ !pFootnote->GetPrev() )
+ {
+ SwLayoutFrame* pBody = pOldBoss->FindBodyCont();
+ if( !pBody || !pBody->Lower() )
+ return true;
+ }
+
+ //fix(9538): if the footnote has neighbors behind itself, remove them temporarily
+ SwLayoutFrame *pNxt = static_cast<SwLayoutFrame*>(pFootnote->GetNext());
+ SwLayoutFrame *pLst = nullptr;
+ while ( pNxt )
+ {
+ while ( pNxt->GetNext() )
+ pNxt = static_cast<SwLayoutFrame*>(pNxt->GetNext());
+ if ( pNxt == pLst )
+ pNxt = nullptr;
+ else
+ { pLst = pNxt;
+ SwContentFrame *pCnt = pNxt->ContainsContent();
+ if( pCnt )
+ pCnt->MoveFootnoteCntFwd( true, pOldBoss );
+ pNxt = static_cast<SwLayoutFrame*>(pFootnote->GetNext());
+ }
+ }
+
+ bool bSamePage = true;
+ SwLayoutFrame *pNewUpper =
+ GetLeaf( bMakePage ? MAKEPAGE_INSERT : MAKEPAGE_NONE, true );
+
+ if ( pNewUpper )
+ {
+ SwFootnoteBossFrame * const pNewBoss = pNewUpper->FindFootnoteBossFrame();
+ // Are we changing the column/page?
+ bool bSameBoss = pNewBoss == pOldBoss;
+ if ( !bSameBoss )
+ {
+ bSamePage = pOldBoss->FindPageFrame() == pNewBoss->FindPageFrame(); // page change?
+ pNewUpper->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ }
+
+ // The layout leaf of the footnote is either a footnote container or a footnote.
+ // If it is a footnote and it has the same footnote reference like the old Upper,
+ // then move the content inside of it.
+ // If it is a container or the reference differs, create a new footnote and add
+ // it into the container.
+ // Create also a SectionFrame if currently in an area inside a footnote.
+ SwFootnoteFrame* pTmpFootnote = pNewUpper->IsFootnoteFrame() ? static_cast<SwFootnoteFrame*>(pNewUpper) : nullptr;
+ if (!pTmpFootnote)
+ {
+ assert(pNewUpper->IsFootnoteContFrame() && "New Upper not a FootnoteCont");
+ SwFootnoteContFrame *pCont = static_cast<SwFootnoteContFrame*>(pNewUpper);
+ pTmpFootnote = SwFootnoteContFrame::AppendChained(this, true);
+ SwFrame* pNx = pCont->Lower();
+ if( pNx && pTmpFootnote->GetAttr()->GetFootnote().IsEndNote() )
+ while(pNx && !static_cast<SwFootnoteFrame*>(pNx)->GetAttr()->GetFootnote().IsEndNote())
+ pNx = pNx->GetNext();
+ pTmpFootnote->Paste( pCont, pNx );
+ pTmpFootnote->Calc(getRootFrame()->GetCurrShell()->GetOut());
+ }
+ OSL_ENSURE( pTmpFootnote->GetAttr() == FindFootnoteFrame()->GetAttr(), "Wrong Footnote!" );
+ // areas inside of footnotes get a special treatment
+ SwLayoutFrame *pNewUp = pTmpFootnote;
+ if( IsInSct() )
+ {
+ SwSectionFrame* pSect = FindSctFrame();
+ // area inside of a footnote (or only footnote in an area)?
+ if( pSect->IsInFootnote() )
+ {
+ if( pTmpFootnote->Lower() && pTmpFootnote->Lower()->IsSctFrame() &&
+ pSect->GetFollow() == static_cast<SwSectionFrame*>(pTmpFootnote->Lower()) )
+ pNewUp = static_cast<SwSectionFrame*>(pTmpFootnote->Lower());
+ else
+ {
+ pNewUp = new SwSectionFrame( *pSect, false );
+ pNewUp->InsertBefore( pTmpFootnote, pTmpFootnote->Lower() );
+ static_cast<SwSectionFrame*>(pNewUp)->Init();
+
+ {
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pNewUp);
+ aFrm.Pos() = pTmpFootnote->getFrameArea().Pos();
+ aFrm.Pos().AdjustY(1 ); // for notifications
+ }
+
+ // If the section frame has a successor then the latter needs
+ // to be moved behind the new Follow of the section frame.
+ SwFrame* pTmp = pSect->GetNext();
+ if( pTmp )
+ {
+ SwFlowFrame* pTmpNxt;
+ if( pTmp->IsContentFrame() )
+ pTmpNxt = static_cast<SwContentFrame*>(pTmp);
+ else if( pTmp->IsSctFrame() )
+ pTmpNxt = static_cast<SwSectionFrame*>(pTmp);
+ else
+ {
+ OSL_ENSURE( pTmp->IsTabFrame(), "GetNextSctLeaf: Wrong Type" );
+ pTmpNxt = static_cast<SwTabFrame*>(pTmp);
+ }
+ // we will dereference pNewUp in the following MoveSubTree call
+ // so it certainly should not be deleted before that
+ SwFrameDeleteGuard aDeleteGuard(pNewUp);
+ pTmpNxt->MoveSubTree( pTmpFootnote, pNewUp->GetNext() );
+ }
+ }
+ }
+ }
+
+ MoveSubTree( pNewUp, pNewUp->Lower() );
+
+ if( !bSameBoss )
+ Prepare( PrepareHint::BossChanged );
+ }
+ return bSamePage;
+}
+
+SwSaveFootnoteHeight::SwSaveFootnoteHeight( SwFootnoteBossFrame *pBs, const SwTwips nDeadLine ) :
+ aGuard(pBs),
+ pBoss( pBs ),
+ nOldHeight( pBs->GetMaxFootnoteHeight() )
+{
+ pBoss->SetFootnoteDeadLine( nDeadLine );
+ nNewHeight = pBoss->GetMaxFootnoteHeight();
+}
+
+SwSaveFootnoteHeight::~SwSaveFootnoteHeight()
+{
+ // If somebody tweaked the deadline meanwhile, we let it happen
+ if ( nNewHeight == pBoss->GetMaxFootnoteHeight() )
+ pBoss->m_nMaxFootnoteHeight = nOldHeight;
+}
+
+#ifdef DBG_UTIL
+//JP 15.10.2001: in a non pro version test if the attribute has the same
+// meaning which his reference is
+
+// Normally, the pRef member and the GetRefFromAttr() result has to be
+// identically. Sometimes footnote will be moved from a master to its follow,
+// but the GetRef() is called first, so we have to ignore a master/follow
+// mismatch.
+
+const SwContentFrame* SwFootnoteFrame::GetRef() const
+{
+ const SwContentFrame* pRefAttr = GetRefFromAttr();
+ // check consistency: access to deleted frame?
+ assert(mpReference == pRefAttr || mpReference->IsAnFollow(pRefAttr)
+ || pRefAttr->IsAnFollow(mpReference));
+ (void) pRefAttr;
+ return mpReference;
+}
+
+SwContentFrame* SwFootnoteFrame::GetRef()
+{
+ const SwContentFrame* pRefAttr = GetRefFromAttr();
+ // check consistency: access to deleted frame?
+ assert(mpReference == pRefAttr || mpReference->IsAnFollow(pRefAttr)
+ || pRefAttr->IsAnFollow(mpReference));
+ (void) pRefAttr;
+ return mpReference;
+}
+#endif
+
+const SwContentFrame* SwFootnoteFrame::GetRefFromAttr() const
+{
+ SwFootnoteFrame* pThis = const_cast<SwFootnoteFrame*>(this);
+ return pThis->GetRefFromAttr();
+}
+
+SwContentFrame* SwFootnoteFrame::GetRefFromAttr()
+{
+ assert(mpAttribute && "invalid Attribute");
+ SwTextNode& rTNd = const_cast<SwTextNode&>(mpAttribute->GetTextNode());
+ SwPosition aPos( rTNd, SwIndex( &rTNd, mpAttribute->GetStart() ));
+ SwContentFrame* pCFrame = rTNd.getLayoutFrame(getRootFrame(), &aPos);
+ return pCFrame;
+}
+
+/** search for last content in the current footnote frame
+
+ OD 2005-12-02 #i27138#
+*/
+SwContentFrame* SwFootnoteFrame::FindLastContent()
+{
+ SwContentFrame* pLastContentFrame( nullptr );
+
+ // find last lower, which is a content frame or contains content.
+ // hidden text frames, empty sections and empty tables have to be skipped.
+ SwFrame* pLastLowerOfFootnote( GetLower() );
+ SwFrame* pTmpLastLower( pLastLowerOfFootnote );
+ while ( pTmpLastLower && pTmpLastLower->GetNext() )
+ {
+ pTmpLastLower = pTmpLastLower->GetNext();
+ if ( ( pTmpLastLower->IsTextFrame() &&
+ !static_cast<SwTextFrame*>(pTmpLastLower)->IsHiddenNow() ) ||
+ ( pTmpLastLower->IsSctFrame() &&
+ static_cast<SwSectionFrame*>(pTmpLastLower)->GetSection() &&
+ static_cast<SwSectionFrame*>(pTmpLastLower)->ContainsContent() ) ||
+ ( pTmpLastLower->IsTabFrame() &&
+ static_cast<SwTabFrame*>(pTmpLastLower)->ContainsContent() ) )
+ {
+ pLastLowerOfFootnote = pTmpLastLower;
+ }
+ }
+
+ // determine last content frame depending on type of found last lower.
+ if ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsTabFrame() )
+ {
+ pLastContentFrame = static_cast<SwTabFrame*>(pLastLowerOfFootnote)->FindLastContent();
+ }
+ else if ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsSctFrame() )
+ {
+ pLastContentFrame = static_cast<SwSectionFrame*>(pLastLowerOfFootnote)->FindLastContent();
+ }
+ else
+ {
+ pLastContentFrame = dynamic_cast<SwContentFrame*>(pLastLowerOfFootnote);
+ }
+
+ return pLastContentFrame;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */