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