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