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