xref: /trunk/main/sw/source/core/docnode/nodes.cxx (revision 69a74367)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 #include <stdlib.h>
28 
29 #include <node.hxx>
30 #include <doc.hxx>
31 #include <IDocumentUndoRedo.hxx>
32 #include <pam.hxx>
33 #include <txtfld.hxx>
34 #include <fmtfld.hxx>
35 #include <hints.hxx>
36 #include <numrule.hxx>
37 #include <ndtxt.hxx>
38 #include <ndnotxt.hxx>
39 #include <swtable.hxx>      // fuer erzuegen / loeschen der Table-Frames
40 #include <tblsel.hxx>
41 #include <section.hxx>
42 #include <ddefld.hxx>
43 #include <swddetbl.hxx>
44 #include <frame.hxx>
45 #include <txtatr.hxx>
46 #include <tox.hxx> // InvalidateTOXMark
47 
48 #include <docsh.hxx>
49 #include <svl/smplhint.hxx>
50 
51 extern sal_Bool CheckNodesRange( const SwNodeIndex& rStt,
52 							const SwNodeIndex& rEnd, sal_Bool bChkSection );
53 
54 SV_DECL_PTRARR(SwSttNdPtrs,SwStartNode*,2,2)
55 
56 
57 //#define JP_DEBUG
58 #ifdef JP_DEBUG
59 #include "shellio.hxx"
60 #endif
61 
62 
63 // Funktion zum bestimmen des hoechsten Levels innerhalb des Bereiches
64 
65 sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange );
66 
67 //-----------------------------------------------------------------------
68 
69 /*******************************************************************
70 |*	SwNodes::SwNodes
71 |*
72 |*	Beschreibung
73 |*		Konstruktor; legt die vier Grundsektions (PostIts,
74 |*		Inserts, Icons, Inhalt) an
75 *******************************************************************/
76 SwNodes::SwNodes( SwDoc* pDocument )
77 	: pRoot( 0 ), pMyDoc( pDocument )
78 {
79 	bInNodesDel = bInDelUpdOutl = bInDelUpdNum = sal_False;
80 
81 	ASSERT( pMyDoc, "in welchem Doc stehe ich denn?" );
82 
83 	sal_uLong nPos = 0;
84 	SwStartNode* pSttNd = new SwStartNode( *this, nPos++ );
85 	pEndOfPostIts = new SwEndNode( *this, nPos++, *pSttNd );
86 
87 	SwStartNode* pTmp = new SwStartNode( *this, nPos++ );
88 	pEndOfInserts = new SwEndNode( *this, nPos++, *pTmp );
89 
90 	pTmp = new SwStartNode( *this, nPos++ );
91 	pTmp->pStartOfSection = pSttNd;
92 	pEndOfAutotext = new SwEndNode( *this, nPos++, *pTmp );
93 
94 	pTmp = new SwStartNode( *this, nPos++ );
95 	pTmp->pStartOfSection = pSttNd;
96 	pEndOfRedlines = new SwEndNode( *this, nPos++, *pTmp );
97 
98 	pTmp = new SwStartNode( *this, nPos++ );
99 	pTmp->pStartOfSection = pSttNd;
100 	pEndOfContent = new SwEndNode( *this, nPos++, *pTmp );
101 
102 	pOutlineNds = new SwOutlineNodes;
103 }
104 
105 /*******************************************************************
106 |*
107 |*	SwNodes::~SwNodes
108 |*
109 |*	Beschreibung
110 |*		dtor, loescht alle Nodes, deren Pointer in diesem dynamischen
111 |*		Array sind. Ist kein Problem, da Nodes ausserhalb dieses
112 |*		Arrays nicht erzeugt werden koennen und somit auch nicht
113 |*		in mehreren drin sein koennen
114 |*
115 |*	Ersterstellung
116 |*		VER0100 vb 901214
117 |*
118 |*	Stand
119 |*		VER0100 vb 901214
120 |*
121 *******************************************************************/
122 
123 SwNodes::~SwNodes()
124 {
125 	delete pOutlineNds;
126 
127 	{
128 		SwNode *pNode;
129 		SwNodeIndex aNdIdx( *this );
130 		while( sal_True )
131 		{
132 			pNode = &aNdIdx.GetNode();
133 			if( pNode == pEndOfContent )
134 				break;
135 
136 			aNdIdx++;
137 			delete pNode;
138 		}
139 	}
140 
141 	// jetzt muessen alle SwNodeIndizies abgemeldet sein!!!
142 	delete pEndOfContent;
143 }
144 
145 void SwNodes::ChgNode( SwNodeIndex& rDelPos, sal_uLong nSz,
146 						SwNodeIndex& rInsPos, sal_Bool bNewFrms )
147 {
148 	// im UndoBereich brauchen wir keine Frames
149 	SwNodes& rNds = rInsPos.GetNodes();
150 	const SwNode* pPrevInsNd = rNds[ rInsPos.GetIndex() -1 ];
151 
152 	//JP 03.02.99: alle Felder als invalide erklaeren, aktu. erfolgt im
153 	//				Idle-Handler des Docs
154 	if( GetDoc()->SetFieldsDirty( sal_True, &rDelPos.GetNode(), nSz ) &&
155 		rNds.GetDoc() != GetDoc() )
156 		rNds.GetDoc()->SetFieldsDirty( true, NULL, 0 );
157 
158 	//JP 12.03.99: 63293 - Nodes vom RedlineBereich NIE aufnehmen
159 	sal_uLong nNd = rInsPos.GetIndex();
160 	sal_Bool bInsOutlineIdx = !(
161             rNds.GetEndOfRedlines().StartOfSectionNode()->GetIndex() < nNd &&
162 			nNd < rNds.GetEndOfRedlines().GetIndex() );
163 
164 	if( &rNds == this ) 		// im gleichen Nodes-Array -> moven !!
165 	{
166 		// wird von vorne nach hinten gemovt, so wird nach vorne immer
167 		// nachgeschoben, d.H. die Loeschposition ist immer gleich
168 		sal_uInt16 nDiff = rDelPos.GetIndex() < rInsPos.GetIndex() ? 0 : 1;
169 
170 		for( sal_uLong n = rDelPos.GetIndex(); nSz; n += nDiff, --nSz )
171 		{
172 			SwNodeIndex aDelIdx( *this, n );
173 			SwNode& rNd = aDelIdx.GetNode();
174 
175             // --> OD 2005-11-16 #i57920#
176             // correction of refactoring done by cws swnumtree:
177             // - <SwTxtNode::SetLevel( NO_NUMBERING ) is deprecated and
178             //   set <IsCounted> state of the text node to <false>, which
179             //   isn't correct here.
180             if ( rNd.IsTxtNode() )
181             {
182                 SwTxtNode* pTxtNode = rNd.GetTxtNode();
183                 pTxtNode->RemoveFromList();
184 
185                 //if ( pTxtNode->GetTxtColl()->GetOutlineLevel() != NO_NUMBERING )//#outline level,zhaojianwei
186                 if ( pTxtNode->GetAttrOutlineLevel() != 0 )//<-end,zhaojianwei
187                 {
188                     const SwNodePtr pSrch = (SwNodePtr)&rNd;
189                     pOutlineNds->Remove( pSrch );
190                 }
191             }
192             // <--
193 
194             BigPtrArray::Move( aDelIdx.GetIndex(), rInsPos.GetIndex() );
195 
196             if( rNd.IsTxtNode() )
197             {
198                 SwTxtNode& rTxtNd = (SwTxtNode&)rNd;
199                 rTxtNd.AddToList();
200 
201                 if( bInsOutlineIdx &&
202                     //NO_NUMBERING != rTxtNd.GetTxtColl()->GetOutlineLevel() )//#outline level,zhaojianwei
203                     0 != rTxtNd.GetAttrOutlineLevel() )//<-end,zhaojianwei
204                 {
205                     const SwNodePtr pSrch = (SwNodePtr)&rNd;
206                     pOutlineNds->Insert( pSrch );
207                 }
208                 rTxtNd.InvalidateNumRule();
209 
210 //FEATURE::CONDCOLL
211 				if( RES_CONDTXTFMTCOLL == rTxtNd.GetTxtColl()->Which() )
212 					rTxtNd.ChkCondColl();
213 //FEATURE::CONDCOLL
214 			}
215 			else if( rNd.IsCntntNode() )
216 				((SwCntntNode&)rNd).InvalidateNumRule();
217 		}
218 	}
219 	else
220 	{
221         bool bSavePersData(GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNds));
222         bool bRestPersData(GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this));
223 		SwDoc* pDestDoc = rNds.GetDoc() != GetDoc() ? rNds.GetDoc() : 0;
224         OSL_ENSURE(!pDestDoc, "SwNodes::ChgNode(): "
225             "the code to handle text fields here looks broken\n"
226             "if the target is in a different document.");
227 		if( !bRestPersData && !bSavePersData && pDestDoc )
228 			bSavePersData = bRestPersData = sal_True;
229 
230 		String sNumRule;
231 		SwNodeIndex aInsPos( rInsPos );
232 		for( sal_uLong n = 0; n < nSz; n++ )
233 		{
234 			SwNode* pNd = &rDelPos.GetNode();
235 
236 			// NoTextNode muessen ihre Persitenten Daten mitnehmen
237 			if( pNd->IsNoTxtNode() )
238 			{
239 				if( bSavePersData )
240 					((SwNoTxtNode*)pNd)->SavePersistentData();
241 			}
242 			else if( pNd->IsTxtNode() )
243 			{
244 				SwTxtNode* pTxtNd = (SwTxtNode*)pNd;
245 
246 				// loesche die Gliederungs-Indizies aus dem alten Nodes-Array
247 				//if( NO_NUMBERING != pTxtNd->GetTxtColl()->GetOutlineLevel() )//#outline level,zhaojianwei
248 				if( 0 != pTxtNd->GetAttrOutlineLevel() )//<-end,zhaojianwei
249 					pOutlineNds->Remove( pNd );
250 
251 				// muss die Rule kopiere werden?
252 				if( pDestDoc )
253 				{
254 					const SwNumRule* pNumRule = pTxtNd->GetNumRule();
255 					if( pNumRule && sNumRule != pNumRule->GetName() )
256 					{
257 						sNumRule = pNumRule->GetName();
258 						SwNumRule* pDestRule = pDestDoc->FindNumRulePtr( sNumRule );
259 						if( pDestRule )
260 							pDestRule->SetInvalidRule( sal_True );
261 						else
262 							pDestDoc->MakeNumRule( sNumRule, pNumRule );
263 					}
264 				}
265 				else
266 					// wenns ins UndoNodes-Array gemoved wird, sollten die
267 					// Numerierungen auch aktualisiert werden.
268 					pTxtNd->InvalidateNumRule();
269 
270                 pTxtNd->RemoveFromList();
271             }
272 
273 			RemoveNode( rDelPos.GetIndex(), 1, sal_False );		// Indizies verschieben !!
274 			SwCntntNode * pCNd = pNd->GetCntntNode();
275             rNds.InsertNode( pNd, aInsPos );
276 
277 			if( pCNd )
278 			{
279 				SwTxtNode* pTxtNd = pCNd->GetTxtNode();
280 				if( pTxtNd )
281                 {
282                     SwpHints * const pHts = pTxtNd->GetpSwpHints();
283 					// setze die OultineNodes im neuen Nodes-Array
284 					//if( bInsOutlineIdx && NO_NUMBERING !=	//#outline level,removed by zhaojianwei
285 					//	pTxtNd->GetTxtColl()->GetOutlineLevel() )
286                     if( bInsOutlineIdx &&
287                         0 != pTxtNd->GetAttrOutlineLevel() ) //#outline level,added by zhaojianwei
288                     {
289 						rNds.pOutlineNds->Insert( pTxtNd );
290                     }
291 
292                     pTxtNd->AddToList();
293 
294 					// Sonderbehandlung fuer die Felder!
295 					if( pHts && pHts->Count() )
296                     {
297                         // this looks fishy if pDestDoc != 0
298                         bool const bToUndo = !pDestDoc &&
299                             GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNds);
300 						for( sal_uInt16 i = pHts->Count(); i; )
301 						{
302 							sal_uInt16 nDelMsg = 0;
303                             SwTxtAttr * const pAttr = pHts->GetTextHint( --i );
304                             switch ( pAttr->Which() )
305                             {
306                             case RES_TXTATR_FIELD:
307                             case RES_TXTATR_INPUTFIELD:
308                                 {
309                                     SwTxtFld* pTxtFld = static_cast<SwTxtFld*>(pAttr);
310                                     rNds.GetDoc()->InsDelFldInFldLst( !bToUndo, *pTxtFld );
311 
312                                     const SwFieldType* pTyp = pTxtFld->GetFmtFld().GetField()->GetTyp();
313                                     if ( RES_POSTITFLD == pTyp->Which() )
314                                     {
315                                         rNds.GetDoc()->GetDocShell()->Broadcast(
316                                             SwFmtFldHint(
317                                                 &pTxtFld->GetFmtFld(),
318                                                 ( pTxtFld->GetFmtFld().IsFldInDoc()
319                                                   ? SWFMTFLD_INSERTED
320                                                   : SWFMTFLD_REMOVED ) ) );
321 									}
322 									else
323 									if( RES_DDEFLD == pTyp->Which() )
324 									{
325 										if( bToUndo )
326 											((SwDDEFieldType*)pTyp)->DecRefCnt();
327 										else
328 											((SwDDEFieldType*)pTyp)->IncRefCnt();
329 									}
330 									nDelMsg = RES_FIELD_DELETED;
331 								}
332 								break;
333 							case RES_TXTATR_FTN:
334 								nDelMsg = RES_FOOTNOTE_DELETED;
335 								break;
336 
337 							case RES_TXTATR_TOXMARK:
338                                 static_cast<SwTOXMark&>(pAttr->GetAttr())
339                                     .InvalidateTOXMark();
340 								break;
341 
342 							case RES_TXTATR_REFMARK:
343 								nDelMsg = RES_REFMARK_DELETED;
344 								break;
345 
346                             case RES_TXTATR_META:
347                             case RES_TXTATR_METAFIELD:
348                                 {
349                                     SwTxtMeta *const pTxtMeta(
350                                         static_cast<SwTxtMeta*>(pAttr));
351                                     // force removal of UNO object
352                                     pTxtMeta->ChgTxtNode(0);
353                                     pTxtMeta->ChgTxtNode(pTxtNd);
354                                 }
355                                 break;
356 
357                             default:
358                                 break;
359 							}
360 							if( nDelMsg && bToUndo )
361 							{
362 								SwPtrMsgPoolItem aMsgHint( nDelMsg,
363 													(void*)&pAttr->GetAttr() );
364 								rNds.GetDoc()->GetUnoCallBack()->
365 											ModifyNotification( &aMsgHint, &aMsgHint );
366 							}
367 						}
368 					}
369 //FEATURE::CONDCOLL
370 					if( RES_CONDTXTFMTCOLL == pTxtNd->GetTxtColl()->Which() )
371 						pTxtNd->ChkCondColl();
372 //FEATURE::CONDCOLL
373 				}
374 				else
375 				{
376 					// in unterschiedliche Docs gemoved ?
377 					// dann die Daten wieder persistent machen
378 					if( pCNd->IsNoTxtNode() && bRestPersData )
379 						((SwNoTxtNode*)pCNd)->RestorePersistentData();
380 				}
381 			}
382 		}
383 	}
384 
385 	//JP 03.02.99: alle Felder als invalide erklaeren, aktu. erfolgt im
386 	//				Idle-Handler des Docs
387 	GetDoc()->SetFieldsDirty( true, NULL, 0 );
388 	if( rNds.GetDoc() != GetDoc() )
389 		rNds.GetDoc()->SetFieldsDirty( true, NULL, 0 );
390 
391 
392 	if( bNewFrms )
393 		bNewFrms = &GetDoc()->GetNodes() == (const SwNodes*)&rNds &&
394 					GetDoc()->GetCurrentViewShell();	//swmod 071108//swmod 071225
395 	if( bNewFrms )
396 	{
397 		// Frames besorgen:
398 		SwNodeIndex aIdx( *pPrevInsNd, 1 );
399 		SwNodeIndex aFrmNdIdx( aIdx );
400 		SwNode* pFrmNd = rNds.FindPrvNxtFrmNode( aFrmNdIdx,
401 										rNds[ rInsPos.GetIndex() - 1 ] );
402 
403 		if( !pFrmNd && aFrmNdIdx > rNds.GetEndOfExtras().GetIndex() )
404 		{
405 			ASSERT( !this, "ob das so richtig ist ??" );
406 			aFrmNdIdx = rNds.GetEndOfContent();
407 			pFrmNd = rNds.GoPrevSection( &aFrmNdIdx, sal_True, sal_False );
408 			if( pFrmNd && !((SwCntntNode*)pFrmNd)->GetDepends() )
409 				pFrmNd = 0;
410 
411 #ifdef DBG_UTIL
412 			if( !pFrmNd )
413 				ASSERT( !this, "ChgNode() - kein FrameNode gefunden" );
414 #endif
415 		}
416 		if( pFrmNd )
417 			while( aIdx != rInsPos )
418 			{
419 				SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
420 				if( pCNd )
421 				{
422 					if( pFrmNd->IsTableNode() )
423 						((SwTableNode*)pFrmNd)->MakeFrms( aIdx );
424 					else if( pFrmNd->IsSectionNode() )
425 						((SwSectionNode*)pFrmNd)->MakeFrms( aIdx );
426 					else
427 						((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd );
428 					pFrmNd = pCNd;
429 				}
430 				aIdx++;
431 			}
432 	}
433 }
434 
435 
436 /***********************************************************************
437 |*
438 |*	SwNodes::Move
439 |*
440 |*	Beschreibung
441 |*	Move loescht die Node-Pointer ab und einschliesslich der Startposition
442 |*	bis zu und ausschliesslich der Endposition und fuegt sie an
443 |*	der vor der Zielposition ein.
444 |*	Wenn das Ziel vor dem ersten oder dem letzten zu bewegenden Element oder
445 |*	dazwischen liegt, geschieht nichts.
446 |*	Wenn der zu bewegende Bereich leer ist oder das Ende vor
447 |*	dem Anfang liegt, geschieht nichts.
448 |*
449 |*	Allg.: aRange beschreibt den Bereich  -exklusive- aEnd !!
450 |*				( 1.Node: aStart, letzer Node: aEnd-1 !! )
451 |*
452 |*
453 |*
454 ***********************************************************************/
455 
456 sal_Bool SwNodes::_MoveNodes( const SwNodeRange& aRange, SwNodes & rNodes,
457 					const SwNodeIndex& aIndex, sal_Bool bNewFrms )
458 {
459 	SwNode * pAktNode;
460 	if( aIndex == 0 ||
461 		( (pAktNode = &aIndex.GetNode())->GetStartNode() &&
462 		  !pAktNode->StartOfSectionIndex() ))
463         return sal_False;
464 
465 	SwNodeRange aRg( aRange );
466 
467 	// "einfache" StartNodes oder EndNodes ueberspringen
468 	while( ND_STARTNODE == (pAktNode = &aRg.aStart.GetNode())->GetNodeType()
469 			|| ( pAktNode->IsEndNode() &&
470 				!pAktNode->pStartOfSection->IsSectionNode() ) )
471 		aRg.aStart++;
472 	aRg.aStart--;
473 
474 	// falls aEnd-1 auf keinem ContentNode steht, dann suche den vorherigen
475 	aRg.aEnd--;
476 	while( ( (( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() &&
477 			!pAktNode->IsSectionNode() ) ||
478 			( pAktNode->IsEndNode() &&
479 			ND_STARTNODE == pAktNode->pStartOfSection->GetNodeType()) ) &&
480             aRg.aEnd > aRg.aStart )
481 		aRg.aEnd--;
482 
483 
484 	// wird im selben Array's verschoben, dann ueberpruefe die Einfuegepos.
485 	if( aRg.aStart >= aRg.aEnd )
486 		return sal_False;
487 
488 	if( this == &rNodes )
489 	{
490 		if( ( aIndex.GetIndex()-1 >= aRg.aStart.GetIndex() &&
491 			  aIndex.GetIndex()-1 < aRg.aEnd.GetIndex()) ||
492 			( aIndex.GetIndex()-1 == aRg.aEnd.GetIndex() ) )
493 			return sal_False;
494 	}
495 
496 	sal_uInt16 nLevel = 0;					// Level-Counter
497 	sal_uLong nInsPos = 0; 					// Cnt fuer das TmpArray
498 
499 	// das Array bildet einen Stack, es werden alle StartOfSelction's gesichert
500 	SwSttNdPtrs aSttNdStack( 1, 5 );
501 
502 	// setze den Start-Index
503 	SwNodeIndex  aIdx( aIndex );
504 /*
505 	--- JP 17.11.94: sollte ueberholt sein, wird im ChgNode schon erledigt!
506 	sal_Bool bCorrNum = pSect && pSect->aStart.GetIndex() == aIdx.GetIndex();
507 */
508 
509 	SwStartNode* pStartNode = aIdx.GetNode().pStartOfSection;
510 	aSttNdStack.C40_INSERT( SwStartNode, pStartNode, 0 );
511 //	aSttNdStack.Insert( rNodes[ aIdx ]->pStartOfSection, 0 );
512 	SwNodeRange aOrigInsPos( aIdx, -1, aIdx );		// Originale Insert Pos
513 
514 	//JP 16.01.98: SectionNodes: DelFrms/MakeFrms beim obersten SectionNode!
515 	sal_uInt16 nSectNdCnt = 0;
516 	sal_Bool bSaveNewFrms = bNewFrms;
517 
518     // Check that the range of nodes to move is valid.
519     // This is a very specific test that only checks that table nodes
520     // are completely covered by the range.  Issue 121479 has a
521     // document for which this test fails.
522     SwNodeIndex aNodeIndex (aRg.aEnd);
523     while (aNodeIndex > aRg.aStart)
524     {
525         SwNode& rNode (aNodeIndex.GetNode());
526         if (rNode.GetNodeType() != ND_ENDNODE)
527             break;
528         SwStartNode* pStartNode = rNode.pStartOfSection;
529         if (pStartNode==NULL)
530             break;
531         if ( ! pStartNode->IsTableNode())
532             break;
533         aNodeIndex = *pStartNode;
534         if (aNodeIndex < aRg.aStart.GetIndex())
535         {
536             return sal_False;
537         }
538         --aNodeIndex;
539     }
540 
541 
542 	// bis alles verschoben ist
543 	while( aRg.aStart < aRg.aEnd )
544 		switch( (pAktNode = &aRg.aEnd.GetNode())->GetNodeType() )
545 		{
546 		case ND_ENDNODE:
547 			{
548 				if( nInsPos )		// verschieb schon mal alle bis hier her
549 				{
550 					// loeschen und kopieren. ACHTUNG: die Indizies ab
551 					// "aRg.aEnd+1" werden mit verschoben !!
552 					SwNodeIndex aSwIndex( aRg.aEnd, 1 );
553 					ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
554 					aIdx -= nInsPos;
555 					nInsPos = 0;
556 				}
557 
558 				SwStartNode* pSttNd = pAktNode->pStartOfSection;
559 				if( pSttNd->IsTableNode() )
560 				{
561 					SwTableNode* pTblNd = (SwTableNode*)pSttNd;
562 
563 					// dann bewege die gesamte Tabelle/den Bereich !!
564 					nInsPos = (aRg.aEnd.GetIndex() -
565 									pSttNd->GetIndex() )+1;
566 					aRg.aEnd -= nInsPos;
567 
568 					//JP 12.03.99: 63293 - Nodes vom RedlineBereich NIE aufnehmen
569 					sal_uLong nNd = aIdx.GetIndex();
570 					sal_Bool bInsOutlineIdx = !( rNodes.GetEndOfRedlines().
571                             StartOfSectionNode()->GetIndex() < nNd &&
572 							nNd < rNodes.GetEndOfRedlines().GetIndex() );
573 
574 					if( bNewFrms )
575 						// loesche erstmal die Frames
576 						pTblNd->DelFrms();
577 					if( &rNodes == this )	// in sich selbst moven ??
578 					{
579 						// dann bewege alle Start/End/ContentNodes. Loesche
580 						// bei den ContentNodes auch die Frames !!
581 						pTblNd->pStartOfSection = aIdx.GetNode().pStartOfSection;
582 						for( sal_uLong n = 0; n < nInsPos; ++n )
583 						{
584 							SwNodeIndex aMvIdx( aRg.aEnd, 1 );
585 							SwCntntNode* pCNd = 0;
586 							SwNode* pTmpNd = &aMvIdx.GetNode();
587 							if( pTmpNd->IsCntntNode() )
588 							{
589 								pCNd = (SwCntntNode*)pTmpNd;
590                                 if( pTmpNd->IsTxtNode() )
591                                     ((SwTxtNode*)pTmpNd)->RemoveFromList();
592 
593 //								if( bNewFrms )
594 //									pCNd->DelFrms();
595 
596 								// setze bei Start/EndNodes die richtigen Indizies
597 								// loesche die Gliederungs-Indizies aus
598 								// dem alten Nodes-Array
599 								//if( pCNd->IsTxtNode() && NO_NUMBERING !=		//#outline level,zhaojianwei
600 								//	((SwTxtNode*)pCNd)->GetTxtColl()->GetOutlineLevel() )
601 								if( pCNd->IsTxtNode() && 0 !=
602 									((SwTxtNode*)pCNd)->GetAttrOutlineLevel() )//<-end,by zhaojianwei
603 									pOutlineNds->Remove( pCNd );
604 								else
605 									pCNd = 0;
606 							}
607 //							else if( bNewFrms && pTmpNd->IsSectionNode() )
608 //								((SwSectionNode*)pTmpNd)->DelFrms();
609 							BigPtrArray::Move( aMvIdx.GetIndex(), aIdx.GetIndex() );
610 
611 							if( bInsOutlineIdx && pCNd )
612 								pOutlineNds->Insert( pCNd );
613                             if( pTmpNd->IsTxtNode() )
614                                 ((SwTxtNode*)pTmpNd)->AddToList();
615 						}
616 					}
617 					else
618 					{
619 						// StartNode holen
620 						// Even aIdx points to a startnode, we need the startnode
621 						// of the environment of aIdx (#i80941)
622 						SwStartNode* pSttNode = aIdx.GetNode().pStartOfSection;
623 
624 						// Hole alle Boxen mit Inhalt. Deren Indizies auf die
625 						// StartNodes muessen umgemeldet werden !!
626 						// (Array kopieren und alle gefunden wieder loeschen;
627 						//  erleichtert das suchen!!)
628 						SwNodeIndex aMvIdx( aRg.aEnd, 1 );
629 						for( sal_uLong n = 0; n < nInsPos; ++n )
630 						{
631 							SwNode* pNd = &aMvIdx.GetNode();
632 /*							if( bNewFrms )
633 							{
634 								if( pNd->IsCntntNode() )
635 									((SwCntntNode*)pNd)->DelFrms();
636 								else if( pNd->IsSectionNode() )
637 									((SwSectionNode*)pNd)->DelFrms();
638 							}
639 */
640 							//sal_Bool bOutlNd = pNd->IsTxtNode() && NO_NUMBERING !=//#outline level,zhaojianwei
641 							//	((SwTxtNode*)pNd)->GetTxtColl()->GetOutlineLevel();
642                             const bool bOutlNd = pNd->IsTxtNode() &&
643                                     0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel();//<-end,zhaojianwei
644 							// loesche die Gliederungs-Indizies aus
645 							// dem alten Nodes-Array
646 							if( bOutlNd )
647 								pOutlineNds->Remove( pNd );
648 
649 							RemoveNode( aMvIdx.GetIndex(), 1, sal_False );
650 							pNd->pStartOfSection = pSttNode;
651                             rNodes.InsertNode( pNd, aIdx );
652 
653 							// setze bei Start/EndNodes die richtigen Indizies
654 							if( bInsOutlineIdx && bOutlNd )
655 								// und setze sie im neuen Nodes-Array
656 								rNodes.pOutlineNds->Insert( pNd );
657 							else if( pNd->IsStartNode() )
658 								pSttNode = (SwStartNode*)pNd;
659 							else if( pNd->IsEndNode() )
660 							{
661 								pSttNode->pEndOfSection = (SwEndNode*)pNd;
662 								if( pSttNode->IsSectionNode() )
663 									((SwSectionNode*)pSttNode)->NodesArrChgd();
664 								pSttNode = pSttNode->pStartOfSection;
665 							}
666 						}
667 
668 						if( pTblNd->GetTable().IsA( TYPE( SwDDETable ) ))
669 						{
670 							SwDDEFieldType* pTyp = ((SwDDETable&)pTblNd->
671 												GetTable()).GetDDEFldType();
672 							if( pTyp )
673 							{
674 								if( rNodes.IsDocNodes() )
675 									pTyp->IncRefCnt();
676 								else
677 									pTyp->DecRefCnt();
678 							}
679 						}
680 
681                         if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(
682                                     rNodes))
683                         {
684 							SwFrmFmt* pTblFmt = pTblNd->GetTable().GetFrmFmt();
685 							SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
686 														pTblFmt );
687 							pTblFmt->ModifyNotification( &aMsgHint, &aMsgHint );
688 						}
689 					}
690 					if( bNewFrms )
691 					{
692 						SwNodeIndex aTmp( aIdx );
693 						pTblNd->MakeFrms( &aTmp );
694 					}
695 					aIdx -= nInsPos;
696 					nInsPos = 0;
697 				}
698 				else if( pSttNd->GetIndex() < aRg.aStart.GetIndex() )
699 				{
700 					// SectionNode: es wird nicht die gesamte Section
701 					//				verschoben, also bewege nur die
702 					//				ContentNodes
703 					// StartNode:	erzeuge an der Postion eine neue Section
704 					do {		// middle check loop
705 						if( !pSttNd->IsSectionNode() )
706 						{
707 							// Start und EndNode an der InsertPos erzeugen
708 							SwStartNode* pTmp = new SwStartNode( aIdx,
709 													ND_STARTNODE,
710 /*?? welcher NodeTyp ??*/
711 													SwNormalStartNode );
712 
713 							nLevel++;			// den Index auf StartNode auf den Stack
714 							aSttNdStack.C40_INSERT( SwStartNode, pTmp, nLevel );
715 
716 							// noch den EndNode erzeugen
717 							new SwEndNode( aIdx, *pTmp );
718                         }
719                         else if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(
720                                     rNodes))
721                         {
722 							// im UndoNodes-Array spendieren wir einen
723 							// Platzhalter
724 							new SwNode( aIdx, ND_SECTIONDUMMY );
725 						}
726 						else
727 						{
728 							// JP 18.5.2001: neue Section anlegen?? Bug 70454
729 							aRg.aEnd--;
730 							break;
731 
732 						}
733 
734 						aRg.aEnd--;
735 						aIdx--;
736 					} while( sal_False );
737 				}
738 				else
739 				{
740 					// Start und EndNode komplett verschieben
741 // s. u. SwIndex aOldStt( pSttNd->theIndex );
742 //JP 21.05.97: sollte der Start genau der Start des Bereiches sein, so muss
743 //				der Node auf jedenfall noch besucht werden!
744 					if( &aRg.aStart.GetNode() == pSttNd )
745 						--aRg.aStart;
746 
747 					SwSectionNode* pSctNd = pSttNd->GetSectionNode();
748 					if( bNewFrms && pSctNd )
749 						pSctNd->DelFrms();
750 
751 					RemoveNode( aRg.aEnd.GetIndex(), 1, sal_False ); // EndNode loeschen
752 					sal_uLong nSttPos = pSttNd->GetIndex();
753 
754 					// dieser StartNode wird spaeter wieder entfernt!
755 					SwStartNode* pTmpSttNd = new SwStartNode( *this, nSttPos+1 );
756 					pTmpSttNd->pStartOfSection = pSttNd->pStartOfSection;
757 
758 					RemoveNode( nSttPos, 1, sal_False ); // SttNode loeschen
759 
760 					pSttNd->pStartOfSection = aIdx.GetNode().pStartOfSection;
761                     rNodes.InsertNode( pSttNd, aIdx  );
762                     rNodes.InsertNode( pAktNode, aIdx );
763 					aIdx--;
764 					pSttNd->pEndOfSection = (SwEndNode*)pAktNode;
765 
766 					aRg.aEnd--;
767 
768 					nLevel++;			// den Index auf StartNode auf den Stack
769 					aSttNdStack.C40_INSERT( SwStartNode, pSttNd, nLevel );
770 
771 					// SectionNode muss noch ein paar Indizies ummelden
772 					if( pSctNd )
773 					{
774 						pSctNd->NodesArrChgd();
775 						++nSectNdCnt;
776 						bNewFrms = sal_False;
777 					}
778 				}
779 			}
780 			break;
781 
782 
783 
784 		case ND_SECTIONNODE:
785 			if( !nLevel &&
786                 GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNodes))
787             {
788 				// dann muss an der akt. InsPos ein SectionDummyNode
789 				// eingefuegt werden
790 				if( nInsPos )		// verschieb schon mal alle bis hier her
791 				{
792 					// loeschen und kopieren. ACHTUNG: die Indizies ab
793 					// "aRg.aEnd+1" werden mit verschoben !!
794 					SwNodeIndex aSwIndex( aRg.aEnd, 1 );
795 					ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
796 					aIdx -= nInsPos;
797 					nInsPos = 0;
798 				}
799 				new SwNode( aIdx, ND_SECTIONDUMMY );
800 				aRg.aEnd--;
801 				aIdx--;
802 				break;
803 			}
804 			// kein break !!
805 		case ND_TABLENODE:
806 		case ND_STARTNODE:
807 			{
808 				// Bug #78589# - empty section -> nothing to do
809 				//  and only if it's a top level section
810 				if( !nInsPos && !nLevel )
811 				{
812 					aRg.aEnd--;
813 					break;
814 				}
815 
816 				if( !nLevel )		// es wird eine Stufe runter gestuft
817 				{
818 					// erzeuge die Runterstufung
819 					SwNodeIndex aTmpSIdx( aOrigInsPos.aStart, 1 );
820 					SwStartNode* pTmpStt = new SwStartNode( aTmpSIdx,
821 								ND_STARTNODE,
822 								((SwStartNode*)pAktNode)->GetStartNodeType() );
823 
824 					aTmpSIdx--;
825 
826 					SwNodeIndex aTmpEIdx( aOrigInsPos.aEnd );
827 					new SwEndNode( aTmpEIdx, *pTmpStt );
828 					aTmpEIdx--;
829 					aTmpSIdx++;
830 
831 					// setze die StartOfSection richtig
832 					aRg.aEnd++;
833 					{
834 						SwNodeIndex aCntIdx( aRg.aEnd );
835 						for( sal_uLong n = 0; n < nInsPos; n++, aCntIdx++)
836 							aCntIdx.GetNode().pStartOfSection = pTmpStt;
837 					}
838 
839 					// Setze auch bei allen runtergestuften den richtigen StartNode
840 					while( aTmpSIdx < aTmpEIdx )
841 						if( 0 != (( pAktNode = &aTmpEIdx.GetNode())->GetEndNode()) )
842 							aTmpEIdx = pAktNode->StartOfSectionIndex();
843 						else
844 						{
845 							pAktNode->pStartOfSection = pTmpStt;
846 							aTmpEIdx--;
847 						}
848 
849 					aIdx--; 				// hinter den eingefuegten StartNode
850 					aRg.aEnd--; 			// vor den StartNode
851 					// kopiere jetzt das Array. ACHTUNG: die Indizies ab
852 					// "aRg.aEnd+1" werden mit verschoben !!
853 					SwNodeIndex aSwIndex( aRg.aEnd, 1 );
854 					ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
855 					aIdx -= nInsPos+1;
856 					nInsPos = 0;
857 				}
858 				else 				// es wurden alle Nodes innerhalb eines
859 				{	 				// Start- und End-Nodes verschoben
860 					ASSERT( pAktNode == aSttNdStack[nLevel] ||
861 							( pAktNode->IsStartNode() &&
862 								aSttNdStack[nLevel]->IsSectionNode()),
863 							 "falscher StartNode" );
864 
865 					SwNodeIndex aSwIndex( aRg.aEnd, 1 );
866 					ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
867 					aIdx -= nInsPos+1;		// vor den eingefuegten StartNode
868 					nInsPos = 0;
869 
870 					// loesche nur noch den Pointer aus dem Nodes-Array.
871 //					RemoveNode( aRg.aEnd.GetIndex(), 1, sal_False );
872 					RemoveNode( aRg.aEnd.GetIndex(), 1, sal_True );
873 					aRg.aEnd--;
874 
875 					SwSectionNode* pSectNd = aSttNdStack[ nLevel ]->GetSectionNode();
876 					if( pSectNd && !--nSectNdCnt )
877 					{
878 						SwNodeIndex aTmp( *pSectNd );
879 						pSectNd->MakeFrms( &aTmp );
880 						bNewFrms = bSaveNewFrms;
881 					}
882 					aSttNdStack.Remove( nLevel ); 	// vom Stack loeschen
883 					nLevel--;
884 				}
885 
886 				// loesche alle entstehenden leeren Start-/End-Node-Paare
887 				SwNode* pTmpNode = (*this)[ aRg.aEnd.GetIndex()+1 ]->GetEndNode();
888 				if( pTmpNode && ND_STARTNODE == (pAktNode = &aRg.aEnd.GetNode())
889 					->GetNodeType() && pAktNode->StartOfSectionIndex() &&
890                     pTmpNode->StartOfSectionNode() == pAktNode )
891 				{
892 					DelNodes( aRg.aEnd, 2 );
893 					aRg.aEnd--;
894 				}
895 //				aRg.aEnd--;
896 			}
897 			break;
898 
899 		case ND_TEXTNODE:
900 			//IAccessibility2 Implementation 2009-----
901 			//Solution:Add special function to text node.
902 			{
903 				if( bNewFrms && pAktNode->GetCntntNode() )
904 					((SwCntntNode*)pAktNode)->DelFrms( sal_False );
905 				pAktNode->pStartOfSection = aSttNdStack[ nLevel ];
906 				nInsPos++;
907 				aRg.aEnd--;
908 			}
909 			break;
910 		    //-----IAccessibility2 Implementation 2009
911 		case ND_GRFNODE:
912 		case ND_OLENODE:
913 			{
914 				if( bNewFrms && pAktNode->GetCntntNode() )
915 					((SwCntntNode*)pAktNode)->DelFrms();
916 
917 				pAktNode->pStartOfSection = aSttNdStack[ nLevel ];
918 				nInsPos++;
919 				aRg.aEnd--;
920 			}
921 			break;
922 
923 		case ND_SECTIONDUMMY:
924             if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this))
925             {
926 				if( &rNodes == this )		// innerhalb vom UndoNodesArray
927 				{
928 					// mit verschieben
929 					pAktNode->pStartOfSection = aSttNdStack[ nLevel ];
930 					nInsPos++;
931 				}
932 				else	// in ein "normales" Nodes-Array verschieben
933 				{
934 					// dann muss an der akt. InsPos auch ein SectionNode
935 					// (Start/Ende) stehen; dann diesen ueberspringen.
936 					// Andernfalls nicht weiter beachten.
937 					if( nInsPos )		// verschieb schon mal alle bis hier her
938 					{
939 						// loeschen und kopieren. ACHTUNG: die Indizies ab
940 						// "aRg.aEnd+1" werden mit verschoben !!
941 						SwNodeIndex aSwIndex( aRg.aEnd, 1 );
942 						ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
943 						aIdx -= nInsPos;
944 						nInsPos = 0;
945 					}
946 					SwNode* pTmpNd = &aIdx.GetNode();
947 					if( pTmpNd->IsSectionNode() ||
948                         pTmpNd->StartOfSectionNode()->IsSectionNode() )
949 						aIdx--;	// ueberspringen
950 				}
951 			}
952 			else {
953 				ASSERT( sal_False, "wie kommt diser Node ins Nodes-Array??" );
954             }
955 			aRg.aEnd--;
956 			break;
957 
958 		default:
959 			ASSERT( sal_False, "was ist das fuer ein Node??" );
960 			break;
961 		}
962 
963 	if( nInsPos )							// kopiere den Rest
964 	{
965 		// der Rest muesste so stimmen
966 		SwNodeIndex aSwIndex( aRg.aEnd, 1 );
967 		ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms );
968 	}
969 	aRg.aEnd++;						// wieder exklusive Ende
970 
971 	// loesche alle leeren Start-/End-Node-Paare
972 	if( ( pAktNode = &aRg.aStart.GetNode())->GetStartNode() &&
973 		pAktNode->StartOfSectionIndex() &&
974 		aRg.aEnd.GetNode().GetEndNode() )
975 			DelNodes( aRg.aStart, 2 );
976 
977 	// rufe jetzt noch das Update fuer die Gliederung/Nummerierung auf
978 	aOrigInsPos.aStart++;
979 	// im gleichen Nodes-Array verschoben ??,
980 	// dann von oben nach unten das Update aufrufen !!
981 	if( this == &rNodes &&
982 		aRg.aEnd.GetIndex() >= aOrigInsPos.aStart.GetIndex() )
983 	{
984 		UpdtOutlineIdx( aOrigInsPos.aStart.GetNode() );
985 		UpdtOutlineIdx( aRg.aEnd.GetNode() );
986 	}
987 	else
988 	{
989 		UpdtOutlineIdx( aRg.aEnd.GetNode() );
990 		rNodes.UpdtOutlineIdx( aOrigInsPos.aStart.GetNode() );
991 	}
992 
993 #ifdef JP_DEBUG
994 	{
995 extern Writer* GetDebugWriter(const String&);
996 
997 		Writer* pWriter = GetDebugWriter(aEmptyStr);
998 		if( pWriter )
999 		{
1000 			int nError;
1001 			SvFileStream aStrm( "c:\\$$move.db", STREAM_WRITE );
1002 			SwWriter aWriter( aStrm, *pMyDoc );
1003 			aWriter.Write( &nError, pWriter );
1004 		}
1005 	}
1006 #endif
1007 
1008 	return sal_True;
1009 }
1010 
1011 
1012 /*******************************************************************
1013 |*
1014 |*	SwNodes::SectionDown
1015 |*
1016 |*	Beschreibung
1017 |*	  SectionDown() legt ein Paar von Start- und EndSection-Node
1018 |*	  (andere Nodes koennen dazwischen liegen) an.
1019 |*
1020 |*	  Zustand des SRange beim Verlassen der Funktion: nStart ist der
1021 |*	  Index des ersten Node hinter dem Start Section Node, nEnd ist
1022 |*	  der Index des End Section Nodes. Beispiel: Wird Insert Section
1023 |*	  mehrmals hintereinander aufgerufen, so werden mehrere
1024 |*	  unmittelbar geschachtelte Sections (keine Content Nodes
1025 |*	  zwischen Start- bzw. End Nodes) angelegt.
1026 |*
1027 |*	Allg.: aRange beschreibt den Bereich  -exklusive- aEnd !!
1028 |*				( 1.Node: aStart, letzer Node: aEnd-1 !! )
1029 |*
1030 |*	Parameter
1031 |*		SwRange &rRange
1032 |*			IO:
1033 |*			IN
1034 |*			rRange.aStart: Einfuegeposition des StartNodes
1035 |*			rRange.aEnd: Einfuegeposition des EndNodes
1036 |*			OUT
1037 |*			rRange.aStart: steht hinter dem eingefuegten Startnode
1038 |*			rRange.aEnd: steht auf dem eingefuegen Endnode
1039 |*
1040 |*	Ausnahmen
1041 |*	 1. SRange-Anfang und SRange-Ende muessen auf dem gleichen Level sein
1042 |*	 2. duerfen nicht auf dem obersten Level sein
1043 |*		Ist dies nicht der Fall, wird die
1044 |*		Funktion durch Aufruf von ERR_RAISE verlassen.
1045 |*
1046 |*	Debug-Funktionen
1047 |*		die Debugging Tools geben rRange beim Eintritt und beim
1048 |*		Verlassen der Funktion aus
1049 |*
1050 |*	Ersterstellung
1051 |*		VER0100 vb 901214
1052 |*
1053 |*	Stand
1054 |*		VER0100 vb 901214
1055 |*
1056 *******************************************************************/
1057 void SwNodes::SectionDown(SwNodeRange *pRange, SwStartNodeType eSttNdTyp )
1058 {
1059 	if( pRange->aStart >= pRange->aEnd ||
1060 		pRange->aEnd >= Count() ||
1061 		!CheckNodesRange( pRange->aStart, pRange->aEnd ))
1062 		return;
1063 
1064 	// Ist der Anfang vom Bereich vor oder auf einem EndNode, so loesche
1065 	// diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen.
1066 	// Bei anderen Nodes wird eine neuer StartNode eingefuegt
1067 	SwNode * pAktNode = &pRange->aStart.GetNode();
1068 	SwNodeIndex aTmpIdx( *pAktNode->StartOfSectionNode() );
1069 
1070 	if( pAktNode->GetEndNode() )
1071 		DelNodes( pRange->aStart, 1 );		// verhinder leere Section
1072 	else
1073 	{
1074 		// fuege einen neuen StartNode ein
1075 		SwNode* pSttNd = new SwStartNode( pRange->aStart, ND_STARTNODE, eSttNdTyp );
1076 		pRange->aStart = *pSttNd;
1077 		aTmpIdx = pRange->aStart;
1078 	}
1079 
1080 	// Ist das Ende vom Bereich vor oder auf einem StartNode, so loesche
1081 	// diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen
1082 	// Bei anderen Nodes wird eine neuer EndNode eingefuegt
1083 	pRange->aEnd--;
1084 	if( pRange->aEnd.GetNode().GetStartNode() )
1085 		DelNodes( pRange->aEnd, 1 );
1086 	else
1087 	{
1088 		pRange->aEnd++;
1089 		// fuege einen neuen EndNode ein
1090 		new SwEndNode( pRange->aEnd, *pRange->aStart.GetNode().GetStartNode() );
1091 	}
1092 	pRange->aEnd--;
1093 
1094 	SectionUpDown( aTmpIdx, pRange->aEnd );
1095 }
1096 
1097 /*******************************************************************
1098 |*
1099 |*	SwNodes::SectionUp
1100 |*
1101 |*	Beschreibung
1102 |*		Der von rRange umspannte Bereich wird auf die naechst hoehere
1103 |*		Ebene gehoben. Das geschieht dadurch, dass bei
1104 |*		rRange.aStart ein Endnode und bei rRange.aEnd ein
1105 |*		Startnode eingefuegt wird. Die Indices fuer den Bereich
1106 |*		innerhalb von rRange werden geupdated.
1107 |*
1108 |*	Allg.: aRange beschreibt den Bereich  -exklusive- aEnd !!
1109 |*				( 1.Node: aStart, letzer Node: aEnd-1 !! )
1110 |*
1111 |*	Parameter
1112 |*		SwRange &rRange
1113 |*			IO:
1114 |*			IN
1115 |*			rRange.aStart: Anfang des hoeher zubewegenden Bereiches
1116 |*			rRange.aEnd:   der 1.Node hinter dem Bereich
1117 |*			OUT
1118 |*			rRange.aStart:	an der ersten Position innerhalb des
1119 |*							hochbewegten Bereiches
1120 |*			rRange.aEnd:	an der letzten Position innerhalb des
1121 |*							hochbewegten Bereiches
1122 |*
1123 |*	Debug-Funktionen
1124 |*		die Debugging Tools geben rRange beim Eintritt und beim
1125 |*		Verlassen der Funktion aus
1126 |*
1127 |*	Ersterstellung
1128 |*		VER0100 vb 901214
1129 |*
1130 |*	Stand
1131 |*		VER0100 vb 901214
1132 |*
1133 *******************************************************************/
1134 void SwNodes::SectionUp(SwNodeRange *pRange)
1135 {
1136 	if( pRange->aStart >= pRange->aEnd ||
1137 		pRange->aEnd >= Count() ||
1138 		!CheckNodesRange( pRange->aStart, pRange->aEnd ) ||
1139 		!( HighestLevel( *this, *pRange ) > 1 ))
1140 		return;
1141 
1142 	// Ist der Anfang vom Bereich vor oder auf einem StartNode, so loesche
1143 	// diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen.
1144 	// Bei anderen Nodes wird eine neuer EndNode eingefuegt
1145 	SwNode * pAktNode = &pRange->aStart.GetNode();
1146 	SwNodeIndex aIdx( *pAktNode->StartOfSectionNode() );
1147 	if( pAktNode->IsStartNode() )		// selbst StartNode
1148 	{
1149 		SwEndNode* pEndNd = pRange->aEnd.GetNode().GetEndNode();
1150 		if( pAktNode == pEndNd->pStartOfSection )
1151 		{
1152 			// dann wurde paarig aufgehoben, also nur die im Berich neu anpassen
1153 			SwStartNode* pTmpSttNd = pAktNode->pStartOfSection;
1154 			RemoveNode( pRange->aStart.GetIndex(), 1, sal_True );
1155 			RemoveNode( pRange->aEnd.GetIndex(), 1, sal_True );
1156 
1157 			SwNodeIndex aTmpIdx( pRange->aStart );
1158 			while( aTmpIdx < pRange->aEnd )
1159 			{
1160 				pAktNode = &aTmpIdx.GetNode();
1161 				pAktNode->pStartOfSection = pTmpSttNd;
1162 				if( pAktNode->IsStartNode() )
1163 					aTmpIdx = pAktNode->EndOfSectionIndex() + 1;
1164 				else
1165 					aTmpIdx++;
1166 			}
1167 			return ;
1168 		}
1169 		DelNodes( pRange->aStart, 1 );
1170 	}
1171 	else if( aIdx == pRange->aStart.GetIndex()-1 )			// vor StartNode
1172 		DelNodes( aIdx, 1 );
1173 	else
1174 		new SwEndNode( pRange->aStart, *aIdx.GetNode().GetStartNode() );
1175 
1176 	// Ist das Ende vom Bereich vor oder auf einem StartNode, so loesche
1177 	// diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes entstehen
1178 	// Bei anderen Nodes wird eine neuer EndNode eingefuegt
1179 	SwNodeIndex aTmpIdx( pRange->aEnd );
1180 	if( pRange->aEnd.GetNode().IsEndNode() )
1181 		DelNodes( pRange->aEnd, 1 );
1182 	else
1183 	{
1184 		pAktNode = new SwStartNode( pRange->aEnd );
1185 /*?? welcher NodeTyp ??*/
1186 		aTmpIdx = *pRange->aEnd.GetNode().EndOfSectionNode();
1187 		pRange->aEnd--;
1188 	}
1189 
1190 	SectionUpDown( aIdx, aTmpIdx );
1191 }
1192 
1193 
1194 /*************************************************************************
1195 |*
1196 |*	SwNodes::SectionUpDown()
1197 |*
1198 |*	Beschreibung
1199 |*		Methode setzt die Indizies die bei SectionUp oder SectionDwon
1200 |*		veraendert wurden wieder richtig, sodass die Ebenen wieder
1201 |*		Konsistent sind.
1202 |*
1203 |*	  Parameter
1204 |*						SwIndex & aStart		StartNode !!!
1205 |*						SwIndex & aEnd			EndPunkt
1206 |*
1207 |*	  Ersterstellung	JP 23.04.91
1208 |*	  Letzte Aenderung	JP 23.04.91
1209 |*
1210 *************************************************************************/
1211 void SwNodes::SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd )
1212 {
1213 	SwNode * pAktNode;
1214 	SwNodeIndex aTmpIdx( aStart, +1 );
1215 	// das Array bildet einen Stack, es werden alle StartOfSelction's gesichert
1216 	SwSttNdPtrs aSttNdStack( 1, 5 );
1217 	SwStartNode* pTmp = aStart.GetNode().GetStartNode();
1218 	aSttNdStack.C40_INSERT( SwStartNode, pTmp, 0 );
1219 
1220 	// durchlaufe bis der erste zu aendernde Start-Node gefunden wurde
1221 	// ( Es wird vom eingefuegten EndNode bis nach vorne die Indexe gesetzt )
1222 	for( ;; aTmpIdx++ )
1223 	{
1224 		pAktNode = &aTmpIdx.GetNode();
1225 		pAktNode->pStartOfSection = aSttNdStack[ aSttNdStack.Count()-1 ];
1226 
1227 		if( pAktNode->GetStartNode() )
1228 		{
1229 			pTmp = (SwStartNode*)pAktNode;
1230 			aSttNdStack.C40_INSERT( SwStartNode, pTmp, aSttNdStack.Count() );
1231 		}
1232 		else if( pAktNode->GetEndNode() )
1233 		{
1234 			SwStartNode* pSttNd = aSttNdStack[ aSttNdStack.Count() - 1 ];
1235 			pSttNd->pEndOfSection = (SwEndNode*)pAktNode;
1236 			aSttNdStack.Remove( aSttNdStack.Count() - 1 );
1237 			if( aSttNdStack.Count() )
1238 				continue;		// noch genuegend EndNodes auf dem Stack
1239 
1240 			else if( aTmpIdx < aEnd ) 	// Uebergewicht an StartNodes
1241 				// ist das Ende noch nicht erreicht, so hole den Start von
1242 				// der uebergeordneten Section
1243 			{
1244 				aSttNdStack.C40_INSERT( SwStartNode, pSttNd->pStartOfSection, 0 );
1245 			}
1246 			else	// wenn ueber den Bereich hinaus, dann Ende
1247 				break;
1248 		}
1249 	}
1250 }
1251 
1252 
1253 
1254 
1255 /*******************************************************************
1256 |*
1257 |*	SwNodes::Delete
1258 |*
1259 |*	Beschreibung
1260 |*		Spezielle Implementierung der Delete-Funktion des
1261 |*		variablen Array. Diese spezielle Implementierung ist
1262 |*		notwendig, da durch das Loeschen von Start- bzw.
1263 |*		Endnodes Inkonsistenzen entstehen koennen. Diese werden
1264 |*		durch diese Funktion beseitigt.
1265 |*
1266 |*	Parameter
1267 |*		IN
1268 |*		SwIndex &rIndex bezeichnet die Position, an der
1269 |*		geloescht wird
1270 |*		rIndex ist nach Aufruf der Funktion unveraendert (Kopie?!)
1271 |*		sal_uInt16 nNodes bezeichnet die Anzahl der zu loeschenden
1272 |*		Nodes; ist auf 1 defaulted
1273 |*
1274 |*	Debug-Funktionen
1275 |*		geben beim Eintritt in die Funktion Position und Anzahl
1276 |*		der zu loeschenden Nodes aus.
1277 |*
1278 |*	Ersterstellung
1279 |*		VER0100 vb 901214
1280 |*
1281 |*	Stand
1282 |*		VER0100 vb 901214
1283 |*
1284 *******************************************************************/
1285 void SwNodes::Delete(const SwNodeIndex &rIndex, sal_uLong nNodes)
1286 {
1287 	sal_uInt16 nLevel = 0;						// Level-Counter
1288 	SwNode * pAktNode;
1289 
1290 	sal_uLong nCnt = Count() - rIndex.GetIndex() - 1;
1291 	if( nCnt > nNodes ) nCnt = nNodes;
1292 
1293 	if( nCnt == 0 ) 		// keine Anzahl -> return
1294 		return;
1295 
1296 	SwNodeRange aRg( rIndex, 0, rIndex, nCnt-1 );
1297 	// ueberprufe ob rIndex..rIndex + nCnt ueber einen Bereich hinausragt !!
1298 	if( ( !aRg.aStart.GetNode().StartOfSectionIndex() &&
1299 			!aRg.aStart.GetIndex() ) ||
1300 			! CheckNodesRange( aRg.aStart, aRg.aEnd ) )
1301 		return;
1302 
1303 
1304 	// falls aEnd auf keinem ContentNode steht, dann suche den vorherigen
1305 	while( ( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() ||
1306 			 ( pAktNode->GetEndNode() &&
1307 				!pAktNode->pStartOfSection->IsTableNode() ))
1308 		aRg.aEnd--;
1309 
1310 	nCnt = 0;
1311 	// Start erhoehen, damit auf < abgefragt wird. ( bei <= kann es zu
1312 	// Problemen fuehren; ist aEnd == aStart und wird aEnd geloscht,
1313 	// so ist aEnd <= aStart
1314 	aRg.aStart--;
1315 
1316 	sal_Bool bSaveInNodesDel = bInNodesDel;
1317 	bInNodesDel = sal_True;
1318 	sal_Bool bUpdateOutline = sal_False;
1319 
1320 	// bis alles geloescht ist
1321 	while( aRg.aStart < aRg.aEnd )
1322 	{
1323 		pAktNode = &aRg.aEnd.GetNode();
1324 
1325 		if( pAktNode->GetEndNode() )
1326 		{
1327 			// die gesamte Section loeschen ?
1328 			if( pAktNode->StartOfSectionIndex() > aRg.aStart.GetIndex() )
1329 			{
1330 				SwTableNode* pTblNd = pAktNode->pStartOfSection->GetTableNode();
1331 				if( pTblNd )
1332 					pTblNd->DelFrms();
1333 
1334 				SwNode *pNd, *pChkNd = pAktNode->pStartOfSection;
1335 				sal_uInt16 nIdxPos;
1336 				do {
1337 					pNd = &aRg.aEnd.GetNode();
1338 
1339 					if( pNd->IsTxtNode() )
1340 					{
1341 						//if( NO_NUMBERING !=					//#outline level,zhaojianwei
1342 						//	((SwTxtNode*)pNd)->GetTxtColl()->GetOutlineLevel() &&
1343 						if( 0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel() &&//<-end,zhaojianwei
1344 								pOutlineNds->Seek_Entry( pNd, &nIdxPos ))
1345 						{
1346 							// loesche die Gliederungs-Indizies.
1347 							pOutlineNds->Remove( nIdxPos );
1348 							bUpdateOutline = sal_True;
1349 						}
1350                         ((SwTxtNode*)pNd)->InvalidateNumRule();
1351 					}
1352 					else if( pNd->IsEndNode() &&
1353 							pNd->pStartOfSection->IsTableNode() )
1354 						((SwTableNode*)pNd->pStartOfSection)->DelFrms();
1355 
1356 					aRg.aEnd--;
1357 					nCnt++;
1358 
1359 				} while( pNd != pChkNd );
1360 			}
1361 			else
1362 			{
1363 				RemoveNode( aRg.aEnd.GetIndex()+1, nCnt, sal_True );	// loesche
1364 				nCnt = 0;
1365 				aRg.aEnd--;				// vor den EndNode
1366 				nLevel++;
1367 			}
1368 		}
1369 		else if( pAktNode->GetStartNode() )	  // StartNode gefunden
1370 		{
1371 			if( nLevel == 0 )		// es wird eine Stufe runter gestuft
1372 			{
1373 				if( nCnt )
1374 				{
1375 					// loesche jetzt das Array
1376 					aRg.aEnd++;
1377 					RemoveNode( aRg.aEnd.GetIndex(), nCnt, sal_True );
1378 					nCnt = 0;
1379 				}
1380 			}
1381 			else	// es werden alle Nodes Innerhalb eines Start- und
1382 			{		// End-Nodes geloescht, loesche mit Start/EndNode
1383 				RemoveNode( aRg.aEnd.GetIndex(), nCnt + 2, sal_True );			// loesche Array
1384 				nCnt = 0;
1385 				nLevel--;
1386 			}
1387 
1388 			// nach dem loeschen kann aEnd auf einem EndNode stehen
1389 			// loesche alle leeren Start-/End-Node-Paare
1390 			SwNode* pTmpNode = aRg.aEnd.GetNode().GetEndNode();
1391 			aRg.aEnd--;
1392 			while(  pTmpNode &&
1393 					( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() &&
1394 					pAktNode->StartOfSectionIndex() )
1395 			{
1396 				// loesche den EndNode und StartNode
1397 				DelNodes( aRg.aEnd, 2 );
1398 				pTmpNode = aRg.aEnd.GetNode().GetEndNode();
1399 				aRg.aEnd--;
1400 			}
1401 		}
1402 		else		// normaler Node, also ins TmpArray einfuegen
1403 		{
1404 			SwTxtNode* pTxtNd = pAktNode->GetTxtNode();
1405 			if( pTxtNd )
1406 			{
1407 				if( pTxtNd->IsOutline())
1408 				{					// loesche die Gliederungs-Indizies.
1409 					pOutlineNds->Remove( pTxtNd );
1410 					bUpdateOutline = sal_True;
1411 				}
1412 				pTxtNd->InvalidateNumRule();
1413 			}
1414 			else if( pAktNode->IsCntntNode() )
1415 				((SwCntntNode*)pAktNode)->InvalidateNumRule();
1416 
1417 			aRg.aEnd--;
1418 			nCnt++;
1419 		}
1420 	}
1421 
1422 	aRg.aEnd++;
1423 	if( nCnt != 0 )
1424 		RemoveNode( aRg.aEnd.GetIndex(), nCnt, sal_True );				// loesche den Rest
1425 
1426 	// loesche alle leeren Start-/End-Node-Paare
1427 	while( aRg.aEnd.GetNode().GetEndNode() &&
1428 			( pAktNode = &aRg.aStart.GetNode())->GetStartNode() &&
1429 			pAktNode->StartOfSectionIndex() )
1430 	// aber ja keinen der heiligen 5.
1431 	{
1432 		DelNodes( aRg.aStart, 2 );	// loesche den Start- und EndNode
1433 		aRg.aStart--;
1434 	}
1435 
1436 	bInNodesDel = bSaveInNodesDel;
1437 
1438 	if( !bInNodesDel )
1439 	{
1440 		// rufe jetzt noch das Update fuer die Gliederung/Nummerierung auf
1441 		if( bUpdateOutline || bInDelUpdOutl )
1442 		{
1443 			UpdtOutlineIdx( aRg.aEnd.GetNode() );
1444 			bInDelUpdOutl = sal_False;
1445 		}
1446 
1447 	}
1448 	else
1449 	{
1450 		if( bUpdateOutline )
1451 			bInDelUpdOutl = sal_True;
1452 	}
1453 }
1454 
1455 /*******************************************************************
1456 |*
1457 |*	SwNodes::GetSectionLevel
1458 |*
1459 |*	Beschreibung
1460 |*		Die Funktion liefert den Sectionlevel an der durch
1461 |*		aIndex bezeichneten Position. Die Funktion ruft die
1462 |*		GetSectionlevel-Funktion des durch aIndex bezeichneten
1463 |*		Nodes. Diese ist eine virtuelle Funktion, die fuer
1464 |*		Endnodes speziell implementiert werden musste.
1465 |*		Die Sectionlevels werden ermittelt, indem rekursiv durch
1466 |*		die Nodesstruktur (jeweils zum naechsten theEndOfSection)
1467 |*		gegangen wird, bis die oberste Ebene erreicht ist
1468 |*		(theEndOfSection == 0)
1469 |*
1470 |*	Parameter
1471 |*		aIndex bezeichnet die Position des Nodes, dessen
1472 |*		Sectionlevel ermittelt werden soll. Hier wird eine Kopie
1473 |*		uebergeben, da eine Veraenderung der Variablen in der
1474 |*		rufenden Funktion nicht wuenschenswert ist.
1475 |*
1476 |*	Ausnahmen
1477 |*		Der erste Node im Array  sollte immer ein Startnode sein.
1478 |*		Dieser erfaehrt in der Funktion SwNodes::GetSectionLevel()
1479 |*      eine Sonderbehandlung; es wird davon ausgegangen, dass der
1480 |*		erste Node auch ein Startnode ist.
1481 |*
1482 |*	Ersterstellung
1483 |*		VER0100 vb 901214
1484 |*
1485 |*	Stand
1486 |*		VER0100 vb 901214
1487 |*
1488 *******************************************************************/
1489 sal_uInt16 SwNodes::GetSectionLevel(const SwNodeIndex &rIdx) const {
1490 	// Sonderbehandlung 1. Node
1491 	if(rIdx == 0) return 1;
1492 	/*
1493 	 * Keine Rekursion! - hier wird das SwNode::GetSectionLevel
1494 	 * aufgerufen
1495 	 */
1496     return rIdx.GetNode().GetSectionLevel();
1497 }
1498 
1499 void SwNodes::GoStartOfSection(SwNodeIndex *pIdx) const
1500 {
1501 	// hinter den naechsten Startnode
1502 	SwNodeIndex aTmp( *pIdx->GetNode().StartOfSectionNode(), +1 );
1503 
1504 	// steht der Index auf keinem ContentNode, dann gehe dahin. Ist aber
1505 	// kein weiterer vorhanden, dann lasse den Index an alter Pos stehen !!!
1506 	while( !aTmp.GetNode().IsCntntNode() )
1507 	{	// gehe vom StartNode ( es kann nur ein StartNode sein ! ) an sein
1508 		// Ende
1509 		if( *pIdx <= aTmp )
1510 			return; 	// FEHLER: Steht schon hinter der Sektion
1511 		aTmp = aTmp.GetNode().EndOfSectionIndex()+1;
1512 		if( *pIdx <= aTmp )
1513 			return; 	// FEHLER: Steht schon hinter der Sektion
1514 	}
1515 	(*pIdx) = aTmp; 	// steht auf einem ContentNode
1516 }
1517 
1518 void SwNodes::GoEndOfSection(SwNodeIndex *pIdx) const
1519 {
1520 	// falls er vor einem Endnode steht --> nichts tun
1521 	if( !pIdx->GetNode().IsEndNode() )
1522 		(*pIdx) = *pIdx->GetNode().EndOfSectionNode();
1523 }
1524 
1525 SwCntntNode* SwNodes::GoNext(SwNodeIndex *pIdx) const
1526 {
1527 	if( pIdx->GetIndex() >= Count() - 1 )
1528 		return 0;
1529 
1530 	SwNodeIndex aTmp(*pIdx, +1);
1531     SwNode* pNd = 0;
1532 	while( aTmp < Count()-1 && 0 == ( pNd = &aTmp.GetNode())->IsCntntNode() )
1533 		aTmp++;
1534 
1535 	if( aTmp == Count()-1 )
1536 		pNd = 0;
1537 	else
1538 		(*pIdx) = aTmp;
1539 	return (SwCntntNode*)pNd;
1540 }
1541 
1542 SwCntntNode* SwNodes::GoPrevious(SwNodeIndex *pIdx) const
1543 {
1544 	if( !pIdx->GetIndex() )
1545 		return 0;
1546 
1547 	SwNodeIndex aTmp( *pIdx, -1 );
1548 	SwNode* pNd = 0;
1549 	while( aTmp.GetIndex() && 0 == ( pNd = &aTmp.GetNode())->IsCntntNode() )
1550 		aTmp--;
1551 
1552 	if( !aTmp.GetIndex() )
1553 		pNd = 0;
1554 	else
1555 		(*pIdx) = aTmp;
1556 	return (SwCntntNode*)pNd;
1557 }
1558 
1559 /*************************************************************************
1560 |*
1561 |*	  sal_Bool SwNodes::CheckNodesRange()
1562 |*
1563 |*	  Beschreibung
1564 |*		Teste ob der uebergene SRange nicht ueber die Grenzen der
1565 |*		einzelnen Bereiche (PosIts, Autotext, Content, Icons und Inserts )
1566 |*		hinaus reicht.
1567 |*		Nach Wahrscheinlichkeit des Ranges sortiert.
1568 |*
1569 |*	Alg.: Da festgelegt ist, das aRange.aEnd den 1.Node hinter dem Bereich
1570 |*		  bezeichnet, wird hier auf aEnd <= End.. getestet !!
1571 |*
1572 |*	  Parameter 		SwIndex &	Start-Index vom Bereich
1573 |*						SwIndex &	End-Index vom Bereich
1574 |*                      sal_Bool		sal_True: 	Start+End in gleicher Section!
1575 |*									sal_False:	Start+End in verschiedenen Sect.
1576 |*	  Return-Wert		sal_Bool		sal_True:	gueltiger SRange
1577 |*									sal_False:	ungueltiger SRange
1578 |*
1579 |*	  Ersterstellung	JP 23.04.91
1580 |*	  Letzte Aenderung	JP 18.06.92
1581 |*
1582 *************************************************************************/
1583 
1584 inline int TstIdx( sal_uLong nSttIdx, sal_uLong nEndIdx, sal_uLong nStt, sal_uLong nEnd )
1585 {
1586 	return nStt < nSttIdx && nEnd >= nSttIdx &&
1587 			nStt < nEndIdx && nEnd >= nEndIdx;
1588 }
1589 
1590 sal_Bool SwNodes::CheckNodesRange( const SwNodeIndex& rStt, const SwNodeIndex& rEnd ) const
1591 {
1592 	sal_uLong nStt = rStt.GetIndex(), nEnd = rEnd.GetIndex();
1593 	if( TstIdx( nStt, nEnd, pEndOfContent->StartOfSectionIndex(),
1594 				pEndOfContent->GetIndex() )) return sal_True;
1595 	if( TstIdx( nStt, nEnd, pEndOfAutotext->StartOfSectionIndex(),
1596 				pEndOfAutotext->GetIndex() )) return sal_True;
1597 	if( TstIdx( nStt, nEnd, pEndOfPostIts->StartOfSectionIndex(),
1598 				pEndOfPostIts->GetIndex() )) return sal_True;
1599 	if( TstIdx( nStt, nEnd, pEndOfInserts->StartOfSectionIndex(),
1600 				pEndOfInserts->GetIndex() )) return sal_True;
1601 	if( TstIdx( nStt, nEnd, pEndOfRedlines->StartOfSectionIndex(),
1602 				pEndOfRedlines->GetIndex() )) return sal_True;
1603 
1604 	return sal_False;		// liegt irgendwo dazwischen, FEHLER
1605 }
1606 
1607 
1608 /*************************************************************************
1609 |*
1610 |*	  void SwNodes::DelNodes()
1611 |*
1612 |*	  Beschreibung
1613 |*		Loesche aus den NodesArray ab einer Position entsprechend Node's.
1614 |*
1615 |*	  Parameter 		SwIndex &	Der Startpunkt im Nodes-Array
1616 |*						sal_uInt16		die Anzahl
1617 |*
1618 |*	  Ersterstellung	JP 23.04.91
1619 |*	  Letzte Aenderung	JP 23.04.91
1620 |*
1621 *************************************************************************/
1622 void SwNodes::DelNodes( const SwNodeIndex & rStart, sal_uLong nCnt )
1623 {
1624 	int bUpdateNum = 0;
1625 	sal_uLong nSttIdx = rStart.GetIndex();
1626 
1627 	if( !nSttIdx && nCnt == GetEndOfContent().GetIndex()+1 )
1628 	{
1629 		// es wird das gesamte Nodes-Array zerstoert, man ist im Doc DTOR!
1630 		// Die initialen Start-/End-Nodes duerfen nur im SwNodes-DTOR
1631 		// zerstoert werden!
1632 		SwNode* aEndNdArr[] = { pEndOfContent,
1633 								pEndOfPostIts, pEndOfInserts,
1634 								pEndOfAutotext, pEndOfRedlines,
1635 								0
1636 							  };
1637 
1638 		SwNode** ppEndNdArr = aEndNdArr;
1639 		while( *ppEndNdArr )
1640 		{
1641 			nSttIdx = (*ppEndNdArr)->StartOfSectionIndex() + 1;
1642 			sal_uLong nEndIdx = (*ppEndNdArr)->GetIndex();
1643 
1644 			if( nSttIdx != nEndIdx )
1645 				RemoveNode( nSttIdx, nEndIdx - nSttIdx, sal_True );
1646 
1647 			++ppEndNdArr;
1648 		}
1649 	}
1650 	else
1651 	{
1652 		for( sal_uLong n = nSttIdx, nEnd = nSttIdx + nCnt; n < nEnd; ++n )
1653 		{
1654 			SwNode* pNd = (*this)[ n ];
1655 
1656 			if( pNd->IsTxtNode() &&
1657 				//NO_NUMBERING != ((SwTxtNode*)pNd)->GetTxtColl()->GetOutlineLevel() )//#outline level,zhaojianwei
1658 				0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel() )	//<-end,zhaojianwei
1659 			{                   // loesche die Gliederungs-Indizies.
1660 				sal_uInt16 nIdxPos;
1661 				if( pOutlineNds->Seek_Entry( pNd, &nIdxPos ))
1662 				{
1663 					pOutlineNds->Remove( nIdxPos );
1664 					bUpdateNum = 1;
1665 				}
1666 			}
1667 			if( pNd->IsCntntNode() )
1668             {
1669 				((SwCntntNode*)pNd)->InvalidateNumRule();
1670                 ((SwCntntNode*)pNd)->DelFrms();
1671             }
1672 		}
1673 		RemoveNode( nSttIdx, nCnt, sal_True );
1674 
1675 		// rufe noch das Update fuer die Gliederungsnumerierung auf
1676 		if( bUpdateNum )
1677 			UpdtOutlineIdx( rStart.GetNode() );
1678 	}
1679 }
1680 
1681 
1682 /*************************************************************************
1683 |*
1684 |*	  sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange )
1685 |*
1686 |*	  Beschreibung
1687 |*		Berechne den hoehsten Level innerhalb des Bereiches
1688 |*
1689 |*	  Parameter 		SwNodes &	das Node-Array
1690 |*						SwNodeRange &	der zu ueberpruefende Bereich
1691 |*	  Return			sal_uInt16		der hoechste Level
1692 |*
1693 |*	  Ersterstellung	JP 24.04.91
1694 |*	  Letzte Aenderung	JP 24.04.91
1695 |*
1696 *************************************************************************/
1697 
1698 struct HighLevel
1699 {
1700 	sal_uInt16 nLevel, nTop;
1701 	HighLevel( sal_uInt16 nLv ) : nLevel( nLv ), nTop( nLv ) {}
1702 
1703 };
1704 
1705 sal_Bool _HighestLevel( const SwNodePtr& rpNode, void * pPara )
1706 {
1707 	HighLevel * pHL = (HighLevel*)pPara;
1708 	if( rpNode->GetStartNode() )
1709 		pHL->nLevel++;
1710 	else if( rpNode->GetEndNode() )
1711 		pHL->nLevel--;
1712 	if( pHL->nTop > pHL->nLevel )
1713 		pHL->nTop = pHL->nLevel;
1714 	return sal_True;
1715 
1716 }
1717 
1718 sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange )
1719 {
1720 	HighLevel aPara( rNodes.GetSectionLevel( rRange.aStart ));
1721 	rNodes.ForEach( rRange.aStart, rRange.aEnd, _HighestLevel, &aPara );
1722 	return aPara.nTop;
1723 
1724 }
1725 
1726 /*************************************************************************
1727 |*
1728 |*    SwNodes::Move()
1729 |*
1730 |*    Beschreibung
1731 |*    Parameter         SwPaM&		zu kopierender Bereich
1732 |*                      SwNodes&	in dieses Nodes-Array
1733 |*                      SwPosition&	auf diese Position im Nodes-Array
1734 |*    Ersterstellung    JP 09.07.92
1735 |*    Letzte Aenderung  JP 09.07.92
1736 |*
1737 *************************************************************************/
1738 void SwNodes::MoveRange( SwPaM & rPam, SwPosition & rPos, SwNodes& rNodes )
1739 {
1740     SwPosition * const pStt = rPam.Start();
1741     SwPosition * const pEnd = rPam.End();
1742 
1743 	if( !rPam.HasMark() || *pStt >= *pEnd )
1744 		return;
1745 
1746 	if( this == &rNodes && *pStt <= rPos && rPos < *pEnd )
1747 		return;
1748 
1749 	SwNodeIndex aEndIdx( pEnd->nNode );
1750 	SwNodeIndex aSttIdx( pStt->nNode );
1751     SwTxtNode *const pSrcNd = aSttIdx.GetNode().GetTxtNode();
1752     SwTxtNode * pDestNd = rPos.nNode.GetNode().GetTxtNode();
1753 	sal_Bool bSplitDestNd = sal_True;
1754 	sal_Bool bCopyCollFmt = pDestNd && !pDestNd->GetTxt().Len();
1755 
1756 	if( pSrcNd )
1757 	{
1758 		// ist der 1.Node ein TextNode, dann muss im NodesArray auch
1759 		// ein TextNode vorhanden sein, in den der Inhalt geschoben wird
1760 		if( !pDestNd )
1761 		{
1762 			pDestNd = rNodes.MakeTxtNode( rPos.nNode, pSrcNd->GetTxtColl() );
1763 			rPos.nNode--;
1764 			rPos.nContent.Assign( pDestNd, 0 );
1765 			bCopyCollFmt = sal_True;
1766 		}
1767 		bSplitDestNd = pDestNd->Len() > rPos.nContent.GetIndex() ||
1768 						pEnd->nNode.GetNode().IsTxtNode();
1769 
1770 		// verschiebe jetzt noch den Inhalt in den neuen Node
1771 		sal_Bool bOneNd = pStt->nNode == pEnd->nNode;
1772         const xub_StrLen nLen =
1773                 ( (bOneNd) ? pEnd->nContent.GetIndex() : pSrcNd->Len() )
1774                 - pStt->nContent.GetIndex();
1775 
1776 		if( !pEnd->nNode.GetNode().IsCntntNode() )
1777 		{
1778 			bOneNd = sal_True;
1779             sal_uLong nSttNdIdx = pStt->nNode.GetIndex() + 1;
1780             const sal_uLong nEndNdIdx = pEnd->nNode.GetIndex();
1781 			for( ; nSttNdIdx < nEndNdIdx; ++nSttNdIdx )
1782             {
1783 				if( (*this)[ nSttNdIdx ]->IsCntntNode() )
1784 				{
1785 					bOneNd = sal_False;
1786 					break;
1787 				}
1788             }
1789 		}
1790 
1791 		// das kopieren / setzen der Vorlagen darf erst nach
1792 		// dem Splitten erfolgen
1793 		if( !bOneNd && bSplitDestNd )
1794 		{
1795             if( !rPos.nContent.GetIndex() )
1796             {
1797                 bCopyCollFmt = sal_True;
1798             }
1799 			if( rNodes.IsDocNodes() )
1800 			{
1801                 SwDoc* const pInsDoc = pDestNd->GetDoc();
1802                 ::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo());
1803 				pInsDoc->SplitNode( rPos, false );
1804             }
1805             else
1806             {
1807                 pDestNd->SplitCntntNode( rPos );
1808             }
1809 
1810 			if( rPos.nNode == aEndIdx )
1811             {
1812 				aEndIdx--;
1813             }
1814 			bSplitDestNd = sal_True;
1815 
1816 			pDestNd = rNodes[ rPos.nNode.GetIndex() - 1 ]->GetTxtNode();
1817 			if( nLen )
1818             {
1819                 pSrcNd->CutText( pDestNd, SwIndex( pDestNd, pDestNd->Len()),
1820                             pStt->nContent, nLen );
1821             }
1822         }
1823         else if ( nLen )
1824         {
1825             pSrcNd->CutText( pDestNd, rPos.nContent, pStt->nContent, nLen );
1826         }
1827 
1828 		if( bCopyCollFmt )
1829 		{
1830             SwDoc* const pInsDoc = pDestNd->GetDoc();
1831             ::sw::UndoGuard const undoGuard(pInsDoc->GetIDocumentUndoRedo());
1832 			pSrcNd->CopyCollFmt( *pDestNd );
1833             bCopyCollFmt = sal_False;
1834 		}
1835 
1836 		if( bOneNd )		// das wars schon
1837 		{
1838 			// der PaM wird korrigiert, denn falls ueber Nodegrenzen verschoben
1839 			// wurde, so stehen sie in unterschieden Nodes. Auch die Selektion
1840 			// wird aufgehoben !
1841 			pEnd->nContent = pStt->nContent;
1842 			rPam.DeleteMark();
1843             GetDoc()->GetDocShell()->Broadcast( SwFmtFldHint( 0,
1844                 rNodes.IsDocNodes() ? SWFMTFLD_INSERTED : SWFMTFLD_REMOVED ) );
1845 			return;
1846 		}
1847 
1848 		aSttIdx++;
1849 	}
1850 	else if( pDestNd )
1851 	{
1852 		if( rPos.nContent.GetIndex() )
1853 		{
1854 			if( rPos.nContent.GetIndex() == pDestNd->Len() )
1855             {
1856 				rPos.nNode++;
1857             }
1858 			else if( rPos.nContent.GetIndex() )
1859 			{
1860 				// falls im EndNode gesplittet wird, dann muss der EndIdx
1861 				// korrigiert werden !!
1862                 const bool bCorrEnd = aEndIdx == rPos.nNode;
1863 				// es wird kein Text an den TextNode angehaengt, also splitte ihn
1864 
1865 				if( rNodes.IsDocNodes() )
1866 				{
1867                     SwDoc* const pInsDoc = pDestNd->GetDoc();
1868                     ::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo());
1869 					pInsDoc->SplitNode( rPos, false );
1870                 }
1871                 else
1872                 {
1873                     pDestNd->SplitCntntNode( rPos );
1874                 }
1875 
1876 				pDestNd = rPos.nNode.GetNode().GetTxtNode();
1877 
1878                 if ( bCorrEnd )
1879                 {
1880 					aEndIdx--;
1881                 }
1882 			}
1883 		}
1884 		// am Ende steht noch ein leerer Text Node herum.
1885 		bSplitDestNd = sal_True;
1886 	}
1887 
1888     SwTxtNode* const pEndSrcNd = aEndIdx.GetNode().GetTxtNode();
1889     if ( pEndSrcNd )
1890 	{
1891 		{
1892 			// am Bereichsende entsteht ein neuer TextNode
1893 			if( !bSplitDestNd )
1894 			{
1895 				if( rPos.nNode < rNodes.GetEndOfContent().GetIndex() )
1896                 {
1897 					rPos.nNode++;
1898                 }
1899 
1900                 pDestNd =
1901                     rNodes.MakeTxtNode( rPos.nNode, pEndSrcNd->GetTxtColl() );
1902 				rPos.nNode--;
1903 				rPos.nContent.Assign( pDestNd, 0 );
1904 			}
1905 			else
1906             {
1907                 pDestNd = rPos.nNode.GetNode().GetTxtNode();
1908             }
1909 
1910 			if( pDestNd && pEnd->nContent.GetIndex() )
1911 			{
1912 				// verschiebe jetzt noch den Inhalt in den neuen Node
1913                 SwIndex aIdx( pEndSrcNd, 0 );
1914                 pEndSrcNd->CutText( pDestNd, rPos.nContent, aIdx,
1915 								pEnd->nContent.GetIndex());
1916 			}
1917 
1918 			if( bCopyCollFmt )
1919 			{
1920                 SwDoc* const pInsDoc = pDestNd->GetDoc();
1921                 ::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo());
1922                 pEndSrcNd->CopyCollFmt( *pDestNd );
1923             }
1924         }
1925     }
1926     else
1927     {
1928         if ( pSrcNd && aEndIdx.GetNode().IsCntntNode() )
1929         {
1930 			aEndIdx++;
1931         }
1932 		if( !bSplitDestNd )
1933 		{
1934 			rPos.nNode++;
1935 			rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), 0 );
1936 		}
1937 	}
1938 
1939 	if( aEndIdx != aSttIdx )
1940 	{
1941 		// verschiebe jetzt die Nodes in das NodesArary
1942         const sal_uLong nSttDiff = aSttIdx.GetIndex() - pStt->nNode.GetIndex();
1943 		SwNodeRange aRg( aSttIdx, aEndIdx );
1944 		_MoveNodes( aRg, rNodes, rPos.nNode );
1945 		// falls ins gleiche Nodes-Array verschoben wurde, stehen die
1946 		// Indizies jetzt auch an der neuen Position !!!!
1947 		// (also alles wieder umsetzen)
1948 		if( &rNodes == this )
1949         {
1950 			pStt->nNode = aRg.aEnd.GetIndex() - nSttDiff;
1951         }
1952 	}
1953 
1954 	// falls der Start-Node verschoben wurde, in dem der Cursor stand, so
1955 	// muss der Content im akt. Content angemeldet werden !!!
1956     if ( &pStt->nNode.GetNode() == &GetEndOfContent() )
1957     {
1958         const bool bSuccess = GoPrevious( &pStt->nNode );
1959         ASSERT( bSuccess, "Move() - no ContentNode here" );
1960         (void) bSuccess;
1961 	}
1962     pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(),
1963 							pStt->nContent.GetIndex() );
1964 	// der PaM wird korrigiert, denn falls ueber Nodegrenzen verschoben
1965 	// wurde, so stehen sie in unterschielichen Nodes. Auch die Selektion
1966 	// wird aufgehoben !
1967 	*pEnd = *pStt;
1968 	rPam.DeleteMark();
1969     GetDoc()->GetDocShell()->Broadcast( SwFmtFldHint( 0,
1970                 rNodes.IsDocNodes() ? SWFMTFLD_INSERTED : SWFMTFLD_REMOVED ) );
1971 }
1972 
1973 
1974 
1975 /*************************************************************************
1976 |*
1977 |*    SwNodes::_Copy()
1978 |*
1979 |*    Beschreibung
1980 |*    Parameter         SwNodeRange&	zu kopierender Bereich
1981 |*                      SwDoc&		in dieses Dokument
1982 |*                      SwIndex&	auf diese Position im Nodes-Array
1983 |*    Ersterstellung    JP 11.11.92
1984 |*    Letzte Aenderung  JP 11.11.92
1985 |*
1986 *************************************************************************/
1987 
1988 inline sal_uInt8 MaxLvl( sal_uInt8 nMin, sal_uInt8 nMax, short nNew )
1989 {
1990 	return (sal_uInt8)(nNew < nMin ? nMin : nNew > nMax ? nMax : nNew);
1991 }
1992 
1993 void SwNodes::_CopyNodes( const SwNodeRange& rRange,
1994 			const SwNodeIndex& rIndex, sal_Bool bNewFrms, sal_Bool bTblInsDummyNode ) const
1995 {
1996 	SwDoc* pDoc = rIndex.GetNode().GetDoc();
1997 
1998 	SwNode * pAktNode;
1999 	if( rIndex == 0 ||
2000 		( (pAktNode = &rIndex.GetNode())->GetStartNode() &&
2001 		  !pAktNode->StartOfSectionIndex() ))
2002 		return;
2003 
2004 	SwNodeRange aRg( rRange );
2005 
2006 	// "einfache" StartNodes oder EndNodes ueberspringen
2007     while( ND_STARTNODE == (pAktNode = & aRg.aStart.GetNode())->GetNodeType()
2008 			|| ( pAktNode->IsEndNode() &&
2009 				!pAktNode->pStartOfSection->IsSectionNode() ) )
2010 		aRg.aStart++;
2011 
2012 	// falls aEnd-1 auf keinem ContentNode steht, dann suche den vorherigen
2013 	aRg.aEnd--;
2014     // #i107142#: if aEnd is start node of a special section, do nothing.
2015     // Otherwise this could lead to crash: going through all previous
2016     // special section nodes and then one before the first.
2017     if (aRg.aEnd.GetNode().StartOfSectionIndex() != 0)
2018     {
2019         while( ((pAktNode = & aRg.aEnd.GetNode())->GetStartNode() &&
2020                 !pAktNode->IsSectionNode() ) ||
2021                 ( pAktNode->IsEndNode() &&
2022                 ND_STARTNODE == pAktNode->pStartOfSection->GetNodeType()) )
2023         {
2024             aRg.aEnd--;
2025         }
2026     }
2027 	aRg.aEnd++;
2028 
2029 	// wird im selben Array's verschoben, dann ueberpruefe die Einfuegepos.
2030 	if( aRg.aStart >= aRg.aEnd )
2031 		return;
2032 
2033     // when inserting into the source range, nothing need to be done
2034     DBG_ASSERT( &aRg.aStart.GetNodes() == this,
2035                 "aRg should use thisnodes array" );
2036     DBG_ASSERT( &aRg.aStart.GetNodes() == &aRg.aEnd.GetNodes(),
2037                "Range across different nodes arrays? You deserve punishment!");
2038     if( &rIndex.GetNodes() == &aRg.aStart.GetNodes() &&
2039 		rIndex.GetIndex() >= aRg.aStart.GetIndex() &&
2040 		rIndex.GetIndex() < aRg.aEnd.GetIndex() )
2041 			return;
2042 
2043 	SwNodeIndex aInsPos( rIndex );
2044 	SwNodeIndex aOrigInsPos( rIndex, -1 );			// Originale Insert Pos
2045 	sal_uInt16 nLevel = 0;							// Level-Counter
2046 
2047 	for( sal_uLong nNodeCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
2048 			nNodeCnt > 0; --nNodeCnt )
2049 	{
2050 		pAktNode = &aRg.aStart.GetNode();
2051 		switch( pAktNode->GetNodeType() )
2052 		{
2053 		case ND_TABLENODE:
2054 			// dann kopiere mal den TableNode
2055 			// Tabell in Fussnote kopieren ?
2056 			if( aInsPos < pDoc->GetNodes().GetEndOfInserts().GetIndex() &&
2057 					pDoc->GetNodes().GetEndOfInserts().StartOfSectionIndex()
2058 					< aInsPos.GetIndex() )
2059 			{
2060 				nNodeCnt -=
2061 					( pAktNode->EndOfSectionIndex() -
2062 						aRg.aStart.GetIndex() );
2063 
2064 				// dann alle Nodes der Tabelle in die akt. Zelle kopieren
2065 				// fuer den TabellenNode einen DummyNode einfuegen?
2066 				if( bTblInsDummyNode )
2067 					new SwNode( aInsPos, ND_SECTIONDUMMY );
2068 
2069 				for( aRg.aStart++; aRg.aStart.GetIndex() <
2070 					pAktNode->EndOfSectionIndex();
2071 					aRg.aStart++ )
2072 				{
2073 					// fuer den Box-StartNode einen DummyNode einfuegen?
2074 					if( bTblInsDummyNode )
2075 						new SwNode( aInsPos, ND_SECTIONDUMMY );
2076 
2077 					SwStartNode* pSttNd = aRg.aStart.GetNode().GetStartNode();
2078 					_CopyNodes( SwNodeRange( *pSttNd, + 1,
2079 											*pSttNd->EndOfSectionNode() ),
2080 								aInsPos, bNewFrms, sal_False );
2081 
2082 					// fuer den Box-EndNode einen DummyNode einfuegen?
2083 					if( bTblInsDummyNode )
2084 						new SwNode( aInsPos, ND_SECTIONDUMMY );
2085 					aRg.aStart = *pSttNd->EndOfSectionNode();
2086 				}
2087 				// fuer den TabellenEndNode einen DummyNode einfuegen?
2088 				if( bTblInsDummyNode )
2089 					new SwNode( aInsPos, ND_SECTIONDUMMY );
2090 				aRg.aStart = *pAktNode->EndOfSectionNode();
2091 			}
2092 			else
2093 			{
2094 				SwNodeIndex nStt( aInsPos, -1 );
2095 				SwTableNode* pTblNd = ((SwTableNode*)pAktNode)->
2096 										MakeCopy( pDoc, aInsPos );
2097 				nNodeCnt -= aInsPos.GetIndex() - nStt.GetIndex() -2;
2098 
2099 				aRg.aStart = pAktNode->EndOfSectionIndex();
2100 
2101 				if( bNewFrms && pTblNd )
2102 				{
2103 					nStt = aInsPos;
2104 					pTblNd->MakeFrms( &nStt );
2105 				}
2106 			}
2107 			break;
2108 
2109 		case ND_SECTIONNODE:			// SectionNode
2110             // If the end of the section is outside the copy range,
2111             // the section node will skipped, not copied!
2112             // If someone want to change this behaviour, he has to adjust the function
2113             // lcl_NonCopyCount(..) in ndcopy.cxx which relies on it.
2114             if( pAktNode->EndOfSectionIndex() < aRg.aEnd.GetIndex() )
2115 			{
2116 				// also der gesamte, lege einen neuen SectionNode an
2117 				SwNodeIndex nStt( aInsPos, -1 );
2118 				SwSectionNode* pSectNd = ((SwSectionNode*)pAktNode)->
2119 									MakeCopy( pDoc, aInsPos );
2120 
2121 				nNodeCnt -= aInsPos.GetIndex() - nStt.GetIndex() -2;
2122 				aRg.aStart = pAktNode->EndOfSectionIndex();
2123 
2124 				if( bNewFrms && pSectNd &&
2125 					!pSectNd->GetSection().IsHidden() )
2126 					pSectNd->MakeFrms( &nStt );
2127 			}
2128 			break;
2129 
2130 		case ND_STARTNODE:				// StartNode gefunden
2131 			{
2132 				SwStartNode* pTmp = new SwStartNode( aInsPos, ND_STARTNODE,
2133 							((SwStartNode*)pAktNode)->GetStartNodeType() );
2134 				new SwEndNode( aInsPos, *pTmp );
2135 				aInsPos--;
2136 				nLevel++;
2137 			}
2138 			break;
2139 
2140 		case ND_ENDNODE:
2141 			if( nLevel )						// vollstaendige Section
2142 			{
2143 				--nLevel;
2144 				aInsPos++;						// EndNode schon vorhanden
2145 			}
2146 			else if( !pAktNode->pStartOfSection->IsSectionNode() )
2147 			{
2148 				// erzeuge eine Section an der originalen InsertPosition
2149 				SwNodeRange aTmpRg( aOrigInsPos, 1, aInsPos );
2150 				pDoc->GetNodes().SectionDown( &aTmpRg,
2151 						pAktNode->pStartOfSection->GetStartNodeType() );
2152 			}
2153 			break;
2154 
2155 		case ND_TEXTNODE:
2156 		case ND_GRFNODE:
2157 		case ND_OLENODE:
2158 			{
2159 				SwCntntNode* pNew = ((SwCntntNode*)pAktNode)->MakeCopy(
2160 											pDoc, aInsPos );
2161 				if( !bNewFrms )	    	// dflt. werden die Frames immer angelegt
2162 					pNew->DelFrms();
2163 			}
2164 			break;
2165 
2166 		case ND_SECTIONDUMMY:
2167             if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this))
2168             {
2169 				// dann muss an der akt. InsPos auch ein SectionNode
2170 				// (Start/Ende) stehen; dann diesen ueberspringen.
2171 				// Andernfalls nicht weiter beachten.
2172                 SwNode *const pTmpNd = & aInsPos.GetNode();
2173 				if( pTmpNd->IsSectionNode() ||
2174                     pTmpNd->StartOfSectionNode()->IsSectionNode() )
2175 					aInsPos++;	// ueberspringen
2176 			}
2177 			else {
2178 				ASSERT( sal_False, "wie kommt diser Node ins Nodes-Array??" );
2179             }
2180 			break;
2181 
2182 		default:
2183 			ASSERT( sal_False, "weder Start-/End-/Content-Node, unbekannter Typ" );
2184 		}
2185 		aRg.aStart++;
2186 	}
2187 
2188 
2189 #ifdef JP_DEBUG
2190 	{
2191 extern Writer* GetDebugWriter(const String&);
2192 
2193 		Writer* pWriter = GetDebugWriter(aEmptyStr);
2194 		if( pWriter )
2195 		{
2196 			int nError;
2197 			SvFileStream aStrm( "c:\\$$copy.db", STREAM_WRITE );
2198 			SwWriter aWriter( aStrm, *pMyDoc );
2199 			aWriter.Write( &nError, pWriter );
2200 		}
2201 	}
2202 #endif
2203 }
2204 
2205 void SwNodes::_DelDummyNodes( const SwNodeRange& rRg )
2206 {
2207 	SwNodeIndex aIdx( rRg.aStart );
2208 	while( aIdx.GetIndex() < rRg.aEnd.GetIndex() )
2209 	{
2210 		if( ND_SECTIONDUMMY == aIdx.GetNode().GetNodeType() )
2211 			RemoveNode( aIdx.GetIndex(), 1, sal_True );
2212 		else
2213 			aIdx++;
2214 	}
2215 }
2216 
2217 SwStartNode* SwNodes::MakeEmptySection( const SwNodeIndex& rIdx,
2218 										SwStartNodeType eSttNdTyp )
2219 {
2220 	SwStartNode* pSttNd = new SwStartNode( rIdx, ND_STARTNODE, eSttNdTyp );
2221 	new SwEndNode( rIdx, *pSttNd );
2222 	return pSttNd;
2223 }
2224 
2225 
2226 SwStartNode* SwNodes::MakeTextSection( const SwNodeIndex & rWhere,
2227 										SwStartNodeType eSttNdTyp,
2228 										SwTxtFmtColl *pColl,
2229 										SwAttrSet* pAutoAttr )
2230 {
2231 	SwStartNode* pSttNd = new SwStartNode( rWhere, ND_STARTNODE, eSttNdTyp );
2232 	new SwEndNode( rWhere, *pSttNd );
2233 	MakeTxtNode( SwNodeIndex( rWhere, - 1 ), pColl, pAutoAttr );
2234 	return pSttNd;
2235 }
2236 
2237 	// zum naechsten Content-Node, der nicht geschuetzt oder versteckt ist
2238 	// (beides auf sal_False ==> GoNext/GoPrevious!!!)
2239 SwCntntNode* SwNodes::GoNextSection( SwNodeIndex * pIdx,
2240 							int bSkipHidden, int bSkipProtect ) const
2241 {
2242 	int bFirst = sal_True;
2243 	SwNodeIndex aTmp( *pIdx );
2244 	const SwNode* pNd;
2245 	while( aTmp < Count() - 1 )
2246 	{
2247         pNd = & aTmp.GetNode();
2248         if (ND_SECTIONNODE == pNd->GetNodeType())
2249 		{
2250 			const SwSection& rSect = ((SwSectionNode*)pNd)->GetSection();
2251 			if( (bSkipHidden && rSect.IsHiddenFlag()) ||
2252 				(bSkipProtect && rSect.IsProtectFlag()) )
2253 				// dann diese Section ueberspringen
2254 				aTmp = *pNd->EndOfSectionNode();
2255 			bFirst = sal_False;
2256 		}
2257 		else if( bFirst )
2258 		{
2259 			bFirst = sal_False;
2260 			if( pNd->pStartOfSection->IsSectionNode() )
2261 			{
2262 				const SwSection& rSect = ((SwSectionNode*)pNd->
2263 								pStartOfSection)->GetSection();
2264 				if( (bSkipHidden && rSect.IsHiddenFlag()) ||
2265 					(bSkipProtect && rSect.IsProtectFlag()) )
2266 					// dann diese Section ueberspringen
2267 					aTmp = *pNd->EndOfSectionNode();
2268 			}
2269 		}
2270 		else if( ND_CONTENTNODE & pNd->GetNodeType() )
2271 		{
2272 			const SwSectionNode* pSectNd;
2273 			if( ( bSkipHidden || bSkipProtect ) &&
2274 				0 != (pSectNd = pNd->FindSectionNode() ) &&
2275 				( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) ||
2276 				  ( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) )
2277 			{
2278 				aTmp = *pSectNd->EndOfSectionNode();
2279 			}
2280 			else
2281 			{
2282 				(*pIdx) = aTmp;
2283 				return (SwCntntNode*)pNd;
2284 			}
2285 		}
2286 		aTmp++;
2287 		bFirst = sal_False;
2288 	}
2289 	return 0;
2290 }
2291 
2292 SwCntntNode* SwNodes::GoPrevSection( SwNodeIndex * pIdx,
2293 							int bSkipHidden, int bSkipProtect ) const
2294 {
2295 	int bFirst = sal_True;
2296 	SwNodeIndex aTmp( *pIdx );
2297 	const SwNode* pNd;
2298 	while( aTmp > 0 )
2299 	{
2300         pNd = & aTmp.GetNode();
2301         if (ND_ENDNODE == pNd->GetNodeType())
2302 		{
2303 			if( pNd->pStartOfSection->IsSectionNode() )
2304 			{
2305 				const SwSection& rSect = ((SwSectionNode*)pNd->
2306 											pStartOfSection)->GetSection();
2307 				if( (bSkipHidden && rSect.IsHiddenFlag()) ||
2308 					(bSkipProtect && rSect.IsProtectFlag()) )
2309 					// dann diese Section ueberspringen
2310 					aTmp = *pNd->StartOfSectionNode();
2311 			}
2312 			bFirst = sal_False;
2313 		}
2314 		else if( bFirst )
2315 		{
2316 			bFirst = sal_False;
2317 			if( pNd->pStartOfSection->IsSectionNode() )
2318 			{
2319 				const SwSection& rSect = ((SwSectionNode*)pNd->
2320 								pStartOfSection)->GetSection();
2321 				if( (bSkipHidden && rSect.IsHiddenFlag()) ||
2322 					(bSkipProtect && rSect.IsProtectFlag()) )
2323 					// dann diese Section ueberspringen
2324 					aTmp = *pNd->StartOfSectionNode();
2325 			}
2326 		}
2327 		else if( ND_CONTENTNODE & pNd->GetNodeType() )
2328 		{
2329 			const SwSectionNode* pSectNd;
2330 			if( ( bSkipHidden || bSkipProtect ) &&
2331 				0 != (pSectNd = pNd->FindSectionNode() ) &&
2332 				( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) ||
2333 				  ( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) )
2334 			{
2335 				aTmp = *pSectNd;
2336 			}
2337 			else
2338 			{
2339 				(*pIdx) = aTmp;
2340 				return (SwCntntNode*)pNd;
2341 			}
2342 		}
2343 		aTmp--;
2344 	}
2345 	return 0;
2346 }
2347 
2348 
2349 	// suche den vorhergehenden [/nachfolgenden ] ContentNode oder
2350 	// TabellenNode mit Frames. Wird kein Ende angeben, dann wird mit
2351 	// dem FrameIndex begonnen; ansonsten, wird mit dem vor rFrmIdx und
2352 	// dem hintern pEnd die Suche gestartet. Sollte kein gueltiger Node
2353 	// gefunden werden, wird 0 returnt. rFrmIdx zeigt auf dem Node mit
2354 	// Frames
2355 SwNode* SwNodes::FindPrvNxtFrmNode( SwNodeIndex& rFrmIdx,
2356 									const SwNode* pEnd ) const
2357 {
2358 	SwNode* pFrmNd = 0;
2359 
2360 	// habe wir gar kein Layout, vergiss es
2361 	if( GetDoc()->GetCurrentViewShell() )	//swmod 071108//swmod 071225
2362 	{
2363 		SwNode* pSttNd = &rFrmIdx.GetNode();
2364 
2365 		// wird in eine versteckte Section verschoben ??
2366 		SwSectionNode* pSectNd = pSttNd->IsSectionNode()
2367                     ? pSttNd->StartOfSectionNode()->FindSectionNode()
2368 					: pSttNd->FindSectionNode();
2369 		if( !( pSectNd && pSectNd->GetSection().CalcHiddenFlag()/*IsHiddenFlag()*/ ) )
2370 		{
2371             // #130650# in a table in table situation we have to assure that we don't leave the
2372             // outer table cell when the inner table is looking for a PrvNxt...
2373             SwTableNode* pTableNd = pSttNd->IsTableNode()
2374 					? pSttNd->StartOfSectionNode()->FindTableNode()
2375 					: pSttNd->FindTableNode();
2376 			SwNodeIndex aIdx( rFrmIdx );
2377 			SwNode* pNd;
2378 			if( pEnd )
2379 			{
2380 				aIdx--;
2381 				pNd = &aIdx.GetNode();
2382 			}
2383 			else
2384 				pNd = pSttNd;
2385 
2386 			if( ( pFrmNd = pNd )->IsCntntNode() )
2387 				rFrmIdx = aIdx;
2388 
2389 				// suche nach vorne/hinten nach einem Content Node
2390 			else if( 0 != ( pFrmNd = GoPrevSection( &aIdx, sal_True, sal_False )) &&
2391 					::CheckNodesRange( aIdx, rFrmIdx, sal_True ) &&
2392 					// nach vorne nie aus der Tabelle hinaus!
2393 					pFrmNd->FindTableNode() == pTableNd &&
2394 					// Bug 37652: nach hinten nie aus der Tabellenzelle hinaus!
2395 					(!pFrmNd->FindTableNode() || pFrmNd->FindTableBoxStartNode()
2396 						== pSttNd->FindTableBoxStartNode() ) &&
2397 					 (!pSectNd || pSttNd->IsSectionNode() ||
2398 					  pSectNd->GetIndex() < pFrmNd->GetIndex())
2399 					)
2400 			{
2401 				rFrmIdx = aIdx;
2402 			}
2403 			else
2404 			{
2405 				if( pEnd )
2406 					aIdx = pEnd->GetIndex() + 1;
2407 				else
2408 					aIdx = rFrmIdx;
2409 
2410 				// JP 19.09.93: aber nie die Section dafuer verlassen !!
2411 				if( ( pEnd && ( pFrmNd = &aIdx.GetNode())->IsCntntNode() ) ||
2412 					( 0 != ( pFrmNd = GoNextSection( &aIdx, sal_True, sal_False )) &&
2413 					::CheckNodesRange( aIdx, rFrmIdx, sal_True ) &&
2414 					( pFrmNd->FindTableNode() == pTableNd &&
2415 						// Bug 37652: nach hinten nie aus der Tabellenzelle hinaus!
2416 						(!pFrmNd->FindTableNode() || pFrmNd->FindTableBoxStartNode()
2417 						== pSttNd->FindTableBoxStartNode() ) ) &&
2418 					 (!pSectNd || pSttNd->IsSectionNode() ||
2419 					  pSectNd->EndOfSectionIndex() > pFrmNd->GetIndex())
2420 					))
2421 				{
2422 					//JP 18.02.99: Undo von Merge einer Tabelle mit der
2423 					// der vorherigen, wenn dahinter auch noch eine steht
2424 					// falls aber der Node in einer Tabelle steht, muss
2425 					// natuerlich dieser returnt werden, wenn der SttNode eine
2426 					// Section oder Tabelle ist!
2427 					SwTableNode* pTblNd;
2428 					if( pSttNd->IsTableNode() &&
2429 						0 != ( pTblNd = pFrmNd->FindTableNode() ) &&
2430                         // TABLE IN TABLE:
2431                         pTblNd != pSttNd->StartOfSectionNode()->FindTableNode() )
2432 					{
2433 						pFrmNd = pTblNd;
2434 						rFrmIdx = *pFrmNd;
2435 					}
2436 					else
2437 						rFrmIdx = aIdx;
2438 				}
2439                 else if( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() )
2440 				{
2441                     pFrmNd = pNd->StartOfSectionNode();
2442 					rFrmIdx = *pFrmNd;
2443 				}
2444 				else
2445 				{
2446 					if( pEnd )
2447 						aIdx = pEnd->GetIndex() + 1;
2448 					else
2449 						aIdx = rFrmIdx.GetIndex() + 1;
2450 
2451 					if( (pFrmNd = &aIdx.GetNode())->IsTableNode() )
2452 						rFrmIdx = aIdx;
2453 					else
2454 					{
2455 						pFrmNd = 0;
2456 
2457 						// is there some sectionnodes before a tablenode?
2458 						while( aIdx.GetNode().IsSectionNode() )
2459 						{
2460 							const SwSection& rSect = aIdx.GetNode().
2461 								GetSectionNode()->GetSection();
2462 							if( rSect.IsHiddenFlag() )
2463 								aIdx = aIdx.GetNode().EndOfSectionIndex()+1;
2464 							else
2465 								aIdx++;
2466 						}
2467 						if( aIdx.GetNode().IsTableNode() )
2468 						{
2469 							rFrmIdx = aIdx;
2470 							pFrmNd = &aIdx.GetNode();
2471 						}
2472 					}
2473 				}
2474 			}
2475 		}
2476 	}
2477 	return pFrmNd;
2478 }
2479 
2480 void SwNodes::ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd,
2481 					FnForEach_SwNodes fnForEach, void* pArgs )
2482 {
2483 	BigPtrArray::ForEach( rStart.GetIndex(), rEnd.GetIndex(),
2484 							(FnForEach) fnForEach, pArgs );
2485 }
2486 
2487 struct _TempBigPtrEntry : public BigPtrEntry
2488 {
2489 	_TempBigPtrEntry() {}
2490 };
2491 
2492 
2493 void SwNodes::RemoveNode( sal_uLong nDelPos, sal_uLong nSz, sal_Bool bDel )
2494 {
2495 	sal_uLong nEnd = nDelPos + nSz;
2496 	SwNode* pNew = (*this)[ nEnd ];
2497 
2498 	if( pRoot )
2499 	{
2500 		SwNodeIndex *p = pRoot;
2501 		while( p )
2502 		{
2503 			sal_uLong nIdx = p->GetIndex();
2504 			SwNodeIndex* pNext = p->pNext;
2505 			if( nDelPos <= nIdx && nIdx < nEnd )
2506 				(*p) = *pNew;
2507 
2508 			p = pNext;
2509 		}
2510 
2511 		p = pRoot->pPrev;
2512 		while( p )
2513 		{
2514 			sal_uLong nIdx = p->GetIndex();
2515 			SwNodeIndex* pPrev = p->pPrev;
2516 			if( nDelPos <= nIdx && nIdx < nEnd )
2517 				(*p) = *pNew;
2518 
2519 			p = pPrev;
2520 		}
2521 	}
2522 
2523     {
2524         for (sal_uLong nCnt = 0; nCnt < nSz; nCnt++)
2525         {
2526             SwTxtNode * pTxtNd = ((*this)[ nDelPos + nCnt ])->GetTxtNode();
2527 
2528             if (pTxtNd)
2529             {
2530                 // --> OD 2008-03-13 #refactorlists#
2531 //                pTxtNd->UnregisterNumber();
2532                 pTxtNd->RemoveFromList();
2533                 // <--
2534             }
2535         }
2536     }
2537 
2538 	if( bDel )
2539 	{
2540 		sal_uLong nCnt = nSz;
2541 		SwNode *pDel = (*this)[ nDelPos+nCnt-1 ], *pPrev = (*this)[ nDelPos+nCnt-2 ];
2542 
2543 // temp. Object setzen
2544 		//JP 24.08.98: muessten eigentlich einzeln removed werden, weil
2545 		//		das Remove auch rekursiv gerufen werden kann, z.B. bei
2546 		//		zeichengebundenen Rahmen. Da aber dabei viel zu viel
2547 		//		ablaueft, wird hier ein temp. Objekt eingefuegt, das
2548 		//		dann mit dem Remove wieder entfernt wird.
2549 		// siehe Bug 55406
2550 		_TempBigPtrEntry aTempEntry;
2551 		BigPtrEntry* pTempEntry = &aTempEntry;
2552 
2553 		while( nCnt-- )
2554 		{
2555 			delete pDel;
2556 			pDel = pPrev;
2557 			sal_uLong nPrevNdIdx = pPrev->GetIndex();
2558 			BigPtrArray::Replace( nPrevNdIdx+1, pTempEntry );
2559 			if( nCnt )
2560 				pPrev = (*this)[ nPrevNdIdx  - 1 ];
2561 		}
2562 		nDelPos = pDel->GetIndex() + 1;
2563 	}
2564 
2565 	BigPtrArray::Remove( nDelPos, nSz );
2566 }
2567 
2568 void SwNodes::RegisterIndex( SwNodeIndex& rIdx )
2569 {
2570 	if( !pRoot )		// noch keine Root gesetzt?
2571 	{
2572 		pRoot = &rIdx;
2573 		pRoot->pPrev = 0;
2574 		pRoot->pNext = 0;
2575 	}
2576 	else
2577 	{
2578 		// immer hinter die Root haengen
2579 		rIdx.pNext = pRoot->pNext;
2580 		pRoot->pNext = &rIdx;
2581 		rIdx.pPrev = pRoot;
2582 		if( rIdx.pNext )
2583 			rIdx.pNext->pPrev = &rIdx;
2584 	}
2585 }
2586 
2587 void SwNodes::DeRegisterIndex( SwNodeIndex& rIdx )
2588 {
2589 	SwNodeIndex* pN = rIdx.pNext;
2590 	SwNodeIndex* pP = rIdx.pPrev;
2591 
2592 	if( pRoot == &rIdx )
2593 		pRoot = pP ? pP : pN;
2594 
2595 	if( pP )
2596 		pP->pNext = pN;
2597 	if( pN )
2598 		pN->pPrev = pP;
2599 
2600 	rIdx.pNext = 0;
2601 	rIdx.pPrev = 0;
2602 }
2603 
2604 void SwNodes::InsertNode( const SwNodePtr pNode,
2605                           const SwNodeIndex& rPos )
2606 {
2607 	const ElementPtr pIns = pNode;
2608     BigPtrArray::Insert( pIns, rPos.GetIndex() );
2609 }
2610 
2611 void SwNodes::InsertNode( const SwNodePtr pNode,
2612                           sal_uLong nPos )
2613 {
2614 	const ElementPtr pIns = pNode;
2615     BigPtrArray::Insert( pIns, nPos );
2616 }
2617 
2618 // ->#112139#
2619 SwNode * SwNodes::DocumentSectionStartNode(SwNode * pNode) const
2620 {
2621     if (NULL != pNode)
2622     {
2623         SwNodeIndex aIdx(*pNode);
2624 
2625         if (aIdx <= (*this)[0]->EndOfSectionIndex())
2626             pNode = (*this)[0];
2627         else
2628         {
2629             while ((*this)[0] != pNode->StartOfSectionNode())
2630                 pNode = pNode->StartOfSectionNode();
2631         }
2632     }
2633 
2634     return pNode;
2635 }
2636 
2637 SwNode * SwNodes::DocumentSectionEndNode(SwNode * pNode) const
2638 {
2639     return DocumentSectionStartNode(pNode)->EndOfSectionNode();
2640 }
2641 
2642 //SwNode * SwNodes::operator[](int n) const
2643 //{
2644 //    return operator[]((sal_uLong) n);
2645 //}
2646 // <-#112139#
2647 
2648 sal_Bool SwNodes::IsDocNodes() const
2649 {
2650     return this == &pMyDoc->GetNodes();
2651 }
2652