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 .
22 #include <ftninfo.hxx>
24 #include <IDocumentLayoutAccess.hxx>
25 #include <IDocumentRedlineAccess.hxx>
26 #include <redline.hxx>
29 #include <ndindex.hxx>
30 #include <section.hxx>
31 #include <fmtftntx.hxx>
32 #include <rootfrm.hxx>
37 bool IsFootnoteDeleted(IDocumentRedlineAccess
const& rIDRA
,
38 SwTextFootnote
const& rTextFootnote
)
40 SwRedlineTable::size_type tmp
;
41 SwPosition
const pos(rTextFootnote
.GetTextNode(), rTextFootnote
.GetStart());
42 SwRangeRedline
const*const pRedline(rIDRA
.GetRedline(pos
, &tmp
));
44 && pRedline
->GetType() == RedlineType::Delete
45 && *pRedline
->GetPoint() != *pRedline
->GetMark());
50 using sw::IsFootnoteDeleted
;
52 bool CompareSwFootnoteIdxs::operator()(SwTextFootnote
* const& lhs
, SwTextFootnote
* const& rhs
) const
54 SwNodeOffset nIdxLHS
= SwTextFootnote_GetIndex( lhs
);
55 SwNodeOffset nIdxRHS
= SwTextFootnote_GetIndex( rhs
);
56 return ( nIdxLHS
== nIdxRHS
&& lhs
->GetStart() < rhs
->GetStart() ) || nIdxLHS
< nIdxRHS
;
59 void SwFootnoteIdxs::UpdateFootnote( const SwNode
& rStt
)
64 // Get the NodesArray using the first foot note's StartIndex
65 SwDoc
& rDoc
= const_cast<SwDoc
&>(rStt
.GetDoc());
66 if( rDoc
.IsInReading() )
68 SwTextFootnote
* pTextFootnote
;
70 const SwEndNoteInfo
& rEndInfo
= rDoc
.GetEndNoteInfo();
71 const SwFootnoteInfo
& rFootnoteInfo
= rDoc
.GetFootnoteInfo();
72 IDocumentRedlineAccess
const& rIDRA(rDoc
.getIDocumentRedlineAccess());
74 // For normal foot notes we treat per-chapter and per-document numbering
75 // separately. For Endnotes we only have per-document numbering.
76 if( FTNNUM_CHAPTER
== rFootnoteInfo
.m_eNum
)
78 SwRootFrame
const* pLayout(nullptr);
79 o3tl::sorted_vector
<SwRootFrame
*> layouts
= rDoc
.GetAllLayouts();
80 // sw_redlinehide: here we need to know if there's *any* layout with
81 // IsHideRedlines(), because then the hidden-numbers have to be updated
82 for (SwRootFrame
const* pTmp
: layouts
)
84 if (pTmp
->IsHideRedlines())
90 const SwOutlineNodes
& rOutlNds
= rDoc
.GetNodes().GetOutLineNds();
91 const SwNode
*pChapterStartHidden(&rDoc
.GetNodes().GetEndOfExtras());
92 SwNodeOffset
nChapterStart(pChapterStartHidden
->GetIndex());
93 SwNodeOffset
nChapterEnd(rDoc
.GetNodes().GetEndOfContent().GetIndex());
94 SwNodeOffset
nChapterEndHidden(nChapterEnd
);
95 if( !rOutlNds
.empty() )
97 // Find the Chapter's start, which contains rStt
100 for( ; n
< rOutlNds
.size(); ++n
)
101 if( rOutlNds
[ n
]->GetIndex() > rStt
.GetIndex() )
103 else if ( rOutlNds
[ n
]->GetTextNode()->GetAttrOutlineLevel() == 1 )
105 nChapterStart
= rOutlNds
[ n
]->GetIndex();
106 if (!pLayout
|| sw::IsParaPropsNode(*pLayout
, *rOutlNds
[n
]->GetTextNode()))
108 pChapterStartHidden
= rOutlNds
[ n
];
111 // now find the end of the range
112 for( ; n
< rOutlNds
.size(); ++n
)
113 if ( rOutlNds
[ n
]->GetTextNode()->GetAttrOutlineLevel() == 1 )
115 nChapterEnd
= rOutlNds
[ n
]->GetIndex();
119 // continue to find end of hidden-chapter
120 for ( ; n
< rOutlNds
.size(); ++n
)
122 if (rOutlNds
[n
]->GetTextNode()->GetAttrOutlineLevel() == 1
123 && (!pLayout
|| sw::IsParaPropsNode(*pLayout
, *rOutlNds
[n
]->GetTextNode())))
125 nChapterEndHidden
= rOutlNds
[n
]->GetIndex();
132 size_t nFootnoteNo
= 1;
133 size_t nFootnoteNoHidden
= 1;
134 if (SeekEntry( *pChapterStartHidden
, &nPos
) && nPos
)
136 // Step forward until the Index is not the same anymore
137 const SwNode
* pCmpNd
= &rStt
;
138 while( nPos
&& pCmpNd
== &((*this)[ --nPos
]->GetTextNode()) )
143 if( nPos
== size() ) // nothing found
146 if( rOutlNds
.empty() )
148 nFootnoteNo
= nPos
+1;
151 nFootnoteNoHidden
= (*this)[nPos
- 1]->GetFootnote().GetNumberRLHidden() + 1;
155 for( ; nPos
< size(); ++nPos
)
157 pTextFootnote
= (*this)[ nPos
];
158 SwNodeOffset
const nNode(pTextFootnote
->GetTextNode().GetIndex());
159 if (nChapterEndHidden
<= nNode
)
162 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
163 if( rFootnote
.GetNumStr().isEmpty() && !rFootnote
.IsEndNote() &&
164 !SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr( *pTextFootnote
))
166 pTextFootnote
->SetNumber(
167 (nChapterStart
<= nNode
&& nNode
< nChapterEnd
)
168 ? rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNo
169 : rFootnote
.GetNumber(),
170 rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNoHidden
,
171 rFootnote
.GetNumStr() );
172 if (nChapterStart
<= nNode
&& nNode
< nChapterEnd
)
176 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
184 SwUpdFootnoteEndNtAtEnd aNumArr
;
186 // unless we have per-document numbering, only look at endnotes here
187 const bool bEndNoteOnly
= FTNNUM_DOC
!= rFootnoteInfo
.m_eNum
;
190 size_t nFootnoteNo
= 1;
192 size_t nFootnoteNoHidden
= 1;
193 size_t nEndNoHidden
= 1;
194 SwNodeOffset nUpdNdIdx
= rStt
.GetIndex();
195 for( nPos
= 0; nPos
< size(); ++nPos
)
197 pTextFootnote
= (*this)[ nPos
];
198 if( nUpdNdIdx
<= pTextFootnote
->GetTextNode().GetIndex() )
201 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
202 if( rFootnote
.GetNumStr().isEmpty() )
204 if (!aNumArr
.ChkNumber(rIDRA
, *pTextFootnote
).first
)
206 if( pTextFootnote
->GetFootnote().IsEndNote() )
209 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
217 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
226 // Set the array number for all footnotes starting from nPos
227 for( ; nPos
< size(); ++nPos
)
229 pTextFootnote
= (*this)[ nPos
];
230 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
231 if( rFootnote
.GetNumStr().isEmpty() )
233 std::pair
<sal_uInt16
, sal_uInt16
> nSectNo
= aNumArr
.ChkNumber(rIDRA
, *pTextFootnote
);
234 if (!nSectNo
.first
&& (rFootnote
.IsEndNote() || !bEndNoteOnly
))
236 if (rFootnote
.IsEndNote())
238 nSectNo
.first
= rEndInfo
.m_nFootnoteOffset
+ nEndNo
;
240 nSectNo
.second
= rEndInfo
.m_nFootnoteOffset
+ nEndNoHidden
;
241 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
248 nSectNo
.first
= rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNo
;
250 nSectNo
.second
= rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNoHidden
;
251 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
260 pTextFootnote
->SetNumber(nSectNo
.first
, nSectNo
.second
, rFootnote
.GetNumStr());
266 void SwFootnoteIdxs::UpdateAllFootnote()
271 // Get the NodesArray via the StartIndex of the first Footnote
272 SwDoc
& rDoc
= const_cast<SwDoc
&>((*this)[ 0 ]->GetTextNode().GetDoc());
273 SwTextFootnote
* pTextFootnote
;
274 const SwEndNoteInfo
& rEndInfo
= rDoc
.GetEndNoteInfo();
275 const SwFootnoteInfo
& rFootnoteInfo
= rDoc
.GetFootnoteInfo();
276 IDocumentRedlineAccess
const& rIDRA(rDoc
.getIDocumentRedlineAccess());
278 SwUpdFootnoteEndNtAtEnd aNumArr
;
280 SwRootFrame
const* pLayout
= rDoc
.getIDocumentLayoutAccess().GetCurrentLayout();
281 o3tl::sorted_vector
<SwRootFrame
*> aAllLayouts
= rDoc
.GetAllLayouts();
282 // For normal Footnotes per-chapter and per-document numbering are treated separately.
283 // For Endnotes we only have document-wise numbering.
284 if( FTNNUM_CHAPTER
== rFootnoteInfo
.m_eNum
)
286 // sw_redlinehide: here we need to know if there's *any* layout with
287 // IsHideRedlines(), because then the hidden-numbers have to be updated
288 for (SwRootFrame
const* pTmp
: aAllLayouts
)
290 if (pTmp
->IsHideRedlines())
296 const SwOutlineNodes
& rOutlNds
= rDoc
.GetNodes().GetOutLineNds();
297 sal_uInt16 nNo
= 1; // Number for the Footnotes
298 sal_uInt16 nNoNo
= 1;
299 size_t nFootnoteIdx
= 0; // Index into theFootnoteIdx array
300 for( size_t n
= 0; n
< rOutlNds
.size(); ++n
)
302 if ( rOutlNds
[ n
]->GetTextNode()->GetAttrOutlineLevel() == 1 )
304 SwNodeOffset nCapStt
= rOutlNds
[ n
]->GetIndex(); // Start of a new chapter
305 for( ; nFootnoteIdx
< size(); ++nFootnoteIdx
)
307 pTextFootnote
= (*this)[ nFootnoteIdx
];
308 if( pTextFootnote
->GetTextNode().GetIndex() >= nCapStt
)
311 // Endnotes are per-document only
312 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
313 if( !rFootnote
.IsEndNote() && rFootnote
.GetNumStr().isEmpty() &&
314 !SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr( *pTextFootnote
))
316 pTextFootnote
->SetNumber(
317 rFootnoteInfo
.m_nFootnoteOffset
+ nNo
,
318 rFootnoteInfo
.m_nFootnoteOffset
+ nNoNo
,
319 rFootnote
.GetNumStr() );
321 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
327 if( nFootnoteIdx
>= size() )
328 break; // ok, everything is updated
330 // sw_redlinehide: this means the numbers are layout dependent in chapter case
331 if (!pLayout
|| sw::IsParaPropsNode(*pLayout
, *rOutlNds
[ n
]->GetTextNode()))
338 for (nNo
= 1, nNoNo
= 1; nFootnoteIdx
< size(); ++nFootnoteIdx
)
340 // Endnotes are per-document
341 pTextFootnote
= (*this)[ nFootnoteIdx
];
342 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
343 if( !rFootnote
.IsEndNote() && rFootnote
.GetNumStr().isEmpty() &&
344 !SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr( *pTextFootnote
))
346 pTextFootnote
->SetNumber(
347 rFootnoteInfo
.m_nFootnoteOffset
+ nNo
,
348 rFootnoteInfo
.m_nFootnoteOffset
+ nNoNo
,
349 rFootnote
.GetNumStr() );
351 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
359 // We use bool here, so that we also iterate through the Endnotes with a chapter setting.
360 const bool bEndNoteOnly
= FTNNUM_DOC
!= rFootnoteInfo
.m_eNum
;
361 sal_uInt16 nFootnoteNo
= 1;
362 sal_uInt16 nEndnoteNo
= 1;
363 sal_uInt16 nFootnoteNoHidden
= 1;
364 sal_uInt16 nEndnoteNoHidden
= 1;
365 for( size_t nPos
= 0; nPos
< size(); ++nPos
)
367 pTextFootnote
= (*this)[ nPos
];
368 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
369 if( rFootnote
.GetNumStr().isEmpty() )
371 std::pair
<sal_uInt16
, sal_uInt16
> nSectNo
= aNumArr
.ChkNumber(rIDRA
, *pTextFootnote
);
372 if (!nSectNo
.first
&& (rFootnote
.IsEndNote() || !bEndNoteOnly
))
374 if (rFootnote
.IsEndNote())
376 nSectNo
.first
= rEndInfo
.m_nFootnoteOffset
+ nEndnoteNo
;
378 nSectNo
.second
= rEndInfo
.m_nFootnoteOffset
+ nEndnoteNoHidden
;
379 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
386 nSectNo
.first
= rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNo
;
388 nSectNo
.second
= rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNoHidden
;
389 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
398 pTextFootnote
->SetNumber(nSectNo
.first
, nSectNo
.second
, rFootnote
.GetNumStr());
403 if (pLayout
&& FTNNUM_PAGE
== rFootnoteInfo
.m_eNum
)
404 for( auto aLayout
: aAllLayouts
)
405 aLayout
->UpdateFootnoteNums();
408 SwTextFootnote
* SwFootnoteIdxs::SeekEntry( const SwNode
& rPos
, size_t* pFndPos
) const
410 SwNodeOffset nIdx
= rPos
.GetIndex();
419 const size_t nM
= nU
+ ( nO
- nU
) / 2;
420 SwNodeOffset nNdIdx
= SwTextFootnote_GetIndex( (*this)[ nM
] );
425 return (*this)[ nM
];
427 else if( nNdIdx
< nIdx
)
444 const SwSectionNode
* SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr(
445 const SwTextFootnote
& rTextFootnote
)
447 sal_uInt16 nWh
= rTextFootnote
.GetFootnote().IsEndNote() ?
448 sal_uInt16(RES_END_AT_TXTEND
) : sal_uInt16(RES_FTN_AT_TXTEND
);
449 const SwSectionNode
* pNd
= rTextFootnote
.GetTextNode().FindSectionNode();
452 sal_uInt16 nVal
= static_cast<const SwFormatFootnoteEndAtTextEnd
&>(pNd
->GetSection().GetFormat()->
453 GetFormatAttr( nWh
)).GetValue();
454 if( FTNEND_ATTXTEND_OWNNUMSEQ
== nVal
|| FTNEND_ATTXTEND_OWNNUMANDFMT
== nVal
)
456 pNd
= pNd
->StartOfSectionNode()->FindSectionNode();
462 std::pair
<sal_uInt16
, sal_uInt16
> SwUpdFootnoteEndNtAtEnd::GetNumber(
463 IDocumentRedlineAccess
const& rIDRA
,
464 const SwTextFootnote
& rTextFootnote
,
465 const SwSectionNode
& rNd
)
467 std::pair
<sal_uInt16
, sal_uInt16
> nRet(0, 0);
469 std::vector
<const SwSectionNode
*>* pArr
;
470 std::vector
<std::pair
<sal_uInt16
, sal_uInt16
>> *pNum
;
471 if( rTextFootnote
.GetFootnote().IsEndNote() )
473 pArr
= &m_aEndSections
;
474 pNum
= &m_aEndNumbers
;
475 nWh
= RES_END_AT_TXTEND
;
479 pArr
= &m_aFootnoteSections
;
480 pNum
= &m_aFootnoteNumbers
;
481 nWh
= RES_FTN_AT_TXTEND
;
484 for( size_t n
= pArr
->size(); n
; )
485 if( (*pArr
)[ --n
] == &rNd
)
487 nRet
.first
= ++((*pNum
)[ n
].first
);
488 if (!IsFootnoteDeleted(rIDRA
, rTextFootnote
))
490 ++((*pNum
)[ n
].second
);
492 nRet
.second
= ((*pNum
)[ n
].second
);
498 pArr
->push_back( &rNd
);
499 sal_uInt16
const tmp
= static_cast<const SwFormatFootnoteEndAtTextEnd
&>(
500 rNd
.GetSection().GetFormat()->
501 GetFormatAttr( nWh
)).GetOffset();
502 nRet
.first
= tmp
+ 1;
503 nRet
.second
= tmp
+ 1;
504 pNum
->push_back( nRet
);
509 std::pair
<sal_uInt16
, sal_uInt16
> SwUpdFootnoteEndNtAtEnd::ChkNumber(
510 IDocumentRedlineAccess
const& rIDRA
,
511 const SwTextFootnote
& rTextFootnote
)
513 const SwSectionNode
* pSectNd
= FindSectNdWithEndAttr( rTextFootnote
);
515 ? GetNumber(rIDRA
, rTextFootnote
, *pSectNd
)
516 : std::pair
<sal_uInt16
, sal_uInt16
>(0, 0);
519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */