/* -*- 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 .
*/
namespace
{ /// Calculates the height of the line that hosts the separator line (the top margin of the /// container), based on the default paragraph style in rDoc. bool FootnoteSeparatorHeightFromParagraph(SwDoc& rDoc, SwTwips& rHeight)
{ const SwTextFormatColl* pDefaultParaFormat
= rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD); if (!pDefaultParaFormat)
{ returnfalse;
}
SwViewShell* pSh = rDoc.GetDocShell()->GetWrtShell(); if (!pSh)
{ returnfalse;
}
/// Search the position of an attribute in the FootnoteArray at the document, /// because all footnotes are located there, ordered by their index. static sal_uInt32 lcl_FindFootnotePos( const SwDoc& rDoc, const SwTextFootnote *pAttr )
{ const SwFootnoteIdxs &rFootnoteIdxs = rDoc.GetFootnoteIdxs();
SwTextFootnote* pBla = const_cast<SwTextFootnote*>(pAttr);
SwFootnoteIdxs::const_iterator it = rFootnoteIdxs.find( pBla ); if ( it != rFootnoteIdxs.end() )
{
sal_uInt32 nRet = it - rFootnoteIdxs.begin(); if( pAttr->GetFootnote().IsEndNote() ) return nRet + ENDNOTE; return nRet;
} return 0;
}
/* |* |* 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. |*
|*/
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;
}
} elseif( 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(SwDoc& rDoc, SwPageFootnoteInfo const& rInf)
{ const IDocumentSettingAccess& rIDSA = rDoc.getIDocumentSettingAccess(); if (rIDSA.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
{ // Word style: try to calculate the height from the default para format.
SwTwips nHeight{}; if (FootnoteSeparatorHeightFromParagraph(rDoc, nHeight))
{ return nHeight;
}
}
// Writer style: calculate from the page style. 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();
SwDoc* pDoc = getRootFrame()->GetCurrShell()->GetDoc(); const SwTwips nBorder = sw::FootnoteSeparatorHeight(*pDoc, rInf);
SwRectFnSet aRectFnSet(this);
if ( !isFramePrintAreaValid() )
{
setFramePrintAreaValid(true);
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
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;
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.AddBottom( aFrm, -nDiff );
aRectFnSet.AddHeight( aFrm, -nDiff );
}
}
nDiff = aRectFnSet.GetHeight(getFrameArea()) - nRemaining; if ( nDiff > 0 )
Shrink( nDiff ); elseif ( 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, SwResizeLimitReason& reason, 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());
bool SwFootnoteFrame::IsDeleteForbidden() const
{ if (SwLayoutFrame::IsDeleteForbidden()) returntrue; // needs to be in sync with the ::Cut logic const SwLayoutFrame *pUp = GetUpper(); if (pUp)
{ if (GetPrev()) returnfalse;
// 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();
} returnfalse;
}
// 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& rDoc = GetFormat()->GetDoc(); if ( GetPrev() )
{
OSL_ENSURE( lcl_FindFootnotePos( rDoc, static_cast<SwFootnoteFrame*>(GetPrev())->GetAttr() ) <=
lcl_FindFootnotePos( rDoc, GetAttr() ), "Prev is not FootnotePrev" );
} if ( GetNext() )
{
OSL_ENSURE( lcl_FindFootnotePos( rDoc, GetAttr() ) <=
lcl_FindFootnotePos( rDoc, 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();
SwFrame* pLower = pLay ? pLay->Lower() : nullptr; if( pLower && pLower->IsColumnFrame() )
pBoss = static_cast<SwFootnoteBossFrame*>(pLower);
} // 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();
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(); bool bContEndnotes = rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES); if( bEndn && pFootnote->IsInSct() && !bContEndnotes)
{
SwSectionFrame* pSect = pFootnote->FindSctFrame(); if( pSect->IsEndnAtEnd() ) // Endnotes at the end of the section.
pTmpRef = pSect->FindLastContent( SwFindMode::LastCnt );
} elseif (bEndn && bContEndnotes)
{ // Endnotes at the end of the document.
pTmpRef = pFootnote->FindFootnoteBossFrame();
} 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. constbool bEndNote = pOldPage->IsEndNotePage(); constbool 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 )
{
SwFrame* pLower = pBody->Lower(); if ( pLower && pLower->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? elseif( 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
{ bool bSplitFly = false; const SwFlyFrame* pFlyFrame = FindFlyFrame(); if (pFlyFrame)
{ // This is a fly. Check if it's a split fly, which is OK to host a footnote.
bSplitFly = pFlyFrame->IsFlySplitAllowed();
}
if (!IsInDocBody() && !bSplitFly) returnfalse;
if ( IsInTab() )
{ // no footnotes in repeated headlines const SwTabFrame *pTab = const_cast<SwFrame*>(this)->ImplFindTabFrame();
assert(pTab); if ( pTab->IsFollow() ) return !pTab->IsInHeadline( *this );
} returntrue;
}
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 )
{
SwContentFrame* pCF = pFootnote->GetRef(); // it's possible that the contentframe is empty when closing Writer if (!pCF) return; if (!pCF->IsInDtor()) // NOTE: I REPRO'D A CRASH HERE BUT THE DEBUGGER DIDN'T INDICATE // WHAT THE PROBLEM WAS -- the objects are valid. Happens when // undoing/redoing rapidly for some time then saving and the crash // happens on close of LO
pCF->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 )
{
SwFrame* pLow = pBody->Lower(); while (pLow)
{ if( pLow->IsSctFrame() && ( !pLow->GetNext() || static_cast<SwSectionFrame*>(pLow)->IsAnyNoteAtEnd() ) )
{
SwFrame* pLowerLower = static_cast<SwSectionFrame*>(pLow)->Lower(); if (pLowerLower && pLowerLower->IsColumnFrame() )
sw_RemoveFootnotes( static_cast<SwColumnFrame*>(pLowerLower),
bPageOnly, bEndNotes );
}
pLow = pLow->GetNext();
}
}
} // is there another column?
pBoss = pBoss->IsColumnFrame() ? static_cast<SwColumnFrame*>(pBoss->GetNext()) : nullptr;
} while( pBoss );
}
/// 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(); // it's possible that there is no page frame when performing an undo operation if (!pPage) return nullptr;
nPgNum = pPage->GetPhyPageNum(); if ( nPgNum == nRefNum )
{
nColNum = lcl_ColumnNum( pBoss ); if( nColNum == nRefCol ) return pRet; // found elseif( nColNum > nRefCol ) return nullptr; // at least one column too far
} elseif ( 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(); // it's possible that there is no boss frame when performing an undo operation if (!pBoss) return nullptr; // it's possible that there is no page frame when performing an undo operation
pPage = pBoss->FindPageFrame(); if (!pPage) return nullptr;
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(); // it's possible that there is no boss frame when performing an undo operation if (!pBoss) return nullptr; // it's possible that there is no page frame when performing an undo operation
pPage = pBoss->FindPageFrame(); if (!pPage) return nullptr;
nPgNum = pPage->GetPhyPageNum(); if ( nPgNum == nRefNum )
{
nColNum = lcl_ColumnNum( pBoss ); if( nColNum == nRefCol ) break; // found elseif( nColNum > nRefCol )
pRet = nullptr; // at least one column too far
} elseif ( 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();
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." );
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.
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( rDoc, 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( rDoc, pSibling->GetAttr() );
SwFootnoteBossFrame *pNxtB; // remember the last one to not
SwFootnoteFrame *pLastSib = nullptr; // go too far.
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( rDoc, 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;
} elseif ( !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; // it's possible pBoss is empty here on an undo/redo operation if (pBoss && (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( rDoc, pSibling->GetAttr() ); if (pSibling && (pSibling != pLastSib))
{ // too far? if ( (nLastPos < nCmpPos) && (nCmpPos > nStPos) )
{
pSibling = pLastSib;
bEnd = true;
}
}
}
} if ( pSibling )
{
nCmpPos = ::lcl_FindFootnotePos( rDoc, 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(constbool bEnd, const SwPageFrame* pPage, const SwDoc& rDoc, 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_uInt32 nStPos = ::lcl_FindFootnotePos(rDoc, pAttr); while (pNxt && (bEnd ? pNxt->IsEndNotePage() : pNxt->IsFootnotePage() && !pNxt->IsEndNotePage()))
{ const SwFootnoteContFrame *pCont = pNxt->FindFootnoteCont(); const SwFrame* pLower = pCont ? pCont->Lower() : nullptr; if (pLower)
{
OSL_ENSURE( pLower->IsFootnoteFrame(), "no footnote in the container" ); if (nStPos > ::lcl_FindFootnotePos(rDoc, static_cast<const SwFootnoteFrame*>(pLower)->GetAttr()))
{
pPage = pNxt;
pNxt = static_cast<const SwPageFrame*>(pPage->GetNext()); continue;
}
} break;
} returnconst_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& rDoc = GetFormat()->GetDoc();
SwFootnoteBossFrame *pBoss = this;
SwPageFrame *pPage = FindPageFrame();
SwPageFrame *pMyPage = pPage; bool bChgPage = false; constbool 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();
}
} elseif (rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
{ // Endnotes at the end of the document. // Find the first page that hosts an endnote section.
SwSectionFrame* pEndnoteSection = pPage->GetEndNoteSection(); while (pPage->GetNext() && !pEndnoteSection)
{
pPage = pPage->GetNext()->DynCastPageFrame();
pEndnoteSection = pPage->GetEndNoteSection();
} // If there are no endnotes sections yet, create one at the end of the document. // Ignore sections which are already marked for deletion, they don't have an SwSection // anymore, so not usable for us. if (!pEndnoteSection || !pEndnoteSection->GetSection())
{
SwSection* pSwSection = rDoc.GetEndNoteInfo().GetSwSection(rDoc);
pEndnoteSection = new SwSectionFrame(*pSwSection, pPage);
SwLayoutFrame* pParent = pPage->FindBodyCont();
SwFrame* pBefore = pPage->FindLastBodyContent(); while (pBefore)
{ // Check if the last content frame is directly under the body frame or there is // something in-between, e.g. a section frame. if (pBefore->GetUpper() == pParent)
{ break;
}
// If so, insert behind the parent of the content frame, not inside the parent.
pBefore = pBefore->GetUpper();
}
pEndnoteSection->InsertBehind(pParent, pBefore);
pEndnoteSection->Init();
pEndnoteSection->SetEndNoteSection(true);
}
// 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( rDoc.GetDfltFrameFormat(), this, pRef, pAttr );
{
SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
::InsertCnt_( pNew, rDoc, 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. constbool 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, constSwTextFootnote *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 = SwNodes::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;
}
/// 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, constbool _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;
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());
// 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(); if (_pFootnote->GetRef() == _pRef && !bEndNote)
{ 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 );
// #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;
}
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::RearrangeFootnotes( const SwTwips nDeadLine, constbool bLock, const SwTextFootnote *pAttr )
{ // Format all footnotes of a column/page so that they might change the column/page.
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( rDoc, pCnt->FindFootnoteFrame()->GetAttr() )
== nFootnotePos; if( bStart )
{
pCnt->InvalidatePos_();
pCnt->InvalidateSize_();
pCnt->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
SwFootnoteFrame* pFootnoteFrame = pCnt->FindFootnoteFrame();
assert(pFootnoteFrame); // #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 overwritten at end of block
}
} 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( rDoc,
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;
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)
/** 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();
assert(pTmp && "NeighbourhoodAdjustment: Missing Lower()"); if( !pTmp->GetNext() )
nRet = SwNeighbourAdjust::GrowShrink; elseif( !GetUpper()->IsColLocked() )
nRet = SwNeighbourAdjust::AdjustGrow;
OSL_ENSURE( !pTmp->GetNext() || pTmp->GetNext()->IsFootnoteContFrame(), "NeighbourhoodAdjustment: Who's that guy?" );
}
}
} return nRet;
}
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();
}
/// 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() ) returntrue;
}
//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());
}
}
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() )
{
SwFrame* pLower = pTmpFootnote->Lower(); if( pLower && pLower->IsSctFrame() &&
pSect->GetFollow() == static_cast<SwSectionFrame*>(pLower) )
pNewUp = static_cast<SwSectionFrame*>(pLower); else
{
pNewUp = new SwSectionFrame( *pSect, false );
pNewUp->InsertBefore( pTmpFootnote, pLower ); static_cast<SwSectionFrame*>(pNewUp)->Init();
// 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); elseif( 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() );
}
}
}
}
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.
// 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->IsHiddenNow()
&& (!pTmpLastLower->IsLayoutFrame()
|| static_cast<SwLayoutFrame*>(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();
} elseif ( pLastLowerOfFootnote && pLastLowerOfFootnote->IsSctFrame() )
{
pLastContentFrame = static_cast<SwSectionFrame*>(pLastLowerOfFootnote)->FindLastContent();
} else
{
pLastContentFrame = dynamic_cast<SwContentFrame*>(pLastLowerOfFootnote);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.