Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <txtftn.hxx>
21 : #include <fmtftn.hxx>
22 : #include <ftninfo.hxx>
23 : #include <doc.hxx>
24 : #include <IDocumentLayoutAccess.hxx>
25 : #include <ftnidx.hxx>
26 : #include <ndtxt.hxx>
27 : #include <ndindex.hxx>
28 : #include <section.hxx>
29 : #include <fmtftntx.hxx>
30 : #include <rootfrm.hxx>
31 :
32 1362 : bool CompareSwFtnIdxs::operator()(SwTxtFtn* const& lhs, SwTxtFtn* const& rhs) const
33 : {
34 1362 : sal_uLong nIdxLHS = _SwTxtFtn_GetIndex( lhs );
35 1362 : sal_uLong nIdxRHS = _SwTxtFtn_GetIndex( rhs );
36 1362 : return ( nIdxLHS == nIdxRHS && lhs->GetStart() < rhs->GetStart() ) || nIdxLHS < nIdxRHS;
37 : }
38 :
39 3824 : void SwFtnIdxs::UpdateFtn( const SwNodeIndex& rStt )
40 : {
41 3824 : if( empty() )
42 7062 : return;
43 :
44 : // Get the NodesArray using the first foot note's StartIndex
45 352 : SwDoc* pDoc = rStt.GetNode().GetDoc();
46 352 : if( pDoc->IsInReading() )
47 118 : return ;
48 : SwTxtFtn* pTxtFtn;
49 :
50 234 : const SwEndNoteInfo& rEndInfo = pDoc->GetEndNoteInfo();
51 234 : const SwFtnInfo& rFtnInfo = pDoc->GetFtnInfo();
52 :
53 : // For normal foot notes we treat per-chapter and per-document numbering
54 : // separately. For Endnotes we only have per-document numbering.
55 234 : if( FTNNUM_CHAPTER == rFtnInfo.eNum )
56 : {
57 6 : const SwOutlineNodes& rOutlNds = pDoc->GetNodes().GetOutLineNds();
58 6 : const SwNode* pCapStt = &pDoc->GetNodes().GetEndOfExtras();
59 6 : sal_uLong nCapEnd = pDoc->GetNodes().GetEndOfContent().GetIndex();
60 6 : if( !rOutlNds.empty() )
61 : {
62 : // Find the Chapter's start, which contains rStt
63 0 : size_t n = 0;
64 :
65 0 : for( ; n < rOutlNds.size(); ++n )
66 0 : if( rOutlNds[ n ]->GetIndex() > rStt.GetIndex() )
67 0 : break; // found it!
68 0 : else if ( rOutlNds[ n ]->GetTxtNode()->GetAttrOutlineLevel() == 1 )
69 0 : pCapStt = rOutlNds[ n ]; // Beginning of a new Chapter
70 : // now find the end of the range
71 0 : for( ; n < rOutlNds.size(); ++n )
72 0 : if ( rOutlNds[ n ]->GetTxtNode()->GetAttrOutlineLevel() == 1 )
73 : {
74 0 : nCapEnd = rOutlNds[ n ]->GetIndex(); // End of the found Chapter
75 0 : break;
76 : }
77 : }
78 :
79 6 : size_t nPos = 0;
80 6 : size_t nFtnNo = 1;
81 6 : if( SeekEntry( *pCapStt, &nPos ) && nPos )
82 : {
83 : // Step forward until the Index is not the same anymore
84 0 : const SwNode* pCmpNd = &rStt.GetNode();
85 0 : while( nPos && pCmpNd == &((*this)[ --nPos ]->GetTxtNode()) )
86 : ;
87 0 : ++nPos;
88 : }
89 :
90 6 : if( nPos == size() ) // nothing found
91 0 : return;
92 :
93 6 : if( rOutlNds.empty() )
94 6 : nFtnNo = nPos+1;
95 :
96 12 : for( ; nPos < size(); ++nPos )
97 : {
98 6 : pTxtFtn = (*this)[ nPos ];
99 6 : if( pTxtFtn->GetTxtNode().GetIndex() >= nCapEnd )
100 0 : break;
101 :
102 6 : const SwFmtFtn &rFtn = pTxtFtn->GetFtn();
103 12 : if( rFtn.GetNumStr().isEmpty() && !rFtn.IsEndNote() &&
104 6 : !SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtFtn ))
105 : {
106 6 : pTxtFtn->SetNumber( rFtnInfo.nFtnOffset + nFtnNo++, rFtn.GetNumStr() );
107 : }
108 : }
109 : }
110 :
111 234 : SwUpdFtnEndNtAtEnd aNumArr;
112 :
113 : // unless we have per-document numbering, only look at endnotes here
114 234 : const bool bEndNoteOnly = FTNNUM_DOC != rFtnInfo.eNum;
115 :
116 : size_t nPos;
117 234 : size_t nFtnNo = 1;
118 234 : size_t nEndNo = 1;
119 234 : sal_uLong nUpdNdIdx = rStt.GetIndex();
120 270 : for( nPos = 0; nPos < size(); ++nPos )
121 : {
122 270 : pTxtFtn = (*this)[ nPos ];
123 270 : if( nUpdNdIdx <= pTxtFtn->GetTxtNode().GetIndex() )
124 234 : break;
125 :
126 36 : const SwFmtFtn &rFtn = pTxtFtn->GetFtn();
127 36 : if( rFtn.GetNumStr().isEmpty() )
128 : {
129 36 : if( !aNumArr.ChkNumber( *pTxtFtn ) )
130 : {
131 36 : if( pTxtFtn->GetFtn().IsEndNote() )
132 18 : nEndNo++;
133 : else
134 18 : nFtnNo++;
135 : }
136 : }
137 : }
138 :
139 : // Set the array number for all footnotes starting from nPos
140 578 : for( ; nPos < size(); ++nPos )
141 : {
142 344 : pTxtFtn = (*this)[ nPos ];
143 344 : const SwFmtFtn &rFtn = pTxtFtn->GetFtn();
144 344 : if( rFtn.GetNumStr().isEmpty() )
145 : {
146 180 : sal_uInt16 nSectNo = aNumArr.ChkNumber( *pTxtFtn );
147 180 : if( !nSectNo && ( rFtn.IsEndNote() || !bEndNoteOnly ))
148 174 : nSectNo = rFtn.IsEndNote()
149 : ? rEndInfo.nFtnOffset + nEndNo++
150 174 : : rFtnInfo.nFtnOffset + nFtnNo++;
151 :
152 180 : if( nSectNo )
153 : {
154 174 : pTxtFtn->SetNumber( nSectNo, rFtn.GetNumStr() );
155 : }
156 : }
157 234 : }
158 : }
159 :
160 76 : void SwFtnIdxs::UpdateAllFtn()
161 : {
162 76 : if( empty() )
163 118 : return;
164 :
165 : // Get the NodesArray via the StartIndex of the first Footnote
166 34 : SwDoc* pDoc = (SwDoc*) (*this)[ 0 ]->GetTxtNode().GetDoc();
167 : SwTxtFtn* pTxtFtn;
168 34 : const SwEndNoteInfo& rEndInfo = pDoc->GetEndNoteInfo();
169 34 : const SwFtnInfo& rFtnInfo = pDoc->GetFtnInfo();
170 :
171 34 : SwUpdFtnEndNtAtEnd aNumArr;
172 :
173 34 : SwRootFrm* pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
174 68 : std::set<SwRootFrm*> aAllLayouts = pDoc->GetAllLayouts();
175 : // For normal Footnotes per-chapter and per-document numbering are treated separately.
176 : // For Endnotes we only have document-wise numbering.
177 34 : if( FTNNUM_CHAPTER == rFtnInfo.eNum )
178 : {
179 10 : const SwOutlineNodes& rOutlNds = pDoc->GetNodes().GetOutLineNds();
180 10 : sal_uInt16 nNo = 1; // Number for the Footnotes
181 10 : size_t nFtnIdx = 0; // Index into theFtnIdx array
182 10 : for( size_t n = 0; n < rOutlNds.size(); ++n )
183 : {
184 0 : if ( rOutlNds[ n ]->GetTxtNode()->GetAttrOutlineLevel() == 1 )
185 : {
186 0 : sal_uLong nCapStt = rOutlNds[ n ]->GetIndex(); // Start of a new chapter
187 0 : for( ; nFtnIdx < size(); ++nFtnIdx )
188 : {
189 0 : pTxtFtn = (*this)[ nFtnIdx ];
190 0 : if( pTxtFtn->GetTxtNode().GetIndex() >= nCapStt )
191 0 : break;
192 :
193 : // Endnotes are per-document only
194 0 : const SwFmtFtn &rFtn = pTxtFtn->GetFtn();
195 0 : if( !rFtn.IsEndNote() && rFtn.GetNumStr().isEmpty() &&
196 0 : !SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtFtn ))
197 : {
198 0 : pTxtFtn->SetNumber( rFtnInfo.nFtnOffset + nNo++, rFtn.GetNumStr() );
199 : }
200 : }
201 0 : if( nFtnIdx >= size() )
202 0 : break; // ok, everything is updated
203 0 : nNo = 1;
204 : }
205 : }
206 :
207 20 : for( nNo = 1; nFtnIdx < size(); ++nFtnIdx )
208 : {
209 : // Endnotes are per-document
210 10 : pTxtFtn = (*this)[ nFtnIdx ];
211 10 : const SwFmtFtn &rFtn = pTxtFtn->GetFtn();
212 20 : if( !rFtn.IsEndNote() && rFtn.GetNumStr().isEmpty() &&
213 10 : !SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtFtn ))
214 : {
215 10 : pTxtFtn->SetNumber( rFtnInfo.nFtnOffset + nNo++, rFtn.GetNumStr() );
216 : }
217 : }
218 : }
219 :
220 : // We use bool here, so that we also iterate through the Endnotes with a chapter setting.
221 34 : const bool bEndNoteOnly = FTNNUM_DOC != rFtnInfo.eNum;
222 34 : sal_uInt16 nFtnNo = 0, nEndNo = 0;
223 68 : for( size_t nPos = 0; nPos < size(); ++nPos )
224 : {
225 34 : pTxtFtn = (*this)[ nPos ];
226 34 : const SwFmtFtn &rFtn = pTxtFtn->GetFtn();
227 34 : if( rFtn.GetNumStr().isEmpty() )
228 : {
229 32 : sal_uInt16 nSectNo = aNumArr.ChkNumber( *pTxtFtn );
230 32 : if( !nSectNo && ( rFtn.IsEndNote() || !bEndNoteOnly ))
231 22 : nSectNo = rFtn.IsEndNote()
232 : ? rEndInfo.nFtnOffset + (++nEndNo)
233 22 : : rFtnInfo.nFtnOffset + (++nFtnNo);
234 :
235 32 : if( nSectNo )
236 : {
237 22 : pTxtFtn->SetNumber( nSectNo, rFtn.GetNumStr() );
238 : }
239 : }
240 : }
241 :
242 34 : if( pTmpRoot && FTNNUM_PAGE == rFtnInfo.eNum )
243 34 : std::for_each( aAllLayouts.begin(), aAllLayouts.end(),std::mem_fun(&SwRootFrm::UpdateFtnNums));
244 : }
245 :
246 370 : SwTxtFtn* SwFtnIdxs::SeekEntry( const SwNodeIndex& rPos, size_t* pFndPos ) const
247 : {
248 370 : sal_uLong nIdx = rPos.GetIndex();
249 :
250 370 : size_t nO = size();
251 370 : size_t nU = 0;
252 370 : if( nO > 0 )
253 : {
254 370 : nO--;
255 898 : while( nU <= nO )
256 : {
257 450 : const size_t nM = nU + ( nO - nU ) / 2;
258 450 : sal_uLong nNdIdx = _SwTxtFtn_GetIndex( (*this)[ nM ] );
259 450 : if( nNdIdx == nIdx )
260 : {
261 154 : if( pFndPos )
262 154 : *pFndPos = nM;
263 154 : return (*this)[ nM ];
264 : }
265 296 : else if( nNdIdx < nIdx )
266 124 : nU = nM + 1;
267 172 : else if( nM == 0 )
268 : {
269 138 : if( pFndPos )
270 138 : *pFndPos = nU;
271 138 : return 0;
272 : }
273 : else
274 34 : nO = nM - 1;
275 : }
276 : }
277 78 : if( pFndPos )
278 78 : *pFndPos = nU;
279 78 : return 0;
280 : }
281 :
282 696 : const SwSectionNode* SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr(
283 : const SwTxtFtn& rTxtFtn )
284 : {
285 696 : sal_uInt16 nWh = static_cast<sal_uInt16>( rTxtFtn.GetFtn().IsEndNote() ?
286 696 : RES_END_AT_TXTEND : RES_FTN_AT_TXTEND );
287 : sal_uInt16 nVal;
288 696 : const SwSectionNode* pNd = rTxtFtn.GetTxtNode().FindSectionNode();
289 1720 : while( pNd && FTNEND_ATTXTEND_OWNNUMSEQ != ( nVal =
290 164 : ((const SwFmtFtnEndAtTxtEnd&)pNd->GetSection().GetFmt()->
291 1188 : GetFmtAttr( nWh, true )).GetValue() ) &&
292 : FTNEND_ATTXTEND_OWNNUMANDFMT != nVal )
293 164 : pNd = pNd->StartOfSectionNode()->FindSectionNode();
294 :
295 696 : return pNd;
296 : }
297 :
298 0 : sal_uInt16 SwUpdFtnEndNtAtEnd::GetNumber( const SwTxtFtn& rTxtFtn,
299 : const SwSectionNode& rNd )
300 : {
301 0 : sal_uInt16 nRet = 0, nWh;
302 : std::vector<const SwSectionNode*>* pArr;
303 : std::vector<sal_uInt16> *pNum;
304 0 : if( rTxtFtn.GetFtn().IsEndNote() )
305 : {
306 0 : pArr = &aEndSects;
307 0 : pNum = &aEndNums;
308 0 : nWh = RES_END_AT_TXTEND;
309 : }
310 : else
311 : {
312 0 : pArr = &aFtnSects;
313 0 : pNum = &aFtnNums;
314 0 : nWh = RES_FTN_AT_TXTEND;
315 : }
316 :
317 0 : for( size_t n = pArr->size(); n; )
318 0 : if( (*pArr)[ --n ] == &rNd )
319 : {
320 0 : nRet = ++((*pNum)[ n ]);
321 0 : break;
322 : }
323 :
324 0 : if( !nRet )
325 : {
326 0 : pArr->push_back( &rNd );
327 0 : nRet = ((SwFmtFtnEndAtTxtEnd&)rNd.GetSection().GetFmt()->
328 0 : GetFmtAttr( nWh )).GetOffset();
329 0 : ++nRet;
330 0 : pNum->push_back( nRet );
331 : }
332 0 : return nRet;
333 : }
334 :
335 248 : sal_uInt16 SwUpdFtnEndNtAtEnd::ChkNumber( const SwTxtFtn& rTxtFtn )
336 : {
337 248 : const SwSectionNode* pSectNd = FindSectNdWithEndAttr( rTxtFtn );
338 248 : return pSectNd ? GetNumber( rTxtFtn, *pSectNd ) : 0;
339 270 : }
340 :
341 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|