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