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