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