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 occuring in the document there has to be a valid
338 target outline level implied by aMoveArr. */
339 bool bMoveApplicable = true;
340 for (n = nSttPos; n < nEndPos; n++)
341 {
342 SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode();
343 SwTxtFmtColl* pColl = pTxtNd->GetTxtColl();
344 // int nLevel = pColl->GetOutlineLevel();//#outline level,zhaojianwei
345 // if (aMoveArr[nLevel] == -1)
346 // bMoveApplicable = false;
347 if( pColl->IsAssignedToListLevelOfOutlineStyle() )
348 {
349 const int nLevel = pColl->GetAssignedOutlineStyleLevel();
350 if (aMoveArr[nLevel] == -1)
351 bMoveApplicable = false;
352 }//<-end,zhaojianwei
353 // --> OD 2008-12-16 #i70748#
354 // Check on outline level attribute of text node, if text node is
355 // not an outline via a to outline style assigned paragraph style.
356 else
357 {
358 const int nNewOutlineLevel = pTxtNd->GetAttrOutlineLevel() + nOffset;
359 if ( nNewOutlineLevel < 1 || nNewOutlineLevel > MAXLEVEL )
360 {
361 bMoveApplicable = false;
362 }
363 }
364 // <--
365 }
366
367 if (! bMoveApplicable )
368 return sal_False;
369
370 /* <-- #i13747 # */
371 if (GetIDocumentUndoRedo().DoesUndo())
372 {
373 GetIDocumentUndoRedo().StartUndo(UNDO_OUTLINE_LR, NULL);
374 SwUndo *const pUndoOLR( new SwUndoOutlineLeftRight( rPam, nOffset ) );
375 GetIDocumentUndoRedo().AppendUndo(pUndoOLR);
376 }
377
378 // 2. allen Nodes die neue Vorlage zuweisen
379
380 n = nSttPos;
381 while( n < nEndPos)
382 {
383 SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode();
384 SwTxtFmtColl* pColl = pTxtNd->GetTxtColl();
385
386 if( pColl->IsAssignedToListLevelOfOutlineStyle() )
387 {
388 // ASSERT(pColl->GetOutlineLevel() < MAXLEVEL, //#outline level,removed by zhaojianwei
389 // "non outline node in outline nodes?");
390 //int nLevel = pColl->GetOutlineLevel();
391 const int nLevel = pColl->GetAssignedOutlineStyleLevel();//#outline level,add by zhaojianwei
392
393 ASSERT(aMoveArr[nLevel] >= 0,
394 "move table: current TxtColl not found when building table!");
395
396
397 if (nLevel < MAXLEVEL && aMoveArr[nLevel] >= 0)
398 {
399 pColl = aCollArr[ aMoveArr[nLevel] ];
400
401 if (pColl != NULL)
402 pColl = (SwTxtFmtColl*)pTxtNd->ChgFmtColl( pColl );
403 }
404
405 }
406 else if( pTxtNd->GetAttrOutlineLevel() > 0) //#outline level,add by zhaojianwei
407 {
408 int nLevel = pTxtNd->GetAttrOutlineLevel() + nOffset;
409 if( 0 <= nLevel && nLevel <= MAXLEVEL)
410 pTxtNd->SetAttrOutlineLevel( nLevel );
411
412 }//<-end,zhaojianwei
413
414 n++;
415 // Undo ???
416 }
417 if (GetIDocumentUndoRedo().DoesUndo())
418 {
419 GetIDocumentUndoRedo().EndUndo(UNDO_OUTLINE_LR, NULL);
420 }
421
422 ChkCondColls();
423 SetModified();
424
425 return sal_True;
426 }
427
428
429
430 // Hoch-/Runter - Verschieben !
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 choosen and this could be the next outline of the same level.
471 // The criteria has to be the outline level: sub level => incorporate, same/higher level => no.
472 if( GetNodes().GetOutLineNds().Seek_Entry( pEndSrch, &nTmpPos ) )
473 {
474 if( !pEndSrch->IsTxtNode() || pEndSrch == pSrch ||
475 //nOutLineLevel < ((SwTxtNode*)pEndSrch)->GetOutlineLevel() )//#outline level,zhaojianwei
476 nOutLineLevel < ((SwTxtNode*)pEndSrch)->GetAttrOutlineLevel()-1 )//<-end,zhaojianwei
477 ++nTmpPos; // For sub outlines only!
478 }
479
480 aEndRg = nTmpPos < GetNodes().GetOutLineNds().Count()
481 ? *GetNodes().GetOutLineNds()[ nTmpPos ]
482 : GetNodes().GetEndOfContent();
483 if( nOffset >= 0 )
484 nAktPos = nTmpPos;
485 if( aEndRg == aSttRg )
486 {
487 ASSERT( false, "Moving outlines: Surprising selection" );
488 aEndRg++;
489 }
490
491 const SwNode* pNd;
492 // The following code corrects the range to handle sections (start/end nodes)
493 // The range will be extended if the least node before the range is a start node
494 // which ends inside the range => The complete section will be moved.
495 // The range will be shrinked if the last position is a start node.
496 // The range will be shrinked if the last node is an end node which starts before the range.
497 aSttRg--;
498 while( aSttRg.GetNode().IsStartNode() )
499 {
500 pNd = aSttRg.GetNode().EndOfSectionNode();
501 if( pNd->GetIndex() >= aEndRg.GetIndex() )
502 break;
503 aSttRg--;
504 }
505 aSttRg++;
506
507 aEndRg--;
508 while( aEndRg.GetNode().IsStartNode() )
509 aEndRg--;
510 while( aEndRg.GetNode().IsEndNode() )
511 {
512 pNd = aEndRg.GetNode().StartOfSectionNode();
513 if( pNd->GetIndex() >= aSttRg.GetIndex() )
514 break;
515 aEndRg--;
516 }
517 aEndRg++;
518
519 // calculation of the new position
520 if( nOffset < 0 && nAktPos < sal_uInt16(-nOffset) )
521 pNd = GetNodes().GetEndOfContent().StartOfSectionNode();
522 else if( nAktPos + nOffset >= GetNodes().GetOutLineNds().Count() )
523 pNd = &GetNodes().GetEndOfContent();
524 else
525 pNd = GetNodes().GetOutLineNds()[ nAktPos + nOffset ];
526
527 sal_uLong nNewPos = pNd->GetIndex();
528
529 // And now a correction of the insert position if necessary...
530 SwNodeIndex aInsertPos( *pNd, -1 );
531 while( aInsertPos.GetNode().IsStartNode() )
532 {
533 // Just before the insert position starts a section:
534 // when I'm moving forward I do not want to enter the section,
535 // when I'm moving backward I want to stay in the section if I'm already a part of,
536 // I want to stay outside if I was outside before.
537 if( nOffset < 0 )
538 {
539 pNd = aInsertPos.GetNode().EndOfSectionNode();
540 if( pNd->GetIndex() >= aEndRg.GetIndex() )
541 break;
542 }
543 aInsertPos--;
544 --nNewPos;
545 }
546 if( nOffset >= 0 )
547 {
548 // When just before the insert position a section ends, it is okay when I'm moving backward
549 // because I want to stay outside the section.
550 // When moving forward I've to check if I started inside or outside the section
551 // because I don't want to enter of leave such a section
552 while( aInsertPos.GetNode().IsEndNode() )
553 {
554 pNd = aInsertPos.GetNode().StartOfSectionNode();
555 if( pNd->GetIndex() >= aSttRg.GetIndex() )
556 break;
557 aInsertPos--;
558 --nNewPos;
559 }
560 }
561 // We do not want to move into tables (at the moment)
562 aInsertPos++;
563 pNd = &aInsertPos.GetNode();
564 if( pNd->IsTableNode() )
565 pNd = pNd->StartOfSectionNode();
566 if( pNd->FindTableNode() )
567 return sal_False;
568
569 ASSERT( aSttRg.GetIndex() > nNewPos || nNewPos >= aEndRg.GetIndex(),
570 "Position liegt im MoveBereich" );
571
572 // wurde ein Position in den Sonderbereichen errechnet, dann
573 // setze die Position auf den Dokumentanfang.
574 // Sollten da Bereiche oder Tabellen stehen, so werden sie nach
575 // hinten verschoben.
576 nNewPos = Max( nNewPos, GetNodes().GetEndOfExtras().GetIndex() + 2 );
577
578 long nOffs = nNewPos - ( 0 < nOffset ? aEndRg.GetIndex() : aSttRg.GetIndex());
579 SwPaM aPam( aSttRg, aEndRg, 0, -1 );
580 return MoveParagraph( aPam, nOffs, sal_True );
581 }
582
583
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( SwDoc& rDoc, const SwNumRule& rRule )
872 {
873 SwNumRule* pOld = rDoc.FindNumRulePtr( rRule.GetName() );
874 ASSERT( pOld, "ohne die alte NumRule geht gar nichts" );
875
876 sal_uInt16 nChgFmtLevel = 0, nMask = 1;
877 sal_uInt8 n;
878
879 for( n = 0; n < MAXLEVEL; ++n, nMask <<= 1 )
880 {
881 const SwNumFmt& rOldFmt = pOld->Get( n ),
882 & rNewFmt = rRule.Get( n );
883
884 if( rOldFmt != rNewFmt )
885 {
886 nChgFmtLevel |= nMask;
887 }
888 else if( SVX_NUM_NUMBER_NONE > rNewFmt.GetNumberingType() && 1 < rNewFmt.GetIncludeUpperLevels() &&
889 0 != (nChgFmtLevel & GetUpperLvlChg( n, rNewFmt.GetIncludeUpperLevels(),nMask )) )
890 nChgFmtLevel |= nMask;
891 }
892
893 if( !nChgFmtLevel ) // es wurde nichts veraendert?
894 {
895 // --> OD 2006-04-27 #i64311#
896 const bool bInvalidateNumRule( pOld->IsContinusNum() != rRule.IsContinusNum() );
897 // <--
898 pOld->CheckCharFmts( &rDoc );
899 pOld->SetContinusNum( rRule.IsContinusNum() );
900 // --> OD 2008-06-17 #i87166#
901 // Do NOT change list style type
902 // pOld->SetRuleType( rRule.GetRuleType() );
903 // <--
904 // --> OD 2006-04-27 #i64311#
905 if ( bInvalidateNumRule )
906 {
907 pOld->SetInvalidRule(sal_True);
908 }
909 // <--
910 return ;
911 }
912
913 // --> OD 2008-02-19 #refactorlists#
914 // SwNumRuleInfo* pUpd = new SwNumRuleInfo( rRule.GetName() );
915 // pUpd->MakeList( rDoc );
916
917 // sal_uInt8 nLvl;
918 // for( sal_uLong nFirst = 0, nLast = pUpd->GetList().Count();
919 // nFirst < nLast; ++nFirst )
920 // {
921 // SwTxtNode* pTxtNd = pUpd->GetList().GetObject( nFirst );
922 // nLvl = static_cast<sal_uInt8>(pTxtNd->GetLevel());
923
924 // if( nLvl < MAXLEVEL )
925 // {
926 // if( nChgFmtLevel & ( 1 << nLvl ))
927 // {
928 // pTxtNd->NumRuleChgd();
929 // }
930 // }
931 // }
932 SwNumRule::tTxtNodeList aTxtNodeList;
933 pOld->GetTxtNodeList( aTxtNodeList );
934 sal_uInt8 nLvl( 0 );
935 for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin();
936 aIter != aTxtNodeList.end(); ++aIter )
937 {
938 SwTxtNode* pTxtNd = *aIter;
939 nLvl = static_cast<sal_uInt8>(pTxtNd->GetActualListLevel());
940
941 if( nLvl < MAXLEVEL )
942 {
943 if( nChgFmtLevel & ( 1 << nLvl ))
944 {
945 pTxtNd->NumRuleChgd();
946 }
947 }
948 }
949 // <--
950
951 for( n = 0; n < MAXLEVEL; ++n )
952 if( nChgFmtLevel & ( 1 << n ))
953 pOld->Set( n, rRule.GetNumFmt( n ));
954
955 pOld->CheckCharFmts( &rDoc );
956 pOld->SetInvalidRule(sal_True);
957 pOld->SetContinusNum( rRule.IsContinusNum() );
958 // --> OD 2008-06-17 #i87166#
959 // Do NOT change list style type
960 // pOld->SetRuleType( rRule.GetRuleType() );
961 // <--
962
963 // --> OD 2008-02-19 #refactorlists#
964 // delete pUpd;
965 // <--
966
967 rDoc.UpdateNumRule();
968 }
969
970 // OD 2008-02-08 #newlistlevelattrs# - add handling of parameter <bResetIndentAttrs>
971 // --> OD 2008-03-17 #refactorlists#
SetNumRule(const SwPaM & rPam,const SwNumRule & rRule,const bool bCreateNewList,const String sContinuedListId,sal_Bool bSetItem,const bool bResetIndentAttrs)972 void SwDoc::SetNumRule( const SwPaM& rPam,
973 const SwNumRule& rRule,
974 const bool bCreateNewList,
975 const String sContinuedListId,
976 sal_Bool bSetItem,
977 const bool bResetIndentAttrs )
978 {
979 SwUndoInsNum * pUndo = NULL;
980 if (GetIDocumentUndoRedo().DoesUndo())
981 {
982 // Start/End for attributes!
983 GetIDocumentUndoRedo().StartUndo( UNDO_INSNUM, NULL );
984 pUndo = new SwUndoInsNum( rPam, rRule );
985 GetIDocumentUndoRedo().AppendUndo(pUndo);
986 }
987
988 SwNumRule * pNew = FindNumRulePtr( rRule.GetName() );
989 bool bUpdateRule = false;
990
991 if( !pNew )
992 {
993 pNew = (*pNumRuleTbl)[ MakeNumRule( rRule.GetName(), &rRule ) ];
994 }
995 else if (rRule != *pNew)
996 {
997 bUpdateRule = true;
998 }
999
1000 if (bUpdateRule)
1001 {
1002 if( pUndo )
1003 {
1004 pUndo->SaveOldNumRule( *pNew );
1005 ::lcl_ChgNumRule( *this, rRule );
1006 pUndo->SetLRSpaceEndPos();
1007 }
1008 else
1009 {
1010 ::lcl_ChgNumRule( *this, rRule );
1011 }
1012 }
1013
1014 if ( bSetItem )
1015 {
1016 if ( bCreateNewList )
1017 {
1018 String sListId;
1019 if ( !bUpdateRule )
1020 {
1021 // apply list id of list, which has been created for the new list style
1022 sListId = pNew->GetDefaultListId();
1023 }
1024 else
1025 {
1026 // create new list and apply its list id
1027 SwList* pNewList = createList( String(), pNew->GetName() );
1028 ASSERT( pNewList,
1029 "<SwDoc::SetNumRule(..)> - could not create new list. Serious defect -> please inform OD." );
1030 sListId = pNewList->GetListId();
1031 }
1032 InsertPoolItem( rPam, SfxStringItem( RES_PARATR_LIST_ID, sListId ), 0 );
1033 }
1034 else if ( sContinuedListId.Len() > 0 )
1035 {
1036 // apply given list id
1037 InsertPoolItem( rPam, SfxStringItem( RES_PARATR_LIST_ID, sContinuedListId ), 0 );
1038 }
1039 }
1040
1041 if ( ! rPam.HasMark())
1042 {
1043 SwTxtNode * pTxtNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode();
1044 // consider case that the PaM doesn't denote a text node - e.g. it denotes a graphic node
1045 if ( pTxtNd )
1046 {
1047 SwNumRule * pRule = pTxtNd->GetNumRule();
1048
1049 if (pRule && pRule->GetName() == pNew->GetName())
1050 {
1051 bSetItem = sal_False;
1052 if ( !pTxtNd->IsInList() )
1053 {
1054 pTxtNd->AddToList();
1055 }
1056 }
1057 // only clear numbering attribute at text node,
1058 // if at paragraph style the new numbering rule is found.
1059 else if ( !pRule )
1060 {
1061 SwTxtFmtColl* pColl = pTxtNd->GetTxtColl();
1062 if ( pColl )
1063 {
1064 SwNumRule* pCollRule = FindNumRulePtr(pColl->GetNumRule().GetValue());
1065 if ( pCollRule && pCollRule->GetName() == pNew->GetName() )
1066 {
1067 pTxtNd->ResetAttr( RES_PARATR_NUMRULE );
1068 bSetItem = sal_False;
1069 }
1070 }
1071 }
1072 }
1073 }
1074
1075 if ( bSetItem )
1076 {
1077 InsertPoolItem( rPam, SwNumRuleItem( pNew->GetName() ), 0 );
1078 }
1079
1080 if ( bResetIndentAttrs &&
1081 pNew && pNew->Get( 0 ).GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1082 {
1083 SvUShortsSort aResetAttrsArray;
1084 aResetAttrsArray.Insert( RES_LR_SPACE );
1085 // On a selection setup a corresponding Point-and-Mark in order to get
1086 // the indentation attribute reset on all paragraphs touched by the selection
1087 if ( rPam.HasMark() &&
1088 rPam.End()->nNode.GetNode().GetTxtNode() )
1089 {
1090 SwPaM aPam( rPam.Start()->nNode,
1091 rPam.End()->nNode );
1092 aPam.Start()->nContent = 0;
1093 aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTxtNode()->Len();
1094 ResetAttrs( aPam, sal_False, &aResetAttrsArray );
1095 }
1096 else
1097 {
1098 ResetAttrs( rPam, sal_False, &aResetAttrsArray );
1099 }
1100 }
1101
1102 if (GetIDocumentUndoRedo().DoesUndo())
1103 {
1104 GetIDocumentUndoRedo().EndUndo( UNDO_INSNUM, NULL );
1105 }
1106
1107 SetModified();
1108 }
1109
SetCounted(const SwPaM & rPam,bool bCounted)1110 void SwDoc::SetCounted(const SwPaM & rPam, bool bCounted)
1111 {
1112 if ( bCounted )
1113 {
1114 SvUShortsSort aResetAttrsArray;
1115 aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED );
1116 // On a selection setup a corresponding Point-and-Mark in order to get
1117 // the list-is-counted attribute reset on all paragraphs touched by the selection
1118 if ( rPam.HasMark() &&
1119 rPam.End()->nNode.GetNode().GetTxtNode() )
1120 {
1121 SwPaM aPam( rPam.Start()->nNode,
1122 rPam.End()->nNode );
1123 aPam.Start()->nContent = 0;
1124 aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTxtNode()->Len();
1125 ResetAttrs( aPam, sal_False, &aResetAttrsArray );
1126 }
1127 else
1128 {
1129 ResetAttrs( rPam, sal_False, &aResetAttrsArray );
1130 }
1131 }
1132 else
1133 {
1134 InsertPoolItem( rPam, SfxBoolItem( RES_PARATR_LIST_ISCOUNTED, sal_False ), 0 );
1135 }
1136 }
1137
SetNumRuleStart(const SwPosition & rPos,sal_Bool bFlag)1138 void SwDoc::SetNumRuleStart( const SwPosition& rPos, sal_Bool bFlag )
1139 {
1140 SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
1141
1142 if (pTxtNd)
1143 {
1144 const SwNumRule* pRule = pTxtNd->GetNumRule();
1145 if( pRule && !bFlag != !pTxtNd->IsListRestart())
1146 {
1147 if (GetIDocumentUndoRedo().DoesUndo())
1148 {
1149 SwUndo *const pUndo( new SwUndoNumRuleStart(rPos, bFlag) );
1150 GetIDocumentUndoRedo().AppendUndo(pUndo);
1151 }
1152
1153 pTxtNd->SetListRestart(bFlag ? true : false);
1154
1155 SetModified();
1156 }
1157 }
1158 }
1159
SetNodeNumStart(const SwPosition & rPos,sal_uInt16 nStt)1160 void SwDoc::SetNodeNumStart( const SwPosition& rPos, sal_uInt16 nStt )
1161 {
1162 SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
1163
1164 if (pTxtNd)
1165 {
1166 // --> OD 2008-02-27 #refactorlists#
1167 // const SwNumRule* pRule = pTxtNd->GetNumRule();
1168 // if( pRule && nStt != pTxtNd->GetListRestartValue() )
1169 // {
1170 // if( DoesUndo() )
1171 // {
1172 // ClearRedo();
1173 // AppendUndo( new SwUndoNumRuleStart( rPos, nStt ));
1174 // }
1175 // }
1176 // pTxtNd->SetListRestartValue(nStt);
1177
1178 // SetModified();
1179 if ( !pTxtNd->HasAttrListRestartValue() ||
1180 pTxtNd->GetAttrListRestartValue() != nStt )
1181 {
1182 if (GetIDocumentUndoRedo().DoesUndo())
1183 {
1184 SwUndo *const pUndo( new SwUndoNumRuleStart(rPos, nStt) );
1185 GetIDocumentUndoRedo().AppendUndo(pUndo);
1186 }
1187 pTxtNd->SetAttrListRestartValue( nStt );
1188
1189 SetModified();
1190 }
1191 // <--
1192 }
1193 }
1194
1195 // loeschen geht nur, wenn die Rule niemand benutzt!
DelNumRule(const String & rName,sal_Bool bBroadcast)1196 sal_Bool SwDoc::DelNumRule( const String& rName, sal_Bool bBroadcast )
1197 {
1198 sal_uInt16 nPos = FindNumRule( rName );
1199
1200 // --> OD 2007-12-17 #151213#
1201 if ( (*pNumRuleTbl)[ nPos ] == GetOutlineNumRule() )
1202 {
1203 ASSERT( false,
1204 "<SwDoc::DelNumRule(..)> - No deletion of outline list style. This is serious defect - please inform OD" );
1205 return sal_False;
1206 }
1207 // <--
1208
1209 if( USHRT_MAX != nPos && !IsUsed( *(*pNumRuleTbl)[ nPos ] ))
1210 {
1211 if (GetIDocumentUndoRedo().DoesUndo())
1212 {
1213 SwUndo * pUndo =
1214 new SwUndoNumruleDelete(*(*pNumRuleTbl)[nPos], this);
1215 GetIDocumentUndoRedo().AppendUndo(pUndo);
1216 }
1217
1218 if (bBroadcast)
1219 BroadcastStyleOperation(rName, SFX_STYLE_FAMILY_PSEUDO,
1220 SFX_STYLESHEET_ERASED);
1221
1222 // --> OD 2008-04-02 #refactorlists#
1223 deleteListForListStyle( rName );
1224 {
1225 // delete further list, which have the deleted list style as default list style
1226 std::vector< SwList* > aListsForDeletion;
1227 tHashMapForLists::iterator aListIter = maLists.begin();
1228 while ( aListIter != maLists.end() )
1229 {
1230 SwList* pList = (*aListIter).second;
1231 if ( pList->GetDefaultListStyleName() == rName )
1232 {
1233 aListsForDeletion.push_back( pList );
1234 }
1235
1236 ++aListIter;
1237 }
1238 while ( aListsForDeletion.size() > 0 )
1239 {
1240 SwList* pList = aListsForDeletion.back();
1241 aListsForDeletion.pop_back();
1242 deleteList( pList->GetListId() );
1243 }
1244 }
1245 // <--
1246 // --> FME 2004-11-02 #i34097# DeleteAndDestroy deletes rName if
1247 // rName is directly taken from the numrule.
1248 const String aTmpName( rName );
1249 // <--
1250 pNumRuleTbl->DeleteAndDestroy( nPos );
1251 maNumRuleMap.erase(aTmpName);
1252
1253 SetModified();
1254 return sal_True;
1255 }
1256 return sal_False;
1257 }
1258
1259 // #106897#
ChgNumRuleFmts(const SwNumRule & rRule,const String * pName)1260 void SwDoc::ChgNumRuleFmts( const SwNumRule& rRule, const String * pName )
1261 {
1262 // #106897#
1263 SwNumRule* pRule = FindNumRulePtr( pName ? *pName : rRule.GetName() );
1264 if( pRule )
1265 {
1266 SwUndoInsNum* pUndo = 0;
1267 if (GetIDocumentUndoRedo().DoesUndo())
1268 {
1269 pUndo = new SwUndoInsNum( *pRule, rRule );
1270 pUndo->GetHistory();
1271 GetIDocumentUndoRedo().AppendUndo( pUndo );
1272 }
1273 ::lcl_ChgNumRule( *this, rRule );
1274
1275 if( pUndo )
1276 pUndo->SetLRSpaceEndPos();
1277
1278 SetModified();
1279 }
1280 }
1281
RenameNumRule(const String & rOldName,const String & rNewName,sal_Bool bBroadcast)1282 sal_Bool SwDoc::RenameNumRule(const String & rOldName, const String & rNewName,
1283 sal_Bool bBroadcast)
1284 {
1285 sal_Bool bResult = sal_False;
1286 SwNumRule * pNumRule = FindNumRulePtr(rOldName);
1287
1288 if (pNumRule)
1289 {
1290 if (GetIDocumentUndoRedo().DoesUndo())
1291 {
1292 SwUndo * pUndo = new SwUndoNumruleRename(rOldName, rNewName, this);
1293 GetIDocumentUndoRedo().AppendUndo(pUndo);
1294 }
1295
1296 // --> OD 2008-02-19 #refactorlists#
1297 // SwNumRuleInfo aInfo(rOldName);
1298 // aInfo.MakeList(*this);
1299 SwNumRule::tTxtNodeList aTxtNodeList;
1300 pNumRule->GetTxtNodeList( aTxtNodeList );
1301 // <--
1302
1303 // --> OD 2008-07-08 #i91400#
1304 pNumRule->SetName( rNewName, *this );
1305 // <--
1306
1307 SwNumRuleItem aItem(rNewName);
1308 // --> OD 2008-02-19 #refactorlists#
1309 // for (sal_uLong nI = 0; nI < aInfo.GetList().Count(); ++nI)
1310 // {
1311 // SwTxtNode * pTxtNd = aInfo.GetList().GetObject(nI);
1312 // pTxtNd->SwCntntNode::SetAttr(aItem);
1313 // }
1314 for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin();
1315 aIter != aTxtNodeList.end(); ++aIter )
1316 {
1317 SwTxtNode * pTxtNd = *aIter;
1318 pTxtNd->SetAttr(aItem);
1319 }
1320 // <--
1321
1322 bResult = sal_True;
1323
1324 if (bBroadcast)
1325 BroadcastStyleOperation(rOldName, SFX_STYLE_FAMILY_PSEUDO,
1326 SFX_STYLESHEET_MODIFIED);
1327 }
1328
1329 return bResult;
1330 }
1331
StopNumRuleAnimations(OutputDevice * pOut)1332 void SwDoc::StopNumRuleAnimations( OutputDevice* pOut )
1333 {
1334 for( sal_uInt16 n = GetNumRuleTbl().Count(); n; )
1335 {
1336 SwNumRule::tTxtNodeList aTxtNodeList;
1337 GetNumRuleTbl()[ --n ]->GetTxtNodeList( aTxtNodeList );
1338 for ( SwNumRule::tTxtNodeList::iterator aTxtNodeIter = aTxtNodeList.begin();
1339 aTxtNodeIter != aTxtNodeList.end(); ++aTxtNodeIter )
1340 {
1341 SwTxtNode* pTNd = *aTxtNodeIter;
1342 SwIterator<SwTxtFrm,SwTxtNode> aIter(*pTNd);
1343 for(SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
1344 if( pFrm->HasAnimation() )
1345 pFrm->StopAnimation( pOut );
1346 }
1347 }
1348 }
1349
ReplaceNumRule(const SwPosition & rPos,const String & rOldRule,const String & rNewRule)1350 sal_Bool SwDoc::ReplaceNumRule( const SwPosition& rPos,
1351 const String& rOldRule, const String& rNewRule )
1352 {
1353 sal_Bool bRet = sal_False;
1354 SwNumRule *pOldRule = FindNumRulePtr( rOldRule ),
1355 *pNewRule = FindNumRulePtr( rNewRule );
1356 if( pOldRule && pNewRule && pOldRule != pNewRule )
1357 {
1358 // --> OD 2008-02-19 #refactorlists#
1359 SwUndoInsNum* pUndo = 0;
1360 if (GetIDocumentUndoRedo().DoesUndo())
1361 {
1362 // Start/End for attributes!
1363 GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL );
1364 pUndo = new SwUndoInsNum( rPos, *pNewRule, rOldRule );
1365 GetIDocumentUndoRedo().AppendUndo(pUndo);
1366 }
1367
1368 // --> OD 2008-02-19 #refactorlists#
1369 // apply new list style <pNewRule> to all text nodes, which have the
1370 // old list style <pOldNRule> applied and belong to the same list as
1371 // the text node of the given <SwPosition>.
1372 // SwNumRuleInfo aUpd( rOldRule );
1373 // aUpd.MakeList( *this );
1374
1375 // if (aUpd.GetList().Count() > 0) // #106897#
1376 SwNumRule::tTxtNodeList aTxtNodeList;
1377 pOldRule->GetTxtNodeList( aTxtNodeList );
1378 if ( aTxtNodeList.size() > 0 )
1379 {
1380 // // Position suchen und bestimme ob ein Node davor oder dahinter
1381 // // einen Start erzwingt
1382 // SwTxtNode* pTxtNd;
1383 // sal_uLong nFndPos, nFirst, nLast;
1384
1385 // if( TABLE_ENTRY_NOTFOUND != aUpd.GetList().SearchKey(
1386 // rPos.nNode.GetIndex(), &nFndPos ))
1387 // ++nFndPos;
1388
1389 // for( nLast = nFndPos; nLast < aUpd.GetList().Count(); ++nLast )
1390 // {
1391 // pTxtNd = aUpd.GetList().GetObject( nLast );
1392 // if(pTxtNd->IsRestart())
1393 // break;
1394 // }
1395 // for( nFirst = nFndPos; nFirst; )
1396 // {
1397 // pTxtNd = aUpd.GetList().GetObject( --nFirst );
1398 // if( pTxtNd->IsRestart() )
1399 // break;
1400 // }
1401 // // dann neue Numerierung ueber diesen Bereich
1402 // // definieren und den Start am Anfang/Ende zurueck setzen
1403 // pTxtNd = aUpd.GetList().GetObject( nFirst );
1404 // if( pTxtNd->IsRestart() )
1405 // {
1406 // pTxtNd->SetRestart(false);
1407 // if( pUndo )
1408 // pUndo->SetSttNum( pTxtNd->GetIndex() );
1409 // }
1410
1411 SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 );
1412 sal_uInt16 nChgFmtLevel = 0;
1413 for( sal_uInt8 n = 0; n < MAXLEVEL; ++n )
1414 {
1415 const SwNumFmt& rOldFmt = pOldRule->Get( n ),
1416 & rNewFmt = pNewRule->Get( n );
1417
1418 if( rOldFmt.GetAbsLSpace() != rNewFmt.GetAbsLSpace() ||
1419 rOldFmt.GetFirstLineOffset() != rNewFmt.GetFirstLineOffset() )
1420 nChgFmtLevel |= ( 1 << n );
1421 }
1422
1423 const SwTxtNode* pGivenTxtNode = rPos.nNode.GetNode().GetTxtNode();
1424 SwNumRuleItem aRule( rNewRule );
1425 // for( ; nFirst < nLast; ++nFirst )
1426 // {
1427 // pTxtNd = aUpd.GetList().GetObject( nFirst );
1428
1429 // aRegH.RegisterInModify( pTxtNd, *pTxtNd );
1430
1431 // pTxtNd->SwCntntNode::SetAttr( aRule );
1432 // pTxtNd->NumRuleChgd();
1433 // }
1434 for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin();
1435 aIter != aTxtNodeList.end(); ++aIter )
1436 {
1437 SwTxtNode* pTxtNd = *aIter;
1438
1439 if ( pGivenTxtNode &&
1440 pGivenTxtNode->GetListId() == pTxtNd->GetListId() )
1441 {
1442 aRegH.RegisterInModify( pTxtNd, *pTxtNd );
1443
1444 pTxtNd->SetAttr( aRule );
1445 pTxtNd->NumRuleChgd();
1446 }
1447 }
1448 GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
1449 SetModified();
1450
1451 bRet = sal_True; // #106897#
1452 }
1453 }
1454
1455 return bRet;
1456 }
1457
1458 // --> OD 2008-03-18 #refactorlists#
1459 namespace
1460 {
1461 struct ListStyleData
1462 {
1463 SwNumRule* pReplaceNumRule;
1464 bool bCreateNewList;
1465 String sListId;
1466
ListStyleData__anonbf58d5930111::ListStyleData1467 ListStyleData()
1468 : pReplaceNumRule( 0 ),
1469 bCreateNewList( false ),
1470 sListId()
1471 {}
1472 };
1473 }
1474 // <--
1475
MakeUniqueNumRules(const SwPaM & rPaM)1476 void SwDoc::MakeUniqueNumRules(const SwPaM & rPaM)
1477 {
1478 ASSERT( rPaM.GetDoc() == this, "need same doc" );
1479
1480 // --> OD 2008-03-18 #refactorlists#
1481 // map<SwNumRule *, SwNumRule *> aMyNumRuleMap;
1482 ::std::map<SwNumRule *, ListStyleData> aMyNumRuleMap;
1483 // <--
1484
1485 sal_uLong nStt = rPaM.Start()->nNode.GetIndex();
1486 sal_uLong nEnd = rPaM.End()->nNode.GetIndex();
1487
1488 bool bFirst = true;
1489
1490 for (sal_uLong n = nStt; n <= nEnd; n++)
1491 {
1492 SwTxtNode * pCNd = GetNodes()[n]->GetTxtNode();
1493
1494 if (pCNd)
1495 {
1496 SwNumRule * pRule = pCNd->GetNumRule();
1497
1498 if (pRule && pRule->IsAutoRule() && ! pRule->IsOutlineRule())
1499 {
1500 // --> OD 2008-03-18 #refactorlists#
1501 // SwNumRule * pReplaceNumRule = aMyNumRuleMap[pRule];
1502 ListStyleData aListStyleData = aMyNumRuleMap[pRule];
1503
1504 // if (! pReplaceNumRule)
1505 if ( aListStyleData.pReplaceNumRule == 0 )
1506 {
1507 if (bFirst)
1508 {
1509 SwPosition aPos(*pCNd);
1510 aListStyleData.pReplaceNumRule =
1511 const_cast<SwNumRule *>
1512 (SearchNumRule( aPos, false, pCNd->HasNumber(),
1513 false, 0,
1514 aListStyleData.sListId, true ));
1515 }
1516
1517 // if (! pReplaceNumRule)
1518 if ( aListStyleData.pReplaceNumRule == 0 )
1519 {
1520 // pReplaceNumRule = new SwNumRule(*pRule);
1521 // pReplaceNumRule->SetName(GetUniqueNumRuleName());
1522 aListStyleData.pReplaceNumRule = new SwNumRule(*pRule);
1523 // --> OD 2008-07-08 #i91400#
1524 aListStyleData.pReplaceNumRule->SetName(
1525 GetUniqueNumRuleName(), *this );
1526 // <--
1527 aListStyleData.bCreateNewList = true;
1528 }
1529
1530 // aMyNumRuleMap[pRule] = pReplaceNumRule;
1531 aMyNumRuleMap[pRule] = aListStyleData;
1532 }
1533
1534 SwPaM aPam(*pCNd);
1535
1536 SetNumRule( aPam, *aListStyleData.pReplaceNumRule,
1537 aListStyleData.bCreateNewList,
1538 aListStyleData.sListId );
1539 if ( aListStyleData.bCreateNewList )
1540 {
1541 aListStyleData.bCreateNewList = false;
1542 aListStyleData.sListId = pCNd->GetListId();
1543 aMyNumRuleMap[pRule] = aListStyleData;
1544 }
1545 // <--
1546
1547 bFirst = false;
1548 }
1549 }
1550 }
1551 }
1552
NoNum(const SwPaM & rPam)1553 sal_Bool SwDoc::NoNum( const SwPaM& rPam )
1554 {
1555
1556 sal_Bool bRet = SplitNode( *rPam.GetPoint(), false );
1557 // ist ueberhaupt Nummerierung im Spiel ?
1558 if( bRet )
1559 {
1560 // NoNum setzen und Upaten
1561 const SwNodeIndex& rIdx = rPam.GetPoint()->nNode;
1562 SwTxtNode* pNd = rIdx.GetNode().GetTxtNode();
1563 const SwNumRule* pRule = pNd->GetNumRule();
1564 if( pRule )
1565 {
1566 pNd->SetCountedInList(false);
1567
1568 SetModified();
1569 }
1570 else
1571 bRet = sal_False; // keine Nummerierung , ?? oder immer sal_True ??
1572 }
1573 return bRet;
1574 }
1575
DelNumRules(const SwPaM & rPam)1576 void SwDoc::DelNumRules( const SwPaM& rPam )
1577 {
1578 sal_uLong nStt = rPam.GetPoint()->nNode.GetIndex(),
1579 nEnd = rPam.GetMark()->nNode.GetIndex();
1580 if( nStt > nEnd )
1581 {
1582 sal_uLong nTmp = nStt; nStt = nEnd; nEnd = nTmp;
1583 }
1584
1585 SwUndoDelNum* pUndo;
1586 if (GetIDocumentUndoRedo().DoesUndo())
1587 {
1588 pUndo = new SwUndoDelNum( rPam );
1589 GetIDocumentUndoRedo().AppendUndo(pUndo);
1590 }
1591 else
1592 pUndo = 0;
1593
1594 SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 );
1595
1596 SwNumRuleItem aEmptyRule( aEmptyStr );
1597 const SwNode* pOutlNd = 0;
1598 for( ; nStt <= nEnd; ++nStt )
1599 {
1600 SwTxtNode* pTNd = GetNodes()[ nStt ]->GetTxtNode();
1601 // --> OD 2008-03-13 #refactorlists#
1602 // if( pTNd && 0 != ( pItem = pTNd->GetNoCondAttr(
1603 // RES_PARATR_NUMRULE, sal_True ) ) &&
1604 // ( pName = &((SwNumRuleItem*)pItem)->GetValue())->Len() )
1605 SwNumRule* pNumRuleOfTxtNode = pTNd ? pTNd->GetNumRule() : 0;
1606 if ( pTNd && pNumRuleOfTxtNode )
1607 // <--
1608 {
1609 // recognize changes of attribute for undo
1610 aRegH.RegisterInModify( pTNd, *pTNd );
1611
1612 if( pUndo )
1613 pUndo->AddNode( *pTNd, sal_False );
1614
1615 // directly set list style attribute is reset, otherwise empty
1616 // list style is applied
1617 const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet();
1618 if ( pAttrSet &&
1619 pAttrSet->GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET )
1620 pTNd->ResetAttr( RES_PARATR_NUMRULE );
1621 else
1622 pTNd->SetAttr( aEmptyRule );
1623
1624 // --> OD 2008-03-26 #refactorlists#
1625 pTNd->ResetAttr( RES_PARATR_LIST_ID );
1626 pTNd->ResetAttr( RES_PARATR_LIST_LEVEL );
1627 pTNd->ResetAttr( RES_PARATR_LIST_ISRESTART );
1628 pTNd->ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
1629 pTNd->ResetAttr( RES_PARATR_LIST_ISCOUNTED );
1630 // <--
1631
1632 if( RES_CONDTXTFMTCOLL == pTNd->GetFmtColl()->Which() )
1633 pTNd->ChkCondColl();
1634 //else if( !pOutlNd && NO_NUMBERING != //#outline level,zhaojianwei
1635 // ((SwTxtFmtColl*)pTNd->GetFmtColl())->GetOutlineLevel() )
1636 else if( !pOutlNd &&
1637 ((SwTxtFmtColl*)pTNd->GetFmtColl())->IsAssignedToListLevelOfOutlineStyle() )//<-end,zhaojianwei
1638 pOutlNd = pTNd;
1639 }
1640 }
1641
1642 // dann noch alle Updaten
1643 UpdateNumRule();
1644
1645 if( pOutlNd )
1646 GetNodes().UpdtOutlineIdx( *pOutlNd );
1647 }
1648
InvalidateNumRules()1649 void SwDoc::InvalidateNumRules()
1650 {
1651 for (sal_uInt16 n = 0; n < pNumRuleTbl->Count(); ++n)
1652 (*pNumRuleTbl)[n]->SetInvalidRule(sal_True);
1653 }
1654
1655 // zum naechsten/vorhergehenden Punkt auf gleicher Ebene
1656
lcl_IsNumOk(sal_uInt8 nSrchNum,sal_uInt8 & rLower,sal_uInt8 & rUpper,sal_Bool bOverUpper,sal_uInt8 nNumber)1657 sal_Bool lcl_IsNumOk( sal_uInt8 nSrchNum, sal_uInt8& rLower, sal_uInt8& rUpper,
1658 sal_Bool bOverUpper, sal_uInt8 nNumber )
1659 {
1660 // --> OD 2008-04-02 #refactorlists#
1661 ASSERT( nNumber < MAXLEVEL,
1662 "<lcl_IsNumOk(..)> - misusage of method" );
1663 // <--
1664
1665 sal_Bool bRet = sal_False;
1666 {
1667 if( bOverUpper ? nSrchNum == nNumber : nSrchNum >= nNumber )
1668 bRet = sal_True;
1669 else if( nNumber > rLower )
1670 rLower = nNumber;
1671 else if( nNumber < rUpper )
1672 rUpper = nNumber;
1673 }
1674 return bRet;
1675 }
1676
lcl_IsValidPrevNextNumNode(const SwNodeIndex & rIdx)1677 sal_Bool lcl_IsValidPrevNextNumNode( const SwNodeIndex& rIdx )
1678 {
1679 sal_Bool bRet = sal_False;
1680 const SwNode& rNd = rIdx.GetNode();
1681 switch( rNd.GetNodeType() )
1682 {
1683 case ND_ENDNODE:
1684 bRet = SwTableBoxStartNode == rNd.StartOfSectionNode()->GetStartNodeType() ||
1685 rNd.StartOfSectionNode()->IsSectionNode();
1686 break;
1687
1688 case ND_STARTNODE:
1689 bRet = SwTableBoxStartNode == ((SwStartNode&)rNd).GetStartNodeType();
1690 break;
1691
1692 case ND_SECTIONNODE: // der ist erlaubt, also weiter
1693 bRet = sal_True;
1694 break;
1695 }
1696 return bRet;
1697 }
1698
lcl_GotoNextPrevNum(SwPosition & rPos,sal_Bool bNext,sal_Bool bOverUpper,sal_uInt8 * pUpper,sal_uInt8 * pLower)1699 sal_Bool lcl_GotoNextPrevNum( SwPosition& rPos, sal_Bool bNext,
1700 sal_Bool bOverUpper, sal_uInt8* pUpper, sal_uInt8* pLower )
1701 {
1702 const SwTxtNode* pNd = rPos.nNode.GetNode().GetTxtNode();
1703 const SwNumRule* pRule;
1704 if( !pNd || 0 == ( pRule = pNd->GetNumRule()))
1705 return sal_False;
1706
1707 sal_uInt8 nSrchNum = static_cast<sal_uInt8>(pNd->GetActualListLevel());
1708
1709 SwNodeIndex aIdx( rPos.nNode );
1710 if( ! pNd->IsCountedInList() )
1711 {
1712 // falls gerade mal NO_NUMLEVEL an ist, so such den vorherigen Node
1713 // mit Nummerierung
1714 sal_Bool bError = sal_False;
1715 do {
1716 aIdx--;
1717 if( aIdx.GetNode().IsTxtNode() )
1718 {
1719 pNd = aIdx.GetNode().GetTxtNode();
1720 pRule = pNd->GetNumRule();
1721
1722 sal_uInt8 nTmpNum;
1723
1724 if( pRule )
1725 {
1726 nTmpNum = static_cast<sal_uInt8>(pNd->GetActualListLevel());
1727 if( !( ! pNd->IsCountedInList() &&
1728 (nTmpNum >= nSrchNum )) )
1729 break; // gefunden
1730 }
1731 else
1732 bError = sal_True;
1733 }
1734 else
1735 bError = !lcl_IsValidPrevNextNumNode( aIdx );
1736
1737 } while( !bError );
1738 if( bError )
1739 return sal_False;
1740 }
1741
1742 sal_uInt8 nLower = nSrchNum, nUpper = nSrchNum;
1743 sal_Bool bRet = sal_False;
1744
1745 const SwTxtNode* pLast;
1746 if( bNext )
1747 aIdx++, pLast = pNd;
1748 else
1749 aIdx--, pLast = 0;
1750
1751 while( bNext ? ( aIdx.GetIndex() < aIdx.GetNodes().Count() - 1 )
1752 : aIdx.GetIndex() )
1753 {
1754 if( aIdx.GetNode().IsTxtNode() )
1755 {
1756 pNd = aIdx.GetNode().GetTxtNode();
1757 pRule = pNd->GetNumRule();
1758 if( pRule )
1759 {
1760 if( ::lcl_IsNumOk( nSrchNum, nLower, nUpper, bOverUpper,
1761 static_cast<sal_uInt8>(pNd->GetActualListLevel()) ))
1762 {
1763 rPos.nNode = aIdx;
1764 rPos.nContent.Assign( (SwTxtNode*)pNd, 0 );
1765 bRet = sal_True;
1766 break;
1767 }
1768 else
1769 pLast = pNd;
1770 }
1771 else
1772 break;
1773 }
1774 else if( !lcl_IsValidPrevNextNumNode( aIdx ))
1775 break;
1776
1777 if( bNext )
1778 aIdx++;
1779 else
1780 aIdx--;
1781 }
1782
1783 if( !bRet && !bOverUpper && pLast ) // nicht ueber hoehere Nummmern, aber bis Ende
1784 {
1785 if( bNext )
1786 {
1787 rPos.nNode = aIdx;
1788 if( aIdx.GetNode().IsCntntNode() )
1789 rPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 );
1790 }
1791 else
1792 {
1793 rPos.nNode.Assign( *pLast );
1794 rPos.nContent.Assign( (SwTxtNode*)pLast, 0 );
1795 }
1796 bRet = sal_True;
1797 }
1798
1799 if( bRet )
1800 {
1801 if( pUpper )
1802 *pUpper = nUpper;
1803 if( pLower )
1804 *pLower = nLower;
1805 }
1806 return bRet;
1807 }
1808
GotoNextNum(SwPosition & rPos,sal_Bool bOverUpper,sal_uInt8 * pUpper,sal_uInt8 * pLower)1809 sal_Bool SwDoc::GotoNextNum( SwPosition& rPos, sal_Bool bOverUpper,
1810 sal_uInt8* pUpper, sal_uInt8* pLower )
1811 {
1812 return ::lcl_GotoNextPrevNum( rPos, sal_True, bOverUpper, pUpper, pLower );
1813 }
1814
1815 // -> #i23731#
1816 // --> 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)1817 const SwNumRule * SwDoc::SearchNumRule(const SwPosition & rPos,
1818 const bool bForward,
1819 const bool bNum,
1820 const bool bOutline,
1821 int nNonEmptyAllowed,
1822 String& sListId,
1823 const bool bInvestigateStartNode)
1824 {
1825 const SwNumRule * pResult = NULL;
1826 SwTxtNode * pTxtNd = rPos.nNode.GetNode().GetTxtNode();
1827 SwNode * pStartFromNode = pTxtNd;
1828
1829 if (pTxtNd)
1830 {
1831 SwNodeIndex aIdx(rPos.nNode);
1832
1833 // --> OD 2005-10-20 #i55391#
1834 // - the start node has also been investigated, if requested.
1835 const SwNode * pNode = NULL;
1836 do
1837 {
1838 // --> OD 2005-10-20 #i55391#
1839 if ( !bInvestigateStartNode )
1840 {
1841 if (bForward)
1842 aIdx++;
1843 else
1844 aIdx--;
1845 }
1846 // <--
1847 if (aIdx.GetNode().IsTxtNode())
1848 {
1849 pTxtNd = aIdx.GetNode().GetTxtNode();
1850
1851 const SwNumRule * pNumRule = pTxtNd->GetNumRule();
1852 if (pNumRule)
1853 {
1854 if ( ( pNumRule->IsOutlineRule() == ( bOutline ? sal_True : sal_False ) ) && // #115901#
1855 ( ( bNum && pNumRule->Get(0).IsEnumeration()) ||
1856 ( !bNum && pNumRule->Get(0).IsItemize() ) ) ) // #i22362#, #i29560#
1857 {
1858 pResult = pTxtNd->GetNumRule();
1859 // --> OD 2008-03-18 #refactorlists#
1860 // provide also the list id, to which the text node belongs.
1861 sListId = pTxtNd->GetListId();
1862 }
1863
1864 break;
1865 }
1866 else if (pTxtNd->Len() > 0 || NULL != pTxtNd->GetNumRule())
1867 {
1868 if (nNonEmptyAllowed == 0)
1869 break;
1870
1871 nNonEmptyAllowed--;
1872
1873 if (nNonEmptyAllowed < 0)
1874 nNonEmptyAllowed = -1;
1875 }
1876 }
1877
1878 // --> OD 2005-10-20 #i55391#
1879 if ( bInvestigateStartNode )
1880 {
1881 if (bForward)
1882 aIdx++;
1883 else
1884 aIdx--;
1885 }
1886 // <--
1887
1888 pNode = &aIdx.GetNode();
1889 }
1890 while (!(pNode == GetNodes().DocumentSectionStartNode(pStartFromNode) ||
1891 pNode == GetNodes().DocumentSectionEndNode(pStartFromNode)));
1892 // <--
1893 }
1894
1895 return pResult;
1896 }
1897 // <- #i23731#
1898
GotoPrevNum(SwPosition & rPos,sal_Bool bOverUpper,sal_uInt8 * pUpper,sal_uInt8 * pLower)1899 sal_Bool SwDoc::GotoPrevNum( SwPosition& rPos, sal_Bool bOverUpper,
1900 sal_uInt8* pUpper, sal_uInt8* pLower )
1901 {
1902 return ::lcl_GotoNextPrevNum( rPos, sal_False, bOverUpper, pUpper, pLower );
1903 }
1904
NumUpDown(const SwPaM & rPam,sal_Bool bDown)1905 sal_Bool SwDoc::NumUpDown( const SwPaM& rPam, sal_Bool bDown )
1906 {
1907 sal_uLong nStt = rPam.GetPoint()->nNode.GetIndex(),
1908 nEnd = rPam.GetMark()->nNode.GetIndex();
1909 if( nStt > nEnd )
1910 {
1911 sal_uLong nTmp = nStt; nStt = nEnd; nEnd = nTmp;
1912 }
1913
1914 // -> #115901# outline nodes are promoted or demoted differently
1915 bool bOnlyOutline = true;
1916 bool bOnlyNonOutline = true;
1917 for (sal_uLong n = nStt; n <= nEnd; n++)
1918 {
1919 SwTxtNode * pTxtNd = GetNodes()[n]->GetTxtNode();
1920
1921 if (pTxtNd)
1922 {
1923 SwNumRule * pRule = pTxtNd->GetNumRule();
1924
1925 if (pRule)
1926 {
1927 if (pRule->IsOutlineRule())
1928 bOnlyNonOutline = false;
1929 else
1930 bOnlyOutline = false;
1931 }
1932 }
1933 }
1934 // <- #115901#
1935
1936 sal_Bool bRet = sal_True;
1937 char nDiff = bDown ? 1 : -1;
1938
1939 // ->#115901#
1940 if (bOnlyOutline)
1941 bRet = OutlineUpDown(rPam, nDiff);
1942 else if (bOnlyNonOutline)
1943 {
1944 /* --> #i24560#
1945
1946 Only promote or demote if all selected paragraphs are
1947 promotable resp. demotable.
1948
1949 */
1950 for (sal_uLong nTmp = nStt; nTmp <= nEnd; ++nTmp)
1951 {
1952 SwTxtNode* pTNd = GetNodes()[ nTmp ]->GetTxtNode();
1953
1954 // --> OD 2006-10-19 #134160# - make code robust:
1955 // consider case that the node doesn't denote a text node.
1956 if ( pTNd )
1957 {
1958 SwNumRule * pRule = pTNd->GetNumRule();
1959
1960 if (pRule)
1961 {
1962 sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel());
1963 if( (-1 == nDiff && 0 >= nLevel) ||
1964 (1 == nDiff && MAXLEVEL - 1 <= nLevel))
1965 bRet = sal_False;
1966 }
1967 }
1968 // <--
1969 }
1970
1971 if( bRet )
1972 {
1973 /* <-- #i24560# */
1974 if (GetIDocumentUndoRedo().DoesUndo())
1975 {
1976 SwUndo *const pUndo( new SwUndoNumUpDown(rPam, nDiff) );
1977 GetIDocumentUndoRedo().AppendUndo(pUndo);
1978 }
1979
1980 String sNumRule;
1981
1982 for(sal_uLong nTmp = nStt; nTmp <= nEnd; ++nTmp )
1983 {
1984 SwTxtNode* pTNd = GetNodes()[ nTmp ]->GetTxtNode();
1985
1986 if( pTNd)
1987 {
1988 SwNumRule * pRule = pTNd->GetNumRule();
1989
1990 if (pRule)
1991 {
1992 sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel());
1993 nLevel = nLevel + nDiff;
1994
1995 pTNd->SetAttrListLevel(nLevel);
1996 }
1997 }
1998 }
1999
2000 ChkCondColls();
2001 SetModified();
2002 }
2003 }
2004
2005 return bRet;
2006 }
2007
MoveParagraph(const SwPaM & rPam,long nOffset,sal_Bool bIsOutlMv)2008 sal_Bool SwDoc::MoveParagraph( const SwPaM& rPam, long nOffset, sal_Bool bIsOutlMv )
2009 {
2010 const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
2011
2012 sal_uLong nStIdx = pStt->nNode.GetIndex();
2013 sal_uLong nEndIdx = pEnd->nNode.GetIndex();
2014
2015 // Here are some sophisticated checks whether the wished PaM will be moved or not.
2016 // For moving outlines (bIsOutlMv) I've already done some checks, so here are two different
2017 // checks...
2018 SwNode *pTmp1;
2019 SwNode *pTmp2;
2020 if( bIsOutlMv )
2021 {
2022 // For moving chapters (outline) the following reason will deny the move:
2023 // if a start node is inside the moved area and its end node outside or vice versa.
2024 // If a start node is the first moved paragraph, its end node has to be within the moved
2025 // area, too (e.g. as last node).
2026 // If an end node is the last node of the moved area, its start node has to be a part of
2027 // the moved section, too.
2028 pTmp1 = GetNodes()[ nStIdx ];
2029 if( pTmp1->IsStartNode() )
2030 { // First is a start node
2031 pTmp2 = pTmp1->EndOfSectionNode();
2032 if( pTmp2->GetIndex() > nEndIdx )
2033 return sal_False; // Its end node is behind the moved range
2034 }
2035 pTmp1 = pTmp1->StartOfSectionNode()->EndOfSectionNode();
2036 if( pTmp1->GetIndex() <= nEndIdx )
2037 return sal_False; // End node inside but start node before moved range => no.
2038 pTmp1 = GetNodes()[ nEndIdx ];
2039 if( pTmp1->IsEndNode() )
2040 { // The last one is an end node
2041 pTmp1 = pTmp1->StartOfSectionNode();
2042 if( pTmp1->GetIndex() < nStIdx )
2043 return sal_False; // Its start node is before the moved range.
2044 }
2045 pTmp1 = pTmp1->StartOfSectionNode();
2046 if( pTmp1->GetIndex() >= nStIdx )
2047 return sal_False; // A start node which ends behind the moved area => no.
2048 }
2049
2050 sal_uLong nInStIdx, nInEndIdx;
2051 long nOffs = nOffset;
2052 if( nOffset > 0 )
2053 {
2054 nInEndIdx = nEndIdx;
2055 nEndIdx += nOffset;
2056 ++nOffs;
2057 }
2058 else
2059 {
2060 //Impossible to move to negative index
2061 if( sal_uLong(abs( nOffset )) > nStIdx)
2062 return sal_False;
2063
2064 nInEndIdx = nStIdx - 1;
2065 nStIdx += nOffset;
2066 }
2067 nInStIdx = nInEndIdx + 1;
2068 // Folgende Absatzbloecke sollen vertauscht werden:
2069 // [ nStIdx, nInEndIdx ] mit [ nInStIdx, nEndIdx ]
2070
2071 if( nEndIdx >= GetNodes().GetEndOfContent().GetIndex() )
2072 return sal_False;
2073
2074 if( !bIsOutlMv )
2075 { // And here the restrictions for moving paragraphs other than chapters (outlines)
2076 // The plan is to exchange [nStIdx,nInEndIdx] and [nStartIdx,nEndIdx]
2077 // It will checked if the both "start" nodes as well as the both "end" notes belongs to
2078 // the same start-end-section. This is more restrictive than the conditions checked above.
2079 // E.g. a paragraph will not escape from a section or be inserted to another section.
2080 pTmp1 = GetNodes()[ nStIdx ]->StartOfSectionNode();
2081 pTmp2 = GetNodes()[ nInStIdx ]->StartOfSectionNode();
2082 if( pTmp1 != pTmp2 )
2083 return sal_False; // "start" nodes in different sections
2084 pTmp1 = GetNodes()[ nEndIdx ];
2085 bool bIsEndNode = pTmp1->IsEndNode();
2086 if( !pTmp1->IsStartNode() )
2087 {
2088 pTmp1 = pTmp1->StartOfSectionNode();
2089 if( bIsEndNode ) // For end nodes the first start node is of course inside the range,
2090 pTmp1 = pTmp1->StartOfSectionNode(); // I've to check the start node of the start node.
2091 }
2092 pTmp1 = pTmp1->EndOfSectionNode();
2093 pTmp2 = GetNodes()[ nInEndIdx ];
2094 if( !pTmp2->IsStartNode() )
2095 {
2096 bIsEndNode = pTmp2->IsEndNode();
2097 pTmp2 = pTmp2->StartOfSectionNode();
2098 if( bIsEndNode )
2099 pTmp2 = pTmp2->StartOfSectionNode();
2100 }
2101 pTmp2 = pTmp2->EndOfSectionNode();
2102 if( pTmp1 != pTmp2 )
2103 return sal_False; // The "end" notes are in different sections
2104 }
2105
2106 // auf Redlining testen - darf die Selektion ueberhaupt verschoben
2107 // werden?
2108 if( !IsIgnoreRedline() )
2109 {
2110 sal_uInt16 nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), nsRedlineType_t::REDLINE_DELETE );
2111 if( USHRT_MAX != nRedlPos )
2112 {
2113 SwPosition aStPos( *pStt ), aEndPos( *pEnd );
2114 aStPos.nContent = 0;
2115 SwCntntNode* pCNd = pEnd->nNode.GetNode().GetCntntNode();
2116 aEndPos.nContent = pCNd ? pCNd->Len() : 1;
2117 sal_Bool bCheckDel = sal_True;
2118
2119 // es existiert fuer den Bereich irgendein Redline-Delete-Object
2120 for( ; nRedlPos < GetRedlineTbl().Count(); ++nRedlPos )
2121 {
2122 const SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
2123 if( !bCheckDel || nsRedlineType_t::REDLINE_DELETE == pTmp->GetType() )
2124 {
2125 const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
2126 switch( ComparePosition( *pRStt, *pREnd, aStPos, aEndPos ))
2127 {
2128 case POS_COLLIDE_START:
2129 case POS_BEHIND: // Pos1 liegt hinter Pos2
2130 nRedlPos = GetRedlineTbl().Count();
2131 break;
2132
2133 case POS_COLLIDE_END:
2134 case POS_BEFORE: // Pos1 liegt vor Pos2
2135 break;
2136 case POS_INSIDE: // Pos1 liegt vollstaendig in Pos2
2137 // ist erlaubt, aber checke dann alle nachfolgenden
2138 // auf Ueberlappungen
2139 bCheckDel = sal_False;
2140 break;
2141
2142 case POS_OUTSIDE: // Pos2 liegt vollstaendig in Pos1
2143 case POS_EQUAL: // Pos1 ist genauso gross wie Pos2
2144 case POS_OVERLAP_BEFORE: // Pos1 ueberlappt Pos2 am Anfang
2145 case POS_OVERLAP_BEHIND: // Pos1 ueberlappt Pos2 am Ende
2146 return sal_False;
2147 }
2148 }
2149 }
2150 }
2151 }
2152
2153 {
2154 // DataChanged vorm verschieben verschicken, dann bekommt
2155 // man noch mit, welche Objecte sich im Bereich befinden.
2156 // Danach koennen sie vor/hinter der Position befinden.
2157 SwDataChanged aTmp( rPam, 0 );
2158 }
2159
2160 SwNodeIndex aIdx( nOffset > 0 ? pEnd->nNode : pStt->nNode, nOffs );
2161 SwNodeRange aMvRg( pStt->nNode, 0, pEnd->nNode, +1 );
2162
2163 SwRedline* pOwnRedl = 0;
2164 if( IsRedlineOn() )
2165 {
2166 // wenn der Bereich komplett im eigenen Redline liegt, kann es
2167 // verschoben werden!
2168 sal_uInt16 nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), nsRedlineType_t::REDLINE_INSERT );
2169 if( USHRT_MAX != nRedlPos )
2170 {
2171 SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
2172 const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
2173 SwRedline aTmpRedl( nsRedlineType_t::REDLINE_INSERT, rPam );
2174 const SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode();
2175 // liegt komplett im Bereich, und ist auch der eigene Redline?
2176 if( aTmpRedl.IsOwnRedline( *pTmp ) &&
2177 (pRStt->nNode < pStt->nNode ||
2178 (pRStt->nNode == pStt->nNode && !pRStt->nContent.GetIndex()) ) &&
2179 (pEnd->nNode < pREnd->nNode ||
2180 (pEnd->nNode == pREnd->nNode &&
2181 pCEndNd ? pREnd->nContent.GetIndex() == pCEndNd->Len()
2182 : !pREnd->nContent.GetIndex() )) )
2183 {
2184 pOwnRedl = pTmp;
2185 if( nRedlPos + 1 < GetRedlineTbl().Count() )
2186 {
2187 pTmp = GetRedlineTbl()[ nRedlPos+1 ];
2188 if( *pTmp->Start() == *pREnd )
2189 // dann doch nicht!
2190 pOwnRedl = 0;
2191 }
2192
2193 if( pOwnRedl &&
2194 !( pRStt->nNode <= aIdx && aIdx <= pREnd->nNode ))
2195 {
2196 // nicht in sich selbst, dann auch nicht moven
2197 pOwnRedl = 0;
2198 }
2199 }
2200 }
2201
2202 if( !pOwnRedl )
2203 {
2204 GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL );
2205
2206 // zuerst das Insert, dann das Loeschen
2207 SwPosition aInsPos( aIdx );
2208 aInsPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 );
2209
2210 SwPaM aPam( pStt->nNode, aMvRg.aEnd );
2211
2212 SwPaM& rOrigPam = (SwPaM&)rPam;
2213 rOrigPam.DeleteMark();
2214 rOrigPam.GetPoint()->nNode = aIdx.GetIndex() - 1;
2215
2216 sal_Bool bDelLastPara = !aInsPos.nNode.GetNode().IsCntntNode();
2217
2218 /* #101076# When copying to a non-content node Copy will
2219 insert a paragraph before that node and insert before
2220 that inserted node. Copy creates an SwUndoInserts that
2221 does not cover the extra paragraph. Thus we insert the
2222 extra paragraph ourselves, _with_ correct undo
2223 information. */
2224 if (bDelLastPara)
2225 {
2226 /* aInsPos points to the non-content node. Move it to
2227 the previous content node. */
2228 SwPaM aInsPam(aInsPos);
2229 sal_Bool bMoved = aInsPam.Move(fnMoveBackward);
2230 ASSERT(bMoved, "No content node found!");
2231
2232 if (bMoved)
2233 {
2234 /* Append the new node after the content node
2235 found. The new position to insert the moved
2236 paragraph at is before the inserted
2237 paragraph. */
2238 AppendTxtNode(*aInsPam.GetPoint());
2239 aInsPos = *aInsPam.GetPoint();
2240 }
2241 }
2242
2243 CopyRange( aPam, aInsPos, false );
2244 if( bDelLastPara )
2245 {
2246 // dann muss der letzte leere Node wieder entfernt werden
2247 aIdx = aInsPos.nNode;
2248 SwCntntNode* pCNd = GetNodes().GoPrevious( &aInsPos.nNode );
2249 xub_StrLen nCLen = 0; if( pCNd ) nCLen = pCNd->Len();
2250 aInsPos.nContent.Assign( pCNd, nCLen );
2251
2252 // alle die im zu loeschenden Node stehen, mussen auf den
2253 // naechsten umgestezt werden
2254 SwPosition* pPos;
2255 for( sal_uInt16 n = 0; n < GetRedlineTbl().Count(); ++n )
2256 {
2257 SwRedline* pTmp = GetRedlineTbl()[ n ];
2258 if( ( pPos = &pTmp->GetBound(sal_True))->nNode == aIdx )
2259 {
2260 pPos->nNode++;
2261 pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0);
2262 }
2263 if( ( pPos = &pTmp->GetBound(sal_False))->nNode == aIdx )
2264 {
2265 pPos->nNode++;
2266 pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0);
2267 }
2268 }
2269 CorrRel( aIdx, aInsPos, 0, sal_False );
2270
2271 pCNd->JoinNext();
2272 }
2273
2274 rOrigPam.GetPoint()->nNode++;
2275 rOrigPam.GetPoint()->nContent.Assign( rOrigPam.GetCntntNode(), 0 );
2276
2277 RedlineMode_t eOld = GetRedlineMode();
2278 checkRedlining(eOld);
2279 if (GetIDocumentUndoRedo().DoesUndo())
2280 {
2281 //JP 06.01.98: MUSS noch optimiert werden!!!
2282 SetRedlineMode(
2283 (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE));
2284 SwUndo *const pUndo(new SwUndoRedlineDelete(aPam, UNDO_DELETE));
2285 GetIDocumentUndoRedo().AppendUndo(pUndo);
2286 }
2287
2288 SwRedline* pNewRedline = new SwRedline( nsRedlineType_t::REDLINE_DELETE, aPam );
2289
2290 // #101654# prevent assertion from aPam's target being deleted
2291 // (Alternatively, one could just let aPam go out of scope, but
2292 // that requires touching a lot of code.)
2293 aPam.GetBound(sal_True).nContent.Assign( NULL, 0 );
2294 aPam.GetBound(sal_False).nContent.Assign( NULL, 0 );
2295
2296 AppendRedline( pNewRedline, true );
2297
2298 //JP 06.01.98: MUSS noch optimiert werden!!!
2299 SetRedlineMode( eOld );
2300 GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
2301 SetModified();
2302
2303 return sal_True;
2304 }
2305 }
2306
2307 if( !pOwnRedl && !IsIgnoreRedline() && GetRedlineTbl().Count() )
2308 {
2309 SwPaM aTemp(aIdx);
2310 SplitRedline(aTemp);
2311 }
2312
2313 sal_uLong nRedlSttNd(0), nRedlEndNd(0);
2314 if( pOwnRedl )
2315 {
2316 const SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End();
2317 nRedlSttNd = pRStt->nNode.GetIndex();
2318 nRedlEndNd = pREnd->nNode.GetIndex();
2319 }
2320
2321 SwUndoMoveNum* pUndo = 0;
2322 sal_uLong nMoved = 0;
2323 if (GetIDocumentUndoRedo().DoesUndo())
2324 {
2325 pUndo = new SwUndoMoveNum( rPam, nOffset, bIsOutlMv );
2326 nMoved = rPam.End()->nNode.GetIndex() - rPam.Start()->nNode.GetIndex() + 1;
2327 }
2328
2329
2330 MoveNodeRange( aMvRg, aIdx, DOC_MOVEREDLINES );
2331
2332 if( pUndo )
2333 {
2334 // i57907: Under circumstances (sections at the end of a chapter)
2335 // the rPam.Start() is not moved to the new position.
2336 // But aIdx should be at the new end position and as long as the number of moved paragraphs
2337 // is nMoved, I know, where the new position is.
2338 pUndo->SetStartNode( aIdx.GetIndex() - nMoved );
2339 GetIDocumentUndoRedo().AppendUndo(pUndo);
2340 }
2341
2342 if( pOwnRedl )
2343 {
2344 SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End();
2345 if( pRStt->nNode.GetIndex() != nRedlSttNd )
2346 {
2347 pRStt->nNode = nRedlSttNd;
2348 pRStt->nContent.Assign( pRStt->nNode.GetNode().GetCntntNode(),0);
2349 }
2350 if( pREnd->nNode.GetIndex() != nRedlEndNd )
2351 {
2352 pREnd->nNode = nRedlEndNd;
2353 SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode();
2354 xub_StrLen nL = 0; if( pCNd ) nL = pCNd->Len();
2355 pREnd->nContent.Assign( pCNd, nL );
2356 }
2357 }
2358
2359 SetModified();
2360 return sal_True;
2361 }
2362
NumOrNoNum(const SwNodeIndex & rIdx,sal_Bool bDel)2363 sal_Bool SwDoc::NumOrNoNum( const SwNodeIndex& rIdx, sal_Bool bDel )
2364 {
2365 sal_Bool bResult = sal_False;
2366 SwTxtNode * pTxtNd = rIdx.GetNode().GetTxtNode();
2367
2368 if (pTxtNd && pTxtNd->GetNumRule() != NULL &&
2369 (pTxtNd->HasNumber() || pTxtNd->HasBullet()))
2370 {
2371 if ( !pTxtNd->IsCountedInList() == !bDel)
2372 {
2373 sal_Bool bOldNum = bDel; // == pTxtNd->IsCounted();
2374 sal_Bool bNewNum = bDel ? sal_False : sal_True;
2375 pTxtNd->SetCountedInList(bNewNum ? true : false);
2376
2377 SetModified();
2378
2379 bResult = sal_True;
2380
2381 if (GetIDocumentUndoRedo().DoesUndo())
2382 {
2383 SwUndoNumOrNoNum * pUndo =
2384 new SwUndoNumOrNoNum(rIdx, bOldNum, bNewNum);
2385
2386 GetIDocumentUndoRedo().AppendUndo(pUndo);
2387 }
2388 }
2389 else if (bDel && pTxtNd->GetNumRule(sal_False) &&
2390 pTxtNd->GetActualListLevel() >= 0 &&
2391 pTxtNd->GetActualListLevel() < MAXLEVEL)
2392 {
2393 SwPaM aPam(*pTxtNd);
2394
2395 DelNumRules(aPam);
2396
2397 bResult = sal_True;
2398 }
2399 }
2400
2401 return bResult;
2402 }
2403
GetCurrNumRule(const SwPosition & rPos) const2404 SwNumRule* SwDoc::GetCurrNumRule( const SwPosition& rPos ) const
2405 {
2406 SwNumRule* pRet = 0;
2407 SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
2408
2409 if( pTNd )
2410 {
2411 // --> OD 2008-02-20 #refactorlists#
2412 // pTNd->SyncNumberAndNumRule();
2413 // <--
2414 pRet = pTNd->GetNumRule();
2415 }
2416
2417 return pRet;
2418 }
2419
FindNumRule(const String & rName) const2420 sal_uInt16 SwDoc::FindNumRule( const String& rName ) const
2421 {
2422 for( sal_uInt16 n = pNumRuleTbl->Count(); n; )
2423 if( (*pNumRuleTbl)[ --n ]->GetName() == rName )
2424 return n;
2425
2426 return USHRT_MAX;
2427 }
2428
FindNumRulePtr(const String & rName) const2429 SwNumRule* SwDoc::FindNumRulePtr( const String& rName ) const
2430 {
2431 SwNumRule * pResult = 0;
2432
2433 pResult = maNumRuleMap[rName];
2434
2435 if ( !pResult )
2436 {
2437 for (sal_uInt16 n = 0; n < pNumRuleTbl->Count(); ++n)
2438 {
2439 if ((*pNumRuleTbl)[n]->GetName() == rName)
2440 {
2441 pResult = (*pNumRuleTbl)[n];
2442
2443 break;
2444 }
2445 }
2446 }
2447
2448 return pResult;
2449 }
2450
2451 // #i36749#
AddNumRule(SwNumRule * pRule)2452 void SwDoc::AddNumRule(SwNumRule * pRule)
2453 {
2454 if ((SAL_MAX_UINT16 - 1) <= pNumRuleTbl->Count())
2455 {
2456 OSL_ENSURE(false, "SwDoc::AddNumRule: table full.");
2457 abort(); // this should never happen on real documents
2458 }
2459 pNumRuleTbl->Insert(pRule, pNumRuleTbl->Count());
2460 maNumRuleMap[pRule->GetName()] = pRule;
2461 pRule->SetNumRuleMap(&maNumRuleMap);
2462
2463 // --> OD 2008-03-26 #refactorlists#
2464 createListForListStyle( pRule->GetName() );
2465 // <--
2466 }
2467
2468 // --> OD 2008-02-11 #newlistlevelattrs#
MakeNumRule(const String & rName,const SwNumRule * pCpy,sal_Bool bBroadcast,const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode)2469 sal_uInt16 SwDoc::MakeNumRule( const String &rName,
2470 const SwNumRule* pCpy,
2471 sal_Bool bBroadcast,
2472 const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode )
2473 {
2474 SwNumRule* pNew;
2475 if( pCpy )
2476 {
2477 pNew = new SwNumRule( *pCpy );
2478
2479 // --> OD 2008-07-08 #i91400#
2480 pNew->SetName( GetUniqueNumRuleName( &rName ), *this );
2481 // <--
2482 if( pNew->GetName() != rName )
2483 {
2484 pNew->SetPoolFmtId( USHRT_MAX );
2485 pNew->SetPoolHelpId( USHRT_MAX );
2486 pNew->SetPoolHlpFileId( UCHAR_MAX );
2487 // --> OD 2008-04-03 #refactorlists#
2488 pNew->SetDefaultListId( String() );
2489 // <--
2490 }
2491 pNew->CheckCharFmts( this );
2492 }
2493 else
2494 {
2495 // --> OD 2008-02-11 #newlistlevelattrs#
2496 pNew = new SwNumRule( GetUniqueNumRuleName( &rName ),
2497 eDefaultNumberFormatPositionAndSpaceMode );
2498 // <--
2499 }
2500
2501 sal_uInt16 nRet = pNumRuleTbl->Count();
2502
2503 AddNumRule(pNew); // #i36749#
2504
2505 if (GetIDocumentUndoRedo().DoesUndo())
2506 {
2507 SwUndo * pUndo = new SwUndoNumruleCreate(pNew, this);
2508 GetIDocumentUndoRedo().AppendUndo(pUndo);
2509 }
2510
2511 if (bBroadcast)
2512 BroadcastStyleOperation(pNew->GetName(), SFX_STYLE_FAMILY_PSEUDO,
2513 SFX_STYLESHEET_CREATED);
2514
2515 return nRet;
2516 }
2517
GetUniqueNumRuleName(const String * pChkStr,sal_Bool bAutoNum) const2518 String SwDoc::GetUniqueNumRuleName( const String* pChkStr, sal_Bool bAutoNum ) const
2519 {
2520 String aName;
2521 if( bAutoNum )
2522 {
2523 // --> OD #o12311627#
2524 static rtlRandomPool s_RandomPool( rtl_random_createPool() );
2525 sal_Int64 n;
2526 rtl_random_getBytes( s_RandomPool, &n, sizeof(n) );
2527 aName = String::CreateFromInt64( (n < 0 ? -n : n) );
2528 // <--
2529 if( pChkStr && !pChkStr->Len() )
2530 pChkStr = 0;
2531 }
2532 else if( pChkStr && pChkStr->Len() )
2533 aName = *pChkStr;
2534 else
2535 {
2536 pChkStr = 0;
2537 aName = SW_RESSTR( STR_NUMRULE_DEFNAME );
2538 }
2539
2540 sal_uInt16 nNum(0), nTmp, nFlagSize = ( pNumRuleTbl->Count() / 8 ) +2;
2541 sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ];
2542 memset( pSetFlags, 0, nFlagSize );
2543
2544 xub_StrLen nNmLen = aName.Len();
2545 if( !bAutoNum && pChkStr )
2546 {
2547 while( nNmLen-- && '0' <= aName.GetChar( nNmLen ) &&
2548 '9' >= aName.GetChar( nNmLen ) )
2549 ; //nop
2550
2551 if( ++nNmLen < aName.Len() )
2552 {
2553 aName.Erase( nNmLen );
2554 pChkStr = 0;
2555 }
2556 }
2557
2558 const SwNumRule* pNumRule;
2559 sal_uInt16 n;
2560
2561 for( n = 0; n < pNumRuleTbl->Count(); ++n )
2562 if( 0 != ( pNumRule = (*pNumRuleTbl)[ n ] ) )
2563 {
2564 const String& rNm = pNumRule->GetName();
2565 if( rNm.Match( aName ) == nNmLen )
2566 {
2567 // Nummer bestimmen und das Flag setzen
2568 nNum = (sal_uInt16)rNm.Copy( nNmLen ).ToInt32();
2569 if( nNum-- && nNum < pNumRuleTbl->Count() )
2570 pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
2571 }
2572 if( pChkStr && pChkStr->Equals( rNm ) )
2573 pChkStr = 0;
2574 }
2575
2576 if( !pChkStr )
2577 {
2578 // alle Nummern entsprechend geflag, also bestimme die richtige Nummer
2579 nNum = pNumRuleTbl->Count();
2580 for( n = 0; n < nFlagSize; ++n )
2581 if( 0xff != ( nTmp = pSetFlags[ n ] ))
2582 {
2583 // also die Nummer bestimmen
2584 nNum = n * 8;
2585 while( nTmp & 1 )
2586 ++nNum, nTmp >>= 1;
2587 break;
2588 }
2589
2590 }
2591 delete [] pSetFlags;
2592 if( pChkStr && pChkStr->Len() )
2593 return *pChkStr;
2594 return aName += String::CreateFromInt32( ++nNum );
2595 }
2596
UpdateNumRule()2597 void SwDoc::UpdateNumRule()
2598 {
2599 const SwNumRuleTbl& rNmTbl = GetNumRuleTbl();
2600 for( sal_uInt16 n = 0; n < rNmTbl.Count(); ++n )
2601 if( rNmTbl[ n ]->IsInvalidRule() )
2602 rNmTbl[ n ]->Validate();
2603 }
2604
2605 // --> OD 2008-04-02 #refactorlists#
MarkListLevel(const String & sListId,const int nListLevel,const sal_Bool bValue)2606 void SwDoc::MarkListLevel( const String& sListId,
2607 const int nListLevel,
2608 const sal_Bool bValue )
2609 {
2610 SwList* pList = getListByName( sListId );
2611
2612 if ( pList )
2613 {
2614 MarkListLevel( *pList, nListLevel, bValue );
2615 }
2616 }
2617
MarkListLevel(SwList & rList,const int nListLevel,const sal_Bool bValue)2618 void SwDoc::MarkListLevel( SwList& rList,
2619 const int nListLevel,
2620 const sal_Bool bValue )
2621 {
2622 // Set new marked list level and notify all affected nodes of the changed mark.
2623 rList.MarkListLevel( nListLevel, bValue );
2624 }
2625 // <- #i27615#
2626 // <--
2627
2628 // #i23726#
IsFirstOfNumRule(SwPosition & rPos)2629 sal_Bool SwDoc::IsFirstOfNumRule(SwPosition & rPos)
2630 {
2631 sal_Bool bResult = sal_False;
2632 SwTxtNode * pTxtNode = rPos.nNode.GetNode().GetTxtNode();
2633
2634 if (pTxtNode)
2635 {
2636 SwNumRule * pNumRule = pTxtNode->GetNumRule();
2637
2638 if (pNumRule)
2639 bResult = pTxtNode->IsFirstOfNumRule();
2640 }
2641
2642 return bResult;
2643 }
2644
2645 // --> OD 2007-10-26 #i83479#
2646 // implementation for interface <IDocumentListItems>
operator ()(const SwNodeNum * pNodeNumOne,const SwNodeNum * pNodeNumTwo) const2647 bool SwDoc::lessThanNodeNum::operator()( const SwNodeNum* pNodeNumOne,
2648 const SwNodeNum* pNodeNumTwo ) const
2649 {
2650 return pNodeNumOne->LessThan( *pNodeNumTwo );
2651 }
2652
addListItem(const SwNodeNum & rNodeNum)2653 void SwDoc::addListItem( const SwNodeNum& rNodeNum )
2654 {
2655 if ( mpListItemsList == 0 )
2656 {
2657 return;
2658 }
2659
2660 const bool bAlreadyInserted(
2661 mpListItemsList->find( &rNodeNum ) != mpListItemsList->end() );
2662 ASSERT( !bAlreadyInserted,
2663 "<SwDoc::InsertListItem(..)> - <SwNodeNum> instance already registered as numbered item!" );
2664 if ( !bAlreadyInserted )
2665 {
2666 mpListItemsList->insert( &rNodeNum );
2667 }
2668 }
2669
removeListItem(const SwNodeNum & rNodeNum)2670 void SwDoc::removeListItem( const SwNodeNum& rNodeNum )
2671 {
2672 if ( mpListItemsList == 0 )
2673 {
2674 return;
2675 }
2676
2677 const tImplSortedNodeNumList::size_type nDeleted = mpListItemsList->erase( &rNodeNum );
2678 if ( nDeleted > 1 )
2679 {
2680 ASSERT( false,
2681 "<SwDoc::RemoveListItem(..)> - <SwNodeNum> was registered more than once as numbered item!" );
2682 }
2683 }
2684
getListItemText(const SwNodeNum & rNodeNum,const bool bWithNumber,const bool bWithSpacesForLevel) const2685 String SwDoc::getListItemText( const SwNodeNum& rNodeNum,
2686 const bool bWithNumber,
2687 const bool bWithSpacesForLevel ) const
2688 {
2689 return rNodeNum.GetTxtNode()
2690 ? rNodeNum.GetTxtNode()->GetExpandTxt( 0, STRING_LEN, bWithNumber,
2691 bWithNumber, bWithSpacesForLevel )
2692 : String();
2693 }
2694
getListItems(tSortedNodeNumList & orNodeNumList) const2695 void SwDoc::getListItems( tSortedNodeNumList& orNodeNumList ) const
2696 {
2697 orNodeNumList.clear();
2698 orNodeNumList.reserve( mpListItemsList->size() );
2699
2700 tImplSortedNodeNumList::iterator aIter;
2701 tImplSortedNodeNumList::iterator aEndIter = mpListItemsList->end();
2702 for ( aIter = mpListItemsList->begin(); aIter != aEndIter; ++aIter )
2703 {
2704 orNodeNumList.push_back( (*aIter) );
2705 }
2706 }
2707
getNumItems(tSortedNodeNumList & orNodeNumList) const2708 void SwDoc::getNumItems( tSortedNodeNumList& orNodeNumList ) const
2709 {
2710 orNodeNumList.clear();
2711 orNodeNumList.reserve( mpListItemsList->size() );
2712
2713 tImplSortedNodeNumList::iterator aIter;
2714 tImplSortedNodeNumList::iterator aEndIter = mpListItemsList->end();
2715 for ( aIter = mpListItemsList->begin(); aIter != aEndIter; ++aIter )
2716 {
2717 const SwNodeNum* pNodeNum = (*aIter);
2718 if ( pNodeNum->IsCounted() &&
2719 pNodeNum->GetTxtNode() && pNodeNum->GetTxtNode()->HasNumber() )
2720 {
2721 orNodeNumList.push_back( pNodeNum );
2722 }
2723 }
2724 }
2725 // <--
2726
2727 // --> OD 2007-11-15 #i83479#
2728 // implementation for interface <IDocumentOutlineNodes>
getOutlineNodesCount() const2729 sal_Int32 SwDoc::getOutlineNodesCount() const
2730 {
2731 return GetNodes().GetOutLineNds().Count();
2732 }
2733
getOutlineLevel(const sal_Int32 nIdx) const2734 int SwDoc::getOutlineLevel( const sal_Int32 nIdx ) const
2735 {
2736 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->
2737 // GetTxtNode()->GetOutlineLevel(); //#outline level,zhaojianwei
2738 GetTxtNode()->GetAttrOutlineLevel()-1; //<-end,zhaojianwei
2739 }
2740
getOutlineText(const sal_Int32 nIdx,const bool bWithNumber,const bool bWithSpacesForLevel) const2741 String SwDoc::getOutlineText( const sal_Int32 nIdx,
2742 const bool bWithNumber,
2743 const bool bWithSpacesForLevel ) const
2744 {
2745 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->
2746 GetTxtNode()->GetExpandTxt( 0, STRING_LEN, bWithNumber,
2747 bWithNumber, bWithSpacesForLevel );
2748 }
2749
getOutlineNode(const sal_Int32 nIdx) const2750 SwTxtNode* SwDoc::getOutlineNode( const sal_Int32 nIdx ) const
2751 {
2752 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->GetTxtNode();
2753 }
2754
getOutlineNodes(IDocumentOutlineNodes::tSortedOutlineNodeList & orOutlineNodeList) const2755 void SwDoc::getOutlineNodes( IDocumentOutlineNodes::tSortedOutlineNodeList& orOutlineNodeList ) const
2756 {
2757 orOutlineNodeList.clear();
2758 orOutlineNodeList.reserve( getOutlineNodesCount() );
2759
2760 const sal_uInt16 nOutlCount( static_cast<sal_uInt16>(getOutlineNodesCount()) );
2761 for ( sal_uInt16 i = 0; i < nOutlCount; ++i )
2762 {
2763 orOutlineNodeList.push_back(
2764 GetNodes().GetOutLineNds()[i]->GetTxtNode() );
2765 }
2766 }
2767 // <--
2768
2769 // --> OD 2008-03-26 #refactorlists#
2770 // implementation of interface IDocumentListsAccess
createList(String sListId,const String sDefaultListStyleName)2771 SwList* SwDoc::createList( String sListId,
2772 const String sDefaultListStyleName )
2773 {
2774 if ( sListId.Len() == 0 )
2775 {
2776 sListId = listfunc::CreateUniqueListId( *this );
2777 }
2778
2779 if ( getListByName( sListId ) )
2780 {
2781 ASSERT( false,
2782 "<SwDoc::createList(..)> - provided list id already used. Serious defect -> please inform OD." );
2783 return 0;
2784 }
2785
2786 SwNumRule* pDefaultNumRuleForNewList = FindNumRulePtr( sDefaultListStyleName );
2787 if ( !pDefaultNumRuleForNewList )
2788 {
2789 ASSERT( false,
2790 "<SwDoc::createList(..)> - for provided default list style name no list style is found. Serious defect -> please inform OD." );
2791 return 0;
2792 }
2793
2794 SwList* pNewList = new SwList( sListId, *pDefaultNumRuleForNewList, GetNodes() );
2795 maLists[sListId] = pNewList;
2796
2797 return pNewList;
2798 }
2799
deleteList(const String sListId)2800 void SwDoc::deleteList( const String sListId )
2801 {
2802 SwList* pList = getListByName( sListId );
2803 if ( pList )
2804 {
2805 maLists.erase( sListId );
2806 delete pList;
2807 }
2808 }
2809
getListByName(const String sListId) const2810 SwList* SwDoc::getListByName( const String sListId ) const
2811 {
2812 SwList* pList = 0;
2813
2814 std::hash_map< String, SwList*, StringHash >::const_iterator
2815 aListIter = maLists.find( sListId );
2816 if ( aListIter != maLists.end() )
2817 {
2818 pList = (*aListIter).second;
2819 }
2820
2821 return pList;
2822 }
2823
createListForListStyle(const String sListStyleName)2824 SwList* SwDoc::createListForListStyle( const String sListStyleName )
2825 {
2826 if ( sListStyleName.Len() == 0 )
2827 {
2828 ASSERT( false,
2829 "<SwDoc::createListForListStyle(..)> - no list style name provided. Serious defect -> please inform OD." );
2830 return 0;
2831 }
2832
2833 if ( getListForListStyle( sListStyleName ) )
2834 {
2835 ASSERT( false,
2836 "<SwDoc::createListForListStyle(..)> - a list for the provided list style name already exists. Serious defect -> please inform OD." );
2837 return 0;
2838 }
2839
2840 SwNumRule* pNumRule = FindNumRulePtr( sListStyleName );
2841 if ( !pNumRule )
2842 {
2843 ASSERT( false,
2844 "<SwDoc::createListForListStyle(..)> - for provided list style name no list style is found. Serious defect -> please inform OD." );
2845 return 0;
2846 }
2847
2848 String sListId( pNumRule->GetDefaultListId() ); // can be empty String
2849 if ( getListByName( sListId ) )
2850 {
2851 sListId = String();
2852 }
2853 SwList* pNewList = createList( sListId, sListStyleName );
2854 maListStyleLists[sListStyleName] = pNewList;
2855 pNumRule->SetDefaultListId( pNewList->GetListId() );
2856
2857 return pNewList;
2858 }
2859
getListForListStyle(const String sListStyleName) const2860 SwList* SwDoc::getListForListStyle( const String sListStyleName ) const
2861 {
2862 SwList* pList = 0;
2863
2864 std::hash_map< String, SwList*, StringHash >::const_iterator
2865 aListIter = maListStyleLists.find( sListStyleName );
2866 if ( aListIter != maListStyleLists.end() )
2867 {
2868 pList = (*aListIter).second;
2869 }
2870
2871 return pList;
2872 }
2873
deleteListForListStyle(const String sListStyleName)2874 void SwDoc::deleteListForListStyle( const String sListStyleName )
2875 {
2876 String sListId;
2877 {
2878 SwList* pList = getListForListStyle( sListStyleName );
2879 ASSERT( pList,
2880 "<SwDoc::deleteListForListStyle(..)> - misusage of method: no list found for given list style name" );
2881 if ( pList )
2882 {
2883 sListId = pList->GetListId();
2884 }
2885 }
2886 if ( sListId.Len() > 0 )
2887 {
2888 maListStyleLists.erase( sListStyleName );
2889 deleteList( sListId );
2890 }
2891 }
2892 // <--
2893 // --> OD 2008-07-08 #i91400#
trackChangeOfListStyleName(const String sListStyleName,const String sNewListStyleName)2894 void SwDoc::trackChangeOfListStyleName( const String sListStyleName,
2895 const String sNewListStyleName )
2896 {
2897 SwList* pList = getListForListStyle( sListStyleName );
2898 ASSERT( pList,
2899 "<SwDoc::changeOfListStyleName(..)> - misusage of method: no list found for given list style name" );
2900
2901 if ( pList != 0 )
2902 {
2903 maListStyleLists.erase( sListStyleName );
2904 maListStyleLists[sNewListStyleName] = pList;
2905 }
2906 }
2907 // <--
2908
2909 // --> OD 2008-03-13 #refactorlists#
2910 namespace listfunc
2911 {
MakeListIdUnique(const SwDoc & rDoc,const String aSuggestedUniqueListId)2912 const String MakeListIdUnique( const SwDoc& rDoc,
2913 const String aSuggestedUniqueListId )
2914 {
2915 long nHitCount = 0;
2916 String aTmpStr = aSuggestedUniqueListId;
2917 while ( rDoc.getListByName( aTmpStr ) )
2918 {
2919 ++nHitCount;
2920 aTmpStr = aSuggestedUniqueListId;
2921 aTmpStr += String::CreateFromInt32( nHitCount );
2922 }
2923
2924 return aTmpStr;
2925 }
CreateUniqueListId(const SwDoc & rDoc)2926 const String CreateUniqueListId( const SwDoc& rDoc )
2927 {
2928 // --> OD 2008-08-06 #i92478#
2929 String aNewListId = String::CreateFromAscii( "list" );
2930 // <--
2931 // --> OD #o12311627#
2932 static rtlRandomPool s_RandomPool( rtl_random_createPool() );
2933 sal_Int64 n;
2934 rtl_random_getBytes( s_RandomPool, &n, sizeof(n) );
2935 aNewListId += String::CreateFromInt64( (n < 0 ? -n : n) );
2936 // <--
2937
2938 return MakeListIdUnique( rDoc, aNewListId );
2939 }
2940 }
2941 // <--
2942