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