android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / doc / ftnidx.cxx
blob81f6378c5a49156c765c4c9d6c4524c30b5bcc73
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 && pCmpNd == &((*this)[ --nPos ]->GetTextNode()) )
140 ++nPos;
143 if( nPos == size() ) // nothing found
144 return;
146 if( rOutlNds.empty() )
148 nFootnoteNo = nPos+1;
149 if (nPos)
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)
160 break;
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)
174 ++nFootnoteNo;
176 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
178 ++nFootnoteNoHidden;
184 SwUpdFootnoteEndNtAtEnd aNumArr;
186 // unless we have per-document numbering, only look at endnotes here
187 const bool bEndNoteOnly = FTNNUM_DOC != rFootnoteInfo.m_eNum;
189 size_t nPos;
190 size_t nFootnoteNo = 1;
191 size_t nEndNo = 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() )
199 break;
201 const SwFormatFootnote &rFootnote = pTextFootnote->GetFootnote();
202 if( rFootnote.GetNumStr().isEmpty() )
204 if (!aNumArr.ChkNumber(rIDRA, *pTextFootnote).first)
206 if( pTextFootnote->GetFootnote().IsEndNote() )
208 nEndNo++;
209 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
211 ++nEndNoHidden;
214 else
216 nFootnoteNo++;
217 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
219 ++nFootnoteNoHidden;
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;
239 ++nEndNo;
240 nSectNo.second = rEndInfo.m_nFootnoteOffset + nEndNoHidden;
241 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
243 ++nEndNoHidden;
246 else
248 nSectNo.first = rFootnoteInfo.m_nFootnoteOffset + nFootnoteNo;
249 ++nFootnoteNo;
250 nSectNo.second = rFootnoteInfo.m_nFootnoteOffset + nFootnoteNoHidden;
251 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
253 ++nFootnoteNoHidden;
258 if (nSectNo.first)
260 pTextFootnote->SetNumber(nSectNo.first, nSectNo.second, rFootnote.GetNumStr());
266 void SwFootnoteIdxs::UpdateAllFootnote()
268 if( empty() )
269 return;
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())
292 pLayout = pTmp;
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 )
309 break;
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() );
320 ++nNo;
321 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
323 ++nNoNo;
327 if( nFootnoteIdx >= size() )
328 break; // ok, everything is updated
329 nNo = 1;
330 // sw_redlinehide: this means the numbers are layout dependent in chapter case
331 if (!pLayout || sw::IsParaPropsNode(*pLayout, *rOutlNds[ n ]->GetTextNode()))
333 nNoNo = 1;
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() );
350 ++nNo;
351 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
353 ++nNoNo;
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;
377 ++nEndnoteNo;
378 nSectNo.second = rEndInfo.m_nFootnoteOffset + nEndnoteNoHidden;
379 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
381 ++nEndnoteNoHidden;
384 else
386 nSectNo.first = rFootnoteInfo.m_nFootnoteOffset + nFootnoteNo;
387 ++nFootnoteNo;
388 nSectNo.second = rFootnoteInfo.m_nFootnoteOffset + nFootnoteNoHidden;
389 if (!IsFootnoteDeleted(rIDRA, *pTextFootnote))
391 ++nFootnoteNoHidden;
396 if (nSectNo.first)
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();
412 size_t nO = size();
413 size_t nU = 0;
414 if( nO > 0 )
416 nO--;
417 while( nU <= nO )
419 const size_t nM = nU + ( nO - nU ) / 2;
420 SwNodeOffset nNdIdx = SwTextFootnote_GetIndex( (*this)[ nM ] );
421 if( nNdIdx == nIdx )
423 if( pFndPos )
424 *pFndPos = nM;
425 return (*this)[ nM ];
427 else if( nNdIdx < nIdx )
428 nU = nM + 1;
429 else if( nM == 0 )
431 if( pFndPos )
432 *pFndPos = nU;
433 return nullptr;
435 else
436 nO = nM - 1;
439 if( pFndPos )
440 *pFndPos = nU;
441 return nullptr;
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();
450 while( pNd )
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 )
455 break;
456 pNd = pNd->StartOfSectionNode()->FindSectionNode();
459 return pNd;
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);
468 sal_uInt16 nWh;
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;
477 else
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);
493 break;
496 if (!nRet.first)
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 );
506 return nRet;
509 std::pair<sal_uInt16, sal_uInt16> SwUpdFootnoteEndNtAtEnd::ChkNumber(
510 IDocumentRedlineAccess const& rIDRA,
511 const SwTextFootnote& rTextFootnote)
513 const SwSectionNode* pSectNd = FindSectNdWithEndAttr( rTextFootnote );
514 return pSectNd
515 ? GetNumber(rIDRA, rTextFootnote, *pSectNd)
516 : std::pair<sal_uInt16, sal_uInt16>(0, 0);
519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */