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