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