xref: /trunk/main/sw/source/core/docnode/nodes.cxx (revision 8e8ee8fefdac26d905672cc573c35fd0ae1f9356)
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