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 #define ENDNOTE 0x80000000
47 /// Search the position of an attribute in the FootnoteArray at the document,
48 /// because all footnotes are located there, ordered by their index.
49 static sal_uLong
lcl_FindFootnotePos( const SwDoc
*pDoc
, const SwTextFootnote
*pAttr
)
51 const SwFootnoteIdxs
&rFootnoteIdxs
= pDoc
->GetFootnoteIdxs();
53 SwTextFootnote
* pBla
= const_cast<SwTextFootnote
*>(pAttr
);
54 SwFootnoteIdxs::const_iterator it
= rFootnoteIdxs
.find( pBla
);
55 if ( it
!= rFootnoteIdxs
.end() )
57 sal_uLong nRet
= it
- rFootnoteIdxs
.begin();
58 if( pAttr
->GetFootnote().IsEndNote() )
59 return nRet
+ ENDNOTE
;
62 OSL_ENSURE( !pDoc
, "FootnotePos not found." );
66 bool SwFootnoteFrame::operator<( const SwTextFootnote
* pTextFootnote
) const
68 const SwDoc
* pDoc
= GetFormat()->GetDoc();
69 OSL_ENSURE( pDoc
, "SwFootnoteFrame: Missing doc!" );
70 return lcl_FindFootnotePos( pDoc
, GetAttr() ) <
71 lcl_FindFootnotePos( pDoc
, pTextFootnote
);
76 |* bool lcl_NextFootnoteBoss( SwFootnoteBossFrame* pBoss, SwPageFrame* pPage)
77 |* sets pBoss on the next SwFootnoteBossFrame, which can either be a column
78 |* or a page (without columns). If the page changes meanwhile,
79 |* pPage contains the new page and this function returns true.
83 static bool lcl_NextFootnoteBoss( SwFootnoteBossFrame
* &rpBoss
, SwPageFrame
* &rpPage
,
86 if( rpBoss
->IsColumnFrame() )
88 if( rpBoss
->GetNext() )
90 rpBoss
= static_cast<SwFootnoteBossFrame
*>(rpBoss
->GetNext()); //next column
93 if( rpBoss
->IsInSct() )
95 SwSectionFrame
* pSct
= rpBoss
->FindSctFrame()->GetFollow();
98 OSL_ENSURE( pSct
->Lower() && pSct
->Lower()->IsColumnFrame(),
99 "Where's the column?" );
100 rpBoss
= static_cast<SwColumnFrame
*>(pSct
->Lower());
101 SwPageFrame
* pOld
= rpPage
;
102 rpPage
= pSct
->FindPageFrame();
103 return pOld
!= rpPage
;
105 else if( bDontLeave
)
113 rpPage
= static_cast<SwPageFrame
*>(rpPage
->GetNext()); // next page
117 SwLayoutFrame
* pBody
= rpPage
->FindBodyCont();
118 if( pBody
&& pBody
->Lower() && pBody
->Lower()->IsColumnFrame() )
119 rpBoss
= static_cast<SwFootnoteBossFrame
*>(pBody
->Lower()); // first column
124 /// @returns column number if pBoss is a column, otherwise 0.
125 static sal_uInt16
lcl_ColumnNum( const SwFrame
* pBoss
)
128 if( !pBoss
->IsColumnFrame() )
131 if( pBoss
->IsInSct() )
133 pCol
= pBoss
->GetUpper()->FindColFrame();
134 if( pBoss
->GetNext() || pBoss
->GetPrev() )
138 ++nRet
; // Section columns
139 pBoss
= pBoss
->GetPrev();
147 nRet
+= 256; // Page columns
148 pCol
= pCol
->GetPrev();
153 SwFootnoteContFrame::SwFootnoteContFrame( SwFrameFormat
*pFormat
, SwFrame
* pSib
):
154 SwLayoutFrame( pFormat
, pSib
)
156 mnFrameType
= SwFrameType::FtnCont
;
159 SwFootnoteFrame
* SwFootnoteContFrame::AddChained(bool bAppend
, SwFrame
* pThis
, bool bDefaultFormat
)
161 SwFootnoteFrame
*pOld
= pThis
->FindFootnoteFrame();
162 SwFrameFormat
*pFormat
= pOld
->GetFormat();
164 pFormat
= pFormat
->GetDoc()->GetDfltFrameFormat();
166 SwFootnoteFrame
*pNew
= new SwFootnoteFrame(pFormat
, pOld
, pOld
->GetRef(), pOld
->GetAttr());
170 if (pOld
->GetFollow())
172 pNew
->SetFollow(pOld
->GetFollow());
173 pOld
->GetFollow()->SetMaster(pNew
);
175 pOld
->SetFollow(pNew
);
176 pNew
->SetMaster(pOld
);
180 if (pOld
->GetMaster())
182 pNew
->SetMaster(pOld
->GetMaster());
183 pOld
->GetMaster()->SetFollow(pNew
);
185 pNew
->SetFollow(pOld
);
186 pOld
->SetMaster(pNew
);
192 // lcl_Undersize(..) walks over a SwFrame and its contents
193 // and returns the sum of all requested TextFrame magnifications.
195 static tools::Long
lcl_Undersize( const SwFrame
* pFrame
)
197 tools::Long nRet
= 0;
198 SwRectFnSet
aRectFnSet(pFrame
);
199 if( pFrame
->IsTextFrame() )
201 if( static_cast<const SwTextFrame
*>(pFrame
)->IsUndersized() )
203 // Does this TextFrame would like to be a little bit bigger?
204 nRet
= static_cast<const SwTextFrame
*>(pFrame
)->GetParHeight() -
205 aRectFnSet
.GetHeight(pFrame
->getFramePrintArea());
210 else if( pFrame
->IsLayoutFrame() )
212 const SwFrame
* pNxt
= static_cast<const SwLayoutFrame
*>(pFrame
)->Lower();
215 nRet
+= lcl_Undersize( pNxt
);
216 pNxt
= pNxt
->GetNext();
224 SwTwips
FootnoteSeparatorHeight(SwPageFootnoteInfo
const& rInf
)
226 return rInf
.GetTopDist() + rInf
.GetBottomDist() + rInf
.GetLineWidth();
231 /// "format" the frame (Fixsize is not set here).
232 void SwFootnoteContFrame::Format( vcl::RenderContext
* /*pRenderContext*/, const SwBorderAttrs
* )
234 // calculate total border, only one distance to the top
235 const SwPageFrame
* pPage
= FindPageFrame();
236 const SwPageFootnoteInfo
&rInf
= pPage
->GetPageDesc()->GetFootnoteInfo();
237 const SwTwips nBorder
= sw::FootnoteSeparatorHeight(rInf
);
238 SwRectFnSet
aRectFnSet(this);
240 if ( !isFramePrintAreaValid() )
242 setFramePrintAreaValid(true);
243 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
245 aRectFnSet
.SetTop( aPrt
, nBorder
);
246 aRectFnSet
.SetWidth( aPrt
, aRectFnSet
.GetWidth(getFrameArea()) );
247 aRectFnSet
.SetHeight(aPrt
, aRectFnSet
.GetHeight(getFrameArea()) - nBorder
);
249 if( aRectFnSet
.GetHeight(aPrt
) < 0 && !pPage
->IsFootnotePage() )
251 setFrameAreaSizeValid(false);
255 if ( isFrameAreaSizeValid() )
258 bool bGrow
= pPage
->IsFootnotePage();
261 const SwViewShell
*pSh
= getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
262 if( pSh
&& pSh
->GetViewOptions()->getBrowseMode() )
269 // VarSize is determined based on the content plus the borders
270 SwTwips nRemaining
= 0;
271 SwFrame
*pFrame
= m_pLower
;
273 { // lcl_Undersize(..) respects (recursively) TextFrames, which
274 // would like to be bigger. They are created especially in
275 // columnized borders, if these do not have their maximum
277 nRemaining
+= aRectFnSet
.GetHeight(pFrame
->getFrameArea()) + lcl_Undersize( pFrame
);
278 pFrame
= pFrame
->GetNext();
280 // add the own border
281 nRemaining
+= nBorder
;
286 nDiff
= -aRectFnSet
.BottomDist( getFrameArea(), aRectFnSet
.GetPrtBottom(*GetUpper()) );
289 if( nDiff
> aRectFnSet
.GetHeight(getFrameArea()) )
291 nDiff
= aRectFnSet
.GetHeight(getFrameArea());
294 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
295 aRectFnSet
.AddBottom( aFrm
, -nDiff
);
296 aRectFnSet
.AddHeight( aFrm
, -nDiff
);
299 nDiff
= aRectFnSet
.GetHeight(getFrameArea()) - nRemaining
;
302 else if ( nDiff
< 0 )
305 // It may happen that there is less space available,
306 // than what the border needs - the size of the PrtArea
307 // will then be negative.
308 SwTwips nPrtHeight
= aRectFnSet
.GetHeight(getFramePrintArea());
311 const SwTwips nTmpDiff
= std::max( SwTwips(aRectFnSet
.GetTop(getFramePrintArea())), -nPrtHeight
);
312 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*this);
313 aRectFnSet
.SubTop( aPrt
, nTmpDiff
);
318 setFrameAreaSizeValid(true);
321 SwTwips
SwFootnoteContFrame::GrowFrame( SwTwips nDist
, bool bTst
, bool )
323 // No check if FixSize since FootnoteContainer are variable up to their max. height.
324 // If the max. height is LONG_MAX, take as much space as needed.
325 // If the page is a special footnote page, take also as much as possible.
326 assert(GetUpper() && GetUpper()->IsFootnoteBossFrame());
328 SwRectFnSet
aRectFnSet(this);
329 if( aRectFnSet
.GetHeight(getFrameArea()) > 0 &&
330 nDist
> ( LONG_MAX
- aRectFnSet
.GetHeight(getFrameArea()) ) )
331 nDist
= LONG_MAX
- aRectFnSet
.GetHeight(getFrameArea());
333 SwFootnoteBossFrame
*pBoss
= static_cast<SwFootnoteBossFrame
*>(GetUpper());
336 SwSectionFrame
* pSect
= FindSctFrame();
337 OSL_ENSURE( pSect
, "GrowFrame: Missing SectFrame" );
338 // In a section, which has to maximize, a footnotecontainer is allowed
339 // to grow, when the section can't grow anymore.
340 if( !bTst
&& !pSect
->IsColLocked() &&
341 pSect
->ToMaximize( false ) && pSect
->Growable() )
343 pSect
->InvalidateSize();
347 const SwViewShell
*pSh
= getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
348 const bool bBrowseMode
= pSh
&& pSh
->GetViewOptions()->getBrowseMode();
349 SwPageFrame
*pPage
= pBoss
->FindPageFrame();
350 if ( bBrowseMode
|| !pPage
->IsFootnotePage() )
352 if ( pBoss
->GetMaxFootnoteHeight() != LONG_MAX
)
354 nDist
= std::min( nDist
,
355 SwTwips(pBoss
->GetMaxFootnoteHeight() - aRectFnSet
.GetHeight(getFrameArea())) );
359 // FootnoteBoss also influences the max value
362 const SwTwips nMax
= pBoss
->GetVarSpace();
369 else if( nDist
> aRectFnSet
.GetHeight(GetPrev()->getFrameArea()) )
370 // do not use more space than the body has
371 nDist
= aRectFnSet
.GetHeight(GetPrev()->getFrameArea());
373 tools::Long nAvail
= 0;
376 nAvail
= GetUpper()->getFramePrintArea().Height();
377 const SwFrame
*pAvail
= GetUpper()->Lower();
379 { nAvail
-= pAvail
->getFrameArea().Height();
380 pAvail
= pAvail
->GetNext();
382 if ( nAvail
> nDist
)
388 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
389 aRectFnSet
.SetHeight( aFrm
, aRectFnSet
.GetHeight(aFrm
) + nDist
);
391 if( IsVertical() && !IsVertLR() )
393 aFrm
.Pos().AdjustX( -nDist
);
396 tools::Long nGrow
= nDist
- nAvail
,
400 SwNeighbourAdjust nAdjust
= pBoss
->NeighbourhoodAdjustment();
401 if( SwNeighbourAdjust::OnlyAdjust
== nAdjust
)
402 nReal
= AdjustNeighbourhood( nGrow
, bTst
);
405 if( SwNeighbourAdjust::GrowAdjust
== nAdjust
)
407 SwFrame
* pFootnote
= Lower();
410 while( pFootnote
->GetNext() )
411 pFootnote
= pFootnote
->GetNext();
412 if( static_cast<SwFootnoteFrame
*>(pFootnote
)->GetAttr()->GetFootnote().IsEndNote() )
414 nReal
= AdjustNeighbourhood( nGrow
, bTst
);
415 nAdjust
= SwNeighbourAdjust::GrowShrink
; // no more AdjustNeighbourhood
419 nReal
+= pBoss
->Grow( nGrow
- nReal
, bTst
);
420 if( ( SwNeighbourAdjust::GrowAdjust
== nAdjust
|| SwNeighbourAdjust::AdjustGrow
== nAdjust
)
422 nReal
+= AdjustNeighbourhood( nGrow
- nReal
, bTst
);
430 if ( nReal
!= nDist
)
434 // We can only respect the boundless wish so much
435 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
436 aFrm
.AddHeight( -nDist
);
438 if( IsVertical() && !IsVertLR() )
440 aFrm
.Pos().AdjustX(nDist
);
444 // growing happens upwards, so successors to not need to be invalidated
449 InvalidatePage( pPage
);
455 SwTwips
SwFootnoteContFrame::ShrinkFrame( SwTwips nDiff
, bool bTst
, bool bInfo
)
457 SwPageFrame
*pPage
= FindPageFrame();
458 bool bShrink
= false;
461 if( !pPage
->IsFootnotePage() )
465 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
466 if( pSh
&& pSh
->GetViewOptions()->getBrowseMode() )
472 SwTwips nRet
= SwLayoutFrame::ShrinkFrame( nDiff
, bTst
, bInfo
);
473 if( IsInSct() && !bTst
)
474 FindSctFrame()->InvalidateNextPos();
478 InvalidatePage( pPage
);
485 SwFootnoteFrame::SwFootnoteFrame( SwFrameFormat
*pFormat
, SwFrame
* pSib
, SwContentFrame
*pCnt
, SwTextFootnote
*pAt
):
486 SwLayoutFrame( pFormat
, pSib
),
491 mbBackMoveLocked( false ),
493 mbUnlockPosOfLowerObjs( true )
495 mnFrameType
= SwFrameType::Ftn
;
498 void SwFootnoteFrame::InvalidateNxtFootnoteCnts( SwPageFrame
const *pPage
)
503 SwFrame
*pCnt
= static_cast<SwLayoutFrame
*>(GetNext())->ContainsAny();
507 pCnt
->InvalidatePage( pPage
);
508 pCnt
->InvalidatePrt_();
510 { pCnt
->InvalidatePos_();
511 if( pCnt
->IsSctFrame() )
513 SwFrame
* pTmp
= static_cast<SwSectionFrame
*>(pCnt
)->ContainsAny();
515 pTmp
->InvalidatePos_();
517 pCnt
->GetUpper()->InvalidateSize_();
518 pCnt
= pCnt
->FindNext();
519 } while ( pCnt
&& GetUpper()->IsAnLower( pCnt
) );
522 bool SwFootnoteFrame::IsDeleteForbidden() const
524 if (SwLayoutFrame::IsDeleteForbidden())
526 // needs to be in sync with the ::Cut logic
527 const SwLayoutFrame
*pUp
= GetUpper();
533 // The last footnote takes its container along if it
534 // is deleted. Cut would put pUp->Lower() to the value
535 // of GetNext(), so if there is no GetNext then
536 // Cut would delete pUp. If that condition is true
537 // here then check if the container is delete-forbidden
538 return !GetNext() && pUp
->IsDeleteForbidden();
543 void SwFootnoteFrame::Cut()
546 GetNext()->InvalidatePos();
547 else if ( GetPrev() )
548 GetPrev()->SetRetouche();
550 // first move then shrink Upper
551 SwLayoutFrame
*pUp
= GetUpper();
554 SwFootnoteFrame
*pFootnote
= this;
555 if ( pFootnote
->GetFollow() )
556 pFootnote
->GetFollow()->SetMaster( pFootnote
->GetMaster() );
557 if ( pFootnote
->GetMaster() )
558 pFootnote
->GetMaster()->SetFollow( pFootnote
->GetFollow() );
559 pFootnote
->SetFollow( nullptr );
560 pFootnote
->SetMaster( nullptr );
562 // cut all connections
568 // The last footnote takes its container along
571 SwPageFrame
*pPage
= pUp
->FindPageFrame();
574 SwLayoutFrame
*pBody
= pPage
->FindBodyCont();
575 if( pBody
&& !pBody
->ContainsContent() )
576 pPage
->getRootFrame()->SetSuperfluous();
578 SwSectionFrame
* pSect
= pUp
->FindSctFrame();
580 SwFrame::DestroyFrame(pUp
);
581 // If the last footnote container was removed from a column
582 // section without a Follow, then this section can be shrunk.
583 if( pSect
&& !pSect
->ToMaximize( false ) && !pSect
->IsColLocked() )
584 pSect
->InvalidateSize_();
587 { if ( getFrameArea().Height() )
588 pUp
->Shrink( getFrameArea().Height() );
589 pUp
->SetCompletePaint();
590 pUp
->InvalidatePage();
594 void SwFootnoteFrame::Paste( SwFrame
* pParent
, SwFrame
* pSibling
)
596 OSL_ENSURE( pParent
, "no parent in Paste." );
597 OSL_ENSURE( pParent
->IsLayoutFrame(), "Parent is ContentFrame." );
598 OSL_ENSURE( pParent
!= this, "I am my own parent." );
599 OSL_ENSURE( pSibling
!= this, "I am my own sibling." );
600 OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
601 "I am still somewhere registered." );
603 // insert into tree structure
604 InsertBefore( static_cast<SwLayoutFrame
*>(pParent
), pSibling
);
606 SwRectFnSet
aRectFnSet(this);
607 if( aRectFnSet
.GetWidth(getFrameArea())!=aRectFnSet
.GetWidth(pParent
->getFramePrintArea()) )
610 if (SwFrame
*const pContent
= ContainsContent())
611 { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
612 pContent
->InvalidatePrt_();
614 SwPageFrame
*pPage
= FindPageFrame();
615 InvalidatePage( pPage
);
616 if (SwFootnoteFrame
*const pNext
= static_cast<SwFootnoteFrame
*>(GetNext()))
618 pNext
->InvalidatePos_();
619 if (SwFrame
*const pContent
= pNext
->ContainsContent())
620 { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
621 pContent
->InvalidatePrt_();
624 if( aRectFnSet
.GetHeight(getFrameArea()) )
625 pParent
->Grow( aRectFnSet
.GetHeight(getFrameArea()) );
627 // If the predecessor is the master and/or the successor is the Follow,
628 // then take their content and destroy them.
629 if ( GetPrev() && GetPrev() == GetMaster() )
631 OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetPrev()->GetLower() ),
632 "Footnote without content?" );
633 SwFlowFrame::CastFlowFrame( GetPrev()->GetLower())->
634 MoveSubTree( this, GetLower() );
635 SwFrame
*pDel
= GetPrev();
636 assert(pDel
!= this);
638 SwFrame::DestroyFrame(pDel
);
640 if ( GetNext() && GetNext() == GetFollow() )
642 OSL_ENSURE( SwFlowFrame::CastFlowFrame( GetNext()->GetLower() ),
643 "Footnote without content?" );
644 SwFlowFrame::CastFlowFrame( GetNext()->GetLower() )->MoveSubTree( this );
645 SwFrame
*pDel
= GetNext();
646 assert(pDel
!= this);
648 SwFrame::DestroyFrame(pDel
);
650 #if OSL_DEBUG_LEVEL > 0
651 SwDoc
*pDoc
= GetFormat()->GetDoc();
654 OSL_ENSURE( lcl_FindFootnotePos( pDoc
, static_cast<SwFootnoteFrame
*>(GetPrev())->GetAttr() ) <=
655 lcl_FindFootnotePos( pDoc
, GetAttr() ), "Prev is not FootnotePrev" );
659 OSL_ENSURE( lcl_FindFootnotePos( pDoc
, GetAttr() ) <=
660 lcl_FindFootnotePos( pDoc
, static_cast<SwFootnoteFrame
*>(GetNext())->GetAttr() ),
661 "Next is not FootnoteNext" );
664 InvalidateNxtFootnoteCnts( pPage
);
667 /// Return the next layout leaf in that the frame can be moved.
668 /// New pages will only be created if specified by the parameter.
669 SwLayoutFrame
*SwFrame::GetNextFootnoteLeaf( MakePageType eMakePage
)
671 SwFootnoteBossFrame
*pOldBoss
= FindFootnoteBossFrame();
672 SwPageFrame
* pOldPage
= pOldBoss
->FindPageFrame();
674 SwFootnoteBossFrame
*pBoss
= pOldBoss
->IsColumnFrame() ?
675 static_cast<SwFootnoteBossFrame
*>(pOldBoss
->GetNext()) : nullptr; // next column, if existing
680 if( pOldBoss
->GetUpper()->IsSctFrame() )
681 { // this can only be in a column area
682 SwLayoutFrame
* pNxt
= pOldBoss
->GetNextSctLeaf( eMakePage
);
685 OSL_ENSURE( pNxt
->IsColBodyFrame(), "GetNextFootnoteLeaf: Funny Leaf" );
686 pBoss
= static_cast<SwFootnoteBossFrame
*>(pNxt
->GetUpper());
687 pPage
= pBoss
->FindPageFrame();
695 pPage
= static_cast<SwPageFrame
*>(pOldPage
->GetNext());
697 if( pPage
&& pPage
->IsEmptyPage() )
698 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
702 // What do we have until here?
703 // pBoss != NULL, pPage==NULL => pBoss is the next column on the same page
704 // pBoss != NULL, pPage!=NULL => pBoss and pPage are the following page (empty pages skipped)
705 // pBoss == NULL => pPage == NULL, so there are no following pages
707 // If the footnote has already a Follow we do not need to search.
708 // However, if there are unwanted empty columns/pages between Footnote and Follow,
709 // create another Follow on the next best column/page and the rest will sort itself out.
710 SwFootnoteFrame
*pFootnote
= FindFootnoteFrame();
711 if ( pFootnote
&& pFootnote
->GetFollow() )
713 SwFootnoteBossFrame
* pTmpBoss
= pFootnote
->GetFollow()->FindFootnoteBossFrame();
714 // Following cases will be handled:
715 // 1. both "FootnoteBoss"es are neighboring columns/pages
716 // 2. the new one is the first column of a neighboring page
717 // 3. the new one is the first column in a section of the next page
718 while( pTmpBoss
!= pBoss
&& pTmpBoss
&& !pTmpBoss
->GetPrev() )
719 pTmpBoss
= pTmpBoss
->GetUpper()->FindFootnoteBossFrame();
720 if( pTmpBoss
== pBoss
)
721 return pFootnote
->GetFollow();
724 // If no pBoss could be found or it is a "wrong" page, we need a new page.
725 if ( !pBoss
|| ( pPage
&& pPage
->IsEndNotePage() && !pOldPage
->IsEndNotePage() ) )
727 if ( eMakePage
== MAKEPAGE_APPEND
|| eMakePage
== MAKEPAGE_INSERT
)
729 pBoss
= InsertPage( pOldPage
, pOldPage
->IsFootnotePage() );
730 static_cast<SwPageFrame
*>(pBoss
)->SetEndNotePage( pOldPage
->IsEndNotePage() );
735 if( pBoss
->IsPageFrame() )
737 // If this page has columns, then go to the first one
738 SwLayoutFrame
* pLay
= pBoss
->FindBodyCont();
739 if( pLay
&& pLay
->Lower() && pLay
->Lower()->IsColumnFrame() )
740 pBoss
= static_cast<SwFootnoteBossFrame
*>(pLay
->Lower());
742 // found column/page - add myself
743 SwFootnoteContFrame
*pCont
= pBoss
->FindFootnoteCont();
744 if ( !pCont
&& pBoss
->GetMaxFootnoteHeight() &&
745 ( eMakePage
== MAKEPAGE_APPEND
|| eMakePage
== MAKEPAGE_INSERT
) )
746 pCont
= pBoss
->MakeFootnoteCont();
750 /// Get the preceding layout leaf in that the frame can be moved.
751 SwLayoutFrame
*SwFrame::GetPrevFootnoteLeaf( MakePageType eMakeFootnote
)
753 // The predecessor of a footnote is (if possible)
754 // the master of the chain of the footnote.
755 SwFootnoteFrame
*pFootnote
= FindFootnoteFrame();
756 SwLayoutFrame
*pRet
= pFootnote
->GetMaster();
758 SwFootnoteBossFrame
* pOldBoss
= FindFootnoteBossFrame();
759 SwPageFrame
*pOldPage
= pOldBoss
->FindPageFrame();
761 if ( !pOldBoss
->GetPrev() && !pOldPage
->GetPrev() )
762 return pRet
; // there is neither a predecessor column nor page
766 bool bEndn
= pFootnote
->GetAttr()->GetFootnote().IsEndNote();
767 SwFrame
* pTmpRef
= nullptr;
768 const IDocumentSettingAccess
& rSettings
769 = pFootnote
->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
770 if( bEndn
&& pFootnote
->IsInSct() )
772 SwSectionFrame
* pSect
= pFootnote
->FindSctFrame();
773 if( pSect
->IsEndnAtEnd() )
774 // Endnotes at the end of the section.
775 pTmpRef
= pSect
->FindLastContent( SwFindMode::LastCnt
);
777 else if (bEndn
&& rSettings
.get(DocumentSettingId::CONTINUOUS_ENDNOTES
))
779 // Endnotes at the end of the document.
780 SwPageFrame
* pPage
= getRootFrame()->GetLastPage();
782 SwFrame
* pPrevPage
= pPage
->GetPrev();
785 // Have a last but one page, use that since we try to get a preceding frame.
786 assert(pPrevPage
->IsPageFrame());
787 pPage
= static_cast<SwPageFrame
*>(pPrevPage
);
789 pTmpRef
= pPage
->FindLastBodyContent();
792 // Endnotes on a separate page.
793 pTmpRef
= pFootnote
->GetRef();
794 SwFootnoteBossFrame
* pStop
= pTmpRef
->FindFootnoteBossFrame( !bEndn
);
796 const sal_uInt16 nNum
= pStop
->GetPhyPageNum();
798 // Do not leave the corresponding page if the footnote should
799 // be shown at the document ending or the footnote is an endnote.
800 const bool bEndNote
= pOldPage
->IsEndNotePage();
801 const bool bFootnoteEndDoc
= pOldPage
->IsFootnotePage();
802 SwFootnoteBossFrame
* pNxtBoss
= pOldBoss
;
803 SwSectionFrame
*pSect
= pNxtBoss
->GetUpper()->IsSctFrame() ?
804 static_cast<SwSectionFrame
*>(pNxtBoss
->GetUpper()) : nullptr;
808 if( pNxtBoss
->IsColumnFrame() && pNxtBoss
->GetPrev() )
809 pNxtBoss
= static_cast<SwFootnoteBossFrame
*>(pNxtBoss
->GetPrev()); // one column backwards
810 else // one page backwards
812 SwLayoutFrame
* pBody
= nullptr;
815 if( pSect
->IsFootnoteLock() )
817 if( pNxtBoss
== pOldBoss
)
823 pSect
= pSect
->FindMaster();
824 if( !pSect
|| !pSect
->Lower() )
826 OSL_ENSURE( pSect
->Lower()->IsColumnFrame(),
827 "GetPrevFootnoteLeaf: Where's the column?" );
828 pNxtBoss
= static_cast<SwFootnoteBossFrame
*>(pSect
->Lower());
834 SwPageFrame
* pPage
= static_cast<SwPageFrame
*>(pNxtBoss
->FindPageFrame()->GetPrev());
835 if( !pPage
|| pPage
->GetPhyPageNum() < nNum
||
836 bEndNote
!= pPage
->IsEndNotePage() || bFootnoteEndDoc
!= pPage
->IsFootnotePage() )
837 return nullptr; // no further pages found
839 pBody
= pPage
->FindBodyCont();
841 // We have the previous page, we might need to find the last column of it
844 if ( pBody
->Lower() && pBody
->Lower()->IsColumnFrame() )
846 pNxtBoss
= static_cast<SwFootnoteBossFrame
*>(pBody
->GetLastLower());
850 SwFootnoteContFrame
*pCont
= pNxtBoss
->FindFootnoteCont();
856 if ( pStop
== pNxtBoss
)
858 // Reached the column/page of the reference.
859 // Try to add a container and paste our content.
860 if ( eMakeFootnote
== MAKEPAGE_FTN
&& pNxtBoss
->GetMaxFootnoteHeight() )
861 pRet
= pNxtBoss
->MakeFootnoteCont();
868 const SwFootnoteBossFrame
* pNewBoss
= pRet
->FindFootnoteBossFrame();
870 if( pOldBoss
->IsColumnFrame() && pOldBoss
->GetPrev() ) // a previous column exists
871 bJump
= pOldBoss
->GetPrev() != static_cast<SwFrame
const *>(pNewBoss
); // did we chose it?
872 else if( pNewBoss
->IsColumnFrame() && pNewBoss
->GetNext() )
873 bJump
= true; // there is another column after the boss (not the old boss)
876 // Will be reached only if old and new boss are both either pages or the last (new)
877 // or first (old) column of a page. In this case, check if pages were skipped.
878 const sal_uInt16 nDiff
= pOldPage
->GetPhyPageNum() - pRet
->FindPageFrame()->GetPhyPageNum();
880 (nDiff
> 1 && !static_cast<SwPageFrame
*>(pOldPage
->GetPrev())->IsEmptyPage()) )
884 SwFlowFrame::SetMoveBwdJump( true );
889 bool SwFrame::IsFootnoteAllowed() const
891 if ( !IsInDocBody() )
896 // no footnotes in repeated headlines
897 const SwTabFrame
*pTab
= const_cast<SwFrame
*>(this)->ImplFindTabFrame();
899 if ( pTab
->IsFollow() )
900 return !pTab
->IsInHeadline( *this );
905 void SwRootFrame::UpdateFootnoteNums()
907 // page numbering only if set at the document
908 if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum
== FTNNUM_PAGE
)
910 SwPageFrame
*pPage
= static_cast<SwPageFrame
*>(Lower());
911 while ( pPage
&& !pPage
->IsFootnotePage() )
913 pPage
->UpdateFootnoteNum();
914 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
919 /// remove all footnotes (not the references) and all footnote pages
920 void sw_RemoveFootnotes( SwFootnoteBossFrame
* pBoss
, bool bPageOnly
, bool bEndNotes
)
924 SwFootnoteContFrame
*pCont
= pBoss
->FindFootnoteCont();
927 SwFootnoteFrame
*pFootnote
= static_cast<SwFootnoteFrame
*>(pCont
->Lower());
930 while ( pFootnote
->GetMaster() )
931 pFootnote
= pFootnote
->GetMaster();
934 SwFootnoteFrame
*pNxt
= static_cast<SwFootnoteFrame
*>(pFootnote
->GetNext());
935 if ( !pFootnote
->GetAttr()->GetFootnote().IsEndNote() ||
938 pFootnote
->GetRef()->Prepare( PrepareHint::FootnoteInvalidation
, static_cast<void*>(pFootnote
->GetAttr()) );
939 if ( bPageOnly
&& !pNxt
)
940 pNxt
= pFootnote
->GetFollow();
942 SwFrame::DestroyFrame(pFootnote
);
946 } while ( pFootnote
);
948 if( !pBoss
->IsInSct() )
950 // A sectionframe with the Footnote/EndnAtEnd-flags may contain
951 // foot/endnotes. If the last lower frame of the bodyframe is
952 // a multicolumned sectionframe, it may contain footnotes, too.
953 SwLayoutFrame
* pBody
= pBoss
->FindBodyCont();
954 if( pBody
&& pBody
->Lower() )
956 SwFrame
* pLow
= pBody
->Lower();
959 if( pLow
->IsSctFrame() && ( !pLow
->GetNext() ||
960 static_cast<SwSectionFrame
*>(pLow
)->IsAnyNoteAtEnd() ) &&
961 static_cast<SwSectionFrame
*>(pLow
)->Lower() &&
962 static_cast<SwSectionFrame
*>(pLow
)->Lower()->IsColumnFrame() )
963 sw_RemoveFootnotes( static_cast<SwColumnFrame
*>(static_cast<SwSectionFrame
*>(pLow
)->Lower()),
964 bPageOnly
, bEndNotes
);
965 pLow
= pLow
->GetNext();
969 // is there another column?
970 pBoss
= pBoss
->IsColumnFrame() ? static_cast<SwColumnFrame
*>(pBoss
->GetNext()) : nullptr;
974 void SwRootFrame::RemoveFootnotes( SwPageFrame
*pPage
, bool bPageOnly
, bool bEndNotes
)
977 pPage
= static_cast<SwPageFrame
*>(Lower());
980 { // On columned pages we have to clean up in all columns
981 SwFootnoteBossFrame
* pBoss
;
982 SwLayoutFrame
* pBody
= pPage
->FindBodyCont();
983 if( pBody
&& pBody
->Lower() && pBody
->Lower()->IsColumnFrame() )
984 pBoss
= static_cast<SwFootnoteBossFrame
*>(pBody
->Lower()); // the first column
986 pBoss
= pPage
; // no columns
987 sw_RemoveFootnotes( pBoss
, bPageOnly
, bEndNotes
);
990 if ( pPage
->IsFootnotePage() &&
991 (!pPage
->IsEndNotePage() || bEndNotes
) )
993 SwFrame
*pDel
= pPage
;
994 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
996 SwFrame::DestroyFrame(pDel
);
999 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
1007 /// Change the page template of the footnote pages
1008 void SwRootFrame::CheckFootnotePageDescs( bool bEndNote
)
1010 SwPageFrame
*pPage
= static_cast<SwPageFrame
*>(Lower());
1011 while ( pPage
&& !pPage
->IsFootnotePage() )
1012 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
1013 while ( pPage
&& pPage
->IsEndNotePage() != bEndNote
)
1014 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
1017 SwFrame::CheckPageDescs( pPage
, false );
1020 /** Insert a footnote container
1022 * A footnote container is always placed directly behind the body text.
1024 * The frame format (FrameFormat) is always the default frame format.
1026 * @return footnote container frame
1028 SwFootnoteContFrame
*SwFootnoteBossFrame::MakeFootnoteCont()
1030 SAL_WARN_IF(FindFootnoteCont(), "sw.core", "footnote container exists already");
1032 SwFootnoteContFrame
*pNew
= new SwFootnoteContFrame( GetFormat()->GetDoc()->GetDfltFrameFormat(), this );
1033 SwLayoutFrame
*pLay
= FindBodyCont();
1034 pNew
->Paste( this, pLay
->GetNext() );
1038 SwFootnoteContFrame
*SwFootnoteBossFrame::FindFootnoteCont()
1040 SwFrame
*pFrame
= Lower();
1041 while( pFrame
&& !pFrame
->IsFootnoteContFrame() )
1042 pFrame
= pFrame
->GetNext();
1044 #if OSL_DEBUG_LEVEL > 0
1047 SwFrame
*pFootnote
= pFrame
->GetLower();
1051 assert(pFootnote
->IsFootnoteFrame() && "Neighbor of footnote must be a footnote");
1052 pFootnote
= pFootnote
->GetNext();
1057 return static_cast<SwFootnoteContFrame
*>(pFrame
);
1060 /// Search the next available footnote container.
1061 SwFootnoteContFrame
*SwFootnoteBossFrame::FindNearestFootnoteCont( bool bDontLeave
)
1063 SwFootnoteContFrame
*pCont
= nullptr;
1064 if ( !GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
1066 pCont
= FindFootnoteCont();
1069 SwPageFrame
*pPage
= FindPageFrame();
1070 SwFootnoteBossFrame
* pBoss
= this;
1071 bool bEndNote
= pPage
->IsEndNotePage();
1074 bool bChgPage
= lcl_NextFootnoteBoss( pBoss
, pPage
, bDontLeave
);
1075 // Found another boss? When changing pages, also the endnote flag must match.
1076 if( pBoss
&& ( !bChgPage
|| pPage
->IsEndNotePage() == bEndNote
) )
1077 pCont
= pBoss
->FindFootnoteCont();
1078 } while ( !pCont
&& pPage
);
1084 SwFootnoteFrame
*SwFootnoteBossFrame::FindFirstFootnote()
1086 // search for the nearest footnote container
1087 SwFootnoteContFrame
*pCont
= FindNearestFootnoteCont();
1091 // Starting from the first footnote, search the first
1092 // footnote that is referenced by the current column/page
1094 SwFootnoteFrame
*pRet
= static_cast<SwFootnoteFrame
*>(pCont
->Lower());
1095 const sal_uInt16 nRefNum
= FindPageFrame()->GetPhyPageNum();
1096 const sal_uInt16 nRefCol
= lcl_ColumnNum( this );
1097 sal_uInt16 nPgNum
, nColNum
; // page number, column number
1098 SwFootnoteBossFrame
* pBoss
;
1102 pBoss
= pRet
->GetRef()->FindFootnoteBossFrame();
1103 OSL_ENSURE( pBoss
, "FindFirstFootnote: No boss found" );
1105 return nullptr; // ?There must be a bug, but no GPF
1106 pPage
= pBoss
->FindPageFrame();
1107 nPgNum
= pPage
->GetPhyPageNum();
1108 if ( nPgNum
== nRefNum
)
1110 nColNum
= lcl_ColumnNum( pBoss
);
1111 if( nColNum
== nRefCol
)
1112 return pRet
; // found
1113 else if( nColNum
> nRefCol
)
1114 return nullptr; // at least one column too far
1116 else if ( nPgNum
> nRefNum
)
1117 return nullptr; // at least one column too far
1121 // Done if Ref is on a subsequent page or on the same page in a subsequent column
1125 while ( pRet
->GetFollow() )
1126 pRet
= pRet
->GetFollow();
1128 SwFootnoteFrame
*pNxt
= static_cast<SwFootnoteFrame
*>(pRet
->GetNext());
1131 pBoss
= pRet
->FindFootnoteBossFrame();
1132 pPage
= pBoss
->FindPageFrame();
1133 lcl_NextFootnoteBoss( pBoss
, pPage
, false ); // next FootnoteBoss
1134 pCont
= pBoss
? pBoss
->FindNearestFootnoteCont() : nullptr;
1136 pNxt
= static_cast<SwFootnoteFrame
*>(pCont
->Lower());
1141 pBoss
= pRet
->GetRef()->FindFootnoteBossFrame();
1142 pPage
= pBoss
->FindPageFrame();
1143 nPgNum
= pPage
->GetPhyPageNum();
1144 if ( nPgNum
== nRefNum
)
1146 nColNum
= lcl_ColumnNum( pBoss
);
1147 if( nColNum
== nRefCol
)
1149 else if( nColNum
> nRefCol
)
1150 pRet
= nullptr; // at least one column too far
1152 else if ( nPgNum
> nRefNum
)
1153 pRet
= nullptr; // at least a page too far
1156 pRet
= nullptr; // there is none
1161 /// Get the first footnote of a given content
1162 const SwFootnoteFrame
*SwFootnoteBossFrame::FindFirstFootnote( SwContentFrame
const *pCnt
) const
1164 const SwFootnoteFrame
*pRet
= const_cast<SwFootnoteBossFrame
*>(this)->FindFirstFootnote();
1167 const sal_uInt16 nColNum
= lcl_ColumnNum( this );
1168 const sal_uInt16 nPageNum
= GetPhyPageNum();
1169 while ( pRet
&& (pRet
->GetRef() != pCnt
) )
1171 while ( pRet
->GetFollow() )
1172 pRet
= pRet
->GetFollow();
1174 if ( pRet
->GetNext() )
1175 pRet
= static_cast<const SwFootnoteFrame
*>(pRet
->GetNext());
1177 { SwFootnoteBossFrame
*pBoss
= const_cast<SwFootnoteBossFrame
*>(pRet
->FindFootnoteBossFrame());
1178 SwPageFrame
*pPage
= pBoss
->FindPageFrame();
1179 lcl_NextFootnoteBoss( pBoss
, pPage
, false ); // next FootnoteBoss
1180 SwFootnoteContFrame
*pCont
= pBoss
? pBoss
->FindNearestFootnoteCont() : nullptr;
1181 pRet
= pCont
? static_cast<SwFootnoteFrame
*>(pCont
->Lower()) : nullptr;
1185 const SwFootnoteBossFrame
* pBoss
= pRet
->GetRef()->FindFootnoteBossFrame();
1186 if( !pBoss
|| pBoss
->GetPhyPageNum() != nPageNum
||
1187 nColNum
!= lcl_ColumnNum( pBoss
) )
1195 void SwFootnoteBossFrame::ResetFootnote( const SwFootnoteFrame
*pCheck
)
1197 // Destroy the incarnations of footnotes to an attribute, if they don't
1198 // belong to pAssumed
1199 OSL_ENSURE( !pCheck
->GetMaster(), "given master is not a Master." );
1201 SwNodeIndex
aIdx( *pCheck
->GetAttr()->GetStartNode(), 1 );
1202 SwContentNode
*pNd
= aIdx
.GetNode().GetContentNode();
1204 pNd
= pCheck
->GetFormat()->GetDoc()->
1205 GetNodes().GoNextSection( &aIdx
, true, false );
1206 SwIterator
<SwFrame
, SwContentNode
, sw::IteratorMode::UnwrapMulti
> aIter(*pNd
);
1207 SwFrame
* pFrame
= aIter
.First();
1210 if( pFrame
->getRootFrame() == pCheck
->getRootFrame() )
1212 SwFrame
*pTmp
= pFrame
->GetUpper();
1213 while ( pTmp
&& !pTmp
->IsFootnoteFrame() )
1214 pTmp
= pTmp
->GetUpper();
1216 SwFootnoteFrame
*pFootnote
= static_cast<SwFootnoteFrame
*>(pTmp
);
1217 while ( pFootnote
&& pFootnote
->GetMaster() )
1218 pFootnote
= pFootnote
->GetMaster();
1219 if ( pFootnote
!= pCheck
)
1221 while (pFootnote
&& !pFootnote
->IsDeleteForbidden())
1223 SwFootnoteFrame
*pNxt
= pFootnote
->GetFollow();
1225 SwFrame::DestroyFrame(pFootnote
);
1231 pFrame
= aIter
.Next();
1235 void SwFootnoteBossFrame::InsertFootnote( SwFootnoteFrame
* pNew
)
1237 // Place the footnote in front of the footnote whose attribute
1238 // is in front of the new one (get position via the Doc).
1239 // If there is no footnote in this footnote-boss yet, create a new container.
1240 // If there is a container but no footnote for this footnote-boss yet, place
1241 // the footnote behind the last footnote of the closest previous column/page.
1243 ResetFootnote( pNew
);
1244 SwFootnoteFrame
*pSibling
= FindFirstFootnote();
1245 bool bDontLeave
= false;
1247 // Ok, a sibling has been found, but is the sibling in an acceptable
1251 SwSectionFrame
* pMySect
= ImplFindSctFrame();
1252 bool bEndnt
= pNew
->GetAttr()->GetFootnote().IsEndNote();
1255 const SwSectionFormat
* pEndFormat
= pMySect
->GetEndSectFormat();
1256 bDontLeave
= nullptr != pEndFormat
;
1261 if( !pSibling
->IsInSct() ||
1262 !pSibling
->ImplFindSctFrame()->IsDescendantFrom( pEndFormat
) )
1265 else if( pSibling
->IsInSct() )
1271 bDontLeave
= pMySect
->IsFootnoteAtEnd();
1274 if( pMySect
->IsFootnoteAtEnd() )
1276 if( !pSibling
->IsInSct() ||
1277 !pMySect
->IsAnFollow( pSibling
->ImplFindSctFrame() ) )
1280 else if( pSibling
->IsInSct() )
1286 if( pSibling
&& pSibling
->FindPageFrame()->IsEndNotePage() !=
1287 FindPageFrame()->IsEndNotePage() )
1290 // use the Doc to find out the position
1291 SwDoc
*pDoc
= GetFormat()->GetDoc();
1292 const sal_uLong nStPos
= ::lcl_FindFootnotePos( pDoc
, pNew
->GetAttr() );
1294 sal_uLong nCmpPos
= 0;
1295 sal_uLong nLastPos
= 0;
1296 SwFootnoteContFrame
*pParent
= nullptr;
1299 nCmpPos
= ::lcl_FindFootnotePos( pDoc
, pSibling
->GetAttr() );
1300 if( nCmpPos
> nStPos
)
1305 { pParent
= FindFootnoteCont();
1308 // There is no footnote container yet. Before creating one, keep in mind that
1309 // there might exist another following footnote that must be placed before the
1310 // new inserted one e.g. because it was divided over multiple pages etc.
1311 pParent
= FindNearestFootnoteCont( bDontLeave
);
1314 SwFootnoteFrame
*pFootnote
= static_cast<SwFootnoteFrame
*>(pParent
->Lower());
1318 nCmpPos
= ::lcl_FindFootnotePos( pDoc
, pFootnote
->GetAttr() );
1319 if ( nCmpPos
> nStPos
)
1327 // here, we are sure that we can create a footnote container
1328 pParent
= MakeFootnoteCont();
1331 // Based on the first footnote below the Parent, search for the first footnote whose
1332 // index is after the index of the newly inserted, to place the new one correctly
1333 pSibling
= static_cast<SwFootnoteFrame
*>(pParent
->Lower());
1336 OSL_ENSURE( false, "Could not find space for footnote.");
1339 nCmpPos
= ::lcl_FindFootnotePos( pDoc
, pSibling
->GetAttr() );
1341 SwFootnoteBossFrame
*pNxtB
; // remember the last one to not
1342 SwFootnoteFrame
*pLastSib
= nullptr; // go too far.
1344 while ( pSibling
&& nCmpPos
<= nStPos
)
1346 pLastSib
= pSibling
; // potential candidate
1349 while ( pSibling
->GetFollow() )
1350 pSibling
= pSibling
->GetFollow();
1352 if ( pSibling
->GetNext() )
1354 pSibling
= static_cast<SwFootnoteFrame
*>(pSibling
->GetNext());
1355 OSL_ENSURE( !pSibling
->GetMaster() || ( ENDNOTE
> nStPos
&&
1356 pSibling
->GetAttr()->GetFootnote().IsEndNote() ),
1357 "InsertFootnote: Master expected I" );
1361 pNxtB
= pSibling
->FindFootnoteBossFrame();
1362 SwPageFrame
*pSibPage
= pNxtB
->FindPageFrame();
1363 bool bEndNote
= pSibPage
->IsEndNotePage();
1364 bool bChgPage
= lcl_NextFootnoteBoss( pNxtB
, pSibPage
, bDontLeave
);
1365 // When changing pages, also the endnote flag must match.
1366 SwFootnoteContFrame
*pCont
= pNxtB
&& ( !bChgPage
||
1367 pSibPage
->IsEndNotePage() == bEndNote
)
1368 ? pNxtB
->FindNearestFootnoteCont( bDontLeave
) : nullptr;
1370 pSibling
= static_cast<SwFootnoteFrame
*>(pCont
->Lower());
1371 else // no further FootnoteContainer, insert after pSibling
1376 nCmpPos
= ::lcl_FindFootnotePos( pDoc
, pSibling
->GetAttr() );
1377 OSL_ENSURE( nCmpPos
> nLastPos
, "InsertFootnote: Order of FootnoteFrame's buggy" );
1380 // pLastSib is the last footnote before the new one and
1381 // pSibling is empty or the first one after the new one
1382 if ( pSibling
&& pLastSib
&& (pSibling
!= pLastSib
) )
1385 if ( nCmpPos
> nStPos
)
1386 pSibling
= pLastSib
;
1388 else if ( !pSibling
)
1390 // Last chance: Take the last footnote of the parent.
1391 // Special case that happens e.g. when moving paragraphs with multiple footnotes.
1392 // To keep the order, use the parent of the last inspected footnote.
1393 pSibling
= pLastSib
;
1394 while( pSibling
->GetFollow() )
1395 pSibling
= pSibling
->GetFollow();
1396 OSL_ENSURE( !pSibling
->GetNext(), "InsertFootnote: Who's that guy?" );
1402 // First footnote of the column/page found. Now search from there for the first one on the
1403 // same column/page whose index is after the given one. The last one found is the predecessor.
1404 SwFootnoteBossFrame
* pBoss
= pNew
->GetRef()->FindFootnoteBossFrame(
1405 !pNew
->GetAttr()->GetFootnote().IsEndNote() );
1406 sal_uInt16 nRefNum
= pBoss
->GetPhyPageNum(); // page number of the new footnote
1407 sal_uInt16 nRefCol
= lcl_ColumnNum( pBoss
); // column number of the new footnote
1409 SwFootnoteFrame
*pLastSib
= nullptr;
1410 while ( pSibling
&& !bEnd
&& (nCmpPos
<= nStPos
) )
1412 pLastSib
= pSibling
;
1415 while ( pSibling
->GetFollow() )
1416 pSibling
= pSibling
->GetFollow();
1418 SwFootnoteFrame
*pFoll
= static_cast<SwFootnoteFrame
*>(pSibling
->GetNext());
1421 pBoss
= pSibling
->GetRef()->FindFootnoteBossFrame( !pSibling
->
1422 GetAttr()->GetFootnote().IsEndNote() );
1424 if( nStPos
>= ENDNOTE
||
1425 (nTmpRef
= pBoss
->GetPhyPageNum()) < nRefNum
||
1426 ( nTmpRef
== nRefNum
&& lcl_ColumnNum( pBoss
) <= nRefCol
))
1433 SwFootnoteBossFrame
* pNxtB
= pSibling
->FindFootnoteBossFrame();
1434 SwPageFrame
*pSibPage
= pNxtB
->FindPageFrame();
1435 bool bEndNote
= pSibPage
->IsEndNotePage();
1436 bool bChgPage
= lcl_NextFootnoteBoss( pNxtB
, pSibPage
, bDontLeave
);
1437 // When changing pages, also the endnote flag must match.
1438 SwFootnoteContFrame
*pCont
= pNxtB
&& ( !bChgPage
||
1439 pSibPage
->IsEndNotePage() == bEndNote
)
1440 ? pNxtB
->FindNearestFootnoteCont( bDontLeave
) : nullptr;
1442 pSibling
= static_cast<SwFootnoteFrame
*>(pCont
->Lower());
1446 if ( !bEnd
&& pSibling
)
1447 nCmpPos
= ::lcl_FindFootnotePos( pDoc
, pSibling
->GetAttr() );
1448 if (pSibling
&& (pSibling
!= pLastSib
))
1451 if ( (nLastPos
< nCmpPos
) && (nCmpPos
> nStPos
) )
1453 pSibling
= pLastSib
;
1461 nCmpPos
= ::lcl_FindFootnotePos( pDoc
, pSibling
->GetAttr() );
1462 if ( nCmpPos
< nStPos
)
1464 while ( pSibling
->GetFollow() )
1465 pSibling
= pSibling
->GetFollow();
1466 pParent
= static_cast<SwFootnoteContFrame
*>(pSibling
->GetUpper());
1467 pSibling
= static_cast<SwFootnoteFrame
*>(pSibling
->GetNext());
1471 if( pSibling
->GetMaster() )
1473 if( ENDNOTE
> nCmpPos
|| nStPos
>= ENDNOTE
)
1475 OSL_FAIL( "InsertFootnote: Master expected II" );
1477 pSibling
= pSibling
->GetMaster();
1478 while ( pSibling
->GetMaster() );
1481 pParent
= static_cast<SwFootnoteContFrame
*>(pSibling
->GetUpper());
1484 OSL_ENSURE( pParent
, "paste in space?" );
1485 pNew
->Paste( pParent
, pSibling
);
1488 static SwPageFrame
* lcl_GetApproximateFootnotePage(const bool bEnd
, const SwPageFrame
* pPage
,
1489 const SwDoc
*pDoc
, const SwTextFootnote
*pAttr
)
1491 // We can at least search the approximately correct page
1492 // to ensure that we will finish in finite time even if
1493 // hundreds of footnotes exist.
1494 const SwPageFrame
*pNxt
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
1495 const sal_uLong nStPos
= ::lcl_FindFootnotePos(pDoc
, pAttr
);
1496 while (pNxt
&& (bEnd
? pNxt
->IsEndNotePage() : pNxt
->IsFootnotePage() && !pNxt
->IsEndNotePage()))
1498 const SwFootnoteContFrame
*pCont
= pNxt
->FindFootnoteCont();
1499 if (pCont
&& pCont
->Lower())
1501 OSL_ENSURE( pCont
->Lower()->IsFootnoteFrame(), "no footnote in the container" );
1502 if (nStPos
> ::lcl_FindFootnotePos(pDoc
,
1503 static_cast<const SwFootnoteFrame
*>(pCont
->Lower())->GetAttr()))
1506 pNxt
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
1512 return const_cast<SwPageFrame
*>(pPage
);
1515 void SwFootnoteBossFrame::AppendFootnote( SwContentFrame
*pRef
, SwTextFootnote
*pAttr
)
1517 // If the footnote already exists, do nothing.
1518 if ( FindFootnote( pRef
, pAttr
) )
1521 // If footnotes are inserted at the end of the document,
1522 // we only need to search from the relevant page on.
1523 // If there is none yet, we need to create one.
1524 // If it is an Endnote, we need to search for or create an
1526 SwDoc
*pDoc
= GetFormat()->GetDoc();
1527 SwFootnoteBossFrame
*pBoss
= this;
1528 SwPageFrame
*pPage
= FindPageFrame();
1529 SwPageFrame
*pMyPage
= pPage
;
1530 bool bChgPage
= false;
1531 const bool bEnd
= pAttr
->GetFootnote().IsEndNote();
1534 const IDocumentSettingAccess
& rSettings
= *pAttr
->GetTextNode().getIDocumentSettingAccess();
1535 if( GetUpper()->IsSctFrame() &&
1536 static_cast<SwSectionFrame
*>(GetUpper())->IsEndnAtEnd() )
1538 // Endnotes at the end of the section.
1540 static_cast<SwSectionFrame
*>(GetUpper())->FindLastContent( SwFindMode::EndNote
);
1543 pBoss
= pLast
->FindFootnoteBossFrame();
1544 pPage
= pBoss
->FindPageFrame();
1547 else if (rSettings
.get(DocumentSettingId::CONTINUOUS_ENDNOTES
))
1549 // Endnotes at the end of the document.
1550 pBoss
= getRootFrame()->GetLastPage();
1551 pPage
= pBoss
->FindPageFrame();
1555 // Endnotes on a separate page.
1556 while ( pPage
->GetNext() && !pPage
->IsEndNotePage() )
1558 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
1561 if ( !pPage
->IsEndNotePage() )
1563 SwPageDesc
*pDesc
= pDoc
->GetEndNoteInfo().GetPageDesc( *pDoc
);
1564 pPage
= ::InsertNewPage( *pDesc
, pPage
->GetUpper(),
1565 !pPage
->OnRightPage(), false, false, true, nullptr );
1566 pPage
->SetEndNotePage( true );
1570 pPage
= lcl_GetApproximateFootnotePage(true, pPage
, pDoc
, pAttr
);
1573 else if( FTNPOS_CHAPTER
== pDoc
->GetFootnoteInfo().m_ePos
&& ( !GetUpper()->
1574 IsSctFrame() || !static_cast<SwSectionFrame
*>(GetUpper())->IsFootnoteAtEnd() ) )
1576 while ( pPage
->GetNext() && !pPage
->IsFootnotePage() &&
1577 !static_cast<SwPageFrame
*>(pPage
->GetNext())->IsEndNotePage() )
1579 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
1583 if ( !pPage
->IsFootnotePage() )
1585 SwPageDesc
*pDesc
= pDoc
->GetFootnoteInfo().GetPageDesc( *pDoc
);
1586 pPage
= ::InsertNewPage( *pDesc
, pPage
->GetUpper(),
1587 !pPage
->OnRightPage(), false, false, true, pPage
->GetNext() );
1591 pPage
= lcl_GetApproximateFootnotePage(false, pPage
, pDoc
, pAttr
);
1594 // For now, create a footnote and the corresponding content frames
1595 if ( !pAttr
->GetStartNode() )
1597 OSL_ENSURE( false, "no footnote content." );
1601 // If there is already a footnote content on the column/page,
1602 // another one cannot be created in a column area.
1603 if( pBoss
->IsInSct() && pBoss
->IsColumnFrame() && !pPage
->IsFootnotePage() )
1605 SwSectionFrame
* pSct
= pBoss
->FindSctFrame();
1606 if( bEnd
? !pSct
->IsEndnAtEnd() : !pSct
->IsFootnoteAtEnd() )
1608 SwFootnoteContFrame
* pFootnoteCont
= pSct
->FindFootnoteBossFrame(!bEnd
)->FindFootnoteCont();
1611 SwFootnoteFrame
* pTmp
= static_cast<SwFootnoteFrame
*>(pFootnoteCont
->Lower());
1613 while( pTmp
&& !pTmp
->GetAttr()->GetFootnote().IsEndNote() )
1614 pTmp
= static_cast<SwFootnoteFrame
*>(pTmp
->GetNext());
1615 if( pTmp
&& *pTmp
< pAttr
)
1621 SwFootnoteFrame
*pNew
= new SwFootnoteFrame( pDoc
->GetDfltFrameFormat(), this, pRef
, pAttr
);
1623 SwNodeIndex
aIdx( *pAttr
->GetStartNode(), 1 );
1624 ::InsertCnt_( pNew
, pDoc
, aIdx
.GetIndex() );
1626 // If the page was changed or newly created,
1627 // we need to place ourselves in the first column
1630 SwLayoutFrame
* pBody
= pPage
->FindBodyCont();
1631 OSL_ENSURE( pBody
, "AppendFootnote: NoPageBody?" );
1632 if( pBody
->Lower() && pBody
->Lower()->IsColumnFrame() )
1633 pBoss
= static_cast<SwFootnoteBossFrame
*>(pBody
->Lower());
1635 pBoss
= pPage
; // page if no columns exist
1637 pBoss
->InsertFootnote( pNew
);
1638 if ( pNew
->GetUpper() ) // inserted or not?
1640 ::RegistFlys( pNew
->FindPageFrame(), pNew
);
1641 SwSectionFrame
* pSect
= FindSctFrame();
1642 // The content of a FootnoteContainer in a (column) section only need to be calculated
1643 // if the section stretches already to the bottom edge of the Upper.
1644 if( pSect
&& !pSect
->IsJoinLocked() && ( bEnd
? !pSect
->IsEndnAtEnd() :
1645 !pSect
->IsFootnoteAtEnd() ) && pSect
->Growable() )
1646 pSect
->InvalidateSize();
1649 // #i49383# - disable unlock of position of
1650 // lower objects during format of footnote content.
1651 const bool bOldFootnoteFrameLocked( pNew
->IsColLocked() );
1653 pNew
->KeepLockPosOfLowerObjs();
1654 // #i57914# - adjust fix #i49383#
1655 SwContentFrame
*pCnt
= pNew
->ContainsContent();
1656 while ( pCnt
&& pCnt
->FindFootnoteFrame()->GetAttr() == pAttr
)
1658 pCnt
->Calc(getRootFrame()->GetCurrShell()->GetOut());
1659 // #i49383# - format anchored objects
1660 if ( pCnt
->IsTextFrame() && pCnt
->isFrameAreaDefinitionValid() )
1662 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt
,
1663 *(pCnt
->FindPageFrame()) ) )
1665 // restart format with first content
1666 pCnt
= pNew
->ContainsContent();
1670 pCnt
= pCnt
->FindNextCnt();
1673 if ( !bOldFootnoteFrameLocked
)
1677 // #i57914# - adjust fix #i49383#
1678 // enable lock of lower object position before format of footnote frame.
1679 pNew
->UnlockPosOfLowerObjs();
1680 pNew
->Calc(getRootFrame()->GetCurrShell()->GetOut());
1681 // #i57914# - adjust fix #i49383#
1682 if ( !bOldFootnoteFrameLocked
&& !pNew
->GetLower() &&
1683 !pNew
->IsColLocked() && !pNew
->IsBackMoveLocked() &&
1684 !pNew
->IsDeleteForbidden() )
1687 SwFrame::DestroyFrame(pNew
);
1690 pMyPage
->UpdateFootnoteNum();
1693 SwFrame::DestroyFrame(pNew
);
1696 SwFootnoteFrame
*SwFootnoteBossFrame::FindFootnote( const SwContentFrame
*pRef
, const SwTextFootnote
*pAttr
)
1698 // the easiest and savest way goes via the attribute
1699 OSL_ENSURE( pAttr
->GetStartNode(), "FootnoteAtr without StartNode." );
1700 SwNodeIndex
aIdx( *pAttr
->GetStartNode(), 1 );
1701 SwContentNode
*pNd
= aIdx
.GetNode().GetContentNode();
1703 pNd
= pRef
->GetAttrSet()->GetDoc()->
1704 GetNodes().GoNextSection( &aIdx
, true, false );
1707 SwIterator
<SwFrame
, SwContentNode
, sw::IteratorMode::UnwrapMulti
> aIter(*pNd
);
1708 SwFrame
* pFrame
= aIter
.First();
1712 pFrame
= pFrame
->GetUpper();
1713 // #i28500#, #i27243# Due to the endnode collector, there are
1714 // SwFootnoteFrames, which are not in the layout. Therefore the
1715 // bInfFootnote flags are not set correctly, and a cell of FindFootnoteFrame
1716 // would return 0. Therefore we better call ImplFindFootnoteFrame().
1717 SwFootnoteFrame
*pFootnote
= pFrame
->ImplFindFootnoteFrame();
1718 if ( pFootnote
&& pFootnote
->GetRef() == pRef
)
1720 // The following condition becomes true, if the whole
1721 // footnotecontent is a section. While no frames exist,
1722 // the HiddenFlag of the section is set, this causes
1723 // the GoNextSection-function leaves the footnote.
1724 if( pFootnote
->GetAttr() != pAttr
)
1726 while ( pFootnote
&& pFootnote
->GetMaster() )
1727 pFootnote
= pFootnote
->GetMaster();
1731 } while ( nullptr != (pFrame
= aIter
.Next()) );
1736 bool SwFootnoteBossFrame::RemoveFootnote(
1737 const SwContentFrame
*const pRef
, const SwTextFootnote
*const pAttr
,
1741 SwFootnoteFrame
*pFootnote
= FindFootnote( pRef
, pAttr
);
1747 SwFootnoteFrame
*pFoll
= pFootnote
->GetFollow();
1749 SwFrame::DestroyFrame(pFootnote
);
1751 } while ( pFootnote
);
1752 if( bPrep
&& pRef
->IsFollow() )
1754 OSL_ENSURE( pRef
->IsTextFrame(), "NoTextFrame has Footnote?" );
1755 SwTextFrame
* pMaster
= pRef
->FindMaster();
1756 if( !pMaster
->IsLocked() )
1757 pMaster
->Prepare( PrepareHint::FootnoteInvalidationGone
);
1760 FindPageFrame()->UpdateFootnoteNum();
1764 void SwFootnoteBossFrame::ChangeFootnoteRef( const SwContentFrame
*pOld
, const SwTextFootnote
*pAttr
,
1765 SwContentFrame
*pNew
)
1767 SwFootnoteFrame
*pFootnote
= FindFootnote( pOld
, pAttr
);
1770 pFootnote
->SetRef( pNew
);
1771 pFootnote
= pFootnote
->GetFollow();
1775 /// OD 03.04.2003 #108446# - add parameter <_bCollectOnlyPreviousFootnotes> in
1776 /// order to control, if only footnotes, which are positioned before the
1777 /// footnote boss frame <this> have to be collected.
1778 void SwFootnoteBossFrame::CollectFootnotes( const SwContentFrame
* _pRef
,
1779 SwFootnoteBossFrame
* _pOld
,
1780 SwFootnoteFrames
& _rFootnoteArr
,
1781 const bool _bCollectOnlyPreviousFootnotes
)
1783 SwFootnoteFrame
*pFootnote
= _pOld
->FindFirstFootnote();
1786 if( _pOld
->IsColumnFrame() )
1789 while ( !pFootnote
&& _pOld
->GetPrev() )
1791 // Still no problem if no footnote was found yet. The loop is needed to pick up
1792 // following rows in tables. In all other cases it might correct bad contexts.
1793 _pOld
= static_cast<SwFootnoteBossFrame
*>(_pOld
->GetPrev());
1794 pFootnote
= _pOld
->FindFirstFootnote();
1801 for ( SwFrame
* pTmp
= _pOld
;
1802 nullptr != ( pPg
= static_cast<SwPageFrame
*>(pTmp
->FindPageFrame()->GetPrev()))
1803 && pPg
->IsEmptyPage() ;
1811 SwLayoutFrame
* pBody
= pPg
->FindBodyCont();
1812 if( pBody
->Lower() && pBody
->Lower()->IsColumnFrame() )
1814 // multiple columns on one page => search last column
1815 _pOld
= static_cast<SwFootnoteBossFrame
*>(pBody
->GetLastLower());
1818 _pOld
= pPg
; // single column page
1819 pFootnote
= _pOld
->FindFirstFootnote();
1823 CollectFootnotes_(_pRef
, pFootnote
, _rFootnoteArr
, _bCollectOnlyPreviousFootnotes
? this : nullptr);
1826 static void FootnoteInArr( SwFootnoteFrames
& rFootnoteArr
, SwFootnoteFrame
* pFootnote
)
1828 if ( rFootnoteArr
.end() == std::find( rFootnoteArr
.begin(), rFootnoteArr
.end(), pFootnote
) )
1829 rFootnoteArr
.push_back( pFootnote
);
1832 void SwFootnoteBossFrame::CollectFootnotes_( const SwContentFrame
* _pRef
,
1833 SwFootnoteFrame
* _pFootnote
,
1834 SwFootnoteFrames
& _rFootnoteArr
,
1835 const SwFootnoteBossFrame
* _pRefFootnoteBossFrame
)
1837 // Collect all footnotes referenced by pRef (attribute by attribute), combine them
1838 // (the content might be divided over multiple pages) and cut them.
1840 // For robustness, we do not log the corresponding footnotes here. If a footnote
1841 // is touched twice, there might be a crash. This allows this function here to
1842 // also handle corrupt layouts in some degrees (without loops or even crashes).
1843 SwFootnoteFrames aNotFootnoteArr
;
1845 // here we have a footnote placed in front of the first one of the reference
1846 OSL_ENSURE( !_pFootnote
->GetMaster() || _pFootnote
->GetRef() != _pRef
, "move FollowFootnote?" );
1847 while ( _pFootnote
->GetMaster() )
1848 _pFootnote
= _pFootnote
->GetMaster();
1850 bool bFound
= false;
1854 // Search for the next footnote in this column/page so that
1855 // we do not start from zero again after cutting one footnote.
1856 SwFootnoteFrame
*pNxtFootnote
= _pFootnote
;
1857 while ( pNxtFootnote
->GetFollow() )
1858 pNxtFootnote
= pNxtFootnote
->GetFollow();
1859 pNxtFootnote
= static_cast<SwFootnoteFrame
*>(pNxtFootnote
->GetNext());
1861 if ( !pNxtFootnote
)
1863 SwFootnoteBossFrame
* pBoss
= _pFootnote
->FindFootnoteBossFrame();
1864 SwPageFrame
* pPage
= pBoss
->FindPageFrame();
1867 lcl_NextFootnoteBoss( pBoss
, pPage
, false );
1870 SwLayoutFrame
* pCont
= pBoss
->FindFootnoteCont();
1873 pNxtFootnote
= static_cast<SwFootnoteFrame
*>(pCont
->Lower());
1876 while( pNxtFootnote
->GetMaster() )
1877 pNxtFootnote
= pNxtFootnote
->GetMaster();
1878 if( pNxtFootnote
== _pFootnote
)
1879 pNxtFootnote
= nullptr;
1883 } while( !pNxtFootnote
&& pBoss
);
1885 else if( !pNxtFootnote
->GetAttr()->GetFootnote().IsEndNote() )
1887 OSL_ENSURE( !pNxtFootnote
->GetMaster(), "_CollectFootnote: Master expected" );
1888 while ( pNxtFootnote
->GetMaster() )
1889 pNxtFootnote
= pNxtFootnote
->GetMaster();
1891 if ( pNxtFootnote
== _pFootnote
)
1893 OSL_FAIL( "_CollectFootnote: Vicious circle" );
1894 pNxtFootnote
= nullptr;
1897 // OD 03.04.2003 #108446# - determine, if found footnote has to be collected.
1898 bool bCollectFoundFootnote
= false;
1899 // Ignore endnotes which are on a separate endnote page.
1900 bool bEndNote
= _pFootnote
->GetAttr()->GetFootnote().IsEndNote();
1901 const IDocumentSettingAccess
& rSettings
1902 = _pFootnote
->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
1903 bool bContinuousEndnotes
= rSettings
.get(DocumentSettingId::CONTINUOUS_ENDNOTES
);
1904 if (_pFootnote
->GetRef() == _pRef
&& (!bEndNote
|| bContinuousEndnotes
))
1906 if (_pRefFootnoteBossFrame
)
1908 SwFootnoteBossFrame
* pBossOfFoundFootnote
= _pFootnote
->FindFootnoteBossFrame( true );
1909 OSL_ENSURE( pBossOfFoundFootnote
,
1910 "<SwFootnoteBossFrame::CollectFootnotes_(..)> - footnote boss frame of found footnote frame missing.\nWrong layout!" );
1911 if ( !pBossOfFoundFootnote
|| // don't crash, if no footnote boss is found.
1912 pBossOfFoundFootnote
->IsBefore( _pRefFootnoteBossFrame
)
1915 bCollectFoundFootnote
= true;
1920 bCollectFoundFootnote
= true;
1924 if ( bCollectFoundFootnote
)
1926 OSL_ENSURE( !_pFootnote
->GetMaster(), "move FollowFootnote?" );
1927 SwFootnoteFrame
*pNxt
= _pFootnote
->GetFollow();
1930 SwFrame
*pCnt
= pNxt
->ContainsAny();
1933 // destroy the follow on the way as it is empty
1935 { SwFrame
*pNxtCnt
= pCnt
->GetNext();
1937 pCnt
->Paste( _pFootnote
);
1943 OSL_ENSURE( !pNxt
, "footnote without content?" );
1945 SwFrame::DestroyFrame(pNxt
);
1947 pNxt
= _pFootnote
->GetFollow();
1950 FootnoteInArr( _rFootnoteArr
, _pFootnote
);
1955 FootnoteInArr( aNotFootnoteArr
, _pFootnote
);
1959 if ( pNxtFootnote
&&
1960 _rFootnoteArr
.end() == std::find( _rFootnoteArr
.begin(), _rFootnoteArr
.end(), pNxtFootnote
) &&
1961 aNotFootnoteArr
.end() == std::find( aNotFootnoteArr
.begin(), aNotFootnoteArr
.end(), pNxtFootnote
) )
1962 _pFootnote
= pNxtFootnote
;
1966 while ( _pFootnote
);
1969 void SwFootnoteBossFrame::MoveFootnotes_( SwFootnoteFrames
&rFootnoteArr
, bool bCalc
)
1971 // All footnotes referenced by pRef need to be moved
1972 // to a new position (based on the new column/page)
1973 const sal_uInt16 nMyNum
= FindPageFrame()->GetPhyPageNum();
1974 const sal_uInt16 nMyCol
= lcl_ColumnNum( this );
1975 SwRectFnSet
aRectFnSet(this);
1977 // #i21478# - keep last inserted footnote in order to
1978 // format the content of the following one.
1979 SwFootnoteFrame
* pLastInsertedFootnote
= nullptr;
1980 for (SwFootnoteFrame
* pFootnote
: rFootnoteArr
)
1982 SwFootnoteBossFrame
* pRefBoss(pFootnote
->GetRef()->FindFootnoteBossFrame(
1983 !pFootnote
->GetAttr()->GetFootnote().IsEndNote()));
1984 if( pRefBoss
!= this )
1986 const sal_uInt16 nRefNum
= pRefBoss
->FindPageFrame()->GetPhyPageNum();
1987 const sal_uInt16 nRefCol
= lcl_ColumnNum( this );
1988 if( nRefNum
< nMyNum
|| ( nRefNum
== nMyNum
&& nRefCol
<= nMyCol
) )
1991 pRefBoss
->InsertFootnote( pFootnote
);
1993 if ( pFootnote
->GetUpper() ) // robust, e.g. with duplicates
1995 // First condense the content so that footnote frames that do not fit on the page
1996 // do not do too much harm (Loop 66312). So, the footnote content first grows as
1997 // soon as the content gets formatted and it is sure that it fits on the page.
1998 SwFrame
*pCnt
= pFootnote
->ContainsAny();
2001 if( pCnt
->IsLayoutFrame() )
2003 SwFrame
* pTmp
= static_cast<SwLayoutFrame
*>(pCnt
)->ContainsAny();
2004 while( pTmp
&& static_cast<SwLayoutFrame
*>(pCnt
)->IsAnLower( pTmp
) )
2006 pTmp
->Prepare( PrepareHint::FootnoteMove
);
2008 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pTmp
);
2009 aRectFnSet
.SetHeight(aFrm
, 0);
2011 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*pTmp
);
2012 aRectFnSet
.SetHeight(aPrt
, 0);
2014 pTmp
= pTmp
->FindNext();
2019 pCnt
->Prepare( PrepareHint::FootnoteMove
);
2022 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pCnt
);
2023 aRectFnSet
.SetHeight(aFrm
, 0);
2025 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*pCnt
);
2026 aRectFnSet
.SetHeight(aPrt
, 0);
2028 pCnt
= pCnt
->GetNext();
2032 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pFootnote
);
2033 aRectFnSet
.SetHeight(aFrm
, 0);
2037 SwFrameAreaDefinition::FramePrintAreaWriteAccess
aPrt(*pFootnote
);
2038 aRectFnSet
.SetHeight(aPrt
, 0);
2041 pFootnote
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2042 pFootnote
->GetUpper()->Calc(getRootFrame()->GetCurrShell()->GetOut());
2046 SwTextFootnote
*pAttr
= pFootnote
->GetAttr();
2047 pCnt
= pFootnote
->ContainsAny();
2048 bool bUnlock
= !pFootnote
->IsBackMoveLocked();
2049 pFootnote
->LockBackMove();
2051 // #i49383# - disable unlock of position of
2052 // lower objects during format of footnote content.
2053 pFootnote
->KeepLockPosOfLowerObjs();
2054 // #i57914# - adjust fix #i49383#
2056 while ( pCnt
&& pCnt
->FindFootnoteFrame()->GetAttr() == pAttr
)
2058 pCnt
->InvalidatePos_();
2059 pCnt
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2060 // #i49383# - format anchored objects
2061 if ( pCnt
->IsTextFrame() && pCnt
->isFrameAreaDefinitionValid() )
2063 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt
,
2064 *(pCnt
->FindPageFrame()) ) )
2066 // restart format with first content
2067 pCnt
= pFootnote
->ContainsAny();
2071 if( pCnt
->IsSctFrame() )
2073 // If the area is not empty, iterate also over the content
2074 SwFrame
* pTmp
= static_cast<SwSectionFrame
*>(pCnt
)->ContainsAny();
2078 pCnt
= pCnt
->FindNext();
2081 pCnt
= pCnt
->FindNext();
2085 pFootnote
->UnlockBackMove();
2086 if( !pFootnote
->ContainsAny() && !pFootnote
->IsColLocked() )
2089 SwFrame::DestroyFrame(pFootnote
);
2091 pFootnote
= nullptr;
2097 // #i57914# - adjust fix #i49383#
2098 // enable lock of lower object position before format of footnote frame.
2099 pFootnote
->UnlockPosOfLowerObjs();
2100 pFootnote
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2106 OSL_ENSURE( !pFootnote
->GetMaster() && !pFootnote
->GetFollow(),
2107 "DelFootnote and Master/Follow?" );
2108 SwFrame::DestroyFrame(pFootnote
);
2110 pFootnote
= nullptr;
2116 pLastInsertedFootnote
= pFootnote
;
2120 // #i21478# - format content of footnote following
2121 // the new inserted ones.
2122 if ( !(bCalc
&& pLastInsertedFootnote
) )
2125 if ( !pLastInsertedFootnote
->GetNext() )
2128 SwFootnoteFrame
* pNextFootnote
= static_cast<SwFootnoteFrame
*>(pLastInsertedFootnote
->GetNext());
2129 SwTextFootnote
* pAttr
= pNextFootnote
->GetAttr();
2130 SwFrame
* pCnt
= pNextFootnote
->ContainsAny();
2132 bool bUnlock
= !pNextFootnote
->IsBackMoveLocked();
2133 pNextFootnote
->LockBackMove();
2134 // #i49383# - disable unlock of position of
2135 // lower objects during format of footnote content.
2136 pNextFootnote
->KeepLockPosOfLowerObjs();
2137 // #i57914# - adjust fix #i49383#
2139 while ( pCnt
&& pCnt
->FindFootnoteFrame()->GetAttr() == pAttr
)
2141 pCnt
->InvalidatePos_();
2142 pCnt
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2143 // #i49383# - format anchored objects
2144 if ( pCnt
->IsTextFrame() && pCnt
->isFrameAreaDefinitionValid() )
2146 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt
,
2147 *(pCnt
->FindPageFrame()) ) )
2149 // restart format with first content
2150 pCnt
= pNextFootnote
->ContainsAny();
2154 if( pCnt
->IsSctFrame() )
2156 // If the area is not empty, iterate also over the content
2157 SwFrame
* pTmp
= static_cast<SwSectionFrame
*>(pCnt
)->ContainsAny();
2161 pCnt
= pCnt
->FindNext();
2164 pCnt
= pCnt
->FindNext();
2168 pNextFootnote
->UnlockBackMove();
2171 // #i57914# - adjust fix #i49383#
2172 // enable lock of lower object position before format of footnote frame.
2173 pNextFootnote
->UnlockPosOfLowerObjs();
2174 pNextFootnote
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2177 void SwFootnoteBossFrame::MoveFootnotes( const SwContentFrame
*pSrc
, SwContentFrame
*pDest
,
2178 SwTextFootnote
const *pAttr
)
2180 if( ( GetFormat()->GetDoc()->GetFootnoteInfo().m_ePos
== FTNPOS_CHAPTER
&&
2181 (!GetUpper()->IsSctFrame() || !static_cast<SwSectionFrame
*>(GetUpper())->IsFootnoteAtEnd()))
2182 || pAttr
->GetFootnote().IsEndNote() )
2185 OSL_ENSURE( this == pSrc
->FindFootnoteBossFrame( true ),
2186 "SwPageFrame::MoveFootnotes: source frame isn't on that FootnoteBoss" );
2188 SwFootnoteFrame
*pFootnote
= FindFirstFootnote();
2192 ChangeFootnoteRef( pSrc
, pAttr
, pDest
);
2193 SwFootnoteBossFrame
*pDestBoss
= pDest
->FindFootnoteBossFrame( true );
2194 OSL_ENSURE( pDestBoss
, "+SwPageFrame::MoveFootnotes: no destination boss" );
2195 if( !pDestBoss
) // robust
2198 SwFootnoteFrames aFootnoteArr
;
2199 SwFootnoteBossFrame::CollectFootnotes_(pDest
, pFootnote
, aFootnoteArr
, nullptr);
2200 if ( aFootnoteArr
.empty() )
2203 pDestBoss
->MoveFootnotes_( aFootnoteArr
, true );
2204 SwPageFrame
* pSrcPage
= FindPageFrame();
2205 SwPageFrame
* pDestPage
= pDestBoss
->FindPageFrame();
2206 // update FootnoteNum only at page change
2207 if( pSrcPage
!= pDestPage
)
2209 if( pSrcPage
->GetPhyPageNum() > pDestPage
->GetPhyPageNum() )
2210 pSrcPage
->UpdateFootnoteNum();
2211 pDestPage
->UpdateFootnoteNum();
2215 void SwFootnoteBossFrame::RearrangeFootnotes( const SwTwips nDeadLine
, const bool bLock
,
2216 const SwTextFootnote
*pAttr
)
2218 // Format all footnotes of a column/page so that they might change the column/page.
2220 SwSaveFootnoteHeight
aSave( this, nDeadLine
);
2221 SwFootnoteFrame
*pFootnote
= FindFirstFootnote();
2222 if( pFootnote
&& pFootnote
->GetPrev() && bLock
)
2224 SwFootnoteFrame
* pFirst
= static_cast<SwFootnoteFrame
*>(pFootnote
->GetUpper()->Lower());
2225 SwFrame
* pContent
= pFirst
->ContainsAny();
2228 bool bUnlock
= !pFirst
->IsBackMoveLocked();
2229 pFirst
->LockBackMove();
2230 pFirst
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2231 pContent
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2232 // #i49383# - format anchored objects
2233 if ( pContent
->IsTextFrame() && pContent
->isFrameAreaDefinitionValid() )
2235 SwObjectFormatter::FormatObjsAtFrame( *pContent
,
2236 *(pContent
->FindPageFrame()) );
2239 pFirst
->UnlockBackMove();
2241 pFootnote
= FindFirstFootnote();
2243 SwDoc
*pDoc
= GetFormat()->GetDoc();
2244 const sal_uLong nFootnotePos
= pAttr
? ::lcl_FindFootnotePos( pDoc
, pAttr
) : 0;
2245 SwFrame
*pCnt
= pFootnote
? pFootnote
->ContainsAny() : nullptr;
2250 bool bStart
= pAttr
== nullptr; // If no attribute is given, process all
2251 // #i49383# - disable unlock of position of
2252 // lower objects during format of footnote and footnote content.
2253 SwFootnoteFrame
* pLastFootnoteFrame( nullptr );
2254 // footnote frame needs to be locked, if <bLock> isn't set.
2255 bool bUnlockLastFootnoteFrame( false );
2259 bStart
= ::lcl_FindFootnotePos( pDoc
, pCnt
->FindFootnoteFrame()->GetAttr() )
2263 pCnt
->InvalidatePos_();
2264 pCnt
->InvalidateSize_();
2265 pCnt
->Prepare( PrepareHint::AdjustSizeWithoutFormatting
);
2266 SwFootnoteFrame
* pFootnoteFrame
= pCnt
->FindFootnoteFrame();
2268 if ( pFootnoteFrame
!= pLastFootnoteFrame
)
2270 if ( pLastFootnoteFrame
)
2272 if ( !bLock
&& bUnlockLastFootnoteFrame
)
2274 pLastFootnoteFrame
->ColUnlock();
2276 // #i57914# - adjust fix #i49383#
2277 // enable lock of lower object position before format of footnote frame.
2278 pLastFootnoteFrame
->UnlockPosOfLowerObjs();
2279 pLastFootnoteFrame
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2280 if ( !bLock
&& bUnlockLastFootnoteFrame
&&
2281 !pLastFootnoteFrame
->GetLower() &&
2282 !pLastFootnoteFrame
->IsColLocked() &&
2283 !pLastFootnoteFrame
->IsBackMoveLocked() &&
2284 !pLastFootnoteFrame
->IsDeleteForbidden() )
2286 pLastFootnoteFrame
->Cut();
2287 SwFrame::DestroyFrame(pLastFootnoteFrame
);
2288 pLastFootnoteFrame
= nullptr;
2293 bUnlockLastFootnoteFrame
= !pFootnoteFrame
->IsColLocked();
2294 pFootnoteFrame
->ColLock();
2296 pFootnoteFrame
->KeepLockPosOfLowerObjs();
2297 pLastFootnoteFrame
= pFootnoteFrame
;
2299 // OD 30.10.2002 #97265# - invalidate position of footnote
2300 // frame, if it's below its footnote container, in order to
2301 // assure its correct position, probably calculating its previous
2304 SwRectFnSet
aRectFnSet(this);
2305 SwFrame
* pFootnoteContFrame
= pFootnoteFrame
->GetUpper();
2306 if ( aRectFnSet
.TopDist(pFootnoteFrame
->getFrameArea(), aRectFnSet
.GetPrtBottom(*pFootnoteContFrame
)) > 0 )
2308 pFootnoteFrame
->InvalidatePos_();
2313 bool bUnlock
= !pFootnoteFrame
->IsBackMoveLocked();
2314 pFootnoteFrame
->LockBackMove();
2315 pFootnoteFrame
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2316 pCnt
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2317 // #i49383# - format anchored objects
2318 if ( pCnt
->IsTextFrame() && pCnt
->isFrameAreaDefinitionValid() )
2320 SwFrameDeleteGuard
aDeleteGuard(pFootnote
);
2321 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt
,
2322 *(pCnt
->FindPageFrame()) ) )
2324 // restart format with first content
2325 pCnt
= pFootnote
? pFootnote
->ContainsAny() : nullptr;
2333 pFootnoteFrame
->UnlockBackMove();
2334 if( !pFootnoteFrame
->Lower() &&
2335 !pFootnoteFrame
->IsColLocked() )
2338 OSL_ENSURE( pLastFootnoteFrame
== pFootnoteFrame
,
2339 "<SwFootnoteBossFrame::RearrangeFootnotes(..)> - <pLastFootnoteFrame> != <pFootnoteFrame>" );
2340 pLastFootnoteFrame
= nullptr;
2341 pFootnoteFrame
->Cut();
2342 SwFrame::DestroyFrame(pFootnoteFrame
);
2343 if (pFootnote
== pFootnoteFrame
)
2344 pFootnote
= nullptr;
2350 pFootnoteFrame
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2351 pCnt
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2352 // #i49383# - format anchored objects
2353 if ( pCnt
->IsTextFrame() && pCnt
->isFrameAreaDefinitionValid() )
2355 if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt
,
2356 *(pCnt
->FindPageFrame()) ) )
2358 // restart format with first content
2359 pCnt
= pFootnote
->ContainsAny();
2365 SwSectionFrame
*pDel
= nullptr;
2366 if( pCnt
->IsSctFrame() )
2368 SwFrame
* pTmp
= static_cast<SwSectionFrame
*>(pCnt
)->ContainsAny();
2374 pDel
= static_cast<SwSectionFrame
*>(pCnt
);
2376 if ( pCnt
->GetNext() )
2377 pCnt
= pCnt
->GetNext();
2380 pCnt
= pCnt
->FindNext();
2383 SwFootnoteFrame
* pFootnoteFrame
= pCnt
->FindFootnoteFrame();
2384 if( pFootnoteFrame
->GetRef()->FindFootnoteBossFrame(
2385 pFootnoteFrame
->GetAttr()->GetFootnote().IsEndNote() ) != this )
2393 bool bUnlockLastFootnoteFrameGuard
= pLastFootnoteFrame
&& !pLastFootnoteFrame
->IsColLocked();
2394 if (bUnlockLastFootnoteFrameGuard
)
2395 pLastFootnoteFrame
->ColLock();
2397 if (bUnlockLastFootnoteFrameGuard
)
2398 pLastFootnoteFrame
->ColUnlock();
2399 SwFrame::DestroyFrame(pDel
);
2403 // Go not further than to the provided footnote (if given)
2405 (::lcl_FindFootnotePos( pDoc
,
2406 pCnt
->FindFootnoteFrame()->GetAttr()) > nFootnotePos
) )
2411 if ( !pLastFootnoteFrame
)
2414 if ( !bLock
&& bUnlockLastFootnoteFrame
)
2416 pLastFootnoteFrame
->ColUnlock();
2418 // #i57914# - adjust fix #i49383#
2419 // enable lock of lower object position before format of footnote frame.
2420 pLastFootnoteFrame
->UnlockPosOfLowerObjs();
2421 pLastFootnoteFrame
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2422 if ( !bLock
&& bUnlockLastFootnoteFrame
&&
2423 !pLastFootnoteFrame
->GetLower() &&
2424 !pLastFootnoteFrame
->IsColLocked() &&
2425 !pLastFootnoteFrame
->IsBackMoveLocked() &&
2426 !pLastFootnoteFrame
->IsDeleteForbidden() )
2428 pLastFootnoteFrame
->Cut();
2429 SwFrame::DestroyFrame(pLastFootnoteFrame
);
2433 void SwPageFrame::UpdateFootnoteNum()
2435 // page numbering only if set at the document
2436 if ( GetFormat()->GetDoc()->GetFootnoteInfo().m_eNum
!= FTNNUM_PAGE
)
2439 SwLayoutFrame
* pBody
= FindBodyCont();
2440 if( !pBody
|| !pBody
->Lower() )
2443 SwContentFrame
* pContent
= pBody
->ContainsContent();
2444 sal_uInt16 nNum
= 0;
2446 while( pContent
&& pContent
->FindPageFrame() == this )
2448 if( static_cast<SwTextFrame
*>(pContent
)->HasFootnote() )
2450 SwFootnoteBossFrame
* pBoss
= pContent
->FindFootnoteBossFrame( true );
2451 if( pBoss
->GetUpper()->IsSctFrame() &&
2452 static_cast<SwSectionFrame
*>(pBoss
->GetUpper())->IsOwnFootnoteNum() )
2453 pContent
= static_cast<SwSectionFrame
*>(pBoss
->GetUpper())->FindLastContent();
2456 SwFootnoteFrame
* pFootnote
= const_cast<SwFootnoteFrame
*>(pBoss
->FindFirstFootnote( pContent
));
2459 SwTextFootnote
* pTextFootnote
= pFootnote
->GetAttr();
2460 if( !pTextFootnote
->GetFootnote().IsEndNote() &&
2461 pTextFootnote
->GetFootnote().GetNumStr().isEmpty() &&
2462 !pFootnote
->GetMaster())
2464 // sw_redlinehide: the layout can only keep one number
2465 // up to date; depending on its setting, this is either
2466 // the non-hidden or the hidden number; the other
2467 // number will simply be preserved as-is (so in case
2468 // there are 2 layouts, maybe both can be updated...)
2470 sal_uInt16
const nOldNum(pTextFootnote
->GetFootnote().GetNumber());
2471 sal_uInt16
const nOldNumRLHidden(pTextFootnote
->GetFootnote().GetNumberRLHidden());
2472 if (getRootFrame()->IsHideRedlines())
2474 if (nNum
!= nOldNumRLHidden
)
2476 pTextFootnote
->SetNumber(nOldNum
, nNum
, OUString());
2481 if (nNum
!= nOldNum
)
2483 pTextFootnote
->SetNumber(nNum
, nOldNumRLHidden
, OUString());
2487 if ( pFootnote
->GetNext() )
2488 pFootnote
= static_cast<SwFootnoteFrame
*>(pFootnote
->GetNext());
2491 SwFootnoteBossFrame
* pTmpBoss
= pFootnote
->FindFootnoteBossFrame( true );
2494 SwPageFrame
* pPage
= pTmpBoss
->FindPageFrame();
2495 pFootnote
= nullptr;
2496 lcl_NextFootnoteBoss( pTmpBoss
, pPage
, false );
2497 SwFootnoteContFrame
*pCont
= pTmpBoss
? pTmpBoss
->FindNearestFootnoteCont() : nullptr;
2499 pFootnote
= static_cast<SwFootnoteFrame
*>(pCont
->Lower());
2502 if( pFootnote
&& pFootnote
->GetRef() != pContent
)
2503 pFootnote
= nullptr;
2507 pContent
= pContent
->FindNextCnt();
2511 void SwFootnoteBossFrame::SetFootnoteDeadLine( const SwTwips nDeadLine
)
2513 SwFrame
*pBody
= FindBodyCont();
2514 pBody
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2516 SwFrame
*pCont
= FindFootnoteCont();
2517 const SwTwips nMax
= m_nMaxFootnoteHeight
;// current should exceed MaxHeight
2518 SwRectFnSet
aRectFnSet(this);
2521 pCont
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2522 m_nMaxFootnoteHeight
= -aRectFnSet
.BottomDist( pCont
->getFrameArea(), nDeadLine
);
2525 m_nMaxFootnoteHeight
= -aRectFnSet
.BottomDist( pBody
->getFrameArea(), nDeadLine
);
2527 const SwViewShell
*pSh
= getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
2528 if( pSh
&& pSh
->GetViewOptions()->getBrowseMode() )
2529 m_nMaxFootnoteHeight
+= pBody
->Grow( LONG_MAX
, true );
2531 m_nMaxFootnoteHeight
+= FindSctFrame()->Grow( LONG_MAX
, true );
2533 if ( m_nMaxFootnoteHeight
< 0 )
2534 m_nMaxFootnoteHeight
= 0;
2535 if ( nMax
!= LONG_MAX
&& m_nMaxFootnoteHeight
> nMax
)
2536 m_nMaxFootnoteHeight
= nMax
;
2539 SwTwips
SwFootnoteBossFrame::GetVarSpace() const
2541 // To not fall below 20% of the page height
2542 // (in contrast to MSOffice where footnotes can fill a whole column/page)
2544 const SwPageFrame
* pPg
= FindPageFrame();
2545 OSL_ENSURE( pPg
|| IsInSct(), "Footnote lost page" );
2547 const SwFrame
*pBody
= FindBodyCont();
2551 SwRectFnSet
aRectFnSet(this);
2555 SwTwips nTmp
= aRectFnSet
.YDiff( aRectFnSet
.GetPrtTop(*pBody
),
2556 aRectFnSet
.GetTop(getFrameArea()) );
2557 const SwSectionFrame
* pSect
= FindSctFrame();
2558 // Endnotes in a ftncontainer causes a deadline:
2559 // the bottom of the last contentfrm
2560 if( pSect
->IsEndnAtEnd() ) // endnotes allowed?
2562 OSL_ENSURE( !Lower() || !Lower()->GetNext() || Lower()->GetNext()->
2563 IsFootnoteContFrame(), "FootnoteContainer expected" );
2564 const SwFootnoteContFrame
* pCont
= Lower() ?
2565 static_cast<const SwFootnoteContFrame
*>(Lower()->GetNext()) : nullptr;
2568 const SwFootnoteFrame
* pFootnote
= static_cast<const SwFootnoteFrame
*>(pCont
->Lower());
2571 if( pFootnote
->GetAttr()->GetFootnote().IsEndNote() )
2573 const SwFrame
* pFrame
= static_cast<const SwLayoutFrame
*>(Lower())->Lower();
2576 while( pFrame
->GetNext() )
2577 pFrame
= pFrame
->GetNext(); // last cntntfrm
2578 nTmp
+= aRectFnSet
.YDiff(
2579 aRectFnSet
.GetTop(getFrameArea()),
2580 aRectFnSet
.GetBottom(pFrame
->getFrameArea()) );
2584 pFootnote
= static_cast<const SwFootnoteFrame
*>(pFootnote
->GetNext());
2592 nRet
= - aRectFnSet
.GetHeight(pPg
->getFramePrintArea())/5;
2593 nRet
+= aRectFnSet
.GetHeight(pBody
->getFrameArea());
2599 if ( IsPageFrame() )
2601 const SwViewShell
*pSh
= getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
2602 if( pSh
&& pSh
->GetViewOptions()->getBrowseMode() )
2603 nRet
+= BROWSE_HEIGHT
- getFrameArea().Height();
2608 /** Obtain if pFrame's size adjustment should be processed
2610 * For a page frame of columns directly below the page AdjustNeighbourhood() needs
2611 * to be called, or Grow()/ Shrink() for frame columns respectively.
2613 * A column section is special, since if there is a footnote container in a column
2614 * and those footnotes are not collected, it is handled like a page frame.
2616 * @see AdjustNeighbourhood()
2620 SwNeighbourAdjust
SwFootnoteBossFrame::NeighbourhoodAdjustment_() const
2622 SwNeighbourAdjust nRet
= SwNeighbourAdjust::OnlyAdjust
;
2623 if( GetUpper() && !GetUpper()->IsPageBodyFrame() )
2625 // column sections need grow/shrink
2626 if( GetUpper()->IsFlyFrame() )
2627 nRet
= SwNeighbourAdjust::GrowShrink
;
2630 OSL_ENSURE( GetUpper()->IsSctFrame(), "NeighbourhoodAdjustment: Unexpected Upper" );
2631 if( !GetNext() && !GetPrev() )
2632 nRet
= SwNeighbourAdjust::GrowAdjust
; // section with a single column (FootnoteAtEnd)
2635 const SwFrame
* pTmp
= Lower();
2636 OSL_ENSURE( pTmp
, "NeighbourhoodAdjustment: Missing Lower()" );
2637 if( !pTmp
->GetNext() )
2638 nRet
= SwNeighbourAdjust::GrowShrink
;
2639 else if( !GetUpper()->IsColLocked() )
2640 nRet
= SwNeighbourAdjust::AdjustGrow
;
2641 OSL_ENSURE( !pTmp
->GetNext() || pTmp
->GetNext()->IsFootnoteContFrame(),
2642 "NeighbourhoodAdjustment: Who's that guy?" );
2649 void SwPageFrame::SetColMaxFootnoteHeight()
2651 SwLayoutFrame
*pBody
= FindBodyCont();
2652 if( pBody
&& pBody
->Lower() && pBody
->Lower()->IsColumnFrame() )
2654 SwColumnFrame
* pCol
= static_cast<SwColumnFrame
*>(pBody
->Lower());
2657 pCol
->SetMaxFootnoteHeight( GetMaxFootnoteHeight() );
2658 pCol
= static_cast<SwColumnFrame
*>(pCol
->GetNext());
2663 bool SwLayoutFrame::MoveLowerFootnotes( SwContentFrame
*pStart
, SwFootnoteBossFrame
*pOldBoss
,
2664 SwFootnoteBossFrame
*pNewBoss
, const bool bFootnoteNums
)
2666 SwDoc
*pDoc
= GetFormat()->GetDoc();
2667 if ( pDoc
->GetFootnoteIdxs().empty() )
2669 if( pDoc
->GetFootnoteInfo().m_ePos
== FTNPOS_CHAPTER
&&
2670 ( !IsInSct() || !FindSctFrame()->IsFootnoteAtEnd() ) )
2674 pNewBoss
= FindFootnoteBossFrame( true );
2675 if ( pNewBoss
== pOldBoss
)
2678 bool bMoved
= false;
2680 pStart
= ContainsContent();
2682 SwFootnoteFrames aFootnoteArr
;
2684 while ( IsAnLower( pStart
) )
2686 if ( static_cast<SwTextFrame
*>(pStart
)->HasFootnote() )
2688 // OD 03.04.2003 #108446# - To avoid unnecessary moves of footnotes
2689 // use new parameter <_bCollectOnlyPreviousFootnote> (4th parameter of
2690 // method <SwFootnoteBossFrame::CollectFootnote(..)>) to control, that only
2691 // footnotes have to be collected, that are positioned before the
2692 // new dedicated footnote boss frame.
2693 pNewBoss
->CollectFootnotes( pStart
, pOldBoss
, aFootnoteArr
, true );
2695 pStart
= pStart
->GetNextContentFrame();
2698 OSL_ENSURE( pOldBoss
->IsInSct() == pNewBoss
->IsInSct(),
2699 "MoveLowerFootnotes: Section confusion" );
2700 std::unique_ptr
<SwFootnoteFrames
> pFootnoteArr
;
2701 SwLayoutFrame
* pNewChief
= nullptr;
2702 SwLayoutFrame
* pOldChief
= nullptr;
2704 bool bFoundCandidate
= false;
2705 if (pStart
&& pOldBoss
->IsInSct())
2707 pOldChief
= pOldBoss
->FindSctFrame();
2708 pNewChief
= pNewBoss
->FindSctFrame();
2709 bFoundCandidate
= pOldChief
!= pNewChief
;
2712 if (bFoundCandidate
)
2714 pFootnoteArr
.reset(new SwFootnoteFrames
);
2715 pOldChief
= pOldBoss
->FindFootnoteBossFrame( true );
2716 pNewChief
= pNewBoss
->FindFootnoteBossFrame( true );
2717 while( pOldChief
->IsAnLower( pStart
) )
2719 if ( static_cast<SwTextFrame
*>(pStart
)->HasFootnote() )
2720 static_cast<SwFootnoteBossFrame
*>(pNewChief
)->CollectFootnotes( pStart
,
2721 pOldBoss
, *pFootnoteArr
);
2722 pStart
= pStart
->GetNextContentFrame();
2724 if( pFootnoteArr
->empty() )
2726 pFootnoteArr
.reset();
2730 pFootnoteArr
= nullptr;
2732 if ( !aFootnoteArr
.empty() || pFootnoteArr
)
2734 if( !aFootnoteArr
.empty() )
2735 pNewBoss
->MoveFootnotes_( aFootnoteArr
, true );
2739 static_cast<SwFootnoteBossFrame
*>(pNewChief
)->MoveFootnotes_( *pFootnoteArr
, true );
2740 pFootnoteArr
.reset();
2744 // update FootnoteNum only at page change
2745 if ( bFootnoteNums
)
2747 SwPageFrame
* pOldPage
= pOldBoss
->FindPageFrame();
2748 SwPageFrame
* pNewPage
=pNewBoss
->FindPageFrame();
2749 if( pOldPage
!= pNewPage
)
2751 pOldPage
->UpdateFootnoteNum();
2752 pNewPage
->UpdateFootnoteNum();
2759 /// Return value guarantees that a new page was not created. See SwFlowFrame::MoveFwd.
2760 bool SwContentFrame::MoveFootnoteCntFwd( bool bMakePage
, SwFootnoteBossFrame
*pOldBoss
)
2762 OSL_ENSURE( IsInFootnote(), "no footnote." );
2763 SwLayoutFrame
*pFootnote
= FindFootnoteFrame();
2765 // The first paragraph in the first footnote in the first column in the
2766 // sectionfrm at the top of the page has not to move forward, if the
2767 // columnbody is empty.
2768 if( pOldBoss
->IsInSct() && !pOldBoss
->GetIndPrev() && !GetIndPrev() &&
2769 !pFootnote
->GetPrev() )
2771 SwLayoutFrame
* pBody
= pOldBoss
->FindBodyCont();
2772 if( !pBody
|| !pBody
->Lower() )
2776 //fix(9538): if the footnote has neighbors behind itself, remove them temporarily
2777 SwLayoutFrame
*pNxt
= static_cast<SwLayoutFrame
*>(pFootnote
->GetNext());
2778 SwLayoutFrame
*pLst
= nullptr;
2781 while ( pNxt
->GetNext() )
2782 pNxt
= static_cast<SwLayoutFrame
*>(pNxt
->GetNext());
2787 SwContentFrame
*pCnt
= pNxt
->ContainsContent();
2789 pCnt
->MoveFootnoteCntFwd( true, pOldBoss
);
2790 pNxt
= static_cast<SwLayoutFrame
*>(pFootnote
->GetNext());
2794 bool bSamePage
= true;
2795 SwLayoutFrame
*pNewUpper
=
2796 GetLeaf( bMakePage
? MAKEPAGE_INSERT
: MAKEPAGE_NONE
, true );
2800 SwFootnoteBossFrame
* const pNewBoss
= pNewUpper
->FindFootnoteBossFrame();
2801 // Are we changing the column/page?
2802 bool bSameBoss
= pNewBoss
== pOldBoss
;
2805 bSamePage
= pOldBoss
->FindPageFrame() == pNewBoss
->FindPageFrame(); // page change?
2806 pNewUpper
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2809 // The layout leaf of the footnote is either a footnote container or a footnote.
2810 // If it is a footnote and it has the same footnote reference like the old Upper,
2811 // then move the content inside of it.
2812 // If it is a container or the reference differs, create a new footnote and add
2813 // it into the container.
2814 // Create also a SectionFrame if currently in an area inside a footnote.
2815 SwFootnoteFrame
* pTmpFootnote
= pNewUpper
->IsFootnoteFrame() ? static_cast<SwFootnoteFrame
*>(pNewUpper
) : nullptr;
2818 assert(pNewUpper
->IsFootnoteContFrame() && "New Upper not a FootnoteCont");
2819 SwFootnoteContFrame
*pCont
= static_cast<SwFootnoteContFrame
*>(pNewUpper
);
2820 pTmpFootnote
= SwFootnoteContFrame::AppendChained(this, true);
2821 SwFrame
* pNx
= pCont
->Lower();
2822 if( pNx
&& pTmpFootnote
->GetAttr()->GetFootnote().IsEndNote() )
2823 while(pNx
&& !static_cast<SwFootnoteFrame
*>(pNx
)->GetAttr()->GetFootnote().IsEndNote())
2824 pNx
= pNx
->GetNext();
2825 pTmpFootnote
->Paste( pCont
, pNx
);
2826 pTmpFootnote
->Calc(getRootFrame()->GetCurrShell()->GetOut());
2828 OSL_ENSURE( pTmpFootnote
->GetAttr() == FindFootnoteFrame()->GetAttr(), "Wrong Footnote!" );
2829 // areas inside of footnotes get a special treatment
2830 SwLayoutFrame
*pNewUp
= pTmpFootnote
;
2833 SwSectionFrame
* pSect
= FindSctFrame();
2834 // area inside of a footnote (or only footnote in an area)?
2835 if( pSect
->IsInFootnote() )
2837 if( pTmpFootnote
->Lower() && pTmpFootnote
->Lower()->IsSctFrame() &&
2838 pSect
->GetFollow() == static_cast<SwSectionFrame
*>(pTmpFootnote
->Lower()) )
2839 pNewUp
= static_cast<SwSectionFrame
*>(pTmpFootnote
->Lower());
2842 pNewUp
= new SwSectionFrame( *pSect
, false );
2843 pNewUp
->InsertBefore( pTmpFootnote
, pTmpFootnote
->Lower() );
2844 static_cast<SwSectionFrame
*>(pNewUp
)->Init();
2847 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*pNewUp
);
2848 aFrm
.Pos() = pTmpFootnote
->getFrameArea().Pos();
2849 aFrm
.Pos().AdjustY(1 ); // for notifications
2852 // If the section frame has a successor then the latter needs
2853 // to be moved behind the new Follow of the section frame.
2854 SwFrame
* pTmp
= pSect
->GetNext();
2857 SwFlowFrame
* pTmpNxt
;
2858 if( pTmp
->IsContentFrame() )
2859 pTmpNxt
= static_cast<SwContentFrame
*>(pTmp
);
2860 else if( pTmp
->IsSctFrame() )
2861 pTmpNxt
= static_cast<SwSectionFrame
*>(pTmp
);
2864 OSL_ENSURE( pTmp
->IsTabFrame(), "GetNextSctLeaf: Wrong Type" );
2865 pTmpNxt
= static_cast<SwTabFrame
*>(pTmp
);
2867 // we will dereference pNewUp in the following MoveSubTree call
2868 // so it certainly should not be deleted before that
2869 SwFrameDeleteGuard
aDeleteGuard(pNewUp
);
2870 pTmpNxt
->MoveSubTree( pTmpFootnote
, pNewUp
->GetNext() );
2876 MoveSubTree( pNewUp
, pNewUp
->Lower() );
2879 Prepare( PrepareHint::BossChanged
);
2884 SwSaveFootnoteHeight::SwSaveFootnoteHeight( SwFootnoteBossFrame
*pBs
, const SwTwips nDeadLine
) :
2887 nOldHeight( pBs
->GetMaxFootnoteHeight() )
2889 pBoss
->SetFootnoteDeadLine( nDeadLine
);
2890 nNewHeight
= pBoss
->GetMaxFootnoteHeight();
2893 SwSaveFootnoteHeight::~SwSaveFootnoteHeight()
2895 // If somebody tweaked the deadline meanwhile, we let it happen
2896 if ( nNewHeight
== pBoss
->GetMaxFootnoteHeight() )
2897 pBoss
->m_nMaxFootnoteHeight
= nOldHeight
;
2901 //JP 15.10.2001: in a non pro version test if the attribute has the same
2902 // meaning which his reference is
2904 // Normally, the pRef member and the GetRefFromAttr() result has to be
2905 // identically. Sometimes footnote will be moved from a master to its follow,
2906 // but the GetRef() is called first, so we have to ignore a master/follow
2909 const SwContentFrame
* SwFootnoteFrame::GetRef() const
2911 const SwContentFrame
* pRefAttr
= GetRefFromAttr();
2912 // check consistency: access to deleted frame?
2913 assert(mpReference
== pRefAttr
|| mpReference
->IsAnFollow(pRefAttr
)
2914 || pRefAttr
->IsAnFollow(mpReference
));
2919 SwContentFrame
* SwFootnoteFrame::GetRef()
2921 const SwContentFrame
* pRefAttr
= GetRefFromAttr();
2922 // check consistency: access to deleted frame?
2923 assert(mpReference
== pRefAttr
|| mpReference
->IsAnFollow(pRefAttr
)
2924 || pRefAttr
->IsAnFollow(mpReference
));
2930 const SwContentFrame
* SwFootnoteFrame::GetRefFromAttr() const
2932 SwFootnoteFrame
* pThis
= const_cast<SwFootnoteFrame
*>(this);
2933 return pThis
->GetRefFromAttr();
2936 SwContentFrame
* SwFootnoteFrame::GetRefFromAttr()
2938 assert(mpAttribute
&& "invalid Attribute");
2939 SwTextNode
& rTNd
= const_cast<SwTextNode
&>(mpAttribute
->GetTextNode());
2940 SwPosition
aPos( rTNd
, mpAttribute
->GetStart() );
2941 SwContentFrame
* pCFrame
= rTNd
.getLayoutFrame(getRootFrame(), &aPos
);
2945 /** search for last content in the current footnote frame
2947 OD 2005-12-02 #i27138#
2949 SwContentFrame
* SwFootnoteFrame::FindLastContent()
2951 SwContentFrame
* pLastContentFrame( nullptr );
2953 // find last lower, which is a content frame or contains content.
2954 // hidden text frames, empty sections and empty tables have to be skipped.
2955 SwFrame
* pLastLowerOfFootnote( GetLower() );
2956 SwFrame
* pTmpLastLower( pLastLowerOfFootnote
);
2957 while ( pTmpLastLower
&& pTmpLastLower
->GetNext() )
2959 pTmpLastLower
= pTmpLastLower
->GetNext();
2960 if ( ( pTmpLastLower
->IsTextFrame() &&
2961 !static_cast<SwTextFrame
*>(pTmpLastLower
)->IsHiddenNow() ) ||
2962 ( pTmpLastLower
->IsSctFrame() &&
2963 static_cast<SwSectionFrame
*>(pTmpLastLower
)->GetSection() &&
2964 static_cast<SwSectionFrame
*>(pTmpLastLower
)->ContainsContent() ) ||
2965 ( pTmpLastLower
->IsTabFrame() &&
2966 static_cast<SwTabFrame
*>(pTmpLastLower
)->ContainsContent() ) )
2968 pLastLowerOfFootnote
= pTmpLastLower
;
2972 // determine last content frame depending on type of found last lower.
2973 if ( pLastLowerOfFootnote
&& pLastLowerOfFootnote
->IsTabFrame() )
2975 pLastContentFrame
= static_cast<SwTabFrame
*>(pLastLowerOfFootnote
)->FindLastContent();
2977 else if ( pLastLowerOfFootnote
&& pLastLowerOfFootnote
->IsSctFrame() )
2979 pLastContentFrame
= static_cast<SwSectionFrame
*>(pLastLowerOfFootnote
)->FindLastContent();
2983 pLastContentFrame
= dynamic_cast<SwContentFrame
*>(pLastLowerOfFootnote
);
2986 return pLastContentFrame
;
2989 void SwFootnoteFrame::dumpAsXml(xmlTextWriterPtr writer
) const
2991 (void)xmlTextWriterStartElement(writer
, reinterpret_cast<const xmlChar
*>("ftn"));
2992 dumpAsXmlAttributes(writer
);
2994 (void)xmlTextWriterStartElement(writer
, BAD_CAST("infos"));
2995 dumpInfosAsXml(writer
);
2996 (void)xmlTextWriterEndElement(writer
);
2997 dumpChildrenAsXml(writer
);
2999 (void)xmlTextWriterEndElement(writer
);
3002 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */