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