/* -*- 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() )
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet)
¤
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.