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