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