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