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