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