ITEM: Refactor ItemType
[LibreOffice.git] / sw / source / core / doc / ftnidx.cxx
blobc96bda71f04f3c43233c967dd20aefabd83209b9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <txtftn.hxx>
21 #include <fmtftn.hxx>
22 #include <ftninfo.hxx>
23 #include <doc.hxx>
24 #include <IDocumentLayoutAccess.hxx>
25 #include <IDocumentRedlineAccess.hxx>
26 #include <redline.hxx>
27 #include <ftnidx.hxx>
28 #include <ndtxt.hxx>
29 #include <ndindex.hxx>
30 #include <section.hxx>
31 #include <fmtftntx.hxx>
32 #include <rootfrm.hxx>
33 #include <txtfrm.hxx>
35 namespace sw {
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));
43 return (pRedline
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 )
61 if( empty() )
62 return;
64 // Get the NodesArray using the first foot note's StartIndex
65 SwDoc& rDoc = const_cast<SwDoc&>(rStt.GetDoc());
66 if( rDoc.IsInReading() )
67 return ;
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())
86 pLayout = pTmp;
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
98 size_t n = 0;
100 for( ; n < rOutlNds.size(); ++n )
101 if( rOutlNds[ n ]->GetIndex() > rStt.GetIndex() )
102 break; // found it!
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();
116 break;
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();
126 break;
131 size_t nPos = 0;
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 > 0)
140 --nPos;
141 if (pCmpNd != &((*this)[nPos]->GetTextNode()))
142 break;
144 ++nPos;
147 if( nPos == size() ) // nothing found
148 return;
150 if( rOutlNds.empty() )
152 nFootnoteNo = nPos+1;
153 if (nPos > 0)
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)
164 break;
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)
178 ++nFootnoteNo;
180 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
182 ++nFootnoteNoHidden;
188 SwUpdFootnoteEndNtAtEnd aNumArr;
190 // unless we have per-document numbering, only look at endnotes here
191 const bool bEndNoteOnly = FTNNUM_DOC != rFootnoteInfo.m_eNum;
193 size_t nPos;
194 size_t nFootnoteNo = 1;
195 size_t nEndNo = 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() )
203 break;
205 const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote();
206 if( rFootnote.GetNumStr().isEmpty() )
208 if (!aNumArr.ChkNumber(rIDRA, *pTextFootnote).first)
210 if( pTextFootnote->GetFootnote().IsEndNote() )
212 nEndNo++;
213 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
215 ++nEndNoHidden;
218 else
220 nFootnoteNo++;
221 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
223 ++nFootnoteNoHidden;
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;
243 ++nEndNo;
244 nSectNo.second = rEndInfo.m_nFootnoteOffset + nEndNoHidden;
245 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
247 ++nEndNoHidden;
250 else
252 nSectNo.first = rFootnoteInfo.m_nFootnoteOffset + nFootnoteNo;
253 ++nFootnoteNo;
254 nSectNo.second = rFootnoteInfo.m_nFootnoteOffset + nFootnoteNoHidden;
255 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
257 ++nFootnoteNoHidden;
262 if (nSectNo.first)
264 pTextFootnote->SetNumber(nSectNo.first, nSectNo.second, rFootnote.GetNumStr());
270 void SwFootnoteIdxs::UpdateAllFootnote()
272 if( empty() )
273 return;
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())
296 pLayout = pTmp;
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 )
313 break;
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() );
324 ++nNo;
325 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
327 ++nNoNo;
331 if( nFootnoteIdx >= size() )
332 break; // ok, everything is updated
333 nNo = 1;
334 // sw_redlinehide: this means the numbers are layout dependent in chapter case
335 if (!pLayout || sw::IsParaPropsNode(*pLayout, *rOutlNds[ n ]->GetTextNode()))
337 nNoNo = 1;
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() );
354 ++nNo;
355 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
357 ++nNoNo;
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;
381 ++nEndnoteNo;
382 nSectNo.second = rEndInfo.m_nFootnoteOffset + nEndnoteNoHidden;
383 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
385 ++nEndnoteNoHidden;
388 else
390 nSectNo.first = rFootnoteInfo.m_nFootnoteOffset + nFootnoteNo;
391 ++nFootnoteNo;
392 nSectNo.second = rFootnoteInfo.m_nFootnoteOffset + nFootnoteNoHidden;
393 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
395 ++nFootnoteNoHidden;
400 if (nSectNo.first)
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();
416 size_t nO = size();
417 size_t nU = 0;
418 if( nO > 0 )
420 nO--;
421 while( nU <= nO )
423 const size_t nM = nU + ( nO - nU ) / 2;
424 SwNodeOffset nNdIdx = SwTextFootnote_GetIndex( (*this)[ nM ] );
425 if( nNdIdx == nIdx )
427 if( pFndPos )
428 *pFndPos = nM;
429 return (*this)[ nM ];
431 else if( nNdIdx < nIdx )
432 nU = nM + 1;
433 else if( nM == 0 )
435 if( pFndPos )
436 *pFndPos = nU;
437 return nullptr;
439 else
440 nO = nM - 1;
443 if( pFndPos )
444 *pFndPos = nU;
445 return nullptr;
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();
454 while( pNd )
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 )
459 break;
460 pNd = pNd->StartOfSectionNode()->FindSectionNode();
463 return pNd;
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);
472 sal_uInt16 nWh;
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;
481 else
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);
497 break;
500 if (!nRet.first)
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 );
510 return nRet;
513 std::pair<sal_uInt16, sal_uInt16> SwUpdFootnoteEndNtAtEnd::ChkNumber(
514 IDocumentRedlineAccess const& rIDRA,
515 const SwTextFootnote& rTextFootnote)
517 const SwSectionNode* pSectNd = FindSectNdWithEndAttr( rTextFootnote );
518 return pSectNd
519 ? GetNumber(rIDRA, rTextFootnote, *pSectNd)
520 : std::pair<sal_uInt16, sal_uInt16>(0, 0);
523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */