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