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