xref: /AOO41X/main/sw/source/core/doc/docnum.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
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 <hintids.hxx>
28 #include <rtl/random.h>
29 #include <tools/resid.hxx>
30 #include <editeng/lrspitem.hxx>
31 #include <ftninfo.hxx>
32 #include <ftnidx.hxx>
33 #include <doc.hxx>
34 #include <IDocumentUndoRedo.hxx>
35 #include <pam.hxx>
36 #include <ndtxt.hxx>
37 #include <doctxm.hxx>       // pTOXBaseRing
38 #include <poolfmt.hxx>
39 #include <UndoCore.hxx>
40 #include <UndoRedline.hxx>
41 #include <UndoNumbering.hxx>
42 #include <swundo.hxx>
43 #include <SwUndoFmt.hxx>
44 #include <rolbck.hxx>
45 #include <paratr.hxx>
46 #include <docary.hxx>
47 #include <mvsave.hxx>
48 #include <txtfrm.hxx>
49 #include <pamtyp.hxx>
50 #include <redline.hxx>
51 #include <comcore.hrc>
52 #include <editeng/adjitem.hxx>
53 #include <editeng/frmdiritem.hxx>
54 #include <frmatr.hxx>
55 #include <SwStyleNameMapper.hxx>
56 #include <SwNodeNum.hxx>
57 #include <list.hxx>
58 #include <listfunc.hxx>
59 #include <switerator.hxx>
60 
61 #include <map>
62 
63 inline sal_uInt8 GetUpperLvlChg( sal_uInt8 nCurLvl, sal_uInt8 nLevel, sal_uInt16 nMask )
64 {
65     if( 1 < nLevel )
66     {
67         if( nCurLvl + 1 >= nLevel )
68             nCurLvl -= nLevel - 1;
69         else
70             nCurLvl = 0;
71     }
72     return static_cast<sal_uInt8>((nMask - 1) & ~(( 1 << nCurLvl ) - 1));
73 }
74 
75 void SwDoc::SetOutlineNumRule( const SwNumRule& rRule )
76 {
77     if( pOutlineRule )
78         (*pOutlineRule) = rRule;
79     else
80     {
81         pOutlineRule = new SwNumRule( rRule );
82 
83         AddNumRule(pOutlineRule); // #i36749#
84     }
85 
86     pOutlineRule->SetRuleType( OUTLINE_RULE );
87     // --> OD 2008-07-08 #i91400#
88     pOutlineRule->SetName( String::CreateFromAscii(
89                                         SwNumRule::GetOutlineRuleName() ),
90                            *this);
91     // <--
92     // --> OD 2006-09-21 #i69522#
93     // assure that the outline numbering rule is an automatic rule
94     pOutlineRule->SetAutoRule( sal_True );
95     // <--
96 
97     // teste ob die evt. gesetzen CharFormate in diesem Document
98     // definiert sind
99     pOutlineRule->CheckCharFmts( this );
100 
101     // --> OD 2008-05-13 #refactorlists#
102     // notify text nodes, which are registered at the outline style, about the
103     // changed outline style
104     SwNumRule::tTxtNodeList aTxtNodeList;
105     pOutlineRule->GetTxtNodeList( aTxtNodeList );
106     for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin();
107           aIter != aTxtNodeList.end(); ++aIter )
108     {
109         SwTxtNode* pTxtNd = *aIter;
110         pTxtNd->NumRuleChgd();
111         // --> OD 2009-01-20 #i94152#
112         // assure that list level corresponds to outline level
113         if ( pTxtNd->GetTxtColl()->IsAssignedToListLevelOfOutlineStyle() &&
114              pTxtNd->GetAttrListLevel() != pTxtNd->GetTxtColl()->GetAssignedOutlineStyleLevel() )
115         {
116             pTxtNd->SetAttrListLevel( pTxtNd->GetTxtColl()->GetAssignedOutlineStyleLevel() );
117         }
118         // <--
119     }
120     // <--
121 
122     PropagateOutlineRule();
123     pOutlineRule->SetInvalidRule(sal_True);
124     UpdateNumRule();
125 
126     // gibt es Fussnoten && gilt Kapitelweises Nummerieren, dann updaten
127     if( GetFtnIdxs().Count() && FTNNUM_CHAPTER == GetFtnInfo().eNum )
128         GetFtnIdxs().UpdateAllFtn();
129 
130     UpdateExpFlds(NULL, true);
131 
132     SetModified();
133 }
134 
135 void SwDoc::PropagateOutlineRule()
136 {
137     for (sal_uInt16 n = 0; n < pTxtFmtCollTbl->Count(); n++)
138     {
139         SwTxtFmtColl *pColl = (*pTxtFmtCollTbl)[n];
140 
141        // if (NO_NUMBERING != pColl->GetOutlineLevel())//#outline level,zhaojianwei
142         if(pColl->IsAssignedToListLevelOfOutlineStyle())//<-end,zhaojianwei
143         {
144             // --> OD 2006-11-20 #i71764#
145             // Check only the list style, which is set at the paragraph style
146             const SwNumRuleItem & rCollRuleItem = pColl->GetNumRule( sal_False );
147             // <--
148 
149             // --> OD 2006-11-20 #i71764#
150             // Check on document setting OUTLINE_LEVEL_YIELDS_OUTLINE_RULE no longer needed.
151             if ( rCollRuleItem.GetValue().Len() == 0 )
152             // <--
153             {
154                 SwNumRule * pMyOutlineRule = GetOutlineNumRule();
155 
156                 if (pMyOutlineRule)
157                 {
158                     SwNumRuleItem aNumItem( pMyOutlineRule->GetName() );
159 
160                     pColl->SetFmtAttr(aNumItem);
161                 }
162             }
163         }
164     }
165 }
166 
167     // Hoch-/Runterstufen
168 sal_Bool SwDoc::OutlineUpDown( const SwPaM& rPam, short nOffset )
169 {
170     if( !GetNodes().GetOutLineNds().Count() || !nOffset )
171         return sal_False;
172 
173     // den Bereich feststellen
174     const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds();
175     const SwNodePtr pSttNd = (SwNodePtr)&rPam.Start()->nNode.GetNode();
176     const SwNodePtr pEndNd = (SwNodePtr)&rPam.End()->nNode.GetNode();
177     sal_uInt16 nSttPos, nEndPos;
178 
179     if( !rOutlNds.Seek_Entry( pSttNd, &nSttPos ) &&
180         !nSttPos-- )
181         // wir stehen in keiner "Outline-Section"
182         return sal_False;
183 
184     if( rOutlNds.Seek_Entry( pEndNd, &nEndPos ) )
185         ++nEndPos;
186 
187     // jetzt haben wir unseren Bereich im OutlineNodes-Array
188     // dann prufe ersmal, ob nicht unterebenen aufgehoben werden
189     // (Stufung ueber die Grenzen)
190     sal_uInt16 n;
191 
192     // so, dann koennen wir:
193     // 1. Vorlagen-Array anlegen
194     SwTxtFmtColl* aCollArr[ MAXLEVEL ];
195     memset( aCollArr, 0, sizeof( SwTxtFmtColl* ) * MAXLEVEL );
196 
197     for( n = 0; n < pTxtFmtCollTbl->Count(); ++n )
198     {
199         //sal_uInt8 nLevel = (*pTxtFmtCollTbl)[ n ]->GetOutlineLevel();//#outline level,zhaojianwei
200         //if( nLevel < MAXLEVEL )
201         //  aCollArr[ nLevel ] = (*pTxtFmtCollTbl)[ n ];
202         if((*pTxtFmtCollTbl)[ n ]->IsAssignedToListLevelOfOutlineStyle())
203         {
204             const int nLevel = (*pTxtFmtCollTbl)[ n ]->GetAssignedOutlineStyleLevel();
205             aCollArr[ nLevel ] = (*pTxtFmtCollTbl)[ n ];
206         }//<-end,zhaojianwei
207     }
208 
209     /* --> #111107# */
210     /* Find the last occupied level (backward). */
211     for (n = MAXLEVEL - 1; n > 0; n--)
212     {
213         if (aCollArr[n] != 0)
214             break;
215     }
216 
217     /* If an occupied level is found, choose next level (which IS
218        unoccupied) until a valid level is found. If no occupied level
219        was found n is 0 and aCollArr[0] is 0. In this case no demoting
220        is possible. */
221     if (aCollArr[n] != 0)
222     {
223         while (n < MAXLEVEL - 1)
224         {
225             n++;
226 
227             SwTxtFmtColl *aTmpColl =
228                 GetTxtCollFromPool(static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + n));
229 
230             //if (aTmpColl->GetOutlineLevel() == n)//#outline level,zhaojianwei
231             if( aTmpColl->IsAssignedToListLevelOfOutlineStyle() &&
232                 aTmpColl->GetAssignedOutlineStyleLevel() == n )//<-end,zhaojianwei
233             {
234                 aCollArr[n] = aTmpColl;
235                 break;
236             }
237         }
238     }
239 
240     /* Find the first occupied level (forward). */
241     for (n = 0; n < MAXLEVEL - 1; n++)
242     {
243         if (aCollArr[n] != 0)
244             break;
245     }
246 
247     /* If an occupied level is found, choose previous level (which IS
248        unoccupied) until a valid level is found. If no occupied level
249        was found n is MAXLEVEL - 1 and aCollArr[MAXLEVEL - 1] is 0. In
250        this case no demoting is possible. */
251     if (aCollArr[n] != 0)
252     {
253         while (n > 0)
254         {
255             n--;
256 
257             SwTxtFmtColl *aTmpColl =
258                 GetTxtCollFromPool(static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + n));
259 
260             //if (aTmpColl->GetOutlineLevel() == n)//#outline level,zhaojianwei
261             if( aTmpColl->IsAssignedToListLevelOfOutlineStyle() &&
262                 aTmpColl->GetAssignedOutlineStyleLevel() == n )//<-end,zhaojianwei
263             {
264                 aCollArr[n] = aTmpColl;
265                 break;
266             }
267         }
268     }
269     /* <-- #111107# */
270 
271     /* --> #i13747#
272 
273        Build a move table that states from which level an outline will
274 
275   be moved to which other level. */
276 
277     /* the move table
278 
279        aMoveArr[n] = m: replace aCollArr[n] with aCollArr[m]
280     */
281     int aMoveArr[MAXLEVEL];
282     int nStep; // step size for searching in aCollArr: -1 or 1
283     int nNum; // amount of steps for stepping in aCollArr
284 
285     if (nOffset < 0)
286     {
287         nStep = -1;
288         nNum = -nOffset;
289     }
290     else
291     {
292         nStep = 1;
293         nNum = nOffset;
294     }
295 
296     /* traverse aCollArr */
297     for (n = 0; n < MAXLEVEL; n++)
298     {
299         /* If outline level n has an assigned paragraph style step
300            nNum steps forwards (nStep == 1) or backwards (nStep ==
301            -1).  One step is to go to the next non-null entry in
302            aCollArr in the selected direction. If nNum steps were
303            possible write the index of the entry found to aCollArr[n],
304            i.e. outline level n will be replaced by outline level
305            aCollArr[n].
306 
307            If outline level n has no assigned paragraph style
308            aMoveArr[n] is set to -1.
309         */
310         if (aCollArr[n] != NULL)
311         {
312             sal_uInt16 m = n;
313             int nCount = nNum;
314 
315             while (nCount > 0 && m + nStep >= 0 && m + nStep < MAXLEVEL)
316             {
317                 m = static_cast<sal_uInt16>(m + nStep);
318 
319                 if (aCollArr[m] != NULL)
320                     nCount--;
321             }
322 
323             if (nCount == 0)
324                 aMoveArr[n] = m;
325             else
326                 aMoveArr[n] = -1;
327 
328         }
329         else
330             aMoveArr[n] = -1;
331     }
332 
333     /* If moving of the outline levels is applicable, i.e. for all
334        outline levels occuring in the document there has to be a valid
335        target outline level implied by aMoveArr. */
336     bool bMoveApplicable = true;
337     for (n = nSttPos; n < nEndPos; n++)
338     {
339         SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode();
340         SwTxtFmtColl* pColl = pTxtNd->GetTxtColl();
341 //        int nLevel = pColl->GetOutlineLevel();//#outline level,zhaojianwei
342 //        if (aMoveArr[nLevel] == -1)
343 //          bMoveApplicable = false;
344         if( pColl->IsAssignedToListLevelOfOutlineStyle() )
345         {
346             const int nLevel = pColl->GetAssignedOutlineStyleLevel();
347             if (aMoveArr[nLevel] == -1)
348                 bMoveApplicable = false;
349         }//<-end,zhaojianwei
350         // --> OD 2008-12-16 #i70748#
351         // Check on outline level attribute of text node, if text node is
352         // not an outline via a to outline style assigned paragraph style.
353         else
354         {
355             const int nNewOutlineLevel = pTxtNd->GetAttrOutlineLevel() + nOffset;
356             if ( nNewOutlineLevel < 1 || nNewOutlineLevel > MAXLEVEL )
357             {
358                 bMoveApplicable = false;
359             }
360         }
361         // <--
362     }
363 
364     if (! bMoveApplicable )
365         return sal_False;
366 
367     /* <-- #i13747 # */
368     if (GetIDocumentUndoRedo().DoesUndo())
369     {
370         GetIDocumentUndoRedo().StartUndo(UNDO_OUTLINE_LR, NULL);
371         SwUndo *const pUndoOLR( new SwUndoOutlineLeftRight( rPam, nOffset ) );
372         GetIDocumentUndoRedo().AppendUndo(pUndoOLR);
373     }
374 
375     // 2. allen Nodes die neue Vorlage zuweisen
376 
377     n = nSttPos;
378     while( n < nEndPos)
379     {
380         SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode();
381         SwTxtFmtColl* pColl = pTxtNd->GetTxtColl();
382 
383         if( pColl->IsAssignedToListLevelOfOutlineStyle() )
384         {
385         // ASSERT(pColl->GetOutlineLevel() < MAXLEVEL,  //#outline level,removed by zhaojianwei
386         //         "non outline node in outline nodes?");
387         //int nLevel = pColl->GetOutlineLevel();
388             const int nLevel = pColl->GetAssignedOutlineStyleLevel();//#outline level,add by zhaojianwei
389 
390             ASSERT(aMoveArr[nLevel] >= 0,
391                 "move table: current TxtColl not found when building table!");
392 
393 
394             if (nLevel < MAXLEVEL && aMoveArr[nLevel] >= 0)
395             {
396                 pColl = aCollArr[ aMoveArr[nLevel] ];
397 
398                 if (pColl != NULL)
399                     pColl = (SwTxtFmtColl*)pTxtNd->ChgFmtColl( pColl );
400             }
401 
402         }
403         else if( pTxtNd->GetAttrOutlineLevel() > 0) //#outline level,add by zhaojianwei
404         {
405             int nLevel = pTxtNd->GetAttrOutlineLevel() + nOffset;
406             if( 0 <= nLevel && nLevel <= MAXLEVEL)
407                 pTxtNd->SetAttrOutlineLevel( nLevel );
408 
409         }//<-end,zhaojianwei
410 
411         n++;
412         // Undo ???
413     }
414     if (GetIDocumentUndoRedo().DoesUndo())
415     {
416         GetIDocumentUndoRedo().EndUndo(UNDO_OUTLINE_LR, NULL);
417     }
418 
419     ChkCondColls();
420     SetModified();
421 
422     return sal_True;
423 }
424 
425 
426 
427     // Hoch-/Runter - Verschieben !
428 sal_Bool SwDoc::MoveOutlinePara( const SwPaM& rPam, short nOffset )
429 {
430     // kein Verschiebung in den Sonderbereichen
431     const SwPosition& rStt = *rPam.Start(),
432                     & rEnd = &rStt == rPam.GetPoint() ? *rPam.GetMark()
433                                                       : *rPam.GetPoint();
434     if( !GetNodes().GetOutLineNds().Count() || !nOffset ||
435         (rStt.nNode.GetIndex() < GetNodes().GetEndOfExtras().GetIndex()) ||
436         (rEnd.nNode.GetIndex() < GetNodes().GetEndOfExtras().GetIndex()))
437     {
438         return sal_False;
439     }
440 
441     sal_uInt16 nAktPos = 0;
442     SwNodeIndex aSttRg( rStt.nNode ), aEndRg( rEnd.nNode );
443 
444     //sal_uInt8 nOutLineLevel = NO_NUMBERING;   //#outline level,zhaojianwei
445     int nOutLineLevel = MAXLEVEL;           //<-end,zhaojianwei
446     SwNode* pSrch = &aSttRg.GetNode();
447     //if( pSrch->IsTxtNode() )              //#outline level,zhaojianwei
448     //     nOutLineLevel = static_cast<sal_uInt8>(((SwTxtNode*)pSrch)->GetOutlineLevel());
449    if( pSrch->IsTxtNode())
450         nOutLineLevel = static_cast<sal_uInt8>(((SwTxtNode*)pSrch)->GetAttrOutlineLevel()-1);//<-end,zhaojianwei
451     SwNode* pEndSrch = &aEndRg.GetNode();
452     if( !GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nAktPos ) )
453     {
454         if( !nAktPos )
455             return sal_False; // Promoting or demoting before the first outline => no.
456         if( --nAktPos )
457             aSttRg = *GetNodes().GetOutLineNds()[ nAktPos ];
458         else if( 0 > nOffset )
459             return sal_False; // Promoting at the top of document?!
460         else
461             aSttRg = *GetNodes().GetEndOfContent().StartOfSectionNode();
462     }
463     sal_uInt16 nTmpPos = 0;
464     // If the given range ends at an outlined text node we have to decide if it has to be a part of
465     // the moving range or not. Normally it will be a sub outline of our chapter
466     // and has to be moved, too. But if the chapter ends with a table(or a section end),
467     // the next text node will be choosen and this could be the next outline of the same level.
468     // The criteria has to be the outline level: sub level => incorporate, same/higher level => no.
469     if( GetNodes().GetOutLineNds().Seek_Entry( pEndSrch, &nTmpPos ) )
470     {
471         if( !pEndSrch->IsTxtNode() || pEndSrch == pSrch ||
472             //nOutLineLevel < ((SwTxtNode*)pEndSrch)->GetOutlineLevel() )//#outline level,zhaojianwei
473             nOutLineLevel < ((SwTxtNode*)pEndSrch)->GetAttrOutlineLevel()-1 )//<-end,zhaojianwei
474             ++nTmpPos; // For sub outlines only!
475     }
476 
477     aEndRg = nTmpPos < GetNodes().GetOutLineNds().Count()
478                     ? *GetNodes().GetOutLineNds()[ nTmpPos ]
479                     : GetNodes().GetEndOfContent();
480     if( nOffset >= 0 )
481         nAktPos = nTmpPos;
482     if( aEndRg == aSttRg )
483     {
484         ASSERT( false, "Moving outlines: Surprising selection" );
485         aEndRg++;
486     }
487 
488     const SwNode* pNd;
489     // The following code corrects the range to handle sections (start/end nodes)
490     // The range will be extended if the least node before the range is a start node
491     // which ends inside the range => The complete section will be moved.
492     // The range will be shrinked if the last position is a start node.
493     // The range will be shrinked if the last node is an end node which starts before the range.
494     aSttRg--;
495     while( aSttRg.GetNode().IsStartNode() )
496     {
497         pNd = aSttRg.GetNode().EndOfSectionNode();
498         if( pNd->GetIndex() >= aEndRg.GetIndex() )
499             break;
500         aSttRg--;
501     }
502     aSttRg++;
503 
504     aEndRg--;
505     while( aEndRg.GetNode().IsStartNode() )
506         aEndRg--;
507     while( aEndRg.GetNode().IsEndNode() )
508     {
509         pNd = aEndRg.GetNode().StartOfSectionNode();
510         if( pNd->GetIndex() >= aSttRg.GetIndex() )
511             break;
512         aEndRg--;
513     }
514     aEndRg++;
515 
516     // calculation of the new position
517     if( nOffset < 0 && nAktPos < sal_uInt16(-nOffset) )
518         pNd = GetNodes().GetEndOfContent().StartOfSectionNode();
519     else if( nAktPos + nOffset >= GetNodes().GetOutLineNds().Count() )
520         pNd = &GetNodes().GetEndOfContent();
521     else
522         pNd = GetNodes().GetOutLineNds()[ nAktPos + nOffset ];
523 
524     sal_uLong nNewPos = pNd->GetIndex();
525 
526     // And now a correction of the insert position if necessary...
527     SwNodeIndex aInsertPos( *pNd, -1 );
528     while( aInsertPos.GetNode().IsStartNode() )
529     {
530         // Just before the insert position starts a section:
531         // when I'm moving forward I do not want to enter the section,
532         // when I'm moving backward I want to stay in the section if I'm already a part of,
533         // I want to stay outside if I was outside before.
534         if( nOffset < 0 )
535         {
536             pNd = aInsertPos.GetNode().EndOfSectionNode();
537             if( pNd->GetIndex() >= aEndRg.GetIndex() )
538                 break;
539         }
540         aInsertPos--;
541         --nNewPos;
542     }
543     if( nOffset >= 0 )
544     {
545         // When just before the insert position a section ends, it is okay when I'm moving backward
546         // because I want to stay outside the section.
547         // When moving forward I've to check if I started inside or outside the section
548         // because I don't want to enter of leave such a section
549         while( aInsertPos.GetNode().IsEndNode() )
550         {
551             pNd = aInsertPos.GetNode().StartOfSectionNode();
552             if( pNd->GetIndex() >= aSttRg.GetIndex() )
553                 break;
554             aInsertPos--;
555             --nNewPos;
556         }
557     }
558     // We do not want to move into tables (at the moment)
559     aInsertPos++;
560     pNd = &aInsertPos.GetNode();
561     if( pNd->IsTableNode() )
562         pNd = pNd->StartOfSectionNode();
563     if( pNd->FindTableNode() )
564         return sal_False;
565 
566     ASSERT( aSttRg.GetIndex() > nNewPos || nNewPos >= aEndRg.GetIndex(),
567                 "Position liegt im MoveBereich" );
568 
569     // wurde ein Position in den Sonderbereichen errechnet, dann
570     // setze die Position auf den Dokumentanfang.
571     // Sollten da Bereiche oder Tabellen stehen, so werden sie nach
572     // hinten verschoben.
573     nNewPos = Max( nNewPos, GetNodes().GetEndOfExtras().GetIndex() + 2 );
574 
575     long nOffs = nNewPos - ( 0 < nOffset ? aEndRg.GetIndex() : aSttRg.GetIndex());
576     SwPaM aPam( aSttRg, aEndRg, 0, -1 );
577     return MoveParagraph( aPam, nOffs, sal_True );
578 }
579 
580 
581 sal_uInt16 lcl_FindOutlineName( const SwNodes& rNds, const String& rName,
582                             sal_Bool bExact )
583 {
584     sal_uInt16 nSavePos = USHRT_MAX;
585     const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds();
586     for( sal_uInt16 n = 0; n < rOutlNds.Count(); ++n )
587     {
588         SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode();
589         String sTxt( pTxtNd->GetExpandTxt() );
590         if( sTxt.Equals( rName ) )
591         {
592             // "exact" gefunden, setze Pos auf den Node
593             nSavePos = n;
594             break;
595         }
596         else if( !bExact && USHRT_MAX == nSavePos &&
597                     COMPARE_EQUAL == sTxt.CompareTo( rName, rName.Len()) )
598         {
599             // dann vielleicht nur den den 1.Teil vom Text gefunden
600             nSavePos = n;
601         }
602     }
603 
604     return nSavePos;
605 }
606 
607 
608 
609 sal_uInt16 lcl_FindOutlineNum( const SwNodes& rNds, String& rName )
610 {
611     // Gueltig Nummern sind (immer nur Offsets!!!):
612     //  ([Nummer]+\.)+  (als regulaerer Ausdruck!)
613     //  (Nummer gefolgt von Punkt, zum 5 Wiederholungen)
614     //  also: "1.1.", "1.", "1.1.1."
615     xub_StrLen nPos = 0;
616     String sNum = rName.GetToken( 0, '.', nPos );
617     if( STRING_NOTFOUND == nPos )
618         return USHRT_MAX;           // ungueltige Nummer!!!
619 
620     sal_uInt16 nLevelVal[ MAXLEVEL ];       // Nummern aller Levels
621     memset( nLevelVal, 0, MAXLEVEL * sizeof( nLevelVal[0] ));
622     sal_uInt8 nLevel = 0;
623     String sName( rName );
624 
625     while( STRING_NOTFOUND != nPos )
626     {
627         sal_uInt16 nVal = 0;
628         sal_Unicode c;
629         for( sal_uInt16 n = 0; n < sNum.Len(); ++n )
630             if( '0' <= ( c = sNum.GetChar( n )) && c <= '9' )
631             {
632                 nVal *= 10;  nVal += c - '0';
633             }
634             else if( nLevel )
635                 break;                      // "fast" gueltige Nummer
636             else
637                 return USHRT_MAX;           // ungueltige Nummer!!!
638 
639         if( MAXLEVEL > nLevel )
640             nLevelVal[ nLevel++ ] = nVal;
641 
642         sName.Erase( 0, nPos );
643         nPos = 0;
644         sNum = sName.GetToken( 0, '.', nPos );
645         // #i4533# without this check all parts delimited by a dot are treated as outline numbers
646         if(!ByteString(sNum, gsl_getSystemTextEncoding()).IsNumericAscii())
647             nPos = STRING_NOTFOUND;
648     }
649     rName = sName;      // das ist der nachfolgende Text.
650 
651     // alle Levels gelesen, dann suche mal im Document nach dieser
652     // Gliederung:
653     const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds();
654     // OS: ohne OutlineNodes lohnt die Suche nicht
655     // und man spart sich einen Absturz #42958#
656     if(!rOutlNds.Count())
657         return USHRT_MAX;
658     SwTxtNode* pNd;
659     nPos = 0;
660     //search in the existing outline nodes for the required outline num array
661     for( ; nPos < rOutlNds.Count(); ++nPos )
662     {
663         pNd = rOutlNds[ nPos ]->GetTxtNode();
664         //sal_uInt8 nLvl = pNd->GetTxtColl()->GetOutlineLevel();    //#outline level,zhaojianwei
665         const int nLvl = pNd->GetAttrOutlineLevel()-1;   //<-end,zhaojianwei
666         if( nLvl == nLevel - 1)
667         {
668             // check for the outline num
669             // --> OD 2005-11-02 #i51089 - TUNING#
670             // --> OD 2006-09-22 #i68289#
671             // Assure, that text node has the correct numbering level. Otherwise,
672             // its number vector will not fit to the searched level.
673 //            if ( pNd->GetNum() )
674             if ( pNd->GetNum() &&
675                  pNd->GetActualListLevel() == ( nLevel - 1 ) )
676             // <--
677             {
678                 const SwNodeNum & rNdNum = *(pNd->GetNum());
679                 SwNumberTree::tNumberVector aLevelVal = rNdNum.GetNumberVector();
680                 //now compare with the one searched for
681                 bool bEqual = true;
682                 for( sal_uInt8 n = 0; (n < nLevel) && bEqual; ++n )
683                 {
684                     bEqual = aLevelVal[n] == nLevelVal[n];
685                 }
686                 if(bEqual)
687                 {
688                     break;
689                 }
690             }
691             else
692             {
693                 // --> OD 2006-01-12 #126588#
694                 // A text node, which has an outline paragraph style applied and
695                 // has as hard attribute 'no numbering' set, has an outline level,
696                 // but no numbering tree node. Thus, consider this situation in
697                 // the assertion condition.
698                 ASSERT( !pNd->GetNumRule(),
699                         "<lcl_FindOutlineNum(..)> - text node with outline level and numbering rule, but without numbering tree node. This is a serious defect -> inform OD" );
700             }
701         }
702     }
703     if( nPos >= rOutlNds.Count() )
704         nPos = USHRT_MAX;
705     return nPos;
706 }
707 
708     // zu diesem Gliederungspunkt
709 
710 
711     // JP 13.06.96:
712     // im Namen kann eine Nummer oder/und der Text stehen.
713     // zuerst wird ueber die Nummer versucht den richtigen Eintrag zu finden.
714     // Gibt es diesen, dann wird ueber den Text verglichen, od es der
715     // gewuenschte ist. Ist das nicht der Fall, wird noch mal nur ueber den
716     // Text gesucht. Wird dieser gefunden ist es der Eintrag. Ansonsten der,
717     // der ueber die Nummer gefunden wurde.
718     // Ist keine Nummer angegeben, dann nur den Text suchen.
719 
720 sal_Bool SwDoc::GotoOutline( SwPosition& rPos, const String& rName ) const
721 {
722     if( rName.Len() )
723     {
724         const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds();
725 
726         // 1. Schritt: ueber die Nummer:
727         String sName( rName );
728         sal_uInt16 nFndPos = ::lcl_FindOutlineNum( GetNodes(), sName );
729         if( USHRT_MAX != nFndPos )
730         {
731             SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode();
732             String sExpandedText = pNd->GetExpandTxt();
733             //#i4533# leading numbers followed by a dot have been remove while
734             //searching for the outline position
735             //to compensate this they must be removed from the paragraphs text content, too
736             sal_uInt16 nPos = 0;
737             String sTempNum;
738             while(sExpandedText.Len() && (sTempNum = sExpandedText.GetToken(0, '.', nPos)).Len() &&
739                     STRING_NOTFOUND != nPos &&
740                     ByteString(sTempNum, gsl_getSystemTextEncoding()).IsNumericAscii())
741             {
742                 sExpandedText.Erase(0, nPos);
743                 nPos = 0;
744             }
745 
746             if( !sExpandedText.Equals( sName ) )
747             {
748                 sal_uInt16 nTmp = ::lcl_FindOutlineName( GetNodes(), sName, sal_True );
749                 if( USHRT_MAX != nTmp )             // ueber den Namen gefunden
750                 {
751                     nFndPos = nTmp;
752                     pNd = rOutlNds[ nFndPos ]->GetTxtNode();
753                 }
754             }
755             rPos.nNode = *pNd;
756             rPos.nContent.Assign( pNd, 0 );
757             return sal_True;
758         }
759 
760         nFndPos = ::lcl_FindOutlineName( GetNodes(), rName, sal_False );
761         if( USHRT_MAX != nFndPos )
762         {
763             SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode();
764             rPos.nNode = *pNd;
765             rPos.nContent.Assign( pNd, 0 );
766             return sal_True;
767         }
768 
769         // --> OD 2006-09-22 #i68289#
770         // additional search on hyperlink URL without its outline numbering part
771         if ( !sName.Equals( rName ) )
772         {
773             nFndPos = ::lcl_FindOutlineName( GetNodes(), sName, sal_False );
774             if( USHRT_MAX != nFndPos )
775             {
776                 SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode();
777                 rPos.nNode = *pNd;
778                 rPos.nContent.Assign( pNd, 0 );
779                 return sal_True;
780             }
781         }
782         // <--
783     }
784     return sal_False;
785 }
786 
787 /*  */
788 
789 // --- Nummerierung -----------------------------------------
790 
791 // --> OD 2008-02-19 #refactorlists#
792 //void SwNumRuleInfo::MakeList( SwDoc& rDoc, sal_Bool )
793 //{
794 //    SwNumRule* pRule = rDoc.FindNumRulePtr(rName);
795 
796 //    // no rule, no fun.
797 //    if ( !pRule )
798 //        return;
799 
800 //    //
801 //    // 1. Case: Information already available at pRule:
802 //    //
803 //    if (pRule->GetTxtNodeList())
804 //    {
805 //        // copy list to own pList pointer:
806 //        aList = *pRule->GetTxtNodeList();
807 //        return;
808 //    }
809 
810 //    //
811 //    // 2. Case: Information has to be generated from scratch:
812 //    //
813 
814 //    if (pRule->IsOutlineRule())
815 //    {
816 //        const SwOutlineNodes & rOutlineNodes = rDoc.GetNodes().GetOutLineNds();
817 
818 //        for (sal_uInt16 i = 0; i < rOutlineNodes.Count(); ++i)
819 //        {
820 //            SwTxtNode & aNode = *((SwTxtNode *) rOutlineNodes[i]);
821 
822 //            if (pRule == aNode.GetNumRule())
823 //                AddNode(aNode);
824 //        }
825 //    }
826 //    {
827 //        SwModify* pMod;
828 //        const SfxPoolItem* pItem;
829 //        sal_uInt16 i, nMaxItems = rDoc.GetAttrPool().GetItemCount
830 //            ( RES_PARATR_NUMRULE);
831 //        for( i = 0; i < nMaxItems; ++i )
832 //        {
833 //            pItem = rDoc.GetAttrPool().GetItem( RES_PARATR_NUMRULE, i );
834 //            if( 0 != pItem)
835 //            {
836 //                pMod = (SwModify*)((SwNumRuleItem*)pItem)->GetDefinedIn();
837 //                if (0 != pMod &&
838 //                    ((SwNumRuleItem*)pItem)->GetValue().Len() &&
839 //                    ((SwNumRuleItem*)pItem)->GetValue() == rName )
840 //                {
841 //                    if( pMod->IsA( TYPE( SwFmt )) )
842 //                        pMod->GetInfo( *this );
843 //                    else
844 //                    {
845 //                        SwTxtNode* pModTxtNode = (SwTxtNode*)pMod;
846 
847 //                        // #115901#
848 //                        if( pModTxtNode->GetNodes().IsDocNodes())
849 //                        {
850 //                            AddNode( *pModTxtNode );
851 //                        }
852 //                    }
853 //                }
854 //            }
855 //        }
856 //    }
857 
858 //    // --> FME 2004-11-03 #i36571# The numrule and this info structure should
859 //    // have different instances of the list:
860 //    // --> OD 2006-09-12 #i69145#
861 //    // method <SwNumRule::SetList(..)> copies content of list provided by the parameter
862 //    pRule->SetTxtNodeList( aList );
863 //    // <--
864 //}
865 // <--
866 
867 
868 void lcl_ChgNumRule( SwDoc& rDoc, const SwNumRule& rRule )
869 {
870     SwNumRule* pOld = rDoc.FindNumRulePtr( rRule.GetName() );
871     ASSERT( pOld, "ohne die alte NumRule geht gar nichts" );
872 
873     sal_uInt16 nChgFmtLevel = 0, nMask = 1;
874     sal_uInt8 n;
875 
876     for( n = 0; n < MAXLEVEL; ++n, nMask <<= 1 )
877     {
878         const SwNumFmt& rOldFmt = pOld->Get( n ),
879                       & rNewFmt = rRule.Get( n );
880 
881         if( rOldFmt != rNewFmt )
882         {
883             nChgFmtLevel |= nMask;
884         }
885         else if( SVX_NUM_NUMBER_NONE > rNewFmt.GetNumberingType() && 1 < rNewFmt.GetIncludeUpperLevels() &&
886                 0 != (nChgFmtLevel & GetUpperLvlChg( n, rNewFmt.GetIncludeUpperLevels(),nMask )) )
887             nChgFmtLevel |= nMask;
888     }
889 
890     if( !nChgFmtLevel )         // es wurde nichts veraendert?
891     {
892         // --> OD 2006-04-27 #i64311#
893         const bool bInvalidateNumRule( pOld->IsContinusNum() != rRule.IsContinusNum() );
894         // <--
895         pOld->CheckCharFmts( &rDoc );
896         pOld->SetContinusNum( rRule.IsContinusNum() );
897         // --> OD 2008-06-17 #i87166#
898         // Do NOT change list style type
899 //        pOld->SetRuleType( rRule.GetRuleType() );
900         // <--
901         // --> OD 2006-04-27 #i64311#
902         if ( bInvalidateNumRule )
903         {
904             pOld->SetInvalidRule(sal_True);
905         }
906         // <--
907         return ;
908     }
909 
910     // --> OD 2008-02-19 #refactorlists#
911 //    SwNumRuleInfo* pUpd = new SwNumRuleInfo( rRule.GetName() );
912 //    pUpd->MakeList( rDoc );
913 
914 //    sal_uInt8 nLvl;
915 //    for( sal_uLong nFirst = 0, nLast = pUpd->GetList().Count();
916 //        nFirst < nLast; ++nFirst )
917 //    {
918 //        SwTxtNode* pTxtNd = pUpd->GetList().GetObject( nFirst );
919 //        nLvl = static_cast<sal_uInt8>(pTxtNd->GetLevel());
920 
921 //        if( nLvl < MAXLEVEL )
922 //        {
923 //            if( nChgFmtLevel & ( 1 << nLvl ))
924 //            {
925 //                pTxtNd->NumRuleChgd();
926 //            }
927 //        }
928 //    }
929     SwNumRule::tTxtNodeList aTxtNodeList;
930     pOld->GetTxtNodeList( aTxtNodeList );
931     sal_uInt8 nLvl( 0 );
932     for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin();
933           aIter != aTxtNodeList.end(); ++aIter )
934     {
935         SwTxtNode* pTxtNd = *aIter;
936         nLvl = static_cast<sal_uInt8>(pTxtNd->GetActualListLevel());
937 
938         if( nLvl < MAXLEVEL )
939         {
940             if( nChgFmtLevel & ( 1 << nLvl ))
941             {
942                 pTxtNd->NumRuleChgd();
943             }
944         }
945     }
946     // <--
947 
948     for( n = 0; n < MAXLEVEL; ++n )
949         if( nChgFmtLevel & ( 1 << n ))
950             pOld->Set( n, rRule.GetNumFmt( n ));
951 
952     pOld->CheckCharFmts( &rDoc );
953     pOld->SetInvalidRule(sal_True);
954     pOld->SetContinusNum( rRule.IsContinusNum() );
955     // --> OD 2008-06-17 #i87166#
956     // Do NOT change list style type
957 //    pOld->SetRuleType( rRule.GetRuleType() );
958     // <--
959 
960     // --> OD 2008-02-19 #refactorlists#
961 //    delete pUpd;
962     // <--
963 
964     rDoc.UpdateNumRule();
965 }
966 
967 // OD 2008-02-08 #newlistlevelattrs# - add handling of parameter <bResetIndentAttrs>
968 // --> OD 2008-03-17 #refactorlists#
969 void SwDoc::SetNumRule( const SwPaM& rPam,
970                         const SwNumRule& rRule,
971                         const bool bCreateNewList,
972                         const String sContinuedListId,
973                         sal_Bool bSetItem,
974                         const bool bResetIndentAttrs )
975 {
976     SwUndoInsNum * pUndo = NULL;
977     if (GetIDocumentUndoRedo().DoesUndo())
978     {
979         // Start/End for attributes!
980         GetIDocumentUndoRedo().StartUndo( UNDO_INSNUM, NULL );
981         pUndo = new SwUndoInsNum( rPam, rRule );
982         GetIDocumentUndoRedo().AppendUndo(pUndo);
983     }
984 
985     SwNumRule * pNew = FindNumRulePtr( rRule.GetName() );
986     bool bUpdateRule = false;
987 
988     if( !pNew )
989     {
990         pNew = (*pNumRuleTbl)[ MakeNumRule( rRule.GetName(), &rRule ) ];
991     }
992     else if (rRule != *pNew)
993     {
994         bUpdateRule = true;
995     }
996 
997     if (bUpdateRule)
998     {
999         if( pUndo )
1000         {
1001             pUndo->SaveOldNumRule( *pNew );
1002             ::lcl_ChgNumRule( *this, rRule );
1003             pUndo->SetLRSpaceEndPos();
1004         }
1005         else
1006         {
1007             ::lcl_ChgNumRule( *this, rRule );
1008         }
1009     }
1010 
1011     // --> OD 2008-03-17 #refactorlists#
1012     if ( bSetItem )
1013     {
1014         if ( bCreateNewList )
1015         {
1016             String sListId;
1017             if ( !bUpdateRule )
1018             {
1019                 // apply list id of list, which has been created for the new list style
1020                 sListId = pNew->GetDefaultListId();
1021             }
1022             else
1023             {
1024                 // create new list and apply its list id
1025                 SwList* pNewList = createList( String(), pNew->GetName() );
1026                 ASSERT( pNewList,
1027                         "<SwDoc::SetNumRule(..)> - could not create new list. Serious defect -> please inform OD." );
1028                 sListId = pNewList->GetListId();
1029             }
1030             InsertPoolItem( rPam,
1031                 SfxStringItem( RES_PARATR_LIST_ID, sListId ), 0 );
1032         }
1033         else if ( sContinuedListId.Len() > 0 )
1034         {
1035             // apply given list id
1036             InsertPoolItem( rPam,
1037                 SfxStringItem( RES_PARATR_LIST_ID, sContinuedListId ), 0 );
1038         }
1039     }
1040     // <--
1041 
1042     if ( ! rPam.HasMark())
1043     {
1044         SwTxtNode * pTxtNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode();
1045         // --> OD 2006-10-19 #134160#
1046         // consider case that the PaM doesn't denote a text node - e.g. it denotes a graphic node
1047         if ( pTxtNd )
1048         {
1049             SwNumRule * pRule = pTxtNd->GetNumRule();
1050 
1051             if (pRule && pRule->GetName() == pNew->GetName())
1052             {
1053                 bSetItem = sal_False;
1054                 // --> OD 2008-06-02 #refactorlists#
1055                 if ( !pTxtNd->IsInList() )
1056                 {
1057                     pTxtNd->AddToList();
1058                 }
1059                 // <--
1060             }
1061             // --> OD 2005-10-26 #b6340308# - only clear numbering attribute at
1062             // text node, if at paragraph style the new numbering rule is found.
1063             else if ( !pRule )
1064             {
1065                 SwTxtFmtColl* pColl = pTxtNd->GetTxtColl();
1066                 if ( pColl )
1067                 {
1068                     SwNumRule* pCollRule = FindNumRulePtr(pColl->GetNumRule().GetValue());
1069                     if ( pCollRule && pCollRule->GetName() == pNew->GetName() )
1070                     {
1071                         pTxtNd->ResetAttr( RES_PARATR_NUMRULE );
1072                         bSetItem = sal_False;
1073                     }
1074                 }
1075             }
1076             // <--
1077         }
1078         // <--
1079     }
1080 
1081     // --> OD 2009-08-18 #i103817#
1082     if ( bSetItem )
1083     // <--
1084     {
1085         InsertPoolItem( rPam, SwNumRuleItem( pNew->GetName() ), 0 );
1086     }
1087 
1088     // --> OD 2008-02-08 #newlistlevelattrs#
1089     if ( bResetIndentAttrs &&
1090          pNew && pNew->Get( 0 ).GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1091     {
1092         SvUShortsSort aResetAttrsArray;
1093         aResetAttrsArray.Insert( RES_LR_SPACE );
1094         // --> OD 2010-10-05 #i114929#
1095         // On a selection setup a corresponding Point-and-Mark in order to get
1096         // the indentation attribute reset on all paragraphs touched by the selection
1097         if ( rPam.HasMark() &&
1098              rPam.End()->nNode.GetNode().GetTxtNode() )
1099         {
1100             SwPaM aPam( rPam.Start()->nNode,
1101                         rPam.End()->nNode );
1102             aPam.Start()->nContent = 0;
1103             aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTxtNode()->Len();
1104             ResetAttrs( aPam, sal_False, &aResetAttrsArray );
1105         }
1106         else
1107         {
1108             ResetAttrs( rPam, sal_False, &aResetAttrsArray );
1109         }
1110         // <--
1111     }
1112     // <--
1113 
1114     if (GetIDocumentUndoRedo().DoesUndo())
1115     {
1116         GetIDocumentUndoRedo().EndUndo( UNDO_INSNUM, NULL );
1117     }
1118 
1119     SetModified();
1120 }
1121 
1122 void SwDoc::SetCounted(const SwPaM & rPam, bool bCounted)
1123 {
1124     if ( bCounted )
1125     {
1126         SvUShortsSort aResetAttrsArray;
1127         aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED );
1128         // --> OD 2010-10-05 #i114929#
1129         // On a selection setup a corresponding Point-and-Mark in order to get
1130         // the list-is-counted attribute reset on all paragraphs touched by the selection
1131         if ( rPam.HasMark() &&
1132              rPam.End()->nNode.GetNode().GetTxtNode() )
1133         {
1134             SwPaM aPam( rPam.Start()->nNode,
1135                         rPam.End()->nNode );
1136             aPam.Start()->nContent = 0;
1137             aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTxtNode()->Len();
1138             ResetAttrs( aPam, sal_False, &aResetAttrsArray );
1139         }
1140         else
1141         {
1142             ResetAttrs( rPam, sal_False, &aResetAttrsArray );
1143         }
1144         // <--
1145     }
1146     else
1147     {
1148         InsertPoolItem( rPam,
1149             SfxBoolItem( RES_PARATR_LIST_ISCOUNTED, sal_False ), 0 );
1150     }
1151 }
1152 
1153 void SwDoc::SetNumRuleStart( const SwPosition& rPos, sal_Bool bFlag )
1154 {
1155     SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
1156 
1157     if (pTxtNd)
1158     {
1159         const SwNumRule* pRule = pTxtNd->GetNumRule();
1160         if( pRule && !bFlag != !pTxtNd->IsListRestart())
1161         {
1162             if (GetIDocumentUndoRedo().DoesUndo())
1163             {
1164                 SwUndo *const pUndo( new SwUndoNumRuleStart(rPos, bFlag) );
1165                 GetIDocumentUndoRedo().AppendUndo(pUndo);
1166             }
1167 
1168             pTxtNd->SetListRestart(bFlag ? true : false);
1169 
1170             SetModified();
1171         }
1172     }
1173 }
1174 
1175 void SwDoc::SetNodeNumStart( const SwPosition& rPos, sal_uInt16 nStt )
1176 {
1177     SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
1178 
1179     if (pTxtNd)
1180     {
1181         // --> OD 2008-02-27 #refactorlists#
1182 //        const SwNumRule* pRule = pTxtNd->GetNumRule();
1183 //        if( pRule && nStt != pTxtNd->GetListRestartValue() )
1184 //        {
1185 //            if( DoesUndo() )
1186 //            {
1187 //                ClearRedo();
1188 //                AppendUndo( new SwUndoNumRuleStart( rPos, nStt ));
1189 //            }
1190 //        }
1191 //        pTxtNd->SetListRestartValue(nStt);
1192 
1193 //        SetModified();
1194         if ( !pTxtNd->HasAttrListRestartValue() ||
1195              pTxtNd->GetAttrListRestartValue() != nStt )
1196         {
1197             if (GetIDocumentUndoRedo().DoesUndo())
1198             {
1199                 SwUndo *const pUndo( new SwUndoNumRuleStart(rPos, nStt) );
1200                 GetIDocumentUndoRedo().AppendUndo(pUndo);
1201             }
1202             pTxtNd->SetAttrListRestartValue( nStt );
1203 
1204             SetModified();
1205         }
1206         // <--
1207     }
1208 }
1209 
1210     // loeschen geht nur, wenn die Rule niemand benutzt!
1211 sal_Bool SwDoc::DelNumRule( const String& rName, sal_Bool bBroadcast )
1212 {
1213     sal_uInt16 nPos = FindNumRule( rName );
1214 
1215     // --> OD 2007-12-17 #151213#
1216     if ( (*pNumRuleTbl)[ nPos ] == GetOutlineNumRule() )
1217     {
1218         ASSERT( false,
1219                 "<SwDoc::DelNumRule(..)> - No deletion of outline list style. This is serious defect - please inform OD" );
1220         return sal_False;
1221     }
1222     // <--
1223 
1224     if( USHRT_MAX != nPos && !IsUsed( *(*pNumRuleTbl)[ nPos ] ))
1225     {
1226         if (GetIDocumentUndoRedo().DoesUndo())
1227         {
1228             SwUndo * pUndo =
1229                 new SwUndoNumruleDelete(*(*pNumRuleTbl)[nPos], this);
1230             GetIDocumentUndoRedo().AppendUndo(pUndo);
1231         }
1232 
1233         if (bBroadcast)
1234             BroadcastStyleOperation(rName, SFX_STYLE_FAMILY_PSEUDO,
1235                                     SFX_STYLESHEET_ERASED);
1236 
1237         // --> OD 2008-04-02 #refactorlists#
1238         deleteListForListStyle( rName );
1239         {
1240             // delete further list, which have the deleted list style as default list style
1241             std::vector< SwList* > aListsForDeletion;
1242             tHashMapForLists::iterator aListIter = maLists.begin();
1243             while ( aListIter != maLists.end() )
1244             {
1245                 SwList* pList = (*aListIter).second;
1246                 if ( pList->GetDefaultListStyleName() == rName )
1247                 {
1248                     aListsForDeletion.push_back( pList );
1249                 }
1250 
1251                 ++aListIter;
1252             }
1253             while ( aListsForDeletion.size() > 0 )
1254             {
1255                 SwList* pList = aListsForDeletion.back();
1256                 aListsForDeletion.pop_back();
1257                 deleteList( pList->GetListId() );
1258             }
1259         }
1260         // <--
1261         // --> FME 2004-11-02 #i34097# DeleteAndDestroy deletes rName if
1262         // rName is directly taken from the numrule.
1263         const String aTmpName( rName );
1264         // <--
1265         pNumRuleTbl->DeleteAndDestroy( nPos );
1266         maNumRuleMap.erase(aTmpName);
1267 
1268         SetModified();
1269         return sal_True;
1270     }
1271     return sal_False;
1272 }
1273 
1274 // #106897#
1275 void SwDoc::ChgNumRuleFmts( const SwNumRule& rRule, const String * pName )
1276 {
1277     // #106897#
1278     SwNumRule* pRule = FindNumRulePtr( pName ? *pName : rRule.GetName() );
1279     if( pRule )
1280     {
1281         SwUndoInsNum* pUndo = 0;
1282         if (GetIDocumentUndoRedo().DoesUndo())
1283         {
1284             pUndo = new SwUndoInsNum( *pRule, rRule );
1285             pUndo->GetHistory();
1286             GetIDocumentUndoRedo().AppendUndo( pUndo );
1287         }
1288         ::lcl_ChgNumRule( *this, rRule );
1289 
1290         if( pUndo )
1291             pUndo->SetLRSpaceEndPos();
1292 
1293         SetModified();
1294     }
1295 }
1296 
1297 sal_Bool SwDoc::RenameNumRule(const String & rOldName, const String & rNewName,
1298                               sal_Bool bBroadcast)
1299 {
1300     sal_Bool bResult = sal_False;
1301     SwNumRule * pNumRule = FindNumRulePtr(rOldName);
1302 
1303     if (pNumRule)
1304     {
1305         if (GetIDocumentUndoRedo().DoesUndo())
1306         {
1307             SwUndo * pUndo = new SwUndoNumruleRename(rOldName, rNewName, this);
1308             GetIDocumentUndoRedo().AppendUndo(pUndo);
1309         }
1310 
1311         // --> OD 2008-02-19 #refactorlists#
1312 //        SwNumRuleInfo aInfo(rOldName);
1313 //        aInfo.MakeList(*this);
1314         SwNumRule::tTxtNodeList aTxtNodeList;
1315         pNumRule->GetTxtNodeList( aTxtNodeList );
1316         // <--
1317 
1318         // --> OD 2008-07-08 #i91400#
1319         pNumRule->SetName( rNewName, *this );
1320         // <--
1321 
1322         SwNumRuleItem aItem(rNewName);
1323         // --> OD 2008-02-19 #refactorlists#
1324 //        for (sal_uLong nI = 0; nI < aInfo.GetList().Count(); ++nI)
1325 //        {
1326 //            SwTxtNode * pTxtNd = aInfo.GetList().GetObject(nI);
1327 //            pTxtNd->SwCntntNode::SetAttr(aItem);
1328 //        }
1329         for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin();
1330               aIter != aTxtNodeList.end(); ++aIter )
1331         {
1332             SwTxtNode * pTxtNd = *aIter;
1333             pTxtNd->SetAttr(aItem);
1334         }
1335         // <--
1336 
1337         bResult = sal_True;
1338 
1339         if (bBroadcast)
1340             BroadcastStyleOperation(rOldName, SFX_STYLE_FAMILY_PSEUDO,
1341                                     SFX_STYLESHEET_MODIFIED);
1342     }
1343 
1344     return bResult;
1345 }
1346 
1347 void SwDoc::StopNumRuleAnimations( OutputDevice* pOut )
1348 {
1349     for( sal_uInt16 n = GetNumRuleTbl().Count(); n; )
1350     {
1351         SwNumRule::tTxtNodeList aTxtNodeList;
1352         GetNumRuleTbl()[ --n ]->GetTxtNodeList( aTxtNodeList );
1353         for ( SwNumRule::tTxtNodeList::iterator aTxtNodeIter = aTxtNodeList.begin();
1354               aTxtNodeIter != aTxtNodeList.end(); ++aTxtNodeIter )
1355         {
1356             SwTxtNode* pTNd = *aTxtNodeIter;
1357             SwIterator<SwTxtFrm,SwTxtNode> aIter(*pTNd);
1358             for(SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
1359                 if( pFrm->HasAnimation() )
1360                     pFrm->StopAnimation( pOut );
1361         }
1362     }
1363 }
1364 
1365 sal_Bool SwDoc::ReplaceNumRule( const SwPosition& rPos,
1366                             const String& rOldRule, const String& rNewRule )
1367 {
1368     sal_Bool bRet = sal_False;
1369     SwNumRule *pOldRule = FindNumRulePtr( rOldRule ),
1370               *pNewRule = FindNumRulePtr( rNewRule );
1371     if( pOldRule && pNewRule && pOldRule != pNewRule )
1372     {
1373         // --> OD 2008-02-19 #refactorlists#
1374         SwUndoInsNum* pUndo = 0;
1375         if (GetIDocumentUndoRedo().DoesUndo())
1376         {
1377             // Start/End for attributes!
1378             GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL );
1379             pUndo = new SwUndoInsNum( rPos, *pNewRule, rOldRule );
1380             GetIDocumentUndoRedo().AppendUndo(pUndo);
1381         }
1382 
1383         // --> OD 2008-02-19 #refactorlists#
1384         // apply new list style <pNewRule> to all text nodes, which have the
1385         // old list style <pOldNRule> applied and belong to the same list as
1386         // the text node of the given <SwPosition>.
1387 //        SwNumRuleInfo aUpd( rOldRule );
1388 //        aUpd.MakeList( *this );
1389 
1390 //        if (aUpd.GetList().Count() > 0)    // #106897#
1391         SwNumRule::tTxtNodeList aTxtNodeList;
1392         pOldRule->GetTxtNodeList( aTxtNodeList );
1393         if ( aTxtNodeList.size() > 0 )
1394         {
1395 //            // Position suchen und bestimme ob ein Node davor oder dahinter
1396 //            // einen Start erzwingt
1397 //            SwTxtNode* pTxtNd;
1398 //            sal_uLong nFndPos, nFirst, nLast;
1399 
1400 //            if( TABLE_ENTRY_NOTFOUND != aUpd.GetList().SearchKey(
1401 //                                                                 rPos.nNode.GetIndex(), &nFndPos ))
1402 //                ++nFndPos;
1403 
1404 //            for( nLast = nFndPos; nLast < aUpd.GetList().Count(); ++nLast )
1405 //            {
1406 //                pTxtNd = aUpd.GetList().GetObject( nLast );
1407 //                if(pTxtNd->IsRestart())
1408 //                    break;
1409 //            }
1410 //            for( nFirst = nFndPos; nFirst; )
1411 //            {
1412 //                pTxtNd = aUpd.GetList().GetObject( --nFirst );
1413 //                if( pTxtNd->IsRestart() )
1414 //                    break;
1415 //            }
1416 //            // dann neue Numerierung ueber diesen Bereich
1417 //            // definieren und den Start am Anfang/Ende zurueck setzen
1418 //            pTxtNd = aUpd.GetList().GetObject( nFirst );
1419 //            if( pTxtNd->IsRestart() )
1420 //            {
1421 //                pTxtNd->SetRestart(false);
1422 //                if( pUndo )
1423 //                    pUndo->SetSttNum( pTxtNd->GetIndex() );
1424 //            }
1425 
1426             SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 );
1427             sal_uInt16 nChgFmtLevel = 0;
1428             for( sal_uInt8 n = 0; n < MAXLEVEL; ++n )
1429             {
1430                 const SwNumFmt& rOldFmt = pOldRule->Get( n ),
1431                     & rNewFmt = pNewRule->Get( n );
1432 
1433                 if( rOldFmt.GetAbsLSpace() != rNewFmt.GetAbsLSpace() ||
1434                     rOldFmt.GetFirstLineOffset() != rNewFmt.GetFirstLineOffset() )
1435                     nChgFmtLevel |= ( 1 << n );
1436             }
1437 
1438             const SwTxtNode* pGivenTxtNode = rPos.nNode.GetNode().GetTxtNode();
1439             SwNumRuleItem aRule( rNewRule );
1440 //            for( ; nFirst < nLast; ++nFirst )
1441 //            {
1442 //                pTxtNd = aUpd.GetList().GetObject( nFirst );
1443 
1444 //                aRegH.RegisterInModify( pTxtNd, *pTxtNd );
1445 
1446 //                pTxtNd->SwCntntNode::SetAttr( aRule );
1447 //                pTxtNd->NumRuleChgd();
1448 //            }
1449             for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin();
1450                   aIter != aTxtNodeList.end(); ++aIter )
1451             {
1452                 SwTxtNode* pTxtNd = *aIter;
1453 
1454                 if ( pGivenTxtNode &&
1455                      pGivenTxtNode->GetListId() == pTxtNd->GetListId() )
1456                 {
1457                     aRegH.RegisterInModify( pTxtNd, *pTxtNd );
1458 
1459                     pTxtNd->SetAttr( aRule );
1460                     pTxtNd->NumRuleChgd();
1461                 }
1462             }
1463             GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
1464             SetModified();
1465 
1466             bRet = sal_True;     // #106897#
1467         }
1468     }
1469 
1470     return bRet;
1471 }
1472 
1473 // --> OD 2008-03-18 #refactorlists#
1474 namespace
1475 {
1476     struct ListStyleData
1477     {
1478         SwNumRule* pReplaceNumRule;
1479         bool bCreateNewList;
1480         String sListId;
1481 
1482         ListStyleData()
1483             : pReplaceNumRule( 0 ),
1484               bCreateNewList( false ),
1485               sListId()
1486         {}
1487     };
1488 }
1489 // <--
1490 
1491 void SwDoc::MakeUniqueNumRules(const SwPaM & rPaM)
1492 {
1493     ASSERT( rPaM.GetDoc() == this, "need same doc" );
1494 
1495     // --> OD 2008-03-18 #refactorlists#
1496 //    map<SwNumRule *, SwNumRule *> aMyNumRuleMap;
1497     ::std::map<SwNumRule *, ListStyleData> aMyNumRuleMap;
1498     // <--
1499 
1500     sal_uLong nStt = rPaM.Start()->nNode.GetIndex();
1501     sal_uLong nEnd = rPaM.End()->nNode.GetIndex();
1502 
1503     bool bFirst = true;
1504 
1505     for (sal_uLong n = nStt; n <= nEnd; n++)
1506     {
1507         SwTxtNode * pCNd = GetNodes()[n]->GetTxtNode();
1508 
1509         if (pCNd)
1510         {
1511             SwNumRule * pRule = pCNd->GetNumRule();
1512 
1513             if (pRule && pRule->IsAutoRule() && ! pRule->IsOutlineRule())
1514             {
1515                 // --> OD 2008-03-18 #refactorlists#
1516 //                SwNumRule * pReplaceNumRule = aMyNumRuleMap[pRule];
1517                 ListStyleData aListStyleData = aMyNumRuleMap[pRule];
1518 
1519 //                if (! pReplaceNumRule)
1520                 if ( aListStyleData.pReplaceNumRule == 0 )
1521                 {
1522                     if (bFirst)
1523                     {
1524                         SwPosition aPos(*pCNd);
1525                         aListStyleData.pReplaceNumRule =
1526                             const_cast<SwNumRule *>
1527                             (SearchNumRule( aPos, false, pCNd->HasNumber(),
1528                                             false, 0,
1529                                             aListStyleData.sListId, true ));
1530                     }
1531 
1532 //                    if (! pReplaceNumRule)
1533                     if ( aListStyleData.pReplaceNumRule == 0 )
1534                     {
1535 //                        pReplaceNumRule = new SwNumRule(*pRule);
1536 //                        pReplaceNumRule->SetName(GetUniqueNumRuleName());
1537                         aListStyleData.pReplaceNumRule = new SwNumRule(*pRule);
1538                         // --> OD 2008-07-08 #i91400#
1539                         aListStyleData.pReplaceNumRule->SetName(
1540                                                 GetUniqueNumRuleName(), *this );
1541                         // <--
1542                         aListStyleData.bCreateNewList = true;
1543                     }
1544 
1545 //                    aMyNumRuleMap[pRule] = pReplaceNumRule;
1546                     aMyNumRuleMap[pRule] = aListStyleData;
1547                 }
1548 
1549                 SwPaM aPam(*pCNd);
1550 
1551                 SetNumRule( aPam, *aListStyleData.pReplaceNumRule,
1552                             aListStyleData.bCreateNewList,
1553                             aListStyleData.sListId );
1554                 if ( aListStyleData.bCreateNewList )
1555                 {
1556                     aListStyleData.bCreateNewList = false;
1557                     aListStyleData.sListId = pCNd->GetListId();
1558                     aMyNumRuleMap[pRule] = aListStyleData;
1559                 }
1560                 // <--
1561 
1562                 bFirst = false;
1563             }
1564         }
1565     }
1566 }
1567 
1568 sal_Bool SwDoc::NoNum( const SwPaM& rPam )
1569 {
1570 
1571     sal_Bool bRet = SplitNode( *rPam.GetPoint(), false );
1572     // ist ueberhaupt Nummerierung im Spiel ?
1573     if( bRet )
1574     {
1575         // NoNum setzen und Upaten
1576         const SwNodeIndex& rIdx = rPam.GetPoint()->nNode;
1577         SwTxtNode* pNd = rIdx.GetNode().GetTxtNode();
1578         const SwNumRule* pRule = pNd->GetNumRule();
1579         if( pRule )
1580         {
1581             pNd->SetCountedInList(false);
1582 
1583             SetModified();
1584         }
1585         else
1586             bRet = sal_False;   // keine Nummerierung , ?? oder immer sal_True ??
1587     }
1588     return bRet;
1589 }
1590 
1591 void SwDoc::DelNumRules( const SwPaM& rPam )
1592 {
1593     sal_uLong nStt = rPam.GetPoint()->nNode.GetIndex(),
1594             nEnd = rPam.GetMark()->nNode.GetIndex();
1595     if( nStt > nEnd )
1596     {
1597         sal_uLong nTmp = nStt; nStt = nEnd; nEnd = nTmp;
1598     }
1599 
1600     SwUndoDelNum* pUndo;
1601     if (GetIDocumentUndoRedo().DoesUndo())
1602     {
1603         pUndo = new SwUndoDelNum( rPam );
1604         GetIDocumentUndoRedo().AppendUndo(pUndo);
1605     }
1606     else
1607         pUndo = 0;
1608 
1609     SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 );
1610 
1611     SwNumRuleItem aEmptyRule( aEmptyStr );
1612     const SwNode* pOutlNd = 0;
1613     for( ; nStt <= nEnd; ++nStt )
1614     {
1615         SwTxtNode* pTNd = GetNodes()[ nStt ]->GetTxtNode();
1616         // --> OD 2008-03-13 #refactorlists#
1617 //        if( pTNd && 0 != ( pItem = pTNd->GetNoCondAttr(
1618 //            RES_PARATR_NUMRULE, sal_True ) ) &&
1619 //            ( pName = &((SwNumRuleItem*)pItem)->GetValue())->Len() )
1620         SwNumRule* pNumRuleOfTxtNode = pTNd ? pTNd->GetNumRule() : 0;
1621         if ( pTNd && pNumRuleOfTxtNode )
1622         // <--
1623         {
1624             // recognize changes of attribute for undo
1625             aRegH.RegisterInModify( pTNd, *pTNd );
1626 
1627             if( pUndo )
1628                 pUndo->AddNode( *pTNd, sal_False );
1629 
1630             // directly set list style attribute is reset, otherwise empty
1631             // list style is applied
1632             const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet();
1633             if ( pAttrSet &&
1634                  pAttrSet->GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET )
1635                 pTNd->ResetAttr( RES_PARATR_NUMRULE );
1636             else
1637                 pTNd->SetAttr( aEmptyRule );
1638 
1639             // --> OD 2008-03-26 #refactorlists#
1640             pTNd->ResetAttr( RES_PARATR_LIST_ID );
1641             pTNd->ResetAttr( RES_PARATR_LIST_LEVEL );
1642             pTNd->ResetAttr( RES_PARATR_LIST_ISRESTART );
1643             pTNd->ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
1644             pTNd->ResetAttr( RES_PARATR_LIST_ISCOUNTED );
1645             // <--
1646 
1647             if( RES_CONDTXTFMTCOLL == pTNd->GetFmtColl()->Which() )
1648                 pTNd->ChkCondColl();
1649             //else if( !pOutlNd && NO_NUMBERING != //#outline level,zhaojianwei
1650             //  ((SwTxtFmtColl*)pTNd->GetFmtColl())->GetOutlineLevel() )
1651             else if( !pOutlNd &&
1652                 ((SwTxtFmtColl*)pTNd->GetFmtColl())->IsAssignedToListLevelOfOutlineStyle() )//<-end,zhaojianwei
1653                 pOutlNd = pTNd;
1654         }
1655     }
1656 
1657     // dann noch alle Updaten
1658     UpdateNumRule();
1659 
1660     if( pOutlNd )
1661         GetNodes().UpdtOutlineIdx( *pOutlNd );
1662 }
1663 
1664 void SwDoc::InvalidateNumRules()
1665 {
1666     for (sal_uInt16 n = 0; n < pNumRuleTbl->Count(); ++n)
1667         (*pNumRuleTbl)[n]->SetInvalidRule(sal_True);
1668 }
1669 
1670     // zum naechsten/vorhergehenden Punkt auf gleicher Ebene
1671 
1672 sal_Bool lcl_IsNumOk( sal_uInt8 nSrchNum, sal_uInt8& rLower, sal_uInt8& rUpper,
1673                     sal_Bool bOverUpper, sal_uInt8 nNumber )
1674 {
1675     // --> OD 2008-04-02 #refactorlists#
1676     ASSERT( nNumber < MAXLEVEL,
1677             "<lcl_IsNumOk(..)> - misusage of method" );
1678     // <--
1679 
1680     sal_Bool bRet = sal_False;
1681     {
1682         if( bOverUpper ? nSrchNum == nNumber : nSrchNum >= nNumber )
1683             bRet = sal_True;
1684         else if( nNumber > rLower )
1685             rLower = nNumber;
1686         else if( nNumber < rUpper )
1687             rUpper = nNumber;
1688     }
1689     return bRet;
1690 }
1691 
1692 sal_Bool lcl_IsValidPrevNextNumNode( const SwNodeIndex& rIdx )
1693 {
1694     sal_Bool bRet = sal_False;
1695     const SwNode& rNd = rIdx.GetNode();
1696     switch( rNd.GetNodeType() )
1697     {
1698     case ND_ENDNODE:
1699         bRet = SwTableBoxStartNode == rNd.StartOfSectionNode()->GetStartNodeType() ||
1700                 rNd.StartOfSectionNode()->IsSectionNode();
1701         break;
1702 
1703     case ND_STARTNODE:
1704         bRet = SwTableBoxStartNode == ((SwStartNode&)rNd).GetStartNodeType();
1705         break;
1706 
1707     case ND_SECTIONNODE:            // der ist erlaubt, also weiter
1708         bRet = sal_True;
1709         break;
1710     }
1711     return bRet;
1712 }
1713 
1714 sal_Bool lcl_GotoNextPrevNum( SwPosition& rPos, sal_Bool bNext,
1715                             sal_Bool bOverUpper, sal_uInt8* pUpper, sal_uInt8* pLower )
1716 {
1717     const SwTxtNode* pNd = rPos.nNode.GetNode().GetTxtNode();
1718     const SwNumRule* pRule;
1719     if( !pNd || 0 == ( pRule = pNd->GetNumRule()))
1720         return sal_False;
1721 
1722     sal_uInt8 nSrchNum = static_cast<sal_uInt8>(pNd->GetActualListLevel());
1723 
1724     SwNodeIndex aIdx( rPos.nNode );
1725     if( ! pNd->IsCountedInList() )
1726     {
1727         // falls gerade mal NO_NUMLEVEL an ist, so such den vorherigen Node
1728         // mit Nummerierung
1729         sal_Bool bError = sal_False;
1730         do {
1731             aIdx--;
1732             if( aIdx.GetNode().IsTxtNode() )
1733             {
1734                 pNd = aIdx.GetNode().GetTxtNode();
1735                 pRule = pNd->GetNumRule();
1736 
1737                 sal_uInt8 nTmpNum;
1738 
1739                 if( pRule  )
1740                 {
1741                     nTmpNum = static_cast<sal_uInt8>(pNd->GetActualListLevel());
1742                     if( !( ! pNd->IsCountedInList() &&
1743                          (nTmpNum >= nSrchNum )) )
1744                         break;      // gefunden
1745                 }
1746                 else
1747                     bError = sal_True;
1748             }
1749             else
1750                 bError = !lcl_IsValidPrevNextNumNode( aIdx );
1751 
1752         } while( !bError );
1753         if( bError )
1754             return sal_False;
1755     }
1756 
1757     sal_uInt8 nLower = nSrchNum, nUpper = nSrchNum;
1758     sal_Bool bRet = sal_False;
1759 
1760     const SwTxtNode* pLast;
1761     if( bNext )
1762         aIdx++, pLast = pNd;
1763     else
1764         aIdx--, pLast = 0;
1765 
1766     while( bNext ? ( aIdx.GetIndex() < aIdx.GetNodes().Count() - 1 )
1767                  : aIdx.GetIndex() )
1768     {
1769         if( aIdx.GetNode().IsTxtNode() )
1770         {
1771             pNd = aIdx.GetNode().GetTxtNode();
1772             pRule = pNd->GetNumRule();
1773             if( pRule )
1774             {
1775                 if( ::lcl_IsNumOk( nSrchNum, nLower, nUpper, bOverUpper,
1776                                     static_cast<sal_uInt8>(pNd->GetActualListLevel()) ))
1777                 {
1778                     rPos.nNode = aIdx;
1779                     rPos.nContent.Assign( (SwTxtNode*)pNd, 0 );
1780                     bRet = sal_True;
1781                     break;
1782                 }
1783                 else
1784                     pLast = pNd;
1785             }
1786             else
1787                 break;
1788         }
1789         else if( !lcl_IsValidPrevNextNumNode( aIdx ))
1790             break;
1791 
1792         if( bNext )
1793             aIdx++;
1794         else
1795             aIdx--;
1796     }
1797 
1798     if( !bRet && !bOverUpper && pLast )     // nicht ueber hoehere Nummmern, aber bis Ende
1799     {
1800         if( bNext )
1801         {
1802             rPos.nNode = aIdx;
1803             if( aIdx.GetNode().IsCntntNode() )
1804                 rPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 );
1805         }
1806         else
1807         {
1808             rPos.nNode.Assign( *pLast );
1809             rPos.nContent.Assign( (SwTxtNode*)pLast, 0 );
1810         }
1811         bRet = sal_True;
1812     }
1813 
1814     if( bRet )
1815     {
1816         if( pUpper )
1817             *pUpper = nUpper;
1818         if( pLower )
1819             *pLower = nLower;
1820     }
1821     return bRet;
1822 }
1823 
1824 sal_Bool SwDoc::GotoNextNum( SwPosition& rPos, sal_Bool bOverUpper,
1825                             sal_uInt8* pUpper, sal_uInt8* pLower  )
1826 {
1827    return ::lcl_GotoNextPrevNum( rPos, sal_True, bOverUpper, pUpper, pLower );
1828 }
1829 
1830 // -> #i23731#
1831 // --> OD 2008-03-18 #refactorlists# - add output parameter <sListId>
1832 const SwNumRule *  SwDoc::SearchNumRule(const SwPosition & rPos,
1833                                         const bool bForward,
1834                                         const bool bNum,
1835                                         const bool bOutline,
1836                                         int nNonEmptyAllowed,
1837                                         String& sListId,
1838                                         const bool bInvestigateStartNode)
1839 {
1840     const SwNumRule * pResult = NULL;
1841     SwTxtNode * pTxtNd = rPos.nNode.GetNode().GetTxtNode();
1842     SwNode * pStartFromNode = pTxtNd;
1843 
1844     if (pTxtNd)
1845     {
1846         SwNodeIndex aIdx(rPos.nNode);
1847 
1848         // --> OD 2005-10-20 #i55391#
1849         // - the start node has also been investigated, if requested.
1850         const SwNode * pNode = NULL;
1851         do
1852         {
1853             // --> OD 2005-10-20 #i55391#
1854             if ( !bInvestigateStartNode )
1855             {
1856                 if (bForward)
1857                     aIdx++;
1858                 else
1859                     aIdx--;
1860             }
1861             // <--
1862             if (aIdx.GetNode().IsTxtNode())
1863             {
1864                 pTxtNd = aIdx.GetNode().GetTxtNode();
1865 
1866                 const SwNumRule * pNumRule = pTxtNd->GetNumRule();
1867                 if (pNumRule)
1868                 {
1869                     if ( ( pNumRule->IsOutlineRule() == ( bOutline ? sal_True : sal_False ) ) && // #115901#
1870                          ( ( bNum && pNumRule->Get(0).IsEnumeration()) ||
1871                            ( !bNum && pNumRule->Get(0).IsItemize() ) ) ) // #i22362#, #i29560#
1872                     {
1873                         pResult = pTxtNd->GetNumRule();
1874                         // --> OD 2008-03-18 #refactorlists#
1875                         // provide also the list id, to which the text node belongs.
1876                         sListId = pTxtNd->GetListId();
1877                     }
1878 
1879                     break;
1880                 }
1881                 else if (pTxtNd->Len() > 0 || NULL != pTxtNd->GetNumRule())
1882                 {
1883                     if (nNonEmptyAllowed == 0)
1884                         break;
1885 
1886                     nNonEmptyAllowed--;
1887 
1888                     if (nNonEmptyAllowed < 0)
1889                         nNonEmptyAllowed = -1;
1890                 }
1891             }
1892 
1893             // --> OD 2005-10-20 #i55391#
1894             if ( bInvestigateStartNode )
1895             {
1896                 if (bForward)
1897                     aIdx++;
1898                 else
1899                     aIdx--;
1900             }
1901             // <--
1902 
1903             pNode = &aIdx.GetNode();
1904         }
1905         while (!(pNode == GetNodes().DocumentSectionStartNode(pStartFromNode) ||
1906                  pNode == GetNodes().DocumentSectionEndNode(pStartFromNode)));
1907         // <--
1908     }
1909 
1910     return pResult;
1911 }
1912 // <- #i23731#
1913 
1914 sal_Bool SwDoc::GotoPrevNum( SwPosition& rPos, sal_Bool bOverUpper,
1915                             sal_uInt8* pUpper, sal_uInt8* pLower  )
1916 {
1917    return ::lcl_GotoNextPrevNum( rPos, sal_False, bOverUpper, pUpper, pLower );
1918 }
1919 
1920 sal_Bool SwDoc::NumUpDown( const SwPaM& rPam, sal_Bool bDown )
1921 {
1922     sal_uLong nStt = rPam.GetPoint()->nNode.GetIndex(),
1923             nEnd = rPam.GetMark()->nNode.GetIndex();
1924     if( nStt > nEnd )
1925     {
1926         sal_uLong nTmp = nStt; nStt = nEnd; nEnd = nTmp;
1927     }
1928 
1929     // -> #115901# outline nodes are promoted or demoted differently
1930     bool bOnlyOutline = true;
1931     bool bOnlyNonOutline = true;
1932     for (sal_uLong n = nStt; n <= nEnd; n++)
1933     {
1934         SwTxtNode * pTxtNd = GetNodes()[n]->GetTxtNode();
1935 
1936         if (pTxtNd)
1937         {
1938             SwNumRule * pRule = pTxtNd->GetNumRule();
1939 
1940             if (pRule)
1941             {
1942                 if (pRule->IsOutlineRule())
1943                     bOnlyNonOutline = false;
1944                 else
1945                     bOnlyOutline = false;
1946             }
1947         }
1948     }
1949     // <- #115901#
1950 
1951     sal_Bool bRet = sal_True;
1952     char nDiff = bDown ? 1 : -1;
1953 
1954     // ->#115901#
1955     if (bOnlyOutline)
1956         bRet = OutlineUpDown(rPam, nDiff);
1957     else if (bOnlyNonOutline)
1958     {
1959         /* --> #i24560#
1960 
1961         Only promote or demote if all selected paragraphs are
1962         promotable resp. demotable.
1963 
1964         */
1965         for (sal_uLong nTmp = nStt; nTmp <= nEnd; ++nTmp)
1966         {
1967             SwTxtNode* pTNd = GetNodes()[ nTmp ]->GetTxtNode();
1968 
1969             // --> OD 2006-10-19 #134160# - make code robust:
1970             // consider case that the node doesn't denote a text node.
1971             if ( pTNd )
1972             {
1973                 SwNumRule * pRule = pTNd->GetNumRule();
1974 
1975                 if (pRule)
1976                 {
1977                     sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel());
1978                     if( (-1 == nDiff && 0 >= nLevel) ||
1979                         (1 == nDiff && MAXLEVEL - 1 <= nLevel))
1980                         bRet = sal_False;
1981                 }
1982             }
1983             // <--
1984         }
1985 
1986         if( bRet )
1987         {
1988             /* <-- #i24560# */
1989             if (GetIDocumentUndoRedo().DoesUndo())
1990             {
1991                 SwUndo *const pUndo( new SwUndoNumUpDown(rPam, nDiff) );
1992                 GetIDocumentUndoRedo().AppendUndo(pUndo);
1993             }
1994 
1995             String sNumRule;
1996 
1997             for(sal_uLong nTmp = nStt; nTmp <= nEnd; ++nTmp )
1998             {
1999                 SwTxtNode* pTNd = GetNodes()[ nTmp ]->GetTxtNode();
2000 
2001                 if( pTNd)
2002                 {
2003                     SwNumRule * pRule = pTNd->GetNumRule();
2004 
2005                     if (pRule)
2006                     {
2007                         sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel());
2008                         nLevel = nLevel + nDiff;
2009 
2010                         pTNd->SetAttrListLevel(nLevel);
2011                     }
2012                 }
2013             }
2014 
2015             ChkCondColls();
2016             SetModified();
2017         }
2018     }
2019 
2020     return bRet;
2021 }
2022 
2023 sal_Bool SwDoc::MoveParagraph( const SwPaM& rPam, long nOffset, sal_Bool bIsOutlMv )
2024 {
2025     const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
2026 
2027     sal_uLong nStIdx = pStt->nNode.GetIndex();
2028     sal_uLong nEndIdx = pEnd->nNode.GetIndex();
2029 
2030     // Here are some sophisticated checks whether the wished PaM will be moved or not.
2031     // For moving outlines (bIsOutlMv) I've already done some checks, so here are two different
2032     // checks...
2033     SwNode *pTmp1;
2034     SwNode *pTmp2;
2035     if( bIsOutlMv )
2036     {
2037         // For moving chapters (outline) the following reason will deny the move:
2038         // if a start node is inside the moved area and its end node outside or vice versa.
2039         // If a start node is the first moved paragraph, its end node has to be within the moved
2040         // area, too (e.g. as last node).
2041         // If an end node is the last node of the moved area, its start node has to be a part of
2042         // the moved section, too.
2043         pTmp1 = GetNodes()[ nStIdx ];
2044         if( pTmp1->IsStartNode() )
2045         {   // First is a start node
2046             pTmp2 = pTmp1->EndOfSectionNode();
2047             if( pTmp2->GetIndex() > nEndIdx )
2048                 return sal_False; // Its end node is behind the moved range
2049         }
2050         pTmp1 = pTmp1->StartOfSectionNode()->EndOfSectionNode();
2051         if( pTmp1->GetIndex() <= nEndIdx )
2052             return sal_False; // End node inside but start node before moved range => no.
2053         pTmp1 = GetNodes()[ nEndIdx ];
2054         if( pTmp1->IsEndNode() )
2055         {   // The last one is an end node
2056             pTmp1 = pTmp1->StartOfSectionNode();
2057             if( pTmp1->GetIndex() < nStIdx )
2058                 return sal_False; // Its start node is before the moved range.
2059         }
2060         pTmp1 = pTmp1->StartOfSectionNode();
2061         if( pTmp1->GetIndex() >= nStIdx )
2062             return sal_False; // A start node which ends behind the moved area => no.
2063     }
2064 
2065     sal_uLong nInStIdx, nInEndIdx;
2066     long nOffs = nOffset;
2067     if( nOffset > 0 )
2068     {
2069         nInEndIdx = nEndIdx;
2070         nEndIdx += nOffset;
2071         ++nOffs;
2072     }
2073     else
2074     {
2075         //Impossible to move to negative index
2076         if( sal_uLong(abs( nOffset )) > nStIdx)
2077             return sal_False;
2078 
2079         nInEndIdx = nStIdx - 1;
2080         nStIdx += nOffset;
2081     }
2082     nInStIdx = nInEndIdx + 1;
2083     // Folgende Absatzbloecke sollen vertauscht werden:
2084     // [ nStIdx, nInEndIdx ] mit [ nInStIdx, nEndIdx ]
2085 
2086     if( nEndIdx >= GetNodes().GetEndOfContent().GetIndex() )
2087         return sal_False;
2088 
2089     if( !bIsOutlMv )
2090     {   // And here the restrictions for moving paragraphs other than chapters (outlines)
2091         // The plan is to exchange [nStIdx,nInEndIdx] and [nStartIdx,nEndIdx]
2092         // It will checked if the both "start" nodes as well as the both "end" notes belongs to
2093         // the same start-end-section. This is more restrictive than the conditions checked above.
2094         // E.g. a paragraph will not escape from a section or be inserted to another section.
2095         pTmp1 = GetNodes()[ nStIdx ]->StartOfSectionNode();
2096         pTmp2 = GetNodes()[ nInStIdx ]->StartOfSectionNode();
2097         if( pTmp1 != pTmp2 )
2098             return sal_False; // "start" nodes in different sections
2099         pTmp1 = GetNodes()[ nEndIdx ];
2100         bool bIsEndNode = pTmp1->IsEndNode();
2101         if( !pTmp1->IsStartNode() )
2102         {
2103             pTmp1 = pTmp1->StartOfSectionNode();
2104             if( bIsEndNode ) // For end nodes the first start node is of course inside the range,
2105                 pTmp1 = pTmp1->StartOfSectionNode(); // I've to check the start node of the start node.
2106         }
2107         pTmp1 = pTmp1->EndOfSectionNode();
2108         pTmp2 = GetNodes()[ nInEndIdx ];
2109         if( !pTmp2->IsStartNode() )
2110         {
2111             bIsEndNode = pTmp2->IsEndNode();
2112             pTmp2 = pTmp2->StartOfSectionNode();
2113             if( bIsEndNode )
2114                 pTmp2 = pTmp2->StartOfSectionNode();
2115         }
2116         pTmp2 = pTmp2->EndOfSectionNode();
2117         if( pTmp1 != pTmp2 )
2118             return sal_False; // The "end" notes are in different sections
2119     }
2120 
2121     // auf Redlining testen - darf die Selektion ueberhaupt verschoben
2122     // werden?
2123     if( !IsIgnoreRedline() )
2124     {
2125         sal_uInt16 nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), nsRedlineType_t::REDLINE_DELETE );
2126         if( USHRT_MAX != nRedlPos )
2127         {
2128             SwPosition aStPos( *pStt ), aEndPos( *pEnd );
2129             aStPos.nContent = 0;
2130             SwCntntNode* pCNd = pEnd->nNode.GetNode().GetCntntNode();
2131             aEndPos.nContent = pCNd ? pCNd->Len() : 1;
2132             sal_Bool bCheckDel = sal_True;
2133 
2134             // es existiert fuer den Bereich irgendein Redline-Delete-Object
2135             for( ; nRedlPos < GetRedlineTbl().Count(); ++nRedlPos )
2136             {
2137                 const SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
2138                 if( !bCheckDel || nsRedlineType_t::REDLINE_DELETE == pTmp->GetType() )
2139                 {
2140                     const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
2141                     switch( ComparePosition( *pRStt, *pREnd, aStPos, aEndPos ))
2142                     {
2143                     case POS_COLLIDE_START:
2144                     case POS_BEHIND:            // Pos1 liegt hinter Pos2
2145                         nRedlPos = GetRedlineTbl().Count();
2146                         break;
2147 
2148                     case POS_COLLIDE_END:
2149                     case POS_BEFORE:            // Pos1 liegt vor Pos2
2150                         break;
2151                     case POS_INSIDE:            // Pos1 liegt vollstaendig in Pos2
2152                         // ist erlaubt, aber checke dann alle nachfolgenden
2153                         // auf Ueberlappungen
2154                         bCheckDel = sal_False;
2155                         break;
2156 
2157                     case POS_OUTSIDE:           // Pos2 liegt vollstaendig in Pos1
2158                     case POS_EQUAL:             // Pos1 ist genauso gross wie Pos2
2159                     case POS_OVERLAP_BEFORE:    // Pos1 ueberlappt Pos2 am Anfang
2160                     case POS_OVERLAP_BEHIND:    // Pos1 ueberlappt Pos2 am Ende
2161                         return sal_False;
2162                     }
2163                 }
2164             }
2165         }
2166     }
2167 
2168     {
2169         // DataChanged vorm verschieben verschicken, dann bekommt
2170         // man noch mit, welche Objecte sich im Bereich befinden.
2171         // Danach koennen sie vor/hinter der Position befinden.
2172         SwDataChanged aTmp( rPam, 0 );
2173     }
2174 
2175     SwNodeIndex aIdx( nOffset > 0 ? pEnd->nNode : pStt->nNode, nOffs );
2176     SwNodeRange aMvRg( pStt->nNode, 0, pEnd->nNode, +1 );
2177 
2178     SwRedline* pOwnRedl = 0;
2179     if( IsRedlineOn() )
2180     {
2181         // wenn der Bereich komplett im eigenen Redline liegt, kann es
2182         // verschoben werden!
2183         sal_uInt16 nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), nsRedlineType_t::REDLINE_INSERT );
2184         if( USHRT_MAX != nRedlPos )
2185         {
2186             SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
2187             const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
2188             SwRedline aTmpRedl( nsRedlineType_t::REDLINE_INSERT, rPam );
2189             const SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();
2190             // liegt komplett im Bereich, und ist auch der eigene Redline?
2191             if( aTmpRedl.IsOwnRedline( *pTmp ) &&
2192                 (pRStt->nNode < pStt->nNode ||
2193                 (pRStt->nNode == pStt->nNode && !pRStt->nContent.GetIndex()) ) &&
2194                 (pEnd->nNode < pREnd->nNode ||
2195                 (pEnd->nNode == pREnd->nNode &&
2196                  pCEndNd ? pREnd->nContent.GetIndex() == pCEndNd->Len()
2197                          : !pREnd->nContent.GetIndex() )) )
2198             {
2199                 pOwnRedl = pTmp;
2200                 if( nRedlPos + 1 < GetRedlineTbl().Count() )
2201                 {
2202                     pTmp = GetRedlineTbl()[ nRedlPos+1 ];
2203                     if( *pTmp->Start() == *pREnd )
2204                         // dann doch nicht!
2205                         pOwnRedl = 0;
2206                 }
2207 
2208                 if( pOwnRedl &&
2209                     !( pRStt->nNode <= aIdx && aIdx <= pREnd->nNode ))
2210                 {
2211                     // nicht in sich selbst, dann auch nicht moven
2212                     pOwnRedl = 0;
2213                 }
2214             }
2215         }
2216 
2217         if( !pOwnRedl )
2218         {
2219             GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL );
2220 
2221             // zuerst das Insert, dann das Loeschen
2222             SwPosition aInsPos( aIdx );
2223             aInsPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 );
2224 
2225             SwPaM aPam( pStt->nNode, aMvRg.aEnd );
2226 
2227             SwPaM& rOrigPam = (SwPaM&)rPam;
2228             rOrigPam.DeleteMark();
2229             rOrigPam.GetPoint()->nNode = aIdx.GetIndex() - 1;
2230 
2231             sal_Bool bDelLastPara = !aInsPos.nNode.GetNode().IsCntntNode();
2232 
2233             /* #101076# When copying to a non-content node Copy will
2234                insert a paragraph before that node and insert before
2235                that inserted node. Copy creates an SwUndoInserts that
2236                does not cover the extra paragraph. Thus we insert the
2237                extra paragraph ourselves, _with_ correct undo
2238                information. */
2239             if (bDelLastPara)
2240             {
2241                 /* aInsPos points to the non-content node. Move it to
2242                    the previous content node. */
2243                 SwPaM aInsPam(aInsPos);
2244                 sal_Bool bMoved = aInsPam.Move(fnMoveBackward);
2245                 ASSERT(bMoved, "No content node found!");
2246 
2247                 if (bMoved)
2248                 {
2249                     /* Append the new node after the content node
2250                        found. The new position to insert the moved
2251                        paragraph at is before the inserted
2252                        paragraph. */
2253                     AppendTxtNode(*aInsPam.GetPoint());
2254                     aInsPos = *aInsPam.GetPoint();
2255                 }
2256             }
2257 
2258             CopyRange( aPam, aInsPos, false );
2259             if( bDelLastPara )
2260             {
2261                 // dann muss der letzte leere Node wieder entfernt werden
2262                 aIdx = aInsPos.nNode;
2263                 SwCntntNode* pCNd = GetNodes().GoPrevious( &aInsPos.nNode );
2264                 xub_StrLen nCLen = 0; if( pCNd ) nCLen = pCNd->Len();
2265                 aInsPos.nContent.Assign( pCNd, nCLen );
2266 
2267                 // alle die im zu loeschenden Node stehen, mussen auf den
2268                 // naechsten umgestezt werden
2269                 SwPosition* pPos;
2270                 for( sal_uInt16 n = 0; n < GetRedlineTbl().Count(); ++n )
2271                 {
2272                     SwRedline* pTmp = GetRedlineTbl()[ n ];
2273                     if( ( pPos = &pTmp->GetBound(sal_True))->nNode == aIdx )
2274                     {
2275                         pPos->nNode++;
2276                         pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0);
2277                     }
2278                     if( ( pPos = &pTmp->GetBound(sal_False))->nNode == aIdx )
2279                     {
2280                         pPos->nNode++;
2281                         pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0);
2282                     }
2283                 }
2284                 CorrRel( aIdx, aInsPos, 0, sal_False );
2285 
2286                 pCNd->JoinNext();
2287             }
2288 
2289             rOrigPam.GetPoint()->nNode++;
2290             rOrigPam.GetPoint()->nContent.Assign( rOrigPam.GetCntntNode(), 0 );
2291 
2292             RedlineMode_t eOld = GetRedlineMode();
2293             checkRedlining(eOld);
2294             if (GetIDocumentUndoRedo().DoesUndo())
2295             {
2296                 //JP 06.01.98: MUSS noch optimiert werden!!!
2297                 SetRedlineMode(
2298                    (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE));
2299                 SwUndo *const pUndo(new SwUndoRedlineDelete(aPam, UNDO_DELETE));
2300                 GetIDocumentUndoRedo().AppendUndo(pUndo);
2301             }
2302 
2303             SwRedline* pNewRedline = new SwRedline( nsRedlineType_t::REDLINE_DELETE, aPam );
2304 
2305             // #101654# prevent assertion from aPam's target being deleted
2306             // (Alternatively, one could just let aPam go out of scope, but
2307             //  that requires touching a lot of code.)
2308             aPam.GetBound(sal_True).nContent.Assign( NULL, 0 );
2309             aPam.GetBound(sal_False).nContent.Assign( NULL, 0 );
2310 
2311             AppendRedline( pNewRedline, true );
2312 
2313 //JP 06.01.98: MUSS noch optimiert werden!!!
2314 SetRedlineMode( eOld );
2315             GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
2316             SetModified();
2317 
2318             return sal_True;
2319         }
2320     }
2321 
2322     if( !pOwnRedl && !IsIgnoreRedline() && GetRedlineTbl().Count() )
2323     {
2324         SwPaM aTemp(aIdx);
2325         SplitRedline(aTemp);
2326     }
2327 
2328     sal_uLong nRedlSttNd(0), nRedlEndNd(0);
2329     if( pOwnRedl )
2330     {
2331         const SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End();
2332         nRedlSttNd = pRStt->nNode.GetIndex();
2333         nRedlEndNd = pREnd->nNode.GetIndex();
2334     }
2335 
2336     SwUndoMoveNum* pUndo = 0;
2337     sal_uLong nMoved = 0;
2338     if (GetIDocumentUndoRedo().DoesUndo())
2339     {
2340         pUndo = new SwUndoMoveNum( rPam, nOffset, bIsOutlMv );
2341         nMoved = rPam.End()->nNode.GetIndex() - rPam.Start()->nNode.GetIndex() + 1;
2342     }
2343 
2344 
2345     MoveNodeRange( aMvRg, aIdx, DOC_MOVEREDLINES );
2346 
2347     if( pUndo )
2348     {
2349         // i57907: Under circumstances (sections at the end of a chapter)
2350         // the rPam.Start() is not moved to the new position.
2351         // But aIdx should be at the new end position and as long as the number of moved paragraphs
2352         // is nMoved, I know, where the new position is.
2353         pUndo->SetStartNode( aIdx.GetIndex() - nMoved );
2354         GetIDocumentUndoRedo().AppendUndo(pUndo);
2355     }
2356 
2357     if( pOwnRedl )
2358     {
2359         SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End();
2360         if( pRStt->nNode.GetIndex() != nRedlSttNd )
2361         {
2362             pRStt->nNode = nRedlSttNd;
2363             pRStt->nContent.Assign( pRStt->nNode.GetNode().GetCntntNode(),0);
2364         }
2365         if( pREnd->nNode.GetIndex() != nRedlEndNd )
2366         {
2367             pREnd->nNode = nRedlEndNd;
2368             SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode();
2369             xub_StrLen nL = 0; if( pCNd ) nL = pCNd->Len();
2370             pREnd->nContent.Assign( pCNd, nL );
2371         }
2372     }
2373 
2374     SetModified();
2375     return sal_True;
2376 }
2377 
2378 sal_Bool SwDoc::NumOrNoNum( const SwNodeIndex& rIdx, sal_Bool bDel )
2379 {
2380     sal_Bool bResult = sal_False;
2381     SwTxtNode * pTxtNd = rIdx.GetNode().GetTxtNode();
2382 
2383     if (pTxtNd && pTxtNd->GetNumRule() != NULL &&
2384         (pTxtNd->HasNumber() || pTxtNd->HasBullet()))
2385     {
2386         if ( !pTxtNd->IsCountedInList() == !bDel)
2387         {
2388             sal_Bool bOldNum = bDel; // == pTxtNd->IsCounted();
2389             sal_Bool bNewNum = bDel ? sal_False : sal_True;
2390             pTxtNd->SetCountedInList(bNewNum ? true : false);
2391 
2392             SetModified();
2393 
2394             bResult = sal_True;
2395 
2396             if (GetIDocumentUndoRedo().DoesUndo())
2397             {
2398                 SwUndoNumOrNoNum * pUndo =
2399                     new SwUndoNumOrNoNum(rIdx, bOldNum, bNewNum);
2400 
2401                 GetIDocumentUndoRedo().AppendUndo(pUndo);
2402             }
2403         }
2404         else if (bDel && pTxtNd->GetNumRule(sal_False) &&
2405                  pTxtNd->GetActualListLevel() >= 0 &&
2406                  pTxtNd->GetActualListLevel() < MAXLEVEL)
2407         {
2408             SwPaM aPam(*pTxtNd);
2409 
2410             DelNumRules(aPam);
2411 
2412             bResult = sal_True;
2413         }
2414     }
2415 
2416     return bResult;
2417 }
2418 
2419 SwNumRule* SwDoc::GetCurrNumRule( const SwPosition& rPos ) const
2420 {
2421     SwNumRule* pRet = 0;
2422     SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
2423 
2424     if( pTNd )
2425     {
2426         // --> OD 2008-02-20 #refactorlists#
2427 //        pTNd->SyncNumberAndNumRule();
2428         // <--
2429         pRet = pTNd->GetNumRule();
2430     }
2431 
2432     return pRet;
2433 }
2434 
2435 sal_uInt16 SwDoc::FindNumRule( const String& rName ) const
2436 {
2437     for( sal_uInt16 n = pNumRuleTbl->Count(); n; )
2438         if( (*pNumRuleTbl)[ --n ]->GetName() == rName )
2439             return n;
2440 
2441     return USHRT_MAX;
2442 }
2443 
2444 SwNumRule* SwDoc::FindNumRulePtr( const String& rName ) const
2445 {
2446     SwNumRule * pResult = 0;
2447 
2448     pResult = maNumRuleMap[rName];
2449 
2450     if ( !pResult )
2451     {
2452         for (sal_uInt16 n = 0; n < pNumRuleTbl->Count(); ++n)
2453         {
2454             if ((*pNumRuleTbl)[n]->GetName() == rName)
2455             {
2456                 pResult = (*pNumRuleTbl)[n];
2457 
2458                 break;
2459             }
2460         }
2461     }
2462 
2463     return pResult;
2464 }
2465 
2466 // #i36749#
2467 void SwDoc::AddNumRule(SwNumRule * pRule)
2468 {
2469     pNumRuleTbl->Insert(pRule, pNumRuleTbl->Count());
2470     maNumRuleMap[pRule->GetName()] = pRule;
2471     pRule->SetNumRuleMap(&maNumRuleMap);
2472 
2473     // --> OD 2008-03-26 #refactorlists#
2474     createListForListStyle( pRule->GetName() );
2475     // <--
2476 }
2477 
2478 // --> OD 2008-02-11 #newlistlevelattrs#
2479 sal_uInt16 SwDoc::MakeNumRule( const String &rName,
2480             const SwNumRule* pCpy,
2481             sal_Bool bBroadcast,
2482             const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode )
2483 {
2484     SwNumRule* pNew;
2485     if( pCpy )
2486     {
2487         pNew = new SwNumRule( *pCpy );
2488 
2489         // --> OD 2008-07-08 #i91400#
2490         pNew->SetName( GetUniqueNumRuleName( &rName ), *this );
2491         // <--
2492         if( pNew->GetName() != rName )
2493         {
2494             pNew->SetPoolFmtId( USHRT_MAX );
2495             pNew->SetPoolHelpId( USHRT_MAX );
2496             pNew->SetPoolHlpFileId( UCHAR_MAX );
2497             // --> OD 2008-04-03 #refactorlists#
2498             pNew->SetDefaultListId( String() );
2499             // <--
2500         }
2501         pNew->CheckCharFmts( this );
2502     }
2503     else
2504     {
2505         // --> OD 2008-02-11 #newlistlevelattrs#
2506         pNew = new SwNumRule( GetUniqueNumRuleName( &rName ),
2507                               eDefaultNumberFormatPositionAndSpaceMode );
2508         // <--
2509     }
2510 
2511     sal_uInt16 nRet = pNumRuleTbl->Count();
2512 
2513     AddNumRule(pNew); // #i36749#
2514 
2515     if (GetIDocumentUndoRedo().DoesUndo())
2516     {
2517         SwUndo * pUndo = new SwUndoNumruleCreate(pNew, this);
2518         GetIDocumentUndoRedo().AppendUndo(pUndo);
2519     }
2520 
2521     if (bBroadcast)
2522         BroadcastStyleOperation(pNew->GetName(), SFX_STYLE_FAMILY_PSEUDO,
2523                                 SFX_STYLESHEET_CREATED);
2524 
2525     return nRet;
2526 }
2527 
2528 String SwDoc::GetUniqueNumRuleName( const String* pChkStr, sal_Bool bAutoNum ) const
2529 {
2530     String aName;
2531     if( bAutoNum )
2532     {
2533         // --> OD #o12311627#
2534         static rtlRandomPool s_RandomPool( rtl_random_createPool() );
2535         sal_Int64 n;
2536         rtl_random_getBytes( s_RandomPool, &n, sizeof(n) );
2537         aName = String::CreateFromInt64( (n < 0 ? -n : n) );
2538         // <--
2539         if( pChkStr && !pChkStr->Len() )
2540             pChkStr = 0;
2541     }
2542     else if( pChkStr && pChkStr->Len() )
2543         aName = *pChkStr;
2544     else
2545     {
2546         pChkStr = 0;
2547         aName = SW_RESSTR( STR_NUMRULE_DEFNAME );
2548     }
2549 
2550     sal_uInt16 nNum(0), nTmp, nFlagSize = ( pNumRuleTbl->Count() / 8 ) +2;
2551     sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ];
2552     memset( pSetFlags, 0, nFlagSize );
2553 
2554     xub_StrLen nNmLen = aName.Len();
2555     if( !bAutoNum && pChkStr )
2556     {
2557         while( nNmLen-- && '0' <= aName.GetChar( nNmLen ) &&
2558                            '9' >= aName.GetChar( nNmLen ) )
2559             ; //nop
2560 
2561         if( ++nNmLen < aName.Len() )
2562         {
2563             aName.Erase( nNmLen );
2564             pChkStr = 0;
2565         }
2566     }
2567 
2568     const SwNumRule* pNumRule;
2569     sal_uInt16 n;
2570 
2571     for( n = 0; n < pNumRuleTbl->Count(); ++n )
2572         if( 0 != ( pNumRule = (*pNumRuleTbl)[ n ] ) )
2573         {
2574             const String& rNm = pNumRule->GetName();
2575             if( rNm.Match( aName ) == nNmLen )
2576             {
2577                 // Nummer bestimmen und das Flag setzen
2578                 nNum = (sal_uInt16)rNm.Copy( nNmLen ).ToInt32();
2579                 if( nNum-- && nNum < pNumRuleTbl->Count() )
2580                     pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
2581             }
2582             if( pChkStr && pChkStr->Equals( rNm ) )
2583                 pChkStr = 0;
2584         }
2585 
2586     if( !pChkStr )
2587     {
2588         // alle Nummern entsprechend geflag, also bestimme die richtige Nummer
2589         nNum = pNumRuleTbl->Count();
2590         for( n = 0; n < nFlagSize; ++n )
2591             if( 0xff != ( nTmp = pSetFlags[ n ] ))
2592             {
2593                 // also die Nummer bestimmen
2594                 nNum = n * 8;
2595                 while( nTmp & 1 )
2596                     ++nNum, nTmp >>= 1;
2597                 break;
2598             }
2599 
2600     }
2601     delete [] pSetFlags;
2602     if( pChkStr && pChkStr->Len() )
2603         return *pChkStr;
2604     return aName += String::CreateFromInt32( ++nNum );
2605 }
2606 
2607 void SwDoc::UpdateNumRule()
2608 {
2609     const SwNumRuleTbl& rNmTbl = GetNumRuleTbl();
2610     for( sal_uInt16 n = 0; n < rNmTbl.Count(); ++n )
2611         if( rNmTbl[ n ]->IsInvalidRule() )
2612             rNmTbl[ n ]->Validate();
2613 }
2614 
2615 // --> OD 2008-04-02 #refactorlists#
2616 void SwDoc::MarkListLevel( const String& sListId,
2617                            const int nListLevel,
2618                            const sal_Bool bValue )
2619 {
2620     SwList* pList = getListByName( sListId );
2621 
2622     if ( pList )
2623     {
2624         MarkListLevel( *pList, nListLevel, bValue );
2625     }
2626 }
2627 
2628 void SwDoc::MarkListLevel( SwList& rList,
2629                            const int nListLevel,
2630                            const sal_Bool bValue )
2631 {
2632     // Set new marked list level and notify all affected nodes of the changed mark.
2633     rList.MarkListLevel( nListLevel, bValue );
2634 }
2635 // <- #i27615#
2636 // <--
2637 
2638 // #i23726#
2639 sal_Bool SwDoc::IsFirstOfNumRule(SwPosition & rPos)
2640 {
2641     sal_Bool bResult = sal_False;
2642     SwTxtNode * pTxtNode = rPos.nNode.GetNode().GetTxtNode();
2643 
2644     if (pTxtNode)
2645     {
2646         SwNumRule * pNumRule = pTxtNode->GetNumRule();
2647 
2648         if (pNumRule)
2649             bResult = pTxtNode->IsFirstOfNumRule();
2650     }
2651 
2652     return bResult;
2653 }
2654 
2655 // --> OD 2007-10-26 #i83479#
2656 // implementation for interface <IDocumentListItems>
2657 bool SwDoc::lessThanNodeNum::operator()( const SwNodeNum* pNodeNumOne,
2658                                          const SwNodeNum* pNodeNumTwo ) const
2659 {
2660     return pNodeNumOne->LessThan( *pNodeNumTwo );
2661 }
2662 
2663 void SwDoc::addListItem( const SwNodeNum& rNodeNum )
2664 {
2665     if ( mpListItemsList == 0 )
2666     {
2667         return;
2668     }
2669 
2670     const bool bAlreadyInserted(
2671             mpListItemsList->find( &rNodeNum ) != mpListItemsList->end() );
2672     ASSERT( !bAlreadyInserted,
2673             "<SwDoc::InsertListItem(..)> - <SwNodeNum> instance already registered as numbered item!" );
2674     if ( !bAlreadyInserted )
2675     {
2676         mpListItemsList->insert( &rNodeNum );
2677     }
2678 }
2679 
2680 void SwDoc::removeListItem( const SwNodeNum& rNodeNum )
2681 {
2682     if ( mpListItemsList == 0 )
2683     {
2684         return;
2685     }
2686 
2687     const tImplSortedNodeNumList::size_type nDeleted = mpListItemsList->erase( &rNodeNum );
2688     if ( nDeleted > 1 )
2689     {
2690         ASSERT( false,
2691                 "<SwDoc::RemoveListItem(..)> - <SwNodeNum> was registered more than once as numbered item!" );
2692     }
2693 }
2694 
2695 String SwDoc::getListItemText( const SwNodeNum& rNodeNum,
2696                                const bool bWithNumber,
2697                                const bool bWithSpacesForLevel ) const
2698 {
2699     return rNodeNum.GetTxtNode()
2700            ? rNodeNum.GetTxtNode()->GetExpandTxt( 0, STRING_LEN, bWithNumber,
2701                                                   bWithNumber, bWithSpacesForLevel )
2702            : String();
2703 }
2704 
2705 void SwDoc::getListItems( tSortedNodeNumList& orNodeNumList ) const
2706 {
2707     orNodeNumList.clear();
2708     orNodeNumList.reserve( mpListItemsList->size() );
2709 
2710     tImplSortedNodeNumList::iterator aIter;
2711     tImplSortedNodeNumList::iterator aEndIter = mpListItemsList->end();
2712     for ( aIter = mpListItemsList->begin(); aIter != aEndIter; ++aIter )
2713     {
2714         orNodeNumList.push_back( (*aIter) );
2715     }
2716 }
2717 
2718 void SwDoc::getNumItems( tSortedNodeNumList& orNodeNumList ) const
2719 {
2720     orNodeNumList.clear();
2721     orNodeNumList.reserve( mpListItemsList->size() );
2722 
2723     tImplSortedNodeNumList::iterator aIter;
2724     tImplSortedNodeNumList::iterator aEndIter = mpListItemsList->end();
2725     for ( aIter = mpListItemsList->begin(); aIter != aEndIter; ++aIter )
2726     {
2727         const SwNodeNum* pNodeNum = (*aIter);
2728         if ( pNodeNum->IsCounted() &&
2729              pNodeNum->GetTxtNode() && pNodeNum->GetTxtNode()->HasNumber() )
2730         {
2731             orNodeNumList.push_back( pNodeNum );
2732         }
2733     }
2734 }
2735 // <--
2736 
2737 // --> OD 2007-11-15 #i83479#
2738 // implementation for interface <IDocumentOutlineNodes>
2739 sal_Int32 SwDoc::getOutlineNodesCount() const
2740 {
2741     return GetNodes().GetOutLineNds().Count();
2742 }
2743 
2744 int SwDoc::getOutlineLevel( const sal_Int32 nIdx ) const
2745 {
2746     return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->
2747                                            // GetTxtNode()->GetOutlineLevel();              //#outline level,zhaojianwei
2748                                 GetTxtNode()->GetAttrOutlineLevel()-1;  //<-end,zhaojianwei
2749 }
2750 
2751 String SwDoc::getOutlineText( const sal_Int32 nIdx,
2752                               const bool bWithNumber,
2753                               const bool bWithSpacesForLevel ) const
2754 {
2755     return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->
2756                 GetTxtNode()->GetExpandTxt( 0, STRING_LEN, bWithNumber,
2757                                             bWithNumber, bWithSpacesForLevel );
2758 }
2759 
2760 SwTxtNode* SwDoc::getOutlineNode( const sal_Int32 nIdx ) const
2761 {
2762     return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->GetTxtNode();
2763 }
2764 
2765 void SwDoc::getOutlineNodes( IDocumentOutlineNodes::tSortedOutlineNodeList& orOutlineNodeList ) const
2766 {
2767     orOutlineNodeList.clear();
2768     orOutlineNodeList.reserve( getOutlineNodesCount() );
2769 
2770     const sal_uInt16 nOutlCount( static_cast<sal_uInt16>(getOutlineNodesCount()) );
2771     for ( sal_uInt16 i = 0; i < nOutlCount; ++i )
2772     {
2773         orOutlineNodeList.push_back(
2774             GetNodes().GetOutLineNds()[i]->GetTxtNode() );
2775     }
2776 }
2777 // <--
2778 
2779 // --> OD 2008-03-26 #refactorlists#
2780 // implementation of interface IDocumentListsAccess
2781 SwList* SwDoc::createList( String sListId,
2782                            const String sDefaultListStyleName )
2783 {
2784     if ( sListId.Len() == 0 )
2785     {
2786         sListId = listfunc::CreateUniqueListId( *this );
2787     }
2788 
2789     if ( getListByName( sListId ) )
2790     {
2791         ASSERT( false,
2792                 "<SwDoc::createList(..)> - provided list id already used. Serious defect -> please inform OD." );
2793         return 0;
2794     }
2795 
2796     SwNumRule* pDefaultNumRuleForNewList = FindNumRulePtr( sDefaultListStyleName );
2797     if ( !pDefaultNumRuleForNewList )
2798     {
2799         ASSERT( false,
2800                 "<SwDoc::createList(..)> - for provided default list style name no list style is found. Serious defect -> please inform OD." );
2801         return 0;
2802     }
2803 
2804     SwList* pNewList = new SwList( sListId, *pDefaultNumRuleForNewList, GetNodes() );
2805     maLists[sListId] = pNewList;
2806 
2807     return pNewList;
2808 }
2809 
2810 void SwDoc::deleteList( const String sListId )
2811 {
2812     SwList* pList = getListByName( sListId );
2813     if ( pList )
2814     {
2815         maLists.erase( sListId );
2816         delete pList;
2817     }
2818 }
2819 
2820 SwList* SwDoc::getListByName( const String sListId ) const
2821 {
2822     SwList* pList = 0;
2823 
2824     std::hash_map< String, SwList*, StringHash >::const_iterator
2825                                             aListIter = maLists.find( sListId );
2826     if ( aListIter != maLists.end() )
2827     {
2828         pList = (*aListIter).second;
2829     }
2830 
2831     return pList;
2832 }
2833 
2834 SwList* SwDoc::createListForListStyle( const String sListStyleName )
2835 {
2836     if ( sListStyleName.Len() == 0 )
2837     {
2838         ASSERT( false,
2839                 "<SwDoc::createListForListStyle(..)> - no list style name provided. Serious defect -> please inform OD." );
2840         return 0;
2841     }
2842 
2843     if ( getListForListStyle( sListStyleName ) )
2844     {
2845         ASSERT( false,
2846                 "<SwDoc::createListForListStyle(..)> - a list for the provided list style name already exists. Serious defect -> please inform OD." );
2847         return 0;
2848     }
2849 
2850     SwNumRule* pNumRule = FindNumRulePtr( sListStyleName );
2851     if ( !pNumRule )
2852     {
2853         ASSERT( false,
2854                 "<SwDoc::createListForListStyle(..)> - for provided list style name no list style is found. Serious defect -> please inform OD." );
2855         return 0;
2856     }
2857 
2858     String sListId( pNumRule->GetDefaultListId() ); // can be empty String
2859     if ( getListByName( sListId ) )
2860     {
2861         sListId = String();
2862     }
2863     SwList* pNewList = createList( sListId, sListStyleName );
2864     maListStyleLists[sListStyleName] = pNewList;
2865     pNumRule->SetDefaultListId( pNewList->GetListId() );
2866 
2867     return pNewList;
2868 }
2869 
2870 SwList* SwDoc::getListForListStyle( const String sListStyleName ) const
2871 {
2872     SwList* pList = 0;
2873 
2874     std::hash_map< String, SwList*, StringHash >::const_iterator
2875                             aListIter = maListStyleLists.find( sListStyleName );
2876     if ( aListIter != maListStyleLists.end() )
2877     {
2878         pList = (*aListIter).second;
2879     }
2880 
2881     return pList;
2882 }
2883 
2884 void SwDoc::deleteListForListStyle( const String sListStyleName )
2885 {
2886     String sListId;
2887     {
2888         SwList* pList = getListForListStyle( sListStyleName );
2889         ASSERT( pList,
2890                 "<SwDoc::deleteListForListStyle(..)> - misusage of method: no list found for given list style name" );
2891         if ( pList )
2892         {
2893             sListId = pList->GetListId();
2894         }
2895     }
2896     if ( sListId.Len() > 0 )
2897     {
2898         maListStyleLists.erase( sListStyleName );
2899         deleteList( sListId );
2900     }
2901 }
2902 // <--
2903 // --> OD 2008-07-08 #i91400#
2904 void SwDoc::trackChangeOfListStyleName( const String sListStyleName,
2905                                         const String sNewListStyleName )
2906 {
2907     SwList* pList = getListForListStyle( sListStyleName );
2908     ASSERT( pList,
2909             "<SwDoc::changeOfListStyleName(..)> - misusage of method: no list found for given list style name" );
2910 
2911     if ( pList != 0 )
2912     {
2913         maListStyleLists.erase( sListStyleName );
2914         maListStyleLists[sNewListStyleName] = pList;
2915     }
2916 }
2917 // <--
2918 
2919 // --> OD 2008-03-13 #refactorlists#
2920 namespace listfunc
2921 {
2922     const String MakeListIdUnique( const SwDoc& rDoc,
2923                                    const String aSuggestedUniqueListId )
2924     {
2925         long nHitCount = 0;
2926         String aTmpStr = aSuggestedUniqueListId;
2927         while ( rDoc.getListByName( aTmpStr ) )
2928         {
2929             ++nHitCount;
2930             aTmpStr = aSuggestedUniqueListId;
2931             aTmpStr += String::CreateFromInt32( nHitCount );
2932         }
2933 
2934         return aTmpStr;
2935     }
2936     const String CreateUniqueListId( const SwDoc& rDoc )
2937     {
2938         // --> OD 2008-08-06 #i92478#
2939         String aNewListId = String::CreateFromAscii( "list" );
2940         // <--
2941         // --> OD #o12311627#
2942         static rtlRandomPool s_RandomPool( rtl_random_createPool() );
2943         sal_Int64 n;
2944         rtl_random_getBytes( s_RandomPool, &n, sizeof(n) );
2945         aNewListId += String::CreateFromInt64( (n < 0 ? -n : n) );
2946         // <--
2947 
2948         return MakeListIdUnique( rDoc, aNewListId );
2949     }
2950 }
2951 // <--
2952