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