File: | home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx |
Warning: | line 650, column 21 Potential leak of memory pointed to by 'pTmpSttNd' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <stdlib.h> | |||
21 | ||||
22 | #include <libxml/xmlwriter.h> | |||
23 | #include <osl/diagnose.h> | |||
24 | ||||
25 | #include <node.hxx> | |||
26 | #include <doc.hxx> | |||
27 | #include <IDocumentUndoRedo.hxx> | |||
28 | #include <IDocumentFieldsAccess.hxx> | |||
29 | #include <IDocumentLayoutAccess.hxx> | |||
30 | #include <pam.hxx> | |||
31 | #include <txtfld.hxx> | |||
32 | #include <fmtfld.hxx> | |||
33 | #include <numrule.hxx> | |||
34 | #include <ndtxt.hxx> | |||
35 | #include <ndnotxt.hxx> | |||
36 | #include <swtable.hxx> | |||
37 | #include <section.hxx> | |||
38 | #include <ddefld.hxx> | |||
39 | #include <swddetbl.hxx> | |||
40 | #include <txtatr.hxx> | |||
41 | #include <tox.hxx> | |||
42 | #include <fmtrfmrk.hxx> | |||
43 | #include <fmtftn.hxx> | |||
44 | ||||
45 | #include <docsh.hxx> | |||
46 | ||||
47 | typedef std::vector<SwStartNode*> SwStartNodePointers; | |||
48 | ||||
49 | // function to determine the highest level in the given range | |||
50 | static sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange ); | |||
51 | ||||
52 | /** Constructor | |||
53 | * | |||
54 | * creates the base sections (PostIts, Inserts, AutoText, RedLines, Content) | |||
55 | * | |||
56 | * @param rDocument TODO: provide documentation | |||
57 | */ | |||
58 | SwNodes::SwNodes( SwDoc& rDocument ) | |||
59 | : m_vIndices(nullptr), m_rMyDoc( rDocument ) | |||
60 | { | |||
61 | m_bInNodesDel = m_bInDelUpdOutline = false; | |||
62 | ||||
63 | sal_uLong nPos = 0; | |||
64 | SwStartNode* pSttNd = new SwStartNode( *this, nPos++ ); | |||
65 | m_pEndOfPostIts = new SwEndNode( *this, nPos++, *pSttNd ); | |||
66 | ||||
67 | SwStartNode* pTmp = new SwStartNode( *this, nPos++ ); | |||
68 | m_pEndOfInserts = new SwEndNode( *this, nPos++, *pTmp ); | |||
69 | ||||
70 | pTmp = new SwStartNode( *this, nPos++ ); | |||
71 | pTmp->m_pStartOfSection = pSttNd; | |||
72 | m_pEndOfAutotext = new SwEndNode( *this, nPos++, *pTmp ); | |||
73 | ||||
74 | pTmp = new SwStartNode( *this, nPos++ ); | |||
75 | pTmp->m_pStartOfSection = pSttNd; | |||
76 | m_pEndOfRedlines = new SwEndNode( *this, nPos++, *pTmp ); | |||
77 | ||||
78 | pTmp = new SwStartNode( *this, nPos++ ); | |||
79 | pTmp->m_pStartOfSection = pSttNd; | |||
80 | m_pEndOfContent.reset(new SwEndNode( *this, nPos++, *pTmp )); | |||
81 | ||||
82 | m_pOutlineNodes.reset(new SwOutlineNodes); | |||
83 | } | |||
84 | ||||
85 | /** Destructor | |||
86 | * | |||
87 | * Deletes all nodes whose pointer are in a dynamic array. This should be no | |||
88 | * problem as nodes cannot be created outside this array and, thus, cannot be | |||
89 | * part of multiple arrays. | |||
90 | */ | |||
91 | SwNodes::~SwNodes() | |||
92 | { | |||
93 | m_pOutlineNodes.reset(); | |||
94 | ||||
95 | { | |||
96 | SwNodeIndex aNdIdx( *this ); | |||
97 | while( true ) | |||
98 | { | |||
99 | SwNode *pNode = &aNdIdx.GetNode(); | |||
100 | if( pNode == m_pEndOfContent.get() ) | |||
101 | break; | |||
102 | ||||
103 | ++aNdIdx; | |||
104 | delete pNode; | |||
105 | } | |||
106 | } | |||
107 | ||||
108 | // here, all SwNodeIndices must be unregistered | |||
109 | m_pEndOfContent.reset(); | |||
110 | } | |||
111 | ||||
112 | void SwNodes::ChgNode( SwNodeIndex const & rDelPos, sal_uLong nSz, | |||
113 | SwNodeIndex& rInsPos, bool bNewFrames ) | |||
114 | { | |||
115 | // no need for frames in the UndoArea | |||
116 | SwNodes& rNds = rInsPos.GetNodes(); | |||
117 | const SwNode* pPrevInsNd = rNds[ rInsPos.GetIndex() -1 ]; | |||
118 | ||||
119 | // declare all fields as invalid, updating will happen | |||
120 | // in the idle-handler of the doc | |||
121 | if( GetDoc().getIDocumentFieldsAccess().SetFieldsDirty( true, &rDelPos.GetNode(), nSz ) && | |||
122 | &rNds.GetDoc() != &GetDoc() ) | |||
123 | rNds.GetDoc().getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 ); | |||
124 | ||||
125 | // NEVER include nodes from the RedLineArea | |||
126 | sal_uLong nNd = rInsPos.GetIndex(); | |||
127 | bool bInsOutlineIdx = ( | |||
128 | rNds.GetEndOfRedlines().StartOfSectionNode()->GetIndex() >= nNd || | |||
129 | nNd >= rNds.GetEndOfRedlines().GetIndex() ); | |||
130 | ||||
131 | if( &rNds == this ) // if in the same node array -> move | |||
132 | { | |||
133 | // Move order: from front to back, so that new entries are added at | |||
134 | // first position, thus, deletion position stays the same | |||
135 | const sal_uLong nDiff = rDelPos.GetIndex() < rInsPos.GetIndex() ? 0 : 1; | |||
136 | ||||
137 | for( sal_uLong n = rDelPos.GetIndex(); nSz; n += nDiff, --nSz ) | |||
138 | { | |||
139 | SwNodeIndex aDelIdx( *this, n ); | |||
140 | SwNode& rNd = aDelIdx.GetNode(); | |||
141 | ||||
142 | // #i57920# - correction of refactoring done by cws swnumtree: | |||
143 | // - <SwTextNode::SetLevel( NO_NUMBERING ) is deprecated and | |||
144 | // set <IsCounted> state of the text node to <false>, which | |||
145 | // isn't correct here. | |||
146 | if ( rNd.IsTextNode() ) | |||
147 | { | |||
148 | SwTextNode* pTextNode = rNd.GetTextNode(); | |||
149 | ||||
150 | pTextNode->RemoveFromList(); | |||
151 | ||||
152 | if (pTextNode->IsOutline()) | |||
153 | { | |||
154 | const SwNodePtr pSrch = &rNd; | |||
155 | m_pOutlineNodes->erase( pSrch ); | |||
156 | } | |||
157 | } | |||
158 | ||||
159 | BigPtrArray::Move( aDelIdx.GetIndex(), rInsPos.GetIndex() ); | |||
160 | ||||
161 | if( rNd.IsTextNode() ) | |||
162 | { | |||
163 | SwTextNode& rTextNd = static_cast<SwTextNode&>(rNd); | |||
164 | ||||
165 | rTextNd.AddToList(); | |||
166 | ||||
167 | if (bInsOutlineIdx && rTextNd.IsOutline()) | |||
168 | { | |||
169 | const SwNodePtr pSrch = &rNd; | |||
170 | m_pOutlineNodes->insert( pSrch ); | |||
171 | } | |||
172 | rTextNd.InvalidateNumRule(); | |||
173 | ||||
174 | //FEATURE::CONDCOLL | |||
175 | if( RES_CONDTXTFMTCOLL == rTextNd.GetTextColl()->Which() ) | |||
176 | rTextNd.ChkCondColl(); | |||
177 | //FEATURE::CONDCOLL | |||
178 | } | |||
179 | else if( rNd.IsContentNode() ) | |||
180 | static_cast<SwContentNode&>(rNd).InvalidateNumRule(); | |||
181 | } | |||
182 | } | |||
183 | else | |||
184 | { | |||
185 | bool bSavePersData(GetDoc().GetIDocumentUndoRedo().IsUndoNodes(rNds)); | |||
186 | bool bRestPersData(GetDoc().GetIDocumentUndoRedo().IsUndoNodes(*this)); | |||
187 | SwDoc* pDestDoc = &rNds.GetDoc() != &GetDoc() ? &rNds.GetDoc() : nullptr; | |||
188 | OSL_ENSURE(!pDestDoc, "SwNodes::ChgNode(): "do { if (true && (!(!pDestDoc))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "190" ": "), "%s", "SwNodes::ChgNode(): " "the code to handle text fields here looks broken\n" "if the target is in a different document."); } } while (false ) | |||
189 | "the code to handle text fields here looks broken\n"do { if (true && (!(!pDestDoc))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "190" ": "), "%s", "SwNodes::ChgNode(): " "the code to handle text fields here looks broken\n" "if the target is in a different document."); } } while (false ) | |||
190 | "if the target is in a different document.")do { if (true && (!(!pDestDoc))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "190" ": "), "%s", "SwNodes::ChgNode(): " "the code to handle text fields here looks broken\n" "if the target is in a different document."); } } while (false ); | |||
191 | if( !bRestPersData && !bSavePersData && pDestDoc ) | |||
192 | bSavePersData = bRestPersData = true; | |||
193 | ||||
194 | OUString sNumRule; | |||
195 | for( sal_uLong n = 0; n < nSz; n++ ) | |||
196 | { | |||
197 | SwNode* pNd = &rDelPos.GetNode(); | |||
198 | ||||
199 | // NoTextNode keep their persistent data | |||
200 | if( pNd->IsNoTextNode() ) | |||
201 | { | |||
202 | if( bSavePersData ) | |||
203 | static_cast<SwNoTextNode*>(pNd)->SavePersistentData(); | |||
204 | } | |||
205 | else if( pNd->IsTextNode() ) | |||
206 | { | |||
207 | SwTextNode* pTextNd = static_cast<SwTextNode*>(pNd); | |||
208 | ||||
209 | // remove outline index from old nodes array | |||
210 | if (pTextNd->IsOutline()) | |||
211 | { | |||
212 | m_pOutlineNodes->erase( pNd ); | |||
213 | } | |||
214 | ||||
215 | // copy rules if needed | |||
216 | if( pDestDoc ) | |||
217 | { | |||
218 | const SwNumRule* pNumRule = pTextNd->GetNumRule(); | |||
219 | if( pNumRule && sNumRule != pNumRule->GetName() ) | |||
220 | { | |||
221 | sNumRule = pNumRule->GetName(); | |||
222 | SwNumRule* pDestRule = pDestDoc->FindNumRulePtr( sNumRule ); | |||
223 | if( pDestRule ) | |||
224 | pDestRule->SetInvalidRule( true ); | |||
225 | else | |||
226 | pDestDoc->MakeNumRule( sNumRule, pNumRule ); | |||
227 | } | |||
228 | } | |||
229 | else | |||
230 | // if movement into the UndoNodes-array, update numbering | |||
231 | pTextNd->InvalidateNumRule(); | |||
232 | ||||
233 | pTextNd->RemoveFromList(); | |||
234 | } | |||
235 | ||||
236 | RemoveNode( rDelPos.GetIndex(), 1, false ); // move indices | |||
237 | SwContentNode * pCNd = pNd->GetContentNode(); | |||
238 | rNds.InsertNode( pNd, rInsPos ); | |||
239 | ||||
240 | if( pCNd ) | |||
241 | { | |||
242 | SwTextNode* pTextNd = pCNd->GetTextNode(); | |||
243 | if( pTextNd ) | |||
244 | { | |||
245 | SwpHints * const pHts = pTextNd->GetpSwpHints(); | |||
246 | // OutlineNodes set the new nodes in the array | |||
247 | if (bInsOutlineIdx && pTextNd->IsOutline()) | |||
248 | { | |||
249 | rNds.m_pOutlineNodes->insert( pTextNd ); | |||
250 | } | |||
251 | ||||
252 | pTextNd->AddToList(); | |||
253 | ||||
254 | // special treatment for fields | |||
255 | if( pHts && pHts->Count() ) | |||
256 | { | |||
257 | bool const bToUndo = !pDestDoc && | |||
258 | GetDoc().GetIDocumentUndoRedo().IsUndoNodes(rNds); | |||
259 | for( size_t i = pHts->Count(); i; ) | |||
260 | { | |||
261 | SwTextAttr * const pAttr = pHts->Get( --i ); | |||
262 | switch ( pAttr->Which() ) | |||
263 | { | |||
264 | case RES_TXTATR_FIELD: | |||
265 | case RES_TXTATR_ANNOTATION: | |||
266 | case RES_TXTATR_INPUTFIELD: | |||
267 | { | |||
268 | SwTextField* pTextField = static_txtattr_cast<SwTextField*>(pAttr); | |||
269 | rNds.GetDoc().getIDocumentFieldsAccess().InsDelFieldInFieldLst( !bToUndo, *pTextField ); | |||
270 | ||||
271 | const SwFieldType* pTyp = pTextField->GetFormatField().GetField()->GetTyp(); | |||
272 | if ( SwFieldIds::Postit == pTyp->Which() ) | |||
273 | { | |||
274 | rNds.GetDoc().GetDocShell()->Broadcast( | |||
275 | SwFormatFieldHint( | |||
276 | &pTextField->GetFormatField(), | |||
277 | ( pTextField->GetFormatField().IsFieldInDoc() | |||
278 | ? SwFormatFieldHintWhich::INSERTED | |||
279 | : SwFormatFieldHintWhich::REMOVED ) ) ); | |||
280 | } | |||
281 | else if( SwFieldIds::Dde == pTyp->Which() ) | |||
282 | { | |||
283 | if( bToUndo ) | |||
284 | const_cast<SwDDEFieldType*>(static_cast<const SwDDEFieldType*>(pTyp))->DecRefCnt(); | |||
285 | else | |||
286 | const_cast<SwDDEFieldType*>(static_cast<const SwDDEFieldType*>(pTyp))->IncRefCnt(); | |||
287 | } | |||
288 | static_cast<SwFormatField&>(pAttr->GetAttr()) | |||
289 | .InvalidateField(); | |||
290 | } | |||
291 | break; | |||
292 | ||||
293 | case RES_TXTATR_FTN: | |||
294 | static_cast<SwFormatFootnote&>(pAttr->GetAttr()) | |||
295 | .InvalidateFootnote(); | |||
296 | break; | |||
297 | ||||
298 | case RES_TXTATR_TOXMARK: | |||
299 | static_cast<SwTOXMark&>(pAttr->GetAttr()) | |||
300 | .InvalidateTOXMark(); | |||
301 | break; | |||
302 | ||||
303 | case RES_TXTATR_REFMARK: | |||
304 | static_cast<SwFormatRefMark&>(pAttr->GetAttr()) | |||
305 | .InvalidateRefMark(); | |||
306 | break; | |||
307 | ||||
308 | case RES_TXTATR_META: | |||
309 | case RES_TXTATR_METAFIELD: | |||
310 | { | |||
311 | SwTextMeta *const pTextMeta( | |||
312 | static_txtattr_cast<SwTextMeta*>(pAttr)); | |||
313 | // force removal of UNO object | |||
314 | pTextMeta->ChgTextNode(nullptr); | |||
315 | pTextMeta->ChgTextNode(pTextNd); | |||
316 | } | |||
317 | break; | |||
318 | ||||
319 | default: | |||
320 | break; | |||
321 | } | |||
322 | } | |||
323 | } | |||
324 | //FEATURE::CONDCOLL | |||
325 | if( RES_CONDTXTFMTCOLL == pTextNd->GetTextColl()->Which() ) | |||
326 | pTextNd->ChkCondColl(); | |||
327 | //FEATURE::CONDCOLL | |||
328 | } | |||
329 | else | |||
330 | { | |||
331 | // Moved into different Docs? Persist data again! | |||
332 | if( pCNd->IsNoTextNode() && bRestPersData ) | |||
333 | static_cast<SwNoTextNode*>(pCNd)->RestorePersistentData(); | |||
334 | } | |||
335 | } | |||
336 | } | |||
337 | } | |||
338 | ||||
339 | // declare all fields as invalid, updating will happen | |||
340 | // in the idle-handler of the doc | |||
341 | GetDoc().getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 ); | |||
342 | if( &rNds.GetDoc() != &GetDoc() ) | |||
343 | rNds.GetDoc().getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 ); | |||
344 | ||||
345 | if( bNewFrames ) | |||
346 | bNewFrames = &GetDoc().GetNodes() == &rNds && | |||
347 | GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell(); | |||
348 | ||||
349 | if( !bNewFrames ) | |||
350 | return; | |||
351 | ||||
352 | // get the frames: | |||
353 | SwNodeIndex aIdx( *pPrevInsNd, 1 ); | |||
354 | SwNodeIndex aFrameNdIdx( aIdx ); | |||
355 | SwNode* pFrameNd = rNds.FindPrvNxtFrameNode( aFrameNdIdx, | |||
356 | rNds[ rInsPos.GetIndex() - 1 ] ); | |||
357 | ||||
358 | if( !pFrameNd ) | |||
359 | return; | |||
360 | ||||
361 | while( aIdx != rInsPos ) | |||
362 | { | |||
363 | SwContentNode* pCNd = aIdx.GetNode().GetContentNode(); | |||
364 | if( pCNd ) | |||
365 | { | |||
366 | if( pFrameNd->IsTableNode() ) | |||
367 | static_cast<SwTableNode*>(pFrameNd)->MakeFramesForAdjacentContentNode(aIdx); | |||
368 | else if( pFrameNd->IsSectionNode() ) | |||
369 | static_cast<SwSectionNode*>(pFrameNd)->MakeFramesForAdjacentContentNode(aIdx); | |||
370 | else | |||
371 | static_cast<SwContentNode*>(pFrameNd)->MakeFramesForAdjacentContentNode(*pCNd); | |||
372 | pFrameNd = pCNd; | |||
373 | } | |||
374 | ++aIdx; | |||
375 | } | |||
376 | } | |||
377 | ||||
378 | // TODO: provide documentation | |||
379 | /** move the node pointer | |||
380 | * | |||
381 | * Move the node pointer from "(inclusive) start position to (exclusive) end | |||
382 | * position" to target position. | |||
383 | * If the target is in front of the first or in the area between first and | |||
384 | * last element to move, nothing happens. | |||
385 | * If the area to move is empty or the end position is before the start | |||
386 | * position, nothing happens. | |||
387 | * | |||
388 | * @param aRange range to move (excluding end node) | |||
389 | * @param rNodes | |||
390 | * @param aIndex | |||
391 | * @param bNewFrames | |||
392 | * @return | |||
393 | */ | |||
394 | bool SwNodes::MoveNodes( const SwNodeRange& aRange, SwNodes & rNodes, | |||
395 | const SwNodeIndex& aIndex, bool bNewFrames ) | |||
396 | { | |||
397 | SwNode * pCurrentNode; | |||
398 | if( aIndex == 0 || | |||
399 | ( (pCurrentNode = &aIndex.GetNode())->GetStartNode() && | |||
400 | !pCurrentNode->StartOfSectionIndex() )) | |||
401 | return false; | |||
402 | ||||
403 | SwNodeRange aRg( aRange ); | |||
404 | ||||
405 | // skip "simple" start or end nodes | |||
406 | while( SwNodeType::Start == (pCurrentNode = &aRg.aStart.GetNode())->GetNodeType() | |||
| ||||
407 | || ( pCurrentNode->IsEndNode() && | |||
408 | !pCurrentNode->m_pStartOfSection->IsSectionNode() ) ) | |||
409 | ++aRg.aStart; | |||
410 | --aRg.aStart; | |||
411 | ||||
412 | // if aEnd-1 points to no ContentNode, search previous one | |||
413 | --aRg.aEnd; | |||
414 | while( ( (( pCurrentNode = &aRg.aEnd.GetNode())->GetStartNode() && | |||
415 | !pCurrentNode->IsSectionNode() ) || | |||
416 | ( pCurrentNode->IsEndNode() && | |||
417 | SwNodeType::Start == pCurrentNode->m_pStartOfSection->GetNodeType()) ) && | |||
418 | aRg.aEnd > aRg.aStart ) | |||
419 | --aRg.aEnd; | |||
420 | ||||
421 | // if in same array, check insertion position | |||
422 | if( aRg.aStart >= aRg.aEnd ) | |||
423 | return false; | |||
424 | ||||
425 | if( this == &rNodes ) | |||
426 | { | |||
427 | if( ( aIndex.GetIndex()-1 >= aRg.aStart.GetIndex() && | |||
428 | aIndex.GetIndex()-1 < aRg.aEnd.GetIndex()) || | |||
429 | ( aIndex.GetIndex()-1 == aRg.aEnd.GetIndex() ) ) | |||
430 | return false; | |||
431 | } | |||
432 | ||||
433 | sal_uLong nInsPos = 0; // counter for tmp array | |||
434 | ||||
435 | // array as a stack, storing all StartOfSelections | |||
436 | SwStartNodePointers aSttNdStack; | |||
437 | SwStartNodePointers::size_type nLevel = 0; // level counter | |||
438 | ||||
439 | // set start index | |||
440 | SwNodeIndex aIdx( aIndex ); | |||
441 | ||||
442 | SwStartNode* pStartNode = aIdx.GetNode().m_pStartOfSection; | |||
443 | aSttNdStack.insert( aSttNdStack.begin(), pStartNode ); | |||
444 | ||||
445 | SwNodeRange aOrigInsPos( aIdx, -1, aIdx ); // original insertion position | |||
446 | ||||
447 | // call DelFrames/MakeFrames for the upmost SectionNode | |||
448 | int nSectNdCnt = 0; | |||
449 | bool bSaveNewFrames = bNewFrames; | |||
450 | ||||
451 | // continue until everything has been moved | |||
452 | while( aRg.aStart < aRg.aEnd ) | |||
453 | { | |||
454 | pCurrentNode = &aRg.aEnd.GetNode(); | |||
455 | switch( pCurrentNode->GetNodeType() ) | |||
456 | { | |||
457 | case SwNodeType::End: | |||
458 | { | |||
459 | if( nInsPos
| |||
460 | { | |||
461 | // delete and copy. CAUTION: all indices after | |||
462 | // "aRg.aEnd+1" will be moved as well! | |||
463 | SwNodeIndex aSwIndex( aRg.aEnd, 1 ); | |||
464 | ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames ); | |||
465 | aIdx -= nInsPos; | |||
466 | nInsPos = 0; | |||
467 | } | |||
468 | ||||
469 | SwStartNode* pSttNd = pCurrentNode->m_pStartOfSection; | |||
470 | if( pSttNd->IsTableNode() ) | |||
471 | { | |||
472 | SwTableNode* pTableNd = static_cast<SwTableNode*>(pSttNd); | |||
473 | ||||
474 | // move the whole table/range | |||
475 | nInsPos = (aRg.aEnd.GetIndex() - | |||
476 | pSttNd->GetIndex() )+1; | |||
477 | aRg.aEnd -= nInsPos; | |||
478 | ||||
479 | // NEVER include nodes from the RedLineArea | |||
480 | sal_uLong nNd = aIdx.GetIndex(); | |||
481 | bool bInsOutlineIdx = ( rNodes.GetEndOfRedlines(). | |||
482 | StartOfSectionNode()->GetIndex() >= nNd || | |||
483 | nNd >= rNodes.GetEndOfRedlines().GetIndex() ); | |||
484 | ||||
485 | if( bNewFrames ) | |||
486 | // delete all frames | |||
487 | pTableNd->DelFrames(nullptr); | |||
488 | if( &rNodes == this ) // move into self? | |||
489 | { | |||
490 | // move all Start/End/ContentNodes | |||
491 | // ContentNodes: delete also the frames! | |||
492 | pTableNd->m_pStartOfSection = aIdx.GetNode().m_pStartOfSection; | |||
493 | for( sal_uLong n = 0; n < nInsPos; ++n ) | |||
494 | { | |||
495 | SwNodeIndex aMvIdx( aRg.aEnd, 1 ); | |||
496 | SwContentNode* pCNd = nullptr; | |||
497 | SwNode* pTmpNd = &aMvIdx.GetNode(); | |||
498 | if( pTmpNd->IsContentNode() ) | |||
499 | { | |||
500 | pCNd = static_cast<SwContentNode*>(pTmpNd); | |||
501 | if( pTmpNd->IsTextNode() ) | |||
502 | static_cast<SwTextNode*>(pTmpNd)->RemoveFromList(); | |||
503 | ||||
504 | // remove outline index from old nodes array | |||
505 | if (pCNd->IsTextNode() && pCNd->GetTextNode()->IsOutline()) | |||
506 | { | |||
507 | m_pOutlineNodes->erase( pCNd ); | |||
508 | } | |||
509 | else | |||
510 | pCNd = nullptr; | |||
511 | } | |||
512 | ||||
513 | BigPtrArray::Move( aMvIdx.GetIndex(), aIdx.GetIndex() ); | |||
514 | ||||
515 | if( bInsOutlineIdx && pCNd ) | |||
516 | m_pOutlineNodes->insert( pCNd ); | |||
517 | if( pTmpNd->IsTextNode() ) | |||
518 | static_cast<SwTextNode*>(pTmpNd)->AddToList(); | |||
519 | } | |||
520 | } | |||
521 | else | |||
522 | { | |||
523 | // get StartNode | |||
524 | // Even aIdx points to a startnode, we need the startnode | |||
525 | // of the environment of aIdx (#i80941) | |||
526 | SwStartNode* pSttNode = aIdx.GetNode().m_pStartOfSection; | |||
527 | ||||
528 | // get all boxes with content because their indices | |||
529 | // pointing to the StartNodes need to be reset | |||
530 | // (copying the array and deleting all found ones eases | |||
531 | // searching) | |||
532 | SwNodeIndex aMvIdx( aRg.aEnd, 1 ); | |||
533 | for( sal_uLong n = 0; n < nInsPos; ++n ) | |||
534 | { | |||
535 | SwNode* pNd = &aMvIdx.GetNode(); | |||
536 | ||||
537 | const bool bOutlNd = pNd->IsTextNode() && pNd->GetTextNode()->IsOutline(); | |||
538 | // delete outline indices from old node array | |||
539 | if( bOutlNd ) | |||
540 | m_pOutlineNodes->erase( pNd ); | |||
541 | ||||
542 | RemoveNode( aMvIdx.GetIndex(), 1, false ); | |||
543 | pNd->m_pStartOfSection = pSttNode; | |||
544 | rNodes.InsertNode( pNd, aIdx ); | |||
545 | ||||
546 | // set correct indices in Start/EndNodes | |||
547 | if( bInsOutlineIdx && bOutlNd ) | |||
548 | // and put them into the new node array | |||
549 | rNodes.m_pOutlineNodes->insert( pNd ); | |||
550 | else if( pNd->IsStartNode() ) | |||
551 | pSttNode = static_cast<SwStartNode*>(pNd); | |||
552 | else if( pNd->IsEndNode() ) | |||
553 | { | |||
554 | pSttNode->m_pEndOfSection = static_cast<SwEndNode*>(pNd); | |||
555 | if( pSttNode->IsSectionNode() ) | |||
556 | static_cast<SwSectionNode*>(pSttNode)->NodesArrChgd(); | |||
557 | pSttNode = pSttNode->m_pStartOfSection; | |||
558 | } | |||
559 | } | |||
560 | ||||
561 | if( dynamic_cast<const SwDDETable*>(&pTableNd->GetTable()) != nullptr ) | |||
562 | { | |||
563 | SwDDEFieldType* pTyp = static_cast<SwDDETable&>(pTableNd-> | |||
564 | GetTable()).GetDDEFieldType(); | |||
565 | if( pTyp ) | |||
566 | { | |||
567 | if( rNodes.IsDocNodes() ) | |||
568 | pTyp->IncRefCnt(); | |||
569 | else | |||
570 | pTyp->DecRefCnt(); | |||
571 | } | |||
572 | } | |||
573 | ||||
574 | if (GetDoc().GetIDocumentUndoRedo().IsUndoNodes(rNodes)) | |||
575 | { | |||
576 | SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat(); | |||
577 | pTableFormat->GetNotifier().Broadcast(SfxHint(SfxHintId::Dying)); | |||
578 | } | |||
579 | } | |||
580 | if( bNewFrames ) | |||
581 | { | |||
582 | SwNodeIndex aTmp( aIdx ); | |||
583 | pTableNd->MakeOwnFrames(&aTmp); | |||
584 | } | |||
585 | aIdx -= nInsPos; | |||
586 | nInsPos = 0; | |||
587 | } | |||
588 | else if( pSttNd->GetIndex() < aRg.aStart.GetIndex() ) | |||
589 | { | |||
590 | // SectionNode: not the whole section will be moved, thus, | |||
591 | // move only the ContentNodes | |||
592 | // StartNode: create a new section at the given position | |||
593 | do { // middle check loop | |||
594 | if( !pSttNd->IsSectionNode() ) | |||
595 | { | |||
596 | // create StartNode and EndNode at InsertPos | |||
597 | SwStartNode* pTmp = new SwStartNode( aIdx, | |||
598 | SwNodeType::Start, | |||
599 | /*?? NodeType ??*/ SwNormalStartNode ); | |||
600 | ||||
601 | nLevel++; // put the index to StartNode on the stack | |||
602 | aSttNdStack.insert( aSttNdStack.begin() + nLevel, pTmp ); | |||
603 | ||||
604 | // create EndNode | |||
605 | new SwEndNode( aIdx, *pTmp ); | |||
606 | } | |||
607 | else if (GetDoc().GetIDocumentUndoRedo().IsUndoNodes( | |||
608 | rNodes)) | |||
609 | { | |||
610 | // use placeholder in UndoNodes array | |||
611 | new SwPlaceholderNode(aIdx); | |||
612 | } | |||
613 | else | |||
614 | { | |||
615 | // JP 18.5.2001 (Bug 70454) creating new section? | |||
616 | --aRg.aEnd; | |||
617 | break; | |||
618 | ||||
619 | } | |||
620 | ||||
621 | --aRg.aEnd; | |||
622 | --aIdx; | |||
623 | } while( false ); | |||
624 | } | |||
625 | else | |||
626 | { | |||
627 | // move StartNode and EndNode in total | |||
628 | ||||
629 | // if Start is exactly the Start of the area, | |||
630 | // then the Node needs to be re-visited | |||
631 | if( &aRg.aStart.GetNode() == pSttNd ) | |||
632 | --aRg.aStart; | |||
633 | ||||
634 | SwSectionNode* pSctNd = pSttNd->GetSectionNode(); | |||
635 | if( bNewFrames && pSctNd ) | |||
636 | { // tdf#135056 skip over code in DelFrames() that moves | |||
637 | // SwNodeIndex around because in case of nested | |||
638 | // sections, m_pStartOfSection will point between | |||
639 | // undo nodes-array and doc nodes-array | |||
640 | pSctNd->DelFrames(nullptr, true); | |||
641 | } | |||
642 | ||||
643 | RemoveNode( aRg.aEnd.GetIndex(), 1, false ); // delete EndNode | |||
644 | sal_uLong nSttPos = pSttNd->GetIndex(); | |||
645 | ||||
646 | // this StartNode will be removed later | |||
647 | SwStartNode* pTmpSttNd = new SwStartNode( *this, nSttPos+1 ); | |||
648 | pTmpSttNd->m_pStartOfSection = pSttNd->m_pStartOfSection; | |||
649 | ||||
650 | RemoveNode( nSttPos, 1, false ); // delete SttNode | |||
| ||||
651 | ||||
652 | pSttNd->m_pStartOfSection = aIdx.GetNode().m_pStartOfSection; | |||
653 | rNodes.InsertNode( pSttNd, aIdx ); | |||
654 | rNodes.InsertNode( pCurrentNode, aIdx ); | |||
655 | --aIdx; | |||
656 | pSttNd->m_pEndOfSection = static_cast<SwEndNode*>(pCurrentNode); | |||
657 | ||||
658 | --aRg.aEnd; | |||
659 | ||||
660 | nLevel++; // put the index pointing to the StartNode onto the stack | |||
661 | aSttNdStack.insert( aSttNdStack.begin() + nLevel, pSttNd ); | |||
662 | ||||
663 | // reset remaining indices if SectionNode | |||
664 | if( pSctNd ) | |||
665 | { | |||
666 | pSctNd->NodesArrChgd(); | |||
667 | ++nSectNdCnt; | |||
668 | // tdf#132326 do not let frames survive in undo nodes | |||
669 | if (!GetDoc().GetIDocumentUndoRedo().IsUndoNodes(rNodes)) | |||
670 | { | |||
671 | bNewFrames = false; | |||
672 | } | |||
673 | } | |||
674 | } | |||
675 | } | |||
676 | break; | |||
677 | ||||
678 | case SwNodeType::Section: | |||
679 | if( !nLevel && | |||
680 | GetDoc().GetIDocumentUndoRedo().IsUndoNodes(rNodes)) | |||
681 | { | |||
682 | // here, a SectionDummyNode needs to be inserted at the current position | |||
683 | if( nInsPos ) // move everything until here | |||
684 | { | |||
685 | // delete and copy. CAUTION: all indices after | |||
686 | // "aRg.aEnd+1" will be moved as well! | |||
687 | SwNodeIndex aSwIndex( aRg.aEnd, 1 ); | |||
688 | ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames ); | |||
689 | aIdx -= nInsPos; | |||
690 | nInsPos = 0; | |||
691 | } | |||
692 | new SwPlaceholderNode(aIdx); | |||
693 | --aRg.aEnd; | |||
694 | --aIdx; | |||
695 | break; | |||
696 | } | |||
697 | [[fallthrough]]; | |||
698 | case SwNodeType::Table: | |||
699 | case SwNodeType::Start: | |||
700 | { | |||
701 | // empty section -> nothing to do | |||
702 | // and only if it's a top level section | |||
703 | if( !nInsPos && !nLevel ) | |||
704 | { | |||
705 | --aRg.aEnd; | |||
706 | break; | |||
707 | } | |||
708 | ||||
709 | if( !nLevel ) // level is decreasing | |||
710 | { | |||
711 | // create decrease | |||
712 | SwNodeIndex aTmpSIdx( aOrigInsPos.aStart, 1 ); | |||
713 | SwStartNode* pTmpStt = new SwStartNode( aTmpSIdx, | |||
714 | SwNodeType::Start, | |||
715 | static_cast<SwStartNode*>(pCurrentNode)->GetStartNodeType() ); | |||
716 | ||||
717 | --aTmpSIdx; | |||
718 | ||||
719 | SwNodeIndex aTmpEIdx( aOrigInsPos.aEnd ); | |||
720 | new SwEndNode( aTmpEIdx, *pTmpStt ); | |||
721 | --aTmpEIdx; | |||
722 | ++aTmpSIdx; | |||
723 | ||||
724 | // set correct StartOfSection | |||
725 | ++aRg.aEnd; | |||
726 | { | |||
727 | SwNodeIndex aCntIdx( aRg.aEnd ); | |||
728 | for( sal_uLong n = 0; n < nInsPos; n++, ++aCntIdx) | |||
729 | aCntIdx.GetNode().m_pStartOfSection = pTmpStt; | |||
730 | } | |||
731 | ||||
732 | // also set correct StartNode for all decreased nodes | |||
733 | while( aTmpSIdx < aTmpEIdx ) | |||
734 | if( nullptr != (( pCurrentNode = &aTmpEIdx.GetNode())->GetEndNode()) ) | |||
735 | aTmpEIdx = pCurrentNode->StartOfSectionIndex(); | |||
736 | else | |||
737 | { | |||
738 | pCurrentNode->m_pStartOfSection = pTmpStt; | |||
739 | --aTmpEIdx; | |||
740 | } | |||
741 | ||||
742 | --aIdx; // after the inserted StartNode | |||
743 | --aRg.aEnd; // before StartNode | |||
744 | // copy array. CAUTION: all indices after | |||
745 | // "aRg.aEnd+1" will be moved as well! | |||
746 | SwNodeIndex aSwIndex( aRg.aEnd, 1 ); | |||
747 | ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames ); | |||
748 | aIdx -= nInsPos+1; | |||
749 | nInsPos = 0; | |||
750 | } | |||
751 | else // all nodes between StartNode and EndNode were moved | |||
752 | { | |||
753 | OSL_ENSURE( pCurrentNode == aSttNdStack[nLevel] ||do { if (true && (!(pCurrentNode == aSttNdStack[nLevel ] || ( pCurrentNode->IsStartNode() && aSttNdStack[ nLevel]->IsSectionNode())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "756" ": "), "%s", "wrong StartNode"); } } while (false) | |||
754 | ( pCurrentNode->IsStartNode() &&do { if (true && (!(pCurrentNode == aSttNdStack[nLevel ] || ( pCurrentNode->IsStartNode() && aSttNdStack[ nLevel]->IsSectionNode())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "756" ": "), "%s", "wrong StartNode"); } } while (false) | |||
755 | aSttNdStack[nLevel]->IsSectionNode()),do { if (true && (!(pCurrentNode == aSttNdStack[nLevel ] || ( pCurrentNode->IsStartNode() && aSttNdStack[ nLevel]->IsSectionNode())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "756" ": "), "%s", "wrong StartNode"); } } while (false) | |||
756 | "wrong StartNode" )do { if (true && (!(pCurrentNode == aSttNdStack[nLevel ] || ( pCurrentNode->IsStartNode() && aSttNdStack[ nLevel]->IsSectionNode())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "756" ": "), "%s", "wrong StartNode"); } } while (false); | |||
757 | ||||
758 | SwNodeIndex aSwIndex( aRg.aEnd, 1 ); | |||
759 | ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames ); | |||
760 | aIdx -= nInsPos+1; // before inserted StartNode | |||
761 | nInsPos = 0; | |||
762 | ||||
763 | // remove pointer from node array | |||
764 | RemoveNode( aRg.aEnd.GetIndex(), 1, true ); | |||
765 | --aRg.aEnd; | |||
766 | ||||
767 | SwSectionNode* pSectNd = aSttNdStack[ nLevel ]->GetSectionNode(); | |||
768 | if( pSectNd && !--nSectNdCnt ) | |||
769 | { | |||
770 | SwNodeIndex aTmp( *pSectNd ); | |||
771 | pSectNd->MakeOwnFrames(&aTmp); | |||
772 | bNewFrames = bSaveNewFrames; | |||
773 | } | |||
774 | aSttNdStack.erase( aSttNdStack.begin() + nLevel ); // remove from stack | |||
775 | nLevel--; | |||
776 | } | |||
777 | ||||
778 | // delete all resulting empty start/end node pairs | |||
779 | SwNode* pTmpNode = (*this)[ aRg.aEnd.GetIndex()+1 ]->GetEndNode(); | |||
780 | if( pTmpNode && SwNodeType::Start == (pCurrentNode = &aRg.aEnd.GetNode()) | |||
781 | ->GetNodeType() && pCurrentNode->StartOfSectionIndex() && | |||
782 | pTmpNode->StartOfSectionNode() == pCurrentNode ) | |||
783 | { | |||
784 | DelNodes( aRg.aEnd, 2 ); | |||
785 | --aRg.aEnd; | |||
786 | } | |||
787 | } | |||
788 | break; | |||
789 | ||||
790 | case SwNodeType::Text: | |||
791 | //Add special function to text node. | |||
792 | { | |||
793 | if( bNewFrames && pCurrentNode->GetContentNode() ) | |||
794 | static_cast<SwContentNode*>(pCurrentNode)->DelFrames(nullptr); | |||
795 | pCurrentNode->m_pStartOfSection = aSttNdStack[ nLevel ]; | |||
796 | nInsPos++; | |||
797 | --aRg.aEnd; | |||
798 | } | |||
799 | break; | |||
800 | case SwNodeType::Grf: | |||
801 | case SwNodeType::Ole: | |||
802 | { | |||
803 | if( bNewFrames && pCurrentNode->GetContentNode() ) | |||
804 | static_cast<SwContentNode*>(pCurrentNode)->DelFrames(nullptr); | |||
805 | ||||
806 | pCurrentNode->m_pStartOfSection = aSttNdStack[ nLevel ]; | |||
807 | nInsPos++; | |||
808 | --aRg.aEnd; | |||
809 | } | |||
810 | break; | |||
811 | ||||
812 | case SwNodeType::PlaceHolder: | |||
813 | if (GetDoc().GetIDocumentUndoRedo().IsUndoNodes(*this)) | |||
814 | { | |||
815 | if( &rNodes == this ) // inside UndoNodesArray | |||
816 | { | |||
817 | // move everything | |||
818 | pCurrentNode->m_pStartOfSection = aSttNdStack[ nLevel ]; | |||
819 | nInsPos++; | |||
820 | } | |||
821 | else // move into "normal" node array | |||
822 | { | |||
823 | // than a SectionNode (start/end) is needed at the current | |||
824 | // InsPos; if so skip it, otherwise ignore current node | |||
825 | if( nInsPos
| |||
826 | { | |||
827 | // delete and copy. CAUTION: all indices after | |||
828 | // "aRg.aEnd+1" will be moved as well! | |||
829 | SwNodeIndex aSwIndex( aRg.aEnd, 1 ); | |||
830 | ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames ); | |||
831 | aIdx -= nInsPos; | |||
832 | nInsPos = 0; | |||
833 | } | |||
834 | SwNode* pTmpNd = &aIdx.GetNode(); | |||
835 | if( pTmpNd->IsSectionNode() || | |||
836 | pTmpNd->StartOfSectionNode()->IsSectionNode() ) | |||
837 | --aIdx; // skip | |||
838 | } | |||
839 | } | |||
840 | else { | |||
841 | assert(!"How can this node be in the node array?")(static_cast <bool> (!"How can this node be in the node array?" ) ? void (0) : __assert_fail ("!\"How can this node be in the node array?\"" , "/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" , 841, __extension__ __PRETTY_FUNCTION__)); | |||
842 | } | |||
843 | --aRg.aEnd; | |||
844 | break; | |||
845 | ||||
846 | default: | |||
847 | assert(!"Unknown node type")(static_cast <bool> (!"Unknown node type") ? void (0) : __assert_fail ("!\"Unknown node type\"", "/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" , 847, __extension__ __PRETTY_FUNCTION__)); | |||
848 | break; | |||
849 | } | |||
850 | } | |||
851 | ||||
852 | if( nInsPos ) // copy remaining rest | |||
853 | { | |||
854 | // rest should be ok | |||
855 | SwNodeIndex aSwIndex( aRg.aEnd, 1 ); | |||
856 | ChgNode( aSwIndex, nInsPos, aIdx, bNewFrames ); | |||
857 | } | |||
858 | ++aRg.aEnd; // again, exclusive end | |||
859 | ||||
860 | // delete all resulting empty start/end node pairs | |||
861 | if( ( pCurrentNode = &aRg.aStart.GetNode())->GetStartNode() && | |||
862 | pCurrentNode->StartOfSectionIndex() && | |||
863 | aRg.aEnd.GetNode().GetEndNode() ) | |||
864 | DelNodes( aRg.aStart, 2 ); | |||
865 | ||||
866 | // initialize numbering update | |||
867 | ++aOrigInsPos.aStart; | |||
868 | // Moved in same node array? Then call update top down! | |||
869 | if( this == &rNodes && | |||
870 | aRg.aEnd.GetIndex() >= aOrigInsPos.aStart.GetIndex() ) | |||
871 | { | |||
872 | UpdateOutlineIdx( aOrigInsPos.aStart.GetNode() ); | |||
873 | UpdateOutlineIdx( aRg.aEnd.GetNode() ); | |||
874 | } | |||
875 | else | |||
876 | { | |||
877 | UpdateOutlineIdx( aRg.aEnd.GetNode() ); | |||
878 | rNodes.UpdateOutlineIdx( aOrigInsPos.aStart.GetNode() ); | |||
879 | } | |||
880 | ||||
881 | return true; | |||
882 | } | |||
883 | ||||
884 | /** create a start/end section pair | |||
885 | * | |||
886 | * Other nodes might be in between. | |||
887 | * | |||
888 | * After this method call, the start node of pRange will be pointing to the | |||
889 | * first node after the start section node and the end node will be the index | |||
890 | * of the end section node. If this method is called multiple times with the | |||
891 | * same input, multiple sections containing the previous ones will be created | |||
892 | * (no content nodes between start or end node). | |||
893 | * | |||
894 | * @note Start and end node of the range must be on the same level but MUST | |||
895 | * NOT be on the top level. | |||
896 | * | |||
897 | * @param [IN,OUT] pRange the range (excl. end) | |||
898 | * @param eSttNdTyp type of the start node | |||
899 | */ | |||
900 | void SwNodes::SectionDown(SwNodeRange *pRange, SwStartNodeType eSttNdTyp ) | |||
901 | { | |||
902 | if( pRange->aStart >= pRange->aEnd || | |||
903 | pRange->aEnd >= Count() || | |||
904 | !::CheckNodesRange(pRange->aStart, pRange->aEnd, false)) | |||
905 | { | |||
906 | return; | |||
907 | } | |||
908 | ||||
909 | // If the beginning of a range is before or at a start node position, so | |||
910 | // delete it, otherwise empty S/E or E/S nodes would be created. | |||
911 | // For other nodes, create a new start node. | |||
912 | SwNode * pCurrentNode = &pRange->aStart.GetNode(); | |||
913 | SwNodeIndex aTmpIdx( *pCurrentNode->StartOfSectionNode() ); | |||
914 | ||||
915 | if( pCurrentNode->GetEndNode() ) | |||
916 | DelNodes( pRange->aStart ); // prevent empty section | |||
917 | else | |||
918 | { | |||
919 | // insert a new StartNode | |||
920 | SwNode* pSttNd = new SwStartNode( pRange->aStart, SwNodeType::Start, eSttNdTyp ); | |||
921 | pRange->aStart = *pSttNd; | |||
922 | aTmpIdx = pRange->aStart; | |||
923 | } | |||
924 | ||||
925 | // If the end of a range is before or at a StartNode, so delete it, | |||
926 | // otherwise empty S/E or E/S nodes would be created. | |||
927 | // For other nodes, insert a new end node. | |||
928 | --pRange->aEnd; | |||
929 | if( pRange->aEnd.GetNode().GetStartNode() ) | |||
930 | DelNodes( pRange->aEnd ); | |||
931 | else | |||
932 | { | |||
933 | ++pRange->aEnd; | |||
934 | // insert a new EndNode | |||
935 | new SwEndNode( pRange->aEnd, *pRange->aStart.GetNode().GetStartNode() ); | |||
936 | } | |||
937 | --pRange->aEnd; | |||
938 | ||||
939 | SectionUpDown( aTmpIdx, pRange->aEnd ); | |||
940 | } | |||
941 | ||||
942 | /** increase level of the given range | |||
943 | * | |||
944 | * The range contained in pRange will be lifted to the next higher level. | |||
945 | * This is done by adding an end node at pRange.start and a start node at | |||
946 | * pRange.end. Furthermore all indices for this range will be updated. | |||
947 | * | |||
948 | * After this method call, the start node of pRange will be pointing to the | |||
949 | * first node inside the lifted range and the end node will be pointing to the | |||
950 | * last position inside the lifted range. | |||
951 | * | |||
952 | * @param [IN,OUT] pRange the range of nodes where the level should be increased | |||
953 | */ | |||
954 | void SwNodes::SectionUp(SwNodeRange *pRange) | |||
955 | { | |||
956 | if( pRange->aStart >= pRange->aEnd || | |||
957 | pRange->aEnd >= Count() || | |||
958 | !::CheckNodesRange(pRange->aStart, pRange->aEnd, false) || | |||
959 | ( HighestLevel( *this, *pRange ) <= 1 )) | |||
960 | { | |||
961 | return; | |||
962 | } | |||
963 | ||||
964 | // If the beginning of a range is before or at a start node position, so | |||
965 | // delete it, otherwise empty S/E or E/S nodes would be created. | |||
966 | // For other nodes, create a new start node. | |||
967 | SwNode * pCurrentNode = &pRange->aStart.GetNode(); | |||
968 | SwNodeIndex aIdx( *pCurrentNode->StartOfSectionNode() ); | |||
969 | if( pCurrentNode->IsStartNode() ) // is StartNode itself | |||
970 | { | |||
971 | SwEndNode* pEndNd = pRange->aEnd.GetNode().GetEndNode(); | |||
972 | if (pEndNd && pCurrentNode == pEndNd->m_pStartOfSection) | |||
973 | { | |||
974 | // there was a pairwise reset, adjust only those in the range | |||
975 | SwStartNode* pTmpSttNd = pCurrentNode->m_pStartOfSection; | |||
976 | RemoveNode( pRange->aStart.GetIndex(), 1, true ); | |||
977 | RemoveNode( pRange->aEnd.GetIndex(), 1, true ); | |||
978 | ||||
979 | SwNodeIndex aTmpIdx( pRange->aStart ); | |||
980 | while( aTmpIdx < pRange->aEnd ) | |||
981 | { | |||
982 | pCurrentNode = &aTmpIdx.GetNode(); | |||
983 | pCurrentNode->m_pStartOfSection = pTmpSttNd; | |||
984 | if( pCurrentNode->IsStartNode() ) | |||
985 | aTmpIdx = pCurrentNode->EndOfSectionIndex() + 1; | |||
986 | else | |||
987 | ++aTmpIdx; | |||
988 | } | |||
989 | return ; | |||
990 | } | |||
991 | DelNodes( pRange->aStart ); | |||
992 | } | |||
993 | else if( aIdx == pRange->aStart.GetIndex()-1 ) // before StartNode | |||
994 | DelNodes( aIdx ); | |||
995 | else | |||
996 | new SwEndNode( pRange->aStart, *aIdx.GetNode().GetStartNode() ); | |||
997 | ||||
998 | // If the end of a range is before or at a StartNode, so delete it, | |||
999 | // otherwise empty S/E or E/S nodes would be created. | |||
1000 | // For other nodes, insert a new end node. | |||
1001 | SwNodeIndex aTmpIdx( pRange->aEnd ); | |||
1002 | if( pRange->aEnd.GetNode().IsEndNode() ) | |||
1003 | DelNodes( pRange->aEnd ); | |||
1004 | else | |||
1005 | { | |||
1006 | new SwStartNode( pRange->aEnd ); | |||
1007 | /*?? which NodeType ??*/ | |||
1008 | aTmpIdx = *pRange->aEnd.GetNode().EndOfSectionNode(); | |||
1009 | --pRange->aEnd; | |||
1010 | } | |||
1011 | ||||
1012 | SectionUpDown( aIdx, aTmpIdx ); | |||
1013 | } | |||
1014 | ||||
1015 | /** correct indices after movement | |||
1016 | * | |||
1017 | * Update all indices after movement so that the levels are consistent again. | |||
1018 | * | |||
1019 | * @param aStart index of the start node | |||
1020 | * @param aEnd index of the end point | |||
1021 | * | |||
1022 | * @see SwNodes::SectionUp | |||
1023 | * @see SwNodes::SectionDown | |||
1024 | */ | |||
1025 | void SwNodes::SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd ) | |||
1026 | { | |||
1027 | SwNodeIndex aTmpIdx( aStart, +1 ); | |||
1028 | // array forms a stack, holding all StartOfSelections | |||
1029 | SwStartNodePointers aSttNdStack; | |||
1030 | SwStartNode* pTmp = aStart.GetNode().GetStartNode(); | |||
1031 | aSttNdStack.push_back( pTmp ); | |||
1032 | ||||
1033 | // loop until the first start node that needs to be change was found | |||
1034 | // (the indices are updated from the end node backwards to the start) | |||
1035 | for( ;; ++aTmpIdx ) | |||
1036 | { | |||
1037 | SwNode * pCurrentNode = &aTmpIdx.GetNode(); | |||
1038 | pCurrentNode->m_pStartOfSection = aSttNdStack[ aSttNdStack.size()-1 ]; | |||
1039 | ||||
1040 | if( pCurrentNode->GetStartNode() ) | |||
1041 | { | |||
1042 | pTmp = static_cast<SwStartNode*>(pCurrentNode); | |||
1043 | aSttNdStack.push_back( pTmp ); | |||
1044 | } | |||
1045 | else if( pCurrentNode->GetEndNode() ) | |||
1046 | { | |||
1047 | SwStartNode* pSttNd = aSttNdStack[ aSttNdStack.size() - 1 ]; | |||
1048 | pSttNd->m_pEndOfSection = static_cast<SwEndNode*>(pCurrentNode); | |||
1049 | aSttNdStack.pop_back(); | |||
1050 | if( !aSttNdStack.empty() ) | |||
1051 | continue; // still enough EndNodes on the stack | |||
1052 | ||||
1053 | else if( aTmpIdx < aEnd ) // too many StartNodes | |||
1054 | // if the end is not reached, yet, get the start of the section above | |||
1055 | { | |||
1056 | aSttNdStack.insert( aSttNdStack.begin(), pSttNd->m_pStartOfSection ); | |||
1057 | } | |||
1058 | else // finished, as soon as out of the range | |||
1059 | break; | |||
1060 | } | |||
1061 | } | |||
1062 | } | |||
1063 | ||||
1064 | /** delete nodes | |||
1065 | * | |||
1066 | * This is a specific implementation of a delete function for a variable array. | |||
1067 | * It is necessary as there might be inconsistencies after deleting start or | |||
1068 | * end nodes. This method can clean those up. | |||
1069 | * | |||
1070 | * @param rIndex position to delete at (unchanged afterwards) | |||
1071 | * @param nNodes number of nodes to delete (default: 1) | |||
1072 | */ | |||
1073 | void SwNodes::Delete(const SwNodeIndex &rIndex, sal_uLong nNodes) | |||
1074 | { | |||
1075 | int nLevel = 0; // level counter | |||
1076 | SwNode * pCurrentNode; | |||
1077 | ||||
1078 | sal_uLong nCnt = Count() - rIndex.GetIndex() - 1; | |||
1079 | if( nCnt > nNodes ) nCnt = nNodes; | |||
1080 | ||||
1081 | if( nCnt == 0 ) // no count -> return | |||
1082 | return; | |||
1083 | ||||
1084 | SwNodeRange aRg( rIndex, 0, rIndex, nCnt-1 ); | |||
1085 | // check if [rIndex..rIndex + nCnt] is larger than the range | |||
1086 | if( ( !aRg.aStart.GetNode().StartOfSectionIndex() && | |||
1087 | !aRg.aStart.GetIndex() ) || | |||
1088 | !::CheckNodesRange(aRg.aStart, aRg.aEnd, false)) | |||
1089 | { | |||
1090 | return; | |||
1091 | } | |||
1092 | ||||
1093 | // if aEnd is not on a ContentNode, search the previous one | |||
1094 | while( ( pCurrentNode = &aRg.aEnd.GetNode())->GetStartNode() || | |||
1095 | ( pCurrentNode->GetEndNode() && | |||
1096 | !pCurrentNode->m_pStartOfSection->IsTableNode() )) | |||
1097 | --aRg.aEnd; | |||
1098 | ||||
1099 | nCnt = 0; | |||
1100 | //TODO: check/improve comment | |||
1101 | // increase start so that we are able to use "<" (using "<=" might cause | |||
1102 | // problems if aEnd == aStart and aEnd is deleted, so aEnd <= aStart) | |||
1103 | --aRg.aStart; | |||
1104 | ||||
1105 | bool bSaveInNodesDel = m_bInNodesDel; | |||
1106 | m_bInNodesDel = true; | |||
1107 | bool bUpdateOutline = false; | |||
1108 | ||||
1109 | // loop until everything is deleted | |||
1110 | while( aRg.aStart < aRg.aEnd ) | |||
1111 | { | |||
1112 | pCurrentNode = &aRg.aEnd.GetNode(); | |||
1113 | ||||
1114 | if( pCurrentNode->GetEndNode() ) | |||
1115 | { | |||
1116 | // delete the whole section? | |||
1117 | if( pCurrentNode->StartOfSectionIndex() > aRg.aStart.GetIndex() ) | |||
1118 | { | |||
1119 | SwTableNode* pTableNd = pCurrentNode->m_pStartOfSection->GetTableNode(); | |||
1120 | if( pTableNd ) | |||
1121 | pTableNd->DelFrames(); | |||
1122 | ||||
1123 | SwNode *pNd, *pChkNd = pCurrentNode->m_pStartOfSection; | |||
1124 | SwOutlineNodes::size_type nIdxPos; | |||
1125 | do { | |||
1126 | pNd = &aRg.aEnd.GetNode(); | |||
1127 | ||||
1128 | if( pNd->IsTextNode() ) | |||
1129 | { | |||
1130 | SwTextNode *const pTextNode(pNd->GetTextNode()); | |||
1131 | if (pTextNode->IsOutline() && | |||
1132 | m_pOutlineNodes->Seek_Entry( pNd, &nIdxPos )) | |||
1133 | { | |||
1134 | // remove outline indices | |||
1135 | m_pOutlineNodes->erase(nIdxPos); | |||
1136 | bUpdateOutline = true; | |||
1137 | } | |||
1138 | pTextNode->InvalidateNumRule(); | |||
1139 | } | |||
1140 | else if( pNd->IsEndNode() && | |||
1141 | pNd->m_pStartOfSection->IsTableNode() ) | |||
1142 | static_cast<SwTableNode*>(pNd->m_pStartOfSection)->DelFrames(); | |||
1143 | ||||
1144 | --aRg.aEnd; | |||
1145 | nCnt++; | |||
1146 | ||||
1147 | } while( pNd != pChkNd ); | |||
1148 | } | |||
1149 | else | |||
1150 | { | |||
1151 | RemoveNode( aRg.aEnd.GetIndex()+1, nCnt, true ); // delete | |||
1152 | nCnt = 0; | |||
1153 | --aRg.aEnd; // before the EndNode | |||
1154 | nLevel++; | |||
1155 | } | |||
1156 | } | |||
1157 | else if( pCurrentNode->GetStartNode() ) // found StartNode | |||
1158 | { | |||
1159 | if( nLevel == 0 ) // decrease one level | |||
1160 | { | |||
1161 | if( nCnt ) | |||
1162 | { | |||
1163 | // now delete array | |||
1164 | ++aRg.aEnd; | |||
1165 | RemoveNode( aRg.aEnd.GetIndex(), nCnt, true ); | |||
1166 | nCnt = 0; | |||
1167 | } | |||
1168 | } | |||
1169 | else // remove all nodes between start and end node (incl. both) | |||
1170 | { | |||
1171 | RemoveNode( aRg.aEnd.GetIndex(), nCnt + 2, true ); // delete array | |||
1172 | nCnt = 0; | |||
1173 | nLevel--; | |||
1174 | } | |||
1175 | ||||
1176 | // after deletion, aEnd might point to an EndNode... | |||
1177 | // delete all empty start/end node pairs | |||
1178 | SwNode* pTmpNode = aRg.aEnd.GetNode().GetEndNode(); | |||
1179 | --aRg.aEnd; | |||
1180 | while( pTmpNode && | |||
1181 | ( pCurrentNode = &aRg.aEnd.GetNode())->GetStartNode() && | |||
1182 | pCurrentNode->StartOfSectionIndex() ) | |||
1183 | { | |||
1184 | // remove end and start node | |||
1185 | DelNodes( aRg.aEnd, 2 ); | |||
1186 | pTmpNode = aRg.aEnd.GetNode().GetEndNode(); | |||
1187 | --aRg.aEnd; | |||
1188 | } | |||
1189 | } | |||
1190 | else // "normal" node, so insert into TmpArray | |||
1191 | { | |||
1192 | SwTextNode* pTextNd = pCurrentNode->GetTextNode(); | |||
1193 | if( pTextNd ) | |||
1194 | { | |||
1195 | if( pTextNd->IsOutline()) | |||
1196 | { | |||
1197 | // delete outline indices | |||
1198 | m_pOutlineNodes->erase( pTextNd ); | |||
1199 | bUpdateOutline = true; | |||
1200 | } | |||
1201 | pTextNd->InvalidateNumRule(); | |||
1202 | } | |||
1203 | else if( pCurrentNode->IsContentNode() ) | |||
1204 | static_cast<SwContentNode*>(pCurrentNode)->InvalidateNumRule(); | |||
1205 | ||||
1206 | --aRg.aEnd; | |||
1207 | nCnt++; | |||
1208 | } | |||
1209 | } | |||
1210 | ||||
1211 | ++aRg.aEnd; | |||
1212 | if( nCnt != 0 ) | |||
1213 | RemoveNode( aRg.aEnd.GetIndex(), nCnt, true ); // delete the rest | |||
1214 | ||||
1215 | // delete all empty start/end node pairs | |||
1216 | while( aRg.aEnd.GetNode().GetEndNode() && | |||
1217 | ( pCurrentNode = &aRg.aStart.GetNode())->GetStartNode() && | |||
1218 | pCurrentNode->StartOfSectionIndex() ) | |||
1219 | // but none of the holy 5. (???) | |||
1220 | { | |||
1221 | DelNodes( aRg.aStart, 2 ); // delete start and end node | |||
1222 | --aRg.aStart; | |||
1223 | } | |||
1224 | ||||
1225 | m_bInNodesDel = bSaveInNodesDel; | |||
1226 | ||||
1227 | if( !m_bInNodesDel ) | |||
1228 | { | |||
1229 | // update numbering | |||
1230 | if( bUpdateOutline || m_bInDelUpdOutline ) | |||
1231 | { | |||
1232 | UpdateOutlineIdx( aRg.aEnd.GetNode() ); | |||
1233 | m_bInDelUpdOutline = false; | |||
1234 | } | |||
1235 | ||||
1236 | } | |||
1237 | else | |||
1238 | { | |||
1239 | if( bUpdateOutline ) | |||
1240 | m_bInDelUpdOutline = true; | |||
1241 | } | |||
1242 | } | |||
1243 | ||||
1244 | /** get section level at the given position | |||
1245 | * | |||
1246 | * @note The first node in an array should always be a start node. | |||
1247 | * Because of this, there is a special treatment here based on the | |||
1248 | * assumption that this is true in this context as well. | |||
1249 | * | |||
1250 | * @param rIdx position of the node | |||
1251 | * @return section level at the given position | |||
1252 | */ | |||
1253 | sal_uInt16 SwNodes::GetSectionLevel(const SwNodeIndex &rIdx) | |||
1254 | { | |||
1255 | // special treatment for 1st Node | |||
1256 | if(rIdx == 0) return 1; | |||
1257 | // no recursion! This calls a SwNode::GetSectionLevel (missing "s") | |||
1258 | return rIdx.GetNode().GetSectionLevel(); | |||
1259 | } | |||
1260 | ||||
1261 | void SwNodes::GoStartOfSection(SwNodeIndex *pIdx) | |||
1262 | { | |||
1263 | // after the next start node | |||
1264 | SwNodeIndex aTmp( *pIdx->GetNode().StartOfSectionNode(), +1 ); | |||
1265 | ||||
1266 | // If index points to no ContentNode, then go to one. | |||
1267 | // If there is no further available, do not change the index' position! | |||
1268 | while( !aTmp.GetNode().IsContentNode() ) | |||
1269 | { // go from this StartNode (can only be one) to its end | |||
1270 | if( *pIdx <= aTmp ) | |||
1271 | return; // ERROR: already after the section | |||
1272 | aTmp = aTmp.GetNode().EndOfSectionIndex()+1; | |||
1273 | if( *pIdx <= aTmp ) | |||
1274 | return; // ERROR: already after the section | |||
1275 | } | |||
1276 | (*pIdx) = aTmp; // is on a ContentNode | |||
1277 | } | |||
1278 | ||||
1279 | void SwNodes::GoEndOfSection(SwNodeIndex *pIdx) | |||
1280 | { | |||
1281 | if( !pIdx->GetNode().IsEndNode() ) | |||
1282 | (*pIdx) = *pIdx->GetNode().EndOfSectionNode(); | |||
1283 | } | |||
1284 | ||||
1285 | SwContentNode* SwNodes::GoNext(SwNodeIndex *pIdx) const | |||
1286 | { | |||
1287 | if( pIdx->GetIndex() >= Count() - 1 ) | |||
1288 | return nullptr; | |||
1289 | ||||
1290 | SwNodeIndex aTmp(*pIdx, +1); | |||
1291 | SwNode* pNd = nullptr; | |||
1292 | while( aTmp < Count()-1 && !( pNd = &aTmp.GetNode())->IsContentNode() ) | |||
1293 | ++aTmp; | |||
1294 | ||||
1295 | if( aTmp == Count()-1 ) | |||
1296 | pNd = nullptr; | |||
1297 | else | |||
1298 | (*pIdx) = aTmp; | |||
1299 | return static_cast<SwContentNode*>(pNd); | |||
1300 | } | |||
1301 | ||||
1302 | SwContentNode* SwNodes::GoPrevious(SwNodeIndex *pIdx) | |||
1303 | { | |||
1304 | if( !pIdx->GetIndex() ) | |||
1305 | return nullptr; | |||
1306 | ||||
1307 | SwNodeIndex aTmp( *pIdx, -1 ); | |||
1308 | SwNode* pNd = nullptr; | |||
1309 | while( aTmp.GetIndex() && !( pNd = &aTmp.GetNode())->IsContentNode() ) | |||
1310 | --aTmp; | |||
1311 | ||||
1312 | if( !aTmp.GetIndex() ) | |||
1313 | pNd = nullptr; | |||
1314 | else | |||
1315 | (*pIdx) = aTmp; | |||
1316 | return static_cast<SwContentNode*>(pNd); | |||
1317 | } | |||
1318 | ||||
1319 | /** Delete a number of nodes | |||
1320 | * | |||
1321 | * @param rStart starting position in this nodes array | |||
1322 | * @param nCnt number of nodes to delete | |||
1323 | */ | |||
1324 | void SwNodes::DelNodes( const SwNodeIndex & rStart, sal_uLong nCnt ) | |||
1325 | { | |||
1326 | sal_uLong nSttIdx = rStart.GetIndex(); | |||
1327 | ||||
1328 | if( !nSttIdx && nCnt == GetEndOfContent().GetIndex()+1 ) | |||
1329 | { | |||
1330 | // The whole nodes array will be destroyed, you're in the Doc's DTOR! | |||
1331 | // The initial start/end nodes should be only destroyed in the SwNodes' DTOR! | |||
1332 | SwNode* aEndNdArr[] = { m_pEndOfContent.get(), | |||
1333 | m_pEndOfPostIts, m_pEndOfInserts, | |||
1334 | m_pEndOfAutotext, m_pEndOfRedlines, | |||
1335 | nullptr | |||
1336 | }; | |||
1337 | ||||
1338 | SwNode** ppEndNdArr = aEndNdArr; | |||
1339 | while( *ppEndNdArr ) | |||
1340 | { | |||
1341 | nSttIdx = (*ppEndNdArr)->StartOfSectionIndex() + 1; | |||
1342 | sal_uLong nEndIdx = (*ppEndNdArr)->GetIndex(); | |||
1343 | ||||
1344 | if( nSttIdx != nEndIdx ) | |||
1345 | RemoveNode( nSttIdx, nEndIdx - nSttIdx, true ); | |||
1346 | ||||
1347 | ++ppEndNdArr; | |||
1348 | } | |||
1349 | } | |||
1350 | else | |||
1351 | { | |||
1352 | int bUpdateNum = 0; | |||
1353 | for( sal_uLong n = nSttIdx, nEnd = nSttIdx + nCnt; n < nEnd; ++n ) | |||
1354 | { | |||
1355 | SwNode* pNd = (*this)[ n ]; | |||
1356 | ||||
1357 | if (pNd->IsTextNode() && pNd->GetTextNode()->IsOutline()) | |||
1358 | { | |||
1359 | // remove the outline indices | |||
1360 | SwOutlineNodes::size_type nIdxPos; | |||
1361 | if( m_pOutlineNodes->Seek_Entry( pNd, &nIdxPos )) | |||
1362 | { | |||
1363 | m_pOutlineNodes->erase(nIdxPos); | |||
1364 | bUpdateNum = 1; | |||
1365 | } | |||
1366 | } | |||
1367 | if( pNd->IsContentNode() ) | |||
1368 | { | |||
1369 | static_cast<SwContentNode*>(pNd)->InvalidateNumRule(); | |||
1370 | static_cast<SwContentNode*>(pNd)->DelFrames(nullptr); | |||
1371 | } | |||
1372 | } | |||
1373 | RemoveNode( nSttIdx, nCnt, true ); | |||
1374 | ||||
1375 | // update numbering | |||
1376 | if( bUpdateNum ) | |||
1377 | UpdateOutlineIdx( rStart.GetNode() ); | |||
1378 | } | |||
1379 | } | |||
1380 | ||||
1381 | namespace { | |||
1382 | ||||
1383 | struct HighLevel | |||
1384 | { | |||
1385 | sal_uInt16 nLevel, nTop; | |||
1386 | explicit HighLevel( sal_uInt16 nLv ) : nLevel( nLv ), nTop( nLv ) {} | |||
1387 | }; | |||
1388 | ||||
1389 | } | |||
1390 | ||||
1391 | static bool lcl_HighestLevel( const SwNodePtr& rpNode, void * pPara ) | |||
1392 | { | |||
1393 | HighLevel * pHL = static_cast<HighLevel*>(pPara); | |||
1394 | if( rpNode->GetStartNode() ) | |||
1395 | pHL->nLevel++; | |||
1396 | else if( rpNode->GetEndNode() ) | |||
1397 | pHL->nLevel--; | |||
1398 | if( pHL->nTop > pHL->nLevel ) | |||
1399 | pHL->nTop = pHL->nLevel; | |||
1400 | return true; | |||
1401 | ||||
1402 | } | |||
1403 | ||||
1404 | /** Calculate the highest level in a range | |||
1405 | * | |||
1406 | * @param rNodes the nodes array | |||
1407 | * @param rRange the range to inspect | |||
1408 | * @return the highest level | |||
1409 | */ | |||
1410 | sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange ) | |||
1411 | { | |||
1412 | HighLevel aPara( SwNodes::GetSectionLevel( rRange.aStart )); | |||
1413 | rNodes.ForEach( rRange.aStart, rRange.aEnd, lcl_HighestLevel, &aPara ); | |||
1414 | return aPara.nTop; | |||
1415 | ||||
1416 | } | |||
1417 | ||||
1418 | /** move a range | |||
1419 | * | |||
1420 | * @param rPam the range to move | |||
1421 | * @param rPos to destination position in the given nodes array | |||
1422 | * @param rNodes the node array to move the range into | |||
1423 | */ | |||
1424 | void SwNodes::MoveRange( SwPaM & rPam, SwPosition & rPos, SwNodes& rNodes ) | |||
1425 | { | |||
1426 | SwPosition * const pStt = rPam.Start(); | |||
1427 | SwPosition * const pEnd = rPam.End(); | |||
1428 | ||||
1429 | if( !rPam.HasMark() || *pStt >= *pEnd ) | |||
1430 | return; | |||
1431 | ||||
1432 | if( this == &rNodes && *pStt <= rPos && rPos < *pEnd ) | |||
1433 | return; | |||
1434 | ||||
1435 | SwNodeIndex aEndIdx( pEnd->nNode ); | |||
1436 | SwNodeIndex aSttIdx( pStt->nNode ); | |||
1437 | SwTextNode *const pSrcNd = aSttIdx.GetNode().GetTextNode(); | |||
1438 | SwTextNode * pDestNd = rPos.nNode.GetNode().GetTextNode(); | |||
1439 | bool bSplitDestNd = true; | |||
1440 | bool bCopyCollFormat = pDestNd && pDestNd->GetText().isEmpty(); | |||
1441 | ||||
1442 | if( pSrcNd ) | |||
1443 | { | |||
1444 | // if the first node is a TextNode, then there must | |||
1445 | // be also a TextNode in the NodesArray to store the content | |||
1446 | if( !pDestNd ) | |||
1447 | { | |||
1448 | pDestNd = rNodes.MakeTextNode( rPos.nNode, pSrcNd->GetTextColl() ); | |||
1449 | --rPos.nNode; | |||
1450 | rPos.nContent.Assign( pDestNd, 0 ); | |||
1451 | bCopyCollFormat = true; | |||
1452 | } | |||
1453 | bSplitDestNd = pDestNd->Len() > rPos.nContent.GetIndex() || | |||
1454 | pEnd->nNode.GetNode().IsTextNode(); | |||
1455 | ||||
1456 | // move the content into the new node | |||
1457 | bool bOneNd = pStt->nNode == pEnd->nNode; | |||
1458 | const sal_Int32 nLen = | |||
1459 | ( bOneNd ? std::min(pEnd->nContent.GetIndex(), pSrcNd->Len()) : pSrcNd->Len() ) | |||
1460 | - pStt->nContent.GetIndex(); | |||
1461 | ||||
1462 | if( !pEnd->nNode.GetNode().IsContentNode() ) | |||
1463 | { | |||
1464 | bOneNd = true; | |||
1465 | sal_uLong nSttNdIdx = pStt->nNode.GetIndex() + 1; | |||
1466 | const sal_uLong nEndNdIdx = pEnd->nNode.GetIndex(); | |||
1467 | for( ; nSttNdIdx < nEndNdIdx; ++nSttNdIdx ) | |||
1468 | { | |||
1469 | if( (*this)[ nSttNdIdx ]->IsContentNode() ) | |||
1470 | { | |||
1471 | bOneNd = false; | |||
1472 | break; | |||
1473 | } | |||
1474 | } | |||
1475 | } | |||
1476 | ||||
1477 | // templates must be copied/set after a split | |||
1478 | if( !bOneNd && bSplitDestNd ) | |||
1479 | { | |||
1480 | if( !rPos.nContent.GetIndex() ) | |||
1481 | { | |||
1482 | bCopyCollFormat = true; | |||
1483 | } | |||
1484 | if( rNodes.IsDocNodes() ) | |||
1485 | { | |||
1486 | SwDoc& rInsDoc = pDestNd->GetDoc(); | |||
1487 | ::sw::UndoGuard const ug(rInsDoc.GetIDocumentUndoRedo()); | |||
1488 | rInsDoc.getIDocumentContentOperations().SplitNode( rPos, false ); | |||
1489 | } | |||
1490 | else | |||
1491 | { | |||
1492 | pDestNd->SplitContentNode(rPos, nullptr); | |||
1493 | } | |||
1494 | ||||
1495 | if( rPos.nNode == aEndIdx ) | |||
1496 | { | |||
1497 | --aEndIdx; | |||
1498 | } | |||
1499 | bSplitDestNd = true; | |||
1500 | ||||
1501 | pDestNd = rNodes[ rPos.nNode.GetIndex() - 1 ]->GetTextNode(); | |||
1502 | if( nLen ) | |||
1503 | { | |||
1504 | pSrcNd->CutText( pDestNd, SwIndex( pDestNd, pDestNd->Len()), | |||
1505 | pStt->nContent, nLen ); | |||
1506 | } | |||
1507 | } | |||
1508 | else if ( nLen ) | |||
1509 | { | |||
1510 | pSrcNd->CutText( pDestNd, rPos.nContent, pStt->nContent, nLen ); | |||
1511 | } | |||
1512 | ||||
1513 | if( bCopyCollFormat ) | |||
1514 | { | |||
1515 | SwDoc& rInsDoc = pDestNd->GetDoc(); | |||
1516 | ::sw::UndoGuard const undoGuard(rInsDoc.GetIDocumentUndoRedo()); | |||
1517 | pSrcNd->CopyCollFormat( *pDestNd ); | |||
1518 | bCopyCollFormat = false; | |||
1519 | } | |||
1520 | ||||
1521 | if( bOneNd ) | |||
1522 | { | |||
1523 | // Correct the PaM, because it might have happened that the move | |||
1524 | // went over the node borders (so the data might be in different nodes). | |||
1525 | // Also, a selection is invalidated. | |||
1526 | pEnd->nContent = pStt->nContent; | |||
1527 | rPam.DeleteMark(); | |||
1528 | GetDoc().GetDocShell()->Broadcast( SwFormatFieldHint( nullptr, | |||
1529 | rNodes.IsDocNodes() ? SwFormatFieldHintWhich::INSERTED : SwFormatFieldHintWhich::REMOVED ) ); | |||
1530 | return; | |||
1531 | } | |||
1532 | ||||
1533 | ++aSttIdx; | |||
1534 | } | |||
1535 | else if( pDestNd ) | |||
1536 | { | |||
1537 | if( rPos.nContent.GetIndex() ) | |||
1538 | { | |||
1539 | if( rPos.nContent.GetIndex() == pDestNd->Len() ) | |||
1540 | { | |||
1541 | ++rPos.nNode; | |||
1542 | } | |||
1543 | else if( rPos.nContent.GetIndex() ) | |||
1544 | { | |||
1545 | // if the EndNode is split than correct the EndIdx | |||
1546 | const bool bCorrEnd = aEndIdx == rPos.nNode; | |||
1547 | ||||
1548 | // if no text is attached to the TextNode, split it | |||
1549 | if( rNodes.IsDocNodes() ) | |||
1550 | { | |||
1551 | SwDoc& rInsDoc = pDestNd->GetDoc(); | |||
1552 | ::sw::UndoGuard const ug(rInsDoc.GetIDocumentUndoRedo()); | |||
1553 | rInsDoc.getIDocumentContentOperations().SplitNode( rPos, false ); | |||
1554 | } | |||
1555 | else | |||
1556 | { | |||
1557 | pDestNd->SplitContentNode(rPos, nullptr); | |||
1558 | } | |||
1559 | ||||
1560 | if ( bCorrEnd ) | |||
1561 | { | |||
1562 | --aEndIdx; | |||
1563 | } | |||
1564 | } | |||
1565 | } | |||
1566 | // at the end only an empty TextNode is left over | |||
1567 | bSplitDestNd = true; | |||
1568 | } | |||
1569 | ||||
1570 | SwTextNode* const pEndSrcNd = aEndIdx.GetNode().GetTextNode(); | |||
1571 | if ( pEndSrcNd ) | |||
1572 | { | |||
1573 | // at the end of this range a new TextNode will be created | |||
1574 | if( !bSplitDestNd ) | |||
1575 | { | |||
1576 | if( rPos.nNode < rNodes.GetEndOfContent().GetIndex() ) | |||
1577 | { | |||
1578 | ++rPos.nNode; | |||
1579 | } | |||
1580 | ||||
1581 | pDestNd = | |||
1582 | rNodes.MakeTextNode( rPos.nNode, pEndSrcNd->GetTextColl() ); | |||
1583 | --rPos.nNode; | |||
1584 | rPos.nContent.Assign( pDestNd, 0 ); | |||
1585 | } | |||
1586 | else | |||
1587 | { | |||
1588 | pDestNd = rPos.nNode.GetNode().GetTextNode(); | |||
1589 | } | |||
1590 | ||||
1591 | if (pDestNd && pEnd->nContent.GetIndex()) | |||
1592 | { | |||
1593 | // move the content into the new node | |||
1594 | SwIndex aIdx( pEndSrcNd, 0 ); | |||
1595 | pEndSrcNd->CutText( pDestNd, rPos.nContent, aIdx, | |||
1596 | pEnd->nContent.GetIndex()); | |||
1597 | } | |||
1598 | ||||
1599 | if (pDestNd && bCopyCollFormat) | |||
1600 | { | |||
1601 | SwDoc& rInsDoc = pDestNd->GetDoc(); | |||
1602 | ::sw::UndoGuard const ug(rInsDoc.GetIDocumentUndoRedo()); | |||
1603 | pEndSrcNd->CopyCollFormat( *pDestNd ); | |||
1604 | } | |||
1605 | } | |||
1606 | else | |||
1607 | { | |||
1608 | if ( pSrcNd && aEndIdx.GetNode().IsContentNode() ) | |||
1609 | { | |||
1610 | ++aEndIdx; | |||
1611 | } | |||
1612 | if( !bSplitDestNd ) | |||
1613 | { | |||
1614 | ++rPos.nNode; | |||
1615 | rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(), 0 ); | |||
1616 | } | |||
1617 | } | |||
1618 | ||||
1619 | if( aEndIdx != aSttIdx ) | |||
1620 | { | |||
1621 | // move the nodes into the NodesArray | |||
1622 | const sal_uLong nSttDiff = aSttIdx.GetIndex() - pStt->nNode.GetIndex(); | |||
1623 | SwNodeRange aRg( aSttIdx, aEndIdx ); | |||
1624 | MoveNodes( aRg, rNodes, rPos.nNode ); | |||
1625 | ||||
1626 | // if in the same node array, all indices are now at new positions (so correct them) | |||
1627 | if( &rNodes == this ) | |||
1628 | { | |||
1629 | pStt->nNode = aRg.aEnd.GetIndex() - nSttDiff; | |||
1630 | } | |||
1631 | } | |||
1632 | ||||
1633 | // if the StartNode was moved to whom the cursor pointed, so | |||
1634 | // the content must be registered in the current content! | |||
1635 | if ( &pStt->nNode.GetNode() == &GetEndOfContent() ) | |||
1636 | { | |||
1637 | const bool bSuccess = GoPrevious( &pStt->nNode ); | |||
1638 | OSL_ENSURE( bSuccess, "Move() - no ContentNode here" )do { if (true && (!(bSuccess))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "1638" ": "), "%s", "Move() - no ContentNode here"); } } while (false); | |||
1639 | } | |||
1640 | pStt->nContent.Assign( pStt->nNode.GetNode().GetContentNode(), | |||
1641 | pStt->nContent.GetIndex() ); | |||
1642 | // Correct the PaM, because it might have happened that the move | |||
1643 | // went over the node borders (so the data might be in different nodes). | |||
1644 | // Also, a selection is invalidated. | |||
1645 | *pEnd = *pStt; | |||
1646 | rPam.DeleteMark(); | |||
1647 | GetDoc().GetDocShell()->Broadcast( SwFormatFieldHint( nullptr, | |||
1648 | rNodes.IsDocNodes() ? SwFormatFieldHintWhich::INSERTED : SwFormatFieldHintWhich::REMOVED ) ); | |||
1649 | } | |||
1650 | ||||
1651 | ///@see SwNodes::MoveNodes (TODO: seems to be C&P programming here) | |||
1652 | void SwNodes::CopyNodes( const SwNodeRange& rRange, | |||
1653 | const SwNodeIndex& rIndex, bool bNewFrames, bool bTableInsDummyNode ) const | |||
1654 | { | |||
1655 | SwDoc& rDoc = rIndex.GetNode().GetDoc(); | |||
1656 | ||||
1657 | SwNode * pCurrentNode; | |||
1658 | if( rIndex == 0 || | |||
1659 | ( (pCurrentNode = &rIndex.GetNode())->GetStartNode() && | |||
1660 | !pCurrentNode->StartOfSectionIndex() )) | |||
1661 | return; | |||
1662 | ||||
1663 | SwNodeRange aRg( rRange ); | |||
1664 | ||||
1665 | // skip "simple" StartNodes or EndNodes | |||
1666 | while( SwNodeType::Start == (pCurrentNode = & aRg.aStart.GetNode())->GetNodeType() | |||
1667 | || ( pCurrentNode->IsEndNode() && | |||
1668 | !pCurrentNode->m_pStartOfSection->IsSectionNode() ) ) | |||
1669 | ++aRg.aStart; | |||
1670 | ||||
1671 | const SwNode *aEndNode = &aRg.aEnd.GetNode(); | |||
1672 | int nIsEndOfContent = (aEndNode == &aEndNode->GetNodes().GetEndOfContent()) ? 1 : 0; | |||
1673 | ||||
1674 | if (0 == nIsEndOfContent) | |||
1675 | { | |||
1676 | // if aEnd-1 points to no ContentNode, search previous one | |||
1677 | --aRg.aEnd; | |||
1678 | // #i107142#: if aEnd is start node of a special section, do nothing. | |||
1679 | // Otherwise this could lead to crash: going through all previous | |||
1680 | // special section nodes and then one before the first. | |||
1681 | if (aRg.aEnd.GetNode().StartOfSectionIndex() != 0) | |||
1682 | { | |||
1683 | while( ((pCurrentNode = & aRg.aEnd.GetNode())->GetStartNode() && | |||
1684 | !pCurrentNode->IsSectionNode() ) || | |||
1685 | ( pCurrentNode->IsEndNode() && | |||
1686 | SwNodeType::Start == pCurrentNode->m_pStartOfSection->GetNodeType()) ) | |||
1687 | { | |||
1688 | --aRg.aEnd; | |||
1689 | } | |||
1690 | } | |||
1691 | ++aRg.aEnd; | |||
1692 | } | |||
1693 | ||||
1694 | // is there anything left to copy? | |||
1695 | if( aRg.aStart >= aRg.aEnd ) | |||
1696 | return; | |||
1697 | ||||
1698 | // when inserting into the source range, nothing need to be done | |||
1699 | OSL_ENSURE( &aRg.aStart.GetNodes() == this,do { if (true && (!(&aRg.aStart.GetNodes() == this ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "1700" ": "), "%s", "aRg should use this node array"); } } while (false) | |||
1700 | "aRg should use this node array" )do { if (true && (!(&aRg.aStart.GetNodes() == this ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "1700" ": "), "%s", "aRg should use this node array"); } } while (false); | |||
1701 | OSL_ENSURE( &aRg.aStart.GetNodes() == &aRg.aEnd.GetNodes(),do { if (true && (!(&aRg.aStart.GetNodes() == & aRg.aEnd.GetNodes()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "1702" ": "), "%s", "Range across different nodes arrays? You deserve punishment!" ); } } while (false) | |||
1702 | "Range across different nodes arrays? You deserve punishment!")do { if (true && (!(&aRg.aStart.GetNodes() == & aRg.aEnd.GetNodes()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" ":" "1702" ": "), "%s", "Range across different nodes arrays? You deserve punishment!" ); } } while (false); | |||
1703 | if( &rIndex.GetNodes() == &aRg.aStart.GetNodes() && | |||
1704 | rIndex.GetIndex() >= aRg.aStart.GetIndex() && | |||
1705 | rIndex.GetIndex() < aRg.aEnd.GetIndex() ) | |||
1706 | return; | |||
1707 | ||||
1708 | SwNodeIndex aInsPos( rIndex ); | |||
1709 | SwNodeIndex aOrigInsPos( rIndex, -1 ); // original insertion position | |||
1710 | int nLevel = 0; // level counter | |||
1711 | ||||
1712 | for( long nNodeCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex(); | |||
1713 | nNodeCnt > 0; --nNodeCnt ) | |||
1714 | { | |||
1715 | pCurrentNode = &aRg.aStart.GetNode(); | |||
1716 | switch( pCurrentNode->GetNodeType() ) | |||
1717 | { | |||
1718 | case SwNodeType::Table: | |||
1719 | // Does it copy a table in(to) a footnote? | |||
1720 | if( aInsPos < rDoc.GetNodes().GetEndOfInserts().GetIndex() && | |||
1721 | rDoc.GetNodes().GetEndOfInserts().StartOfSectionIndex() | |||
1722 | < aInsPos.GetIndex() ) | |||
1723 | { | |||
1724 | const long nDistance = | |||
1725 | pCurrentNode->EndOfSectionIndex() - | |||
1726 | aRg.aStart.GetIndex(); | |||
1727 | if (nDistance < nNodeCnt) | |||
1728 | nNodeCnt -= nDistance; | |||
1729 | else | |||
1730 | nNodeCnt = 1; | |||
1731 | ||||
1732 | // insert a DummyNode for a TableNode | |||
1733 | if( bTableInsDummyNode ) | |||
1734 | new SwPlaceholderNode(aInsPos); | |||
1735 | ||||
1736 | // copy all of the table's nodes into the current cell | |||
1737 | for( ++aRg.aStart; aRg.aStart.GetIndex() < | |||
1738 | pCurrentNode->EndOfSectionIndex(); | |||
1739 | ++aRg.aStart ) | |||
1740 | { | |||
1741 | // insert a DummyNode for the box-StartNode? | |||
1742 | if( bTableInsDummyNode ) | |||
1743 | new SwPlaceholderNode(aInsPos); | |||
1744 | ||||
1745 | SwStartNode* pSttNd = aRg.aStart.GetNode().GetStartNode(); | |||
1746 | CopyNodes( SwNodeRange( *pSttNd, + 1, | |||
1747 | *pSttNd->EndOfSectionNode() ), | |||
1748 | aInsPos, bNewFrames ); | |||
1749 | ||||
1750 | // insert a DummyNode for the box-EndNode? | |||
1751 | if( bTableInsDummyNode ) | |||
1752 | new SwPlaceholderNode(aInsPos); | |||
1753 | aRg.aStart = *pSttNd->EndOfSectionNode(); | |||
1754 | } | |||
1755 | // insert a DummyNode for the table-EndNode | |||
1756 | if( bTableInsDummyNode ) | |||
1757 | new SwPlaceholderNode(aInsPos); | |||
1758 | aRg.aStart = *pCurrentNode->EndOfSectionNode(); | |||
1759 | } | |||
1760 | else | |||
1761 | { | |||
1762 | SwNodeIndex nStt( aInsPos, -1 ); | |||
1763 | SwTableNode* pTableNd = static_cast<SwTableNode*>(pCurrentNode)-> | |||
1764 | MakeCopy( rDoc, aInsPos ); | |||
1765 | const long nDistance = aInsPos.GetIndex() - nStt.GetIndex() - 2; | |||
1766 | if (nDistance < nNodeCnt) | |||
1767 | nNodeCnt -= nDistance; | |||
1768 | else | |||
1769 | nNodeCnt = 1 - nIsEndOfContent; | |||
1770 | ||||
1771 | aRg.aStart = pCurrentNode->EndOfSectionIndex(); | |||
1772 | ||||
1773 | if( bNewFrames && pTableNd ) | |||
1774 | { | |||
1775 | nStt = aInsPos; | |||
1776 | pTableNd->MakeOwnFrames(&nStt); | |||
1777 | } | |||
1778 | } | |||
1779 | break; | |||
1780 | ||||
1781 | case SwNodeType::Section: | |||
1782 | // If the end of the section is outside the copy range, | |||
1783 | // the section node will skipped, not copied! | |||
1784 | // If someone want to change this behaviour, he has to adjust the function | |||
1785 | // lcl_NonCopyCount(..) in ndcopy.cxx which relies on it. | |||
1786 | if( pCurrentNode->EndOfSectionIndex() < aRg.aEnd.GetIndex() ) | |||
1787 | { | |||
1788 | // copy of the whole section, so create a new SectionNode | |||
1789 | SwNodeIndex nStt( aInsPos, -1 ); | |||
1790 | SwSectionNode* pSectNd = static_cast<SwSectionNode*>(pCurrentNode)-> | |||
1791 | MakeCopy( rDoc, aInsPos ); | |||
1792 | ||||
1793 | const long nDistance = aInsPos.GetIndex() - nStt.GetIndex() - 2; | |||
1794 | if (nDistance < nNodeCnt) | |||
1795 | nNodeCnt -= nDistance; | |||
1796 | else | |||
1797 | nNodeCnt = 1 - nIsEndOfContent; | |||
1798 | aRg.aStart = pCurrentNode->EndOfSectionIndex(); | |||
1799 | ||||
1800 | if( bNewFrames && pSectNd && | |||
1801 | !pSectNd->GetSection().IsHidden() ) | |||
1802 | pSectNd->MakeOwnFrames(&nStt); | |||
1803 | } | |||
1804 | break; | |||
1805 | ||||
1806 | case SwNodeType::Start: | |||
1807 | { | |||
1808 | SwStartNode* pTmp = new SwStartNode( aInsPos, SwNodeType::Start, | |||
1809 | static_cast<SwStartNode*>(pCurrentNode)->GetStartNodeType() ); | |||
1810 | new SwEndNode( aInsPos, *pTmp ); | |||
1811 | --aInsPos; | |||
1812 | nLevel++; | |||
1813 | } | |||
1814 | break; | |||
1815 | ||||
1816 | case SwNodeType::End: | |||
1817 | if( nLevel ) // complete section | |||
1818 | { | |||
1819 | --nLevel; | |||
1820 | ++aInsPos; // EndNode already exists | |||
1821 | } | |||
1822 | else if( 1 == nNodeCnt && 1 == nIsEndOfContent ) | |||
1823 | // we have reached the EndOfContent node - nothing to do! | |||
1824 | continue; | |||
1825 | else if( !pCurrentNode->m_pStartOfSection->IsSectionNode() ) | |||
1826 | { | |||
1827 | // create a section at the original InsertPosition | |||
1828 | SwNodeRange aTmpRg( aOrigInsPos, 1, aInsPos ); | |||
1829 | rDoc.GetNodes().SectionDown( &aTmpRg, | |||
1830 | pCurrentNode->m_pStartOfSection->GetStartNodeType() ); | |||
1831 | } | |||
1832 | break; | |||
1833 | ||||
1834 | case SwNodeType::Text: | |||
1835 | case SwNodeType::Grf: | |||
1836 | case SwNodeType::Ole: | |||
1837 | { | |||
1838 | static_cast<SwContentNode*>(pCurrentNode)->MakeCopy( | |||
1839 | rDoc, aInsPos, bNewFrames); | |||
1840 | } | |||
1841 | break; | |||
1842 | ||||
1843 | case SwNodeType::PlaceHolder: | |||
1844 | if (GetDoc().GetIDocumentUndoRedo().IsUndoNodes(*this)) | |||
1845 | { | |||
1846 | // than a SectionNode (start/end) is needed at the current | |||
1847 | // InsPos; if so skip it, otherwise ignore current node | |||
1848 | SwNode *const pTmpNd = & aInsPos.GetNode(); | |||
1849 | if( pTmpNd->IsSectionNode() || | |||
1850 | pTmpNd->StartOfSectionNode()->IsSectionNode() ) | |||
1851 | ++aInsPos; // skip | |||
1852 | } | |||
1853 | else { | |||
1854 | assert(!"How can this node be in the node array?")(static_cast <bool> (!"How can this node be in the node array?" ) ? void (0) : __assert_fail ("!\"How can this node be in the node array?\"" , "/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" , 1854, __extension__ __PRETTY_FUNCTION__)); | |||
1855 | } | |||
1856 | break; | |||
1857 | ||||
1858 | default: | |||
1859 | assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail ( "false", "/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" , 1859, __extension__ __PRETTY_FUNCTION__)); | |||
1860 | } | |||
1861 | ++aRg.aStart; | |||
1862 | } | |||
1863 | } | |||
1864 | ||||
1865 | void SwNodes::DelDummyNodes( const SwNodeRange& rRg ) | |||
1866 | { | |||
1867 | SwNodeIndex aIdx( rRg.aStart ); | |||
1868 | while( aIdx.GetIndex() < rRg.aEnd.GetIndex() ) | |||
1869 | { | |||
1870 | if (SwNodeType::PlaceHolder == aIdx.GetNode().GetNodeType()) | |||
1871 | RemoveNode( aIdx.GetIndex(), 1, true ); | |||
1872 | else | |||
1873 | ++aIdx; | |||
1874 | } | |||
1875 | } | |||
1876 | ||||
1877 | SwStartNode* SwNodes::MakeEmptySection( const SwNodeIndex& rIdx, | |||
1878 | SwStartNodeType eSttNdTyp ) | |||
1879 | { | |||
1880 | SwStartNode* pSttNd = new SwStartNode( rIdx, SwNodeType::Start, eSttNdTyp ); | |||
1881 | new SwEndNode( rIdx, *pSttNd ); | |||
1882 | return pSttNd; | |||
1883 | } | |||
1884 | ||||
1885 | SwStartNode* SwNodes::MakeTextSection( const SwNodeIndex & rWhere, | |||
1886 | SwStartNodeType eSttNdTyp, | |||
1887 | SwTextFormatColl *pColl ) | |||
1888 | { | |||
1889 | SwStartNode* pSttNd = new SwStartNode( rWhere, SwNodeType::Start, eSttNdTyp ); | |||
1890 | new SwEndNode( rWhere, *pSttNd ); | |||
1891 | MakeTextNode( SwNodeIndex( rWhere, - 1 ), pColl ); | |||
1892 | return pSttNd; | |||
1893 | } | |||
1894 | ||||
1895 | //TODO: provide better documentation | |||
1896 | /** go to next section that is not protected nor hidden | |||
1897 | * | |||
1898 | * @note if !bSkipHidden and !bSkipProtect, use GoNext/GoPrevious | |||
1899 | * | |||
1900 | * @param pIdx | |||
1901 | * @param bSkipHidden | |||
1902 | * @param bSkipProtect | |||
1903 | * @return | |||
1904 | * @see SwNodes::GoNext | |||
1905 | * @see SwNodes::GoPrevious | |||
1906 | * @see SwNodes::GoNextSection (TODO: seems to be C&P programming here) | |||
1907 | */ | |||
1908 | SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx, | |||
1909 | bool bSkipHidden, bool bSkipProtect ) const | |||
1910 | { | |||
1911 | bool bFirst = true; | |||
1912 | SwNodeIndex aTmp( *pIdx ); | |||
1913 | const SwNode* pNd; | |||
1914 | while( aTmp < Count() - 1 ) | |||
1915 | { | |||
1916 | pNd = & aTmp.GetNode(); | |||
1917 | if (SwNodeType::Section == pNd->GetNodeType()) | |||
1918 | { | |||
1919 | const SwSection& rSect = static_cast<const SwSectionNode*>(pNd)->GetSection(); | |||
1920 | if( (bSkipHidden && rSect.IsHiddenFlag()) || | |||
1921 | (bSkipProtect && rSect.IsProtectFlag()) ) | |||
1922 | // than skip the section | |||
1923 | aTmp = *pNd->EndOfSectionNode(); | |||
1924 | } | |||
1925 | else if( bFirst ) | |||
1926 | { | |||
1927 | if( pNd->m_pStartOfSection->IsSectionNode() ) | |||
1928 | { | |||
1929 | const SwSection& rSect = static_cast<SwSectionNode*>(pNd-> | |||
1930 | m_pStartOfSection)->GetSection(); | |||
1931 | if( (bSkipHidden && rSect.IsHiddenFlag()) || | |||
1932 | (bSkipProtect && rSect.IsProtectFlag()) ) | |||
1933 | // than skip the section | |||
1934 | aTmp = *pNd->EndOfSectionNode(); | |||
1935 | } | |||
1936 | } | |||
1937 | else if( SwNodeType::ContentMask & pNd->GetNodeType() ) | |||
1938 | { | |||
1939 | const SwSectionNode* pSectNd; | |||
1940 | if( ( bSkipHidden || bSkipProtect ) && | |||
1941 | nullptr != (pSectNd = pNd->FindSectionNode() ) && | |||
1942 | ( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) || | |||
1943 | ( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) ) | |||
1944 | { | |||
1945 | aTmp = *pSectNd->EndOfSectionNode(); | |||
1946 | } | |||
1947 | else | |||
1948 | { | |||
1949 | (*pIdx) = aTmp; | |||
1950 | return const_cast<SwContentNode*>(static_cast<const SwContentNode*>(pNd)); | |||
1951 | } | |||
1952 | } | |||
1953 | ++aTmp; | |||
1954 | bFirst = false; | |||
1955 | } | |||
1956 | return nullptr; | |||
1957 | } | |||
1958 | ||||
1959 | ///@see SwNodes::GoNextSection (TODO: seems to be C&P programming here) | |||
1960 | SwContentNode* SwNodes::GoPrevSection( SwNodeIndex * pIdx, | |||
1961 | bool bSkipHidden, bool bSkipProtect ) | |||
1962 | { | |||
1963 | bool bFirst = true; | |||
1964 | SwNodeIndex aTmp( *pIdx ); | |||
1965 | const SwNode* pNd; | |||
1966 | while( aTmp > 0 ) | |||
1967 | { | |||
1968 | pNd = & aTmp.GetNode(); | |||
1969 | if (SwNodeType::End == pNd->GetNodeType()) | |||
1970 | { | |||
1971 | if( pNd->m_pStartOfSection->IsSectionNode() ) | |||
1972 | { | |||
1973 | const SwSection& rSect = static_cast<SwSectionNode*>(pNd-> | |||
1974 | m_pStartOfSection)->GetSection(); | |||
1975 | if( (bSkipHidden && rSect.IsHiddenFlag()) || | |||
1976 | (bSkipProtect && rSect.IsProtectFlag()) ) | |||
1977 | // than skip section | |||
1978 | aTmp = *pNd->StartOfSectionNode(); | |||
1979 | } | |||
1980 | bFirst = false; | |||
1981 | } | |||
1982 | else if( bFirst ) | |||
1983 | { | |||
1984 | bFirst = false; | |||
1985 | if( pNd->m_pStartOfSection->IsSectionNode() ) | |||
1986 | { | |||
1987 | const SwSection& rSect = static_cast<SwSectionNode*>(pNd-> | |||
1988 | m_pStartOfSection)->GetSection(); | |||
1989 | if( (bSkipHidden && rSect.IsHiddenFlag()) || | |||
1990 | (bSkipProtect && rSect.IsProtectFlag()) ) | |||
1991 | // than skip section | |||
1992 | aTmp = *pNd->StartOfSectionNode(); | |||
1993 | } | |||
1994 | } | |||
1995 | else if( SwNodeType::ContentMask & pNd->GetNodeType() ) | |||
1996 | { | |||
1997 | const SwSectionNode* pSectNd; | |||
1998 | if( ( bSkipHidden || bSkipProtect ) && | |||
1999 | nullptr != (pSectNd = pNd->FindSectionNode() ) && | |||
2000 | ( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) || | |||
2001 | ( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) ) | |||
2002 | { | |||
2003 | aTmp = *pSectNd; | |||
2004 | } | |||
2005 | else | |||
2006 | { | |||
2007 | (*pIdx) = aTmp; | |||
2008 | return const_cast<SwContentNode*>(static_cast<const SwContentNode*>(pNd)); | |||
2009 | } | |||
2010 | } | |||
2011 | --aTmp; | |||
2012 | } | |||
2013 | return nullptr; | |||
2014 | } | |||
2015 | ||||
2016 | //TODO: improve documentation | |||
2017 | //TODO: The inventor of the "single responsibility principle" will be crying if you ever show this code to him! | |||
2018 | /** find the next/previous ContentNode or a table node with frames | |||
2019 | * | |||
2020 | * If no pEnd is given, search is started with FrameIndex; otherwise | |||
2021 | * search is started with the one before rFrameIdx and after pEnd. | |||
2022 | * | |||
2023 | * @param rFrameIdx node with frames to search in | |||
2024 | * @param pEnd ??? | |||
2025 | * @return result node; 0 (!!!) if not found | |||
2026 | */ | |||
2027 | SwNode* SwNodes::FindPrvNxtFrameNode( SwNodeIndex& rFrameIdx, | |||
2028 | const SwNode* pEnd ) const | |||
2029 | { | |||
2030 | SwNode* pFrameNd = nullptr; | |||
2031 | ||||
2032 | // no layout -> skip | |||
2033 | if( GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell() ) | |||
2034 | { | |||
2035 | SwNode* pSttNd = &rFrameIdx.GetNode(); | |||
2036 | ||||
2037 | // move of a hidden section? | |||
2038 | SwSectionNode* pSectNd = pSttNd->IsSectionNode() | |||
2039 | ? pSttNd->StartOfSectionNode()->FindSectionNode() | |||
2040 | : pSttNd->FindSectionNode(); | |||
2041 | if( !( pSectNd && pSectNd->GetSection().CalcHiddenFlag() ) ) | |||
2042 | { | |||
2043 | // in a table in table situation we have to assure that we don't leave the | |||
2044 | // outer table cell when the inner table is looking for a PrvNxt... | |||
2045 | SwTableNode* pTableNd = pSttNd->IsTableNode() | |||
2046 | ? pSttNd->StartOfSectionNode()->FindTableNode() | |||
2047 | : pSttNd->FindTableNode(); | |||
2048 | SwNodeIndex aIdx( rFrameIdx ); | |||
2049 | SwNode* pNd; | |||
2050 | if( pEnd ) | |||
2051 | { | |||
2052 | --aIdx; | |||
2053 | pNd = &aIdx.GetNode(); | |||
2054 | } | |||
2055 | else | |||
2056 | pNd = pSttNd; | |||
2057 | ||||
2058 | if( ( pFrameNd = pNd )->IsContentNode() ) | |||
2059 | rFrameIdx = aIdx; | |||
2060 | ||||
2061 | // search forward or backward for a content node | |||
2062 | else if( nullptr != ( pFrameNd = GoPrevSection( &aIdx, true, false )) && | |||
2063 | ::CheckNodesRange( aIdx, rFrameIdx, true ) && | |||
2064 | // Never out of the table at the start | |||
2065 | pFrameNd->FindTableNode() == pTableNd && | |||
2066 | // Bug 37652: Never out of the table at the end | |||
2067 | (!pFrameNd->FindTableNode() || pFrameNd->FindTableBoxStartNode() | |||
2068 | == pSttNd->FindTableBoxStartNode() ) && | |||
2069 | (!pSectNd || pSttNd->IsSectionNode() || | |||
2070 | pSectNd->GetIndex() < pFrameNd->GetIndex()) | |||
2071 | ) | |||
2072 | { | |||
2073 | rFrameIdx = aIdx; | |||
2074 | } | |||
2075 | else | |||
2076 | { | |||
2077 | if( pEnd ) | |||
2078 | aIdx = pEnd->GetIndex() + 1; | |||
2079 | else | |||
2080 | aIdx = rFrameIdx; | |||
2081 | ||||
2082 | // NEVER leave the section when doing this! | |||
2083 | if( ( pEnd && ( pFrameNd = &aIdx.GetNode())->IsContentNode() ) || | |||
2084 | ( nullptr != ( pFrameNd = GoNextSection( &aIdx, true, false )) && | |||
2085 | ::CheckNodesRange( aIdx, rFrameIdx, true ) && | |||
2086 | ( pFrameNd->FindTableNode() == pTableNd && | |||
2087 | // NEVER go out of the table cell at the end | |||
2088 | (!pFrameNd->FindTableNode() || pFrameNd->FindTableBoxStartNode() | |||
2089 | == pSttNd->FindTableBoxStartNode() ) ) && | |||
2090 | (!pSectNd || pSttNd->IsSectionNode() || | |||
2091 | pSectNd->EndOfSectionIndex() > pFrameNd->GetIndex()) | |||
2092 | )) | |||
2093 | { | |||
2094 | // Undo when merging a table with one before, if there is also one after it. | |||
2095 | // However, if the node is in a table, it needs to be returned if the | |||
2096 | // SttNode is a section or a table! | |||
2097 | SwTableNode* pTableNode; | |||
2098 | if (pSttNd->IsTableNode() && | |||
2099 | nullptr != (pTableNode = pFrameNd->FindTableNode()) && | |||
2100 | // TABLE IN TABLE: | |||
2101 | pTableNode != pSttNd->StartOfSectionNode()->FindTableNode()) | |||
2102 | { | |||
2103 | pFrameNd = pTableNode; | |||
2104 | rFrameIdx = *pFrameNd; | |||
2105 | } | |||
2106 | else | |||
2107 | rFrameIdx = aIdx; | |||
2108 | } | |||
2109 | else if( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() ) | |||
2110 | { | |||
2111 | pFrameNd = pNd->StartOfSectionNode(); | |||
2112 | rFrameIdx = *pFrameNd; | |||
2113 | } | |||
2114 | else | |||
2115 | { | |||
2116 | if( pEnd ) | |||
2117 | aIdx = pEnd->GetIndex() + 1; | |||
2118 | else | |||
2119 | aIdx = rFrameIdx.GetIndex() + 1; | |||
2120 | ||||
2121 | if( (pFrameNd = &aIdx.GetNode())->IsTableNode() ) | |||
2122 | rFrameIdx = aIdx; | |||
2123 | else | |||
2124 | { | |||
2125 | pFrameNd = nullptr; | |||
2126 | ||||
2127 | // is there some sectionnodes before a tablenode? | |||
2128 | while( aIdx.GetNode().IsSectionNode() ) | |||
2129 | { | |||
2130 | const SwSection& rSect = aIdx.GetNode(). | |||
2131 | GetSectionNode()->GetSection(); | |||
2132 | if( rSect.IsHiddenFlag() ) | |||
2133 | aIdx = aIdx.GetNode().EndOfSectionIndex()+1; | |||
2134 | else | |||
2135 | ++aIdx; | |||
2136 | } | |||
2137 | if( aIdx.GetNode().IsTableNode() ) | |||
2138 | { | |||
2139 | rFrameIdx = aIdx; | |||
2140 | pFrameNd = &aIdx.GetNode(); | |||
2141 | } | |||
2142 | } | |||
2143 | } | |||
2144 | } | |||
2145 | } | |||
2146 | } | |||
2147 | return pFrameNd; | |||
2148 | } | |||
2149 | ||||
2150 | void SwNodes::ForEach( sal_uLong nStart, sal_uLong nEnd, | |||
2151 | FnForEach_SwNodes fn, void* pArgs ) | |||
2152 | { | |||
2153 | if( nEnd > m_nSize ) | |||
2154 | nEnd = m_nSize; | |||
2155 | ||||
2156 | if( nStart >= nEnd ) | |||
2157 | return; | |||
2158 | ||||
2159 | sal_uInt16 cur = Index2Block( nStart ); | |||
2160 | BlockInfo** pp = m_ppInf.get() + cur; | |||
2161 | BlockInfo* p = *pp; | |||
2162 | sal_uInt16 nElem = sal_uInt16( nStart - p->nStart ); | |||
2163 | auto pElem = p->mvData.begin() + nElem; | |||
2164 | nElem = p->nElem - nElem; | |||
2165 | for(;;) | |||
2166 | { | |||
2167 | if( !(*fn)( static_cast<SwNode *>(*pElem++), pArgs ) || ++nStart >= nEnd ) | |||
2168 | break; | |||
2169 | ||||
2170 | // next element | |||
2171 | if( !--nElem ) | |||
2172 | { | |||
2173 | // new block | |||
2174 | p = *++pp; | |||
2175 | pElem = p->mvData.begin(); | |||
2176 | nElem = p->nElem; | |||
2177 | } | |||
2178 | } | |||
2179 | } | |||
2180 | ||||
2181 | void SwNodes::ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd, | |||
2182 | FnForEach_SwNodes fnForEach, void* pArgs ) | |||
2183 | { | |||
2184 | ForEach( rStart.GetIndex(), rEnd.GetIndex(), fnForEach, pArgs ); | |||
2185 | } | |||
2186 | ||||
2187 | void SwNodes::RemoveNode( sal_uLong nDelPos, sal_uLong nSz, bool bDel ) | |||
2188 | { | |||
2189 | #ifndef NDEBUG | |||
2190 | SwNode *const pFirst((*this)[nDelPos]); | |||
2191 | #endif | |||
2192 | for (sal_uLong nCnt = 0; nCnt < nSz; nCnt++) | |||
2193 | { | |||
2194 | SwNode* pNode = (*this)[ nDelPos + nCnt ]; | |||
2195 | SwTextNode * pTextNd = pNode->GetTextNode(); | |||
2196 | ||||
2197 | if (pTextNd) | |||
2198 | { | |||
2199 | pTextNd->RemoveFromList(); | |||
2200 | // remove RndStdIds::FLY_AS_CHAR *before* adjusting SwNodeIndex | |||
2201 | // so their anchor still points to correct node when deleted! | |||
2202 | // NOTE: this will call RemoveNode() recursively! | |||
2203 | // so adjust our indexes to account for removed nodes | |||
2204 | sal_uLong const nPos = pTextNd->GetIndex(); | |||
2205 | SwpHints *const pHints(pTextNd->GetpSwpHints()); | |||
2206 | if (pHints) | |||
2207 | { | |||
2208 | std::vector<SwTextAttr*> flys; | |||
2209 | for (size_t i = 0; i < pHints->Count(); ++i) | |||
2210 | { | |||
2211 | SwTextAttr *const pHint(pHints->Get(i)); | |||
2212 | if (RES_TXTATR_FLYCNT == pHint->Which()) | |||
2213 | { | |||
2214 | flys.push_back(pHint); | |||
2215 | } | |||
2216 | } | |||
2217 | for (SwTextAttr * pHint : flys) | |||
2218 | { | |||
2219 | pTextNd->DeleteAttribute(pHint); | |||
2220 | } // pHints may be dead now | |||
2221 | sal_uLong const nDiff = nPos - pTextNd->GetIndex(); | |||
2222 | if (nDiff) | |||
2223 | { | |||
2224 | nDelPos -= nDiff; | |||
2225 | } | |||
2226 | assert(pTextNd == (*this)[nDelPos + nCnt])(static_cast <bool> (pTextNd == (*this)[nDelPos + nCnt] ) ? void (0) : __assert_fail ("pTextNd == (*this)[nDelPos + nCnt]" , "/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" , 2226, __extension__ __PRETTY_FUNCTION__)); | |||
2227 | assert(pFirst == (*this)[nDelPos])(static_cast <bool> (pFirst == (*this)[nDelPos]) ? void (0) : __assert_fail ("pFirst == (*this)[nDelPos]", "/home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx" , 2227, __extension__ __PRETTY_FUNCTION__)); | |||
2228 | } | |||
2229 | } | |||
2230 | SwTableNode* pTableNode = pNode->GetTableNode(); | |||
2231 | if (pTableNode) | |||
2232 | { | |||
2233 | // The node that is deleted is a table node. | |||
2234 | // Need to make sure that all the redlines that are | |||
2235 | // related to this table are removed from the | |||
2236 | // 'Extra Redlines' array | |||
2237 | pTableNode->RemoveRedlines(); | |||
2238 | } | |||
2239 | } | |||
2240 | ||||
2241 | sal_uLong nEnd = nDelPos + nSz; | |||
2242 | SwNode* pNew = (*this)[ nEnd ]; | |||
2243 | ||||
2244 | for (SwNodeIndex& rIndex : m_vIndices->GetRingContainer()) | |||
2245 | { | |||
2246 | sal_uLong const nIdx = rIndex.GetIndex(); | |||
2247 | if (nDelPos <= nIdx && nIdx < nEnd) | |||
2248 | rIndex = *pNew; | |||
2249 | } | |||
2250 | ||||
2251 | std::vector<BigPtrEntry> aTempEntries; | |||
2252 | if( bDel ) | |||
2253 | { | |||
2254 | sal_uLong nCnt = nSz; | |||
2255 | BigPtrEntry *pDel = (*this)[ nDelPos+nCnt-1 ], *pPrev = (*this)[ nDelPos+nCnt-2 ]; | |||
2256 | ||||
2257 | // set temporary object | |||
2258 | // JP 24.08.98: this should actually be removed because one could | |||
2259 | // call Remove recursively, e.g. for character bound frames. However, | |||
2260 | // since there happens way too much here, this temporary object was | |||
2261 | // inserted that will be deleted in Remove again (see Bug 55406) | |||
2262 | aTempEntries.resize(nCnt); | |||
2263 | ||||
2264 | while( nCnt-- ) | |||
2265 | { | |||
2266 | delete pDel; | |||
2267 | pDel = pPrev; | |||
2268 | sal_uLong nPrevNdIdx = pPrev->GetPos(); | |||
2269 | BigPtrEntry* pTempEntry = &aTempEntries[nCnt]; | |||
2270 | BigPtrArray::Replace( nPrevNdIdx+1, pTempEntry ); | |||
2271 | if( nCnt ) | |||
2272 | pPrev = BigPtrArray::operator []( nPrevNdIdx - 1 ); | |||
2273 | // the accessed element can be a naked BigPtrEntry from | |||
2274 | // aTempEntries, so the downcast to SwNode* in | |||
2275 | // SwNodes::operator[] would be illegal (and unnecessary) | |||
2276 | } | |||
2277 | nDelPos = pDel->GetPos() + 1; | |||
2278 | } | |||
2279 | ||||
2280 | BigPtrArray::Remove( nDelPos, nSz ); | |||
2281 | } | |||
2282 | ||||
2283 | void SwNodes::InsertNode( const SwNodePtr pNode, | |||
2284 | const SwNodeIndex& rPos ) | |||
2285 | { | |||
2286 | BigPtrEntry* pIns = pNode; | |||
2287 | BigPtrArray::Insert( pIns, rPos.GetIndex() ); | |||
2288 | } | |||
2289 | ||||
2290 | void SwNodes::InsertNode( const SwNodePtr pNode, | |||
2291 | sal_uLong nPos ) | |||
2292 | { | |||
2293 | BigPtrEntry* pIns = pNode; | |||
2294 | BigPtrArray::Insert( pIns, nPos ); | |||
2295 | } | |||
2296 | ||||
2297 | // ->#112139# | |||
2298 | SwNode * SwNodes::DocumentSectionStartNode(SwNode * pNode) const | |||
2299 | { | |||
2300 | if (nullptr != pNode) | |||
2301 | { | |||
2302 | SwNodeIndex aIdx(*pNode); | |||
2303 | ||||
2304 | if (aIdx <= (*this)[0]->EndOfSectionIndex()) | |||
2305 | pNode = (*this)[0]; | |||
2306 | else | |||
2307 | { | |||
2308 | while ((*this)[0] != pNode->StartOfSectionNode()) | |||
2309 | pNode = pNode->StartOfSectionNode(); | |||
2310 | } | |||
2311 | } | |||
2312 | ||||
2313 | return pNode; | |||
2314 | } | |||
2315 | ||||
2316 | SwNode * SwNodes::DocumentSectionEndNode(SwNode * pNode) const | |||
2317 | { | |||
2318 | return DocumentSectionStartNode(pNode)->EndOfSectionNode(); | |||
2319 | } | |||
2320 | ||||
2321 | bool SwNodes::IsDocNodes() const | |||
2322 | { | |||
2323 | return this == &m_rMyDoc.GetNodes(); | |||
2324 | } | |||
2325 | ||||
2326 | void SwNodes::dumpAsXml(xmlTextWriterPtr pWriter) const | |||
2327 | { | |||
2328 | xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("SwNodes")); | |||
2329 | for (sal_uLong i = 0; i < Count(); ++i) | |||
2330 | (*this)[i]->dumpAsXml(pWriter); | |||
2331 | xmlTextWriterEndElement(pWriter); | |||
2332 | } | |||
2333 | ||||
2334 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |