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