Bug Summary

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'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name nodes.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/docnode/nodes.cxx
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
47typedef std::vector<SwStartNode*> SwStartNodePointers;
48
49// function to determine the highest level in the given range
50static 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 */
58SwNodes::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 */
91SwNodes::~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
112void 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 */
394bool 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()
1
Assuming the condition is false
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 )
2
Taking false branch
423 return false;
424
425 if( this == &rNodes )
3
Assuming the condition is false
4
Taking false branch
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 )
5
Loop condition is true. Entering loop body
13
Loop condition is true. Entering loop body
453 {
454 pCurrentNode = &aRg.aEnd.GetNode();
455 switch( pCurrentNode->GetNodeType() )
6
Control jumps to 'case PlaceHolder:' at line 812
14
Control jumps to 'case End:' at line 457
456 {
457 case SwNodeType::End:
458 {
459 if( nInsPos
14.1
'nInsPos' is 0
) // move everything until here
15
Taking false branch
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() )
16
Taking false branch
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() )
17
Assuming the condition is false
18
Taking false branch
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 )
19
Assuming the condition is false
20
Taking false branch
632 --aRg.aStart;
633
634 SwSectionNode* pSctNd = pSttNd->GetSectionNode();
635 if( bNewFrames && pSctNd )
21
Assuming 'bNewFrames' is false
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 );
22
Memory is allocated
648 pTmpSttNd->m_pStartOfSection = pSttNd->m_pStartOfSection;
649
650 RemoveNode( nSttPos, 1, false ); // delete SttNode
23
Potential leak of memory pointed to by 'pTmpSttNd'
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))
7
Assuming the condition is true
8
Taking true branch
814 {
815 if( &rNodes == this ) // inside UndoNodesArray
9
Taking false branch
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
9.1
'nInsPos' is 0
) // move everything until here
10
Taking false branch
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() ||
11
Taking false branch
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;
12
Execution continues on line 452
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 */
900void 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 */
954void 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 */
1025void 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 */
1073void 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 */
1253sal_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
1261void 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
1279void SwNodes::GoEndOfSection(SwNodeIndex *pIdx)
1280{
1281 if( !pIdx->GetNode().IsEndNode() )
1282 (*pIdx) = *pIdx->GetNode().EndOfSectionNode();
1283}
1284
1285SwContentNode* 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
1302SwContentNode* 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 */
1324void 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
1381namespace {
1382
1383struct HighLevel
1384{
1385 sal_uInt16 nLevel, nTop;
1386 explicit HighLevel( sal_uInt16 nLv ) : nLevel( nLv ), nTop( nLv ) {}
1387};
1388
1389}
1390
1391static 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 */
1410sal_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 */
1424void 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)
1652void 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
1865void 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
1877SwStartNode* 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
1885SwStartNode* 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*/
1908SwContentNode* 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)
1960SwContentNode* 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 */
2027SwNode* 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
2150void 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
2181void 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
2187void 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
2283void SwNodes::InsertNode( const SwNodePtr pNode,
2284 const SwNodeIndex& rPos )
2285{
2286 BigPtrEntry* pIns = pNode;
2287 BigPtrArray::Insert( pIns, rPos.GetIndex() );
2288}
2289
2290void SwNodes::InsertNode( const SwNodePtr pNode,
2291 sal_uLong nPos )
2292{
2293 BigPtrEntry* pIns = pNode;
2294 BigPtrArray::Insert( pIns, nPos );
2295}
2296
2297// ->#112139#
2298SwNode * 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
2316SwNode * SwNodes::DocumentSectionEndNode(SwNode * pNode) const
2317{
2318 return DocumentSectionStartNode(pNode)->EndOfSectionNode();
2319}
2320
2321bool SwNodes::IsDocNodes() const
2322{
2323 return this == &m_rMyDoc.GetNodes();
2324}
2325
2326void 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: */