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
;
141 if (pCmpNd
!= &((*this)[nPos
]->GetTextNode()))
147 if( nPos
== size() ) // nothing found
150 if( rOutlNds
.empty() )
152 nFootnoteNo
= nPos
+1;
155 nFootnoteNoHidden
= (*this)[nPos
- 1]->GetFootnote().GetNumberRLHidden() + 1;
159 for( ; nPos
< size(); ++nPos
)
161 pTextFootnote
= (*this)[ nPos
];
162 SwNodeOffset
const nNode(pTextFootnote
->GetTextNode().GetIndex());
163 if (nChapterEndHidden
<= nNode
)
166 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
167 if( rFootnote
.GetNumStr().isEmpty() && !rFootnote
.IsEndNote() &&
168 !SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr( *pTextFootnote
))
170 pTextFootnote
->SetNumber(
171 (nChapterStart
<= nNode
&& nNode
< nChapterEnd
)
172 ? rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNo
173 : rFootnote
.GetNumber(),
174 rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNoHidden
,
175 rFootnote
.GetNumStr() );
176 if (nChapterStart
<= nNode
&& nNode
< nChapterEnd
)
180 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
188 SwUpdFootnoteEndNtAtEnd aNumArr
;
190 // unless we have per-document numbering, only look at endnotes here
191 const bool bEndNoteOnly
= FTNNUM_DOC
!= rFootnoteInfo
.m_eNum
;
194 size_t nFootnoteNo
= 1;
196 size_t nFootnoteNoHidden
= 1;
197 size_t nEndNoHidden
= 1;
198 SwNodeOffset nUpdNdIdx
= rStt
.GetIndex();
199 for( nPos
= 0; nPos
< size(); ++nPos
)
201 pTextFootnote
= (*this)[ nPos
];
202 if( nUpdNdIdx
<= pTextFootnote
->GetTextNode().GetIndex() )
205 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
206 if( rFootnote
.GetNumStr().isEmpty() )
208 if (!aNumArr
.ChkNumber(rIDRA
, *pTextFootnote
).first
)
210 if( pTextFootnote
->GetFootnote().IsEndNote() )
213 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
221 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
230 // Set the array number for all footnotes starting from nPos
231 for( ; nPos
< size(); ++nPos
)
233 pTextFootnote
= (*this)[ nPos
];
234 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
235 if( rFootnote
.GetNumStr().isEmpty() )
237 std::pair
<sal_uInt16
, sal_uInt16
> nSectNo
= aNumArr
.ChkNumber(rIDRA
, *pTextFootnote
);
238 if (!nSectNo
.first
&& (rFootnote
.IsEndNote() || !bEndNoteOnly
))
240 if (rFootnote
.IsEndNote())
242 nSectNo
.first
= rEndInfo
.m_nFootnoteOffset
+ nEndNo
;
244 nSectNo
.second
= rEndInfo
.m_nFootnoteOffset
+ nEndNoHidden
;
245 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
252 nSectNo
.first
= rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNo
;
254 nSectNo
.second
= rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNoHidden
;
255 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
264 pTextFootnote
->SetNumber(nSectNo
.first
, nSectNo
.second
, rFootnote
.GetNumStr());
270 void SwFootnoteIdxs::UpdateAllFootnote()
275 // Get the NodesArray via the StartIndex of the first Footnote
276 SwDoc
& rDoc
= const_cast<SwDoc
&>((*this)[ 0 ]->GetTextNode().GetDoc());
277 SwTextFootnote
* pTextFootnote
;
278 const SwEndNoteInfo
& rEndInfo
= rDoc
.GetEndNoteInfo();
279 const SwFootnoteInfo
& rFootnoteInfo
= rDoc
.GetFootnoteInfo();
280 IDocumentRedlineAccess
const& rIDRA(rDoc
.getIDocumentRedlineAccess());
282 SwUpdFootnoteEndNtAtEnd aNumArr
;
284 SwRootFrame
const* pLayout
= rDoc
.getIDocumentLayoutAccess().GetCurrentLayout();
285 o3tl::sorted_vector
<SwRootFrame
*> aAllLayouts
= rDoc
.GetAllLayouts();
286 // For normal Footnotes per-chapter and per-document numbering are treated separately.
287 // For Endnotes we only have document-wise numbering.
288 if( FTNNUM_CHAPTER
== rFootnoteInfo
.m_eNum
)
290 // sw_redlinehide: here we need to know if there's *any* layout with
291 // IsHideRedlines(), because then the hidden-numbers have to be updated
292 for (SwRootFrame
const* pTmp
: aAllLayouts
)
294 if (pTmp
->IsHideRedlines())
300 const SwOutlineNodes
& rOutlNds
= rDoc
.GetNodes().GetOutLineNds();
301 sal_uInt16 nNo
= 1; // Number for the Footnotes
302 sal_uInt16 nNoNo
= 1;
303 size_t nFootnoteIdx
= 0; // Index into theFootnoteIdx array
304 for( size_t n
= 0; n
< rOutlNds
.size(); ++n
)
306 if ( rOutlNds
[ n
]->GetTextNode()->GetAttrOutlineLevel() == 1 )
308 SwNodeOffset nCapStt
= rOutlNds
[ n
]->GetIndex(); // Start of a new chapter
309 for( ; nFootnoteIdx
< size(); ++nFootnoteIdx
)
311 pTextFootnote
= (*this)[ nFootnoteIdx
];
312 if( pTextFootnote
->GetTextNode().GetIndex() >= nCapStt
)
315 // Endnotes are per-document only
316 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
317 if( !rFootnote
.IsEndNote() && rFootnote
.GetNumStr().isEmpty() &&
318 !SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr( *pTextFootnote
))
320 pTextFootnote
->SetNumber(
321 rFootnoteInfo
.m_nFootnoteOffset
+ nNo
,
322 rFootnoteInfo
.m_nFootnoteOffset
+ nNoNo
,
323 rFootnote
.GetNumStr() );
325 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
331 if( nFootnoteIdx
>= size() )
332 break; // ok, everything is updated
334 // sw_redlinehide: this means the numbers are layout dependent in chapter case
335 if (!pLayout
|| sw::IsParaPropsNode(*pLayout
, *rOutlNds
[ n
]->GetTextNode()))
342 for (nNo
= 1, nNoNo
= 1; nFootnoteIdx
< size(); ++nFootnoteIdx
)
344 // Endnotes are per-document
345 pTextFootnote
= (*this)[ nFootnoteIdx
];
346 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
347 if( !rFootnote
.IsEndNote() && rFootnote
.GetNumStr().isEmpty() &&
348 !SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr( *pTextFootnote
))
350 pTextFootnote
->SetNumber(
351 rFootnoteInfo
.m_nFootnoteOffset
+ nNo
,
352 rFootnoteInfo
.m_nFootnoteOffset
+ nNoNo
,
353 rFootnote
.GetNumStr() );
355 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
363 // We use bool here, so that we also iterate through the Endnotes with a chapter setting.
364 const bool bEndNoteOnly
= FTNNUM_DOC
!= rFootnoteInfo
.m_eNum
;
365 sal_uInt16 nFootnoteNo
= 1;
366 sal_uInt16 nEndnoteNo
= 1;
367 sal_uInt16 nFootnoteNoHidden
= 1;
368 sal_uInt16 nEndnoteNoHidden
= 1;
369 for( size_t nPos
= 0; nPos
< size(); ++nPos
)
371 pTextFootnote
= (*this)[ nPos
];
372 const SwFormatFootnote
&rFootnote
= pTextFootnote
->GetFootnote();
373 if( rFootnote
.GetNumStr().isEmpty() )
375 std::pair
<sal_uInt16
, sal_uInt16
> nSectNo
= aNumArr
.ChkNumber(rIDRA
, *pTextFootnote
);
376 if (!nSectNo
.first
&& (rFootnote
.IsEndNote() || !bEndNoteOnly
))
378 if (rFootnote
.IsEndNote())
380 nSectNo
.first
= rEndInfo
.m_nFootnoteOffset
+ nEndnoteNo
;
382 nSectNo
.second
= rEndInfo
.m_nFootnoteOffset
+ nEndnoteNoHidden
;
383 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
390 nSectNo
.first
= rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNo
;
392 nSectNo
.second
= rFootnoteInfo
.m_nFootnoteOffset
+ nFootnoteNoHidden
;
393 if (!IsFootnoteDeleted(rIDRA
, *pTextFootnote
))
402 pTextFootnote
->SetNumber(nSectNo
.first
, nSectNo
.second
, rFootnote
.GetNumStr());
407 if (pLayout
&& FTNNUM_PAGE
== rFootnoteInfo
.m_eNum
)
408 for( auto aLayout
: aAllLayouts
)
409 aLayout
->UpdateFootnoteNums();
412 SwTextFootnote
* SwFootnoteIdxs::SeekEntry( const SwNode
& rPos
, size_t* pFndPos
) const
414 SwNodeOffset nIdx
= rPos
.GetIndex();
423 const size_t nM
= nU
+ ( nO
- nU
) / 2;
424 SwNodeOffset nNdIdx
= SwTextFootnote_GetIndex( (*this)[ nM
] );
429 return (*this)[ nM
];
431 else if( nNdIdx
< nIdx
)
448 const SwSectionNode
* SwUpdFootnoteEndNtAtEnd::FindSectNdWithEndAttr(
449 const SwTextFootnote
& rTextFootnote
)
451 sal_uInt16 nWh
= rTextFootnote
.GetFootnote().IsEndNote() ?
452 sal_uInt16(RES_END_AT_TXTEND
) : sal_uInt16(RES_FTN_AT_TXTEND
);
453 const SwSectionNode
* pNd
= rTextFootnote
.GetTextNode().FindSectionNode();
456 sal_uInt16 nVal
= static_cast<const SwFormatFootnoteEndAtTextEnd
&>(pNd
->GetSection().GetFormat()->
457 GetFormatAttr( nWh
)).GetValue();
458 if( FTNEND_ATTXTEND_OWNNUMSEQ
== nVal
|| FTNEND_ATTXTEND_OWNNUMANDFMT
== nVal
)
460 pNd
= pNd
->StartOfSectionNode()->FindSectionNode();
466 std::pair
<sal_uInt16
, sal_uInt16
> SwUpdFootnoteEndNtAtEnd::GetNumber(
467 IDocumentRedlineAccess
const& rIDRA
,
468 const SwTextFootnote
& rTextFootnote
,
469 const SwSectionNode
& rNd
)
471 std::pair
<sal_uInt16
, sal_uInt16
> nRet(0, 0);
473 std::vector
<const SwSectionNode
*>* pArr
;
474 std::vector
<std::pair
<sal_uInt16
, sal_uInt16
>> *pNum
;
475 if( rTextFootnote
.GetFootnote().IsEndNote() )
477 pArr
= &m_aEndSections
;
478 pNum
= &m_aEndNumbers
;
479 nWh
= RES_END_AT_TXTEND
;
483 pArr
= &m_aFootnoteSections
;
484 pNum
= &m_aFootnoteNumbers
;
485 nWh
= RES_FTN_AT_TXTEND
;
488 for( size_t n
= pArr
->size(); n
; )
489 if( (*pArr
)[ --n
] == &rNd
)
491 nRet
.first
= ++((*pNum
)[ n
].first
);
492 if (!IsFootnoteDeleted(rIDRA
, rTextFootnote
))
494 ++((*pNum
)[ n
].second
);
496 nRet
.second
= ((*pNum
)[ n
].second
);
502 pArr
->push_back( &rNd
);
503 sal_uInt16
const tmp
= static_cast<const SwFormatFootnoteEndAtTextEnd
&>(
504 rNd
.GetSection().GetFormat()->
505 GetFormatAttr( nWh
)).GetOffset();
506 nRet
.first
= tmp
+ 1;
507 nRet
.second
= tmp
+ 1;
508 pNum
->push_back( nRet
);
513 std::pair
<sal_uInt16
, sal_uInt16
> SwUpdFootnoteEndNtAtEnd::ChkNumber(
514 IDocumentRedlineAccess
const& rIDRA
,
515 const SwTextFootnote
& rTextFootnote
)
517 const SwSectionNode
* pSectNd
= FindSectNdWithEndAttr( rTextFootnote
);
519 ? GetNumber(rIDRA
, rTextFootnote
, *pSectNd
)
520 : std::pair
<sal_uInt16
, sal_uInt16
>(0, 0);
523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */