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