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