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 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 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 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 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 ! 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 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 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 723 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 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 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 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 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 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! 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# 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 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 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 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 1389 ListStyleData() 1390 : pReplaceNumRule( 0 ), 1391 bCreateNewList( false ), 1392 sListId() 1393 {} 1394 }; 1395 } 1396 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 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 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 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 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 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 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 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> 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 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 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 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 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 2312 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 2325 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 2334 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# 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# 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 2423 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 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 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 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 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> 2547 bool SwDoc::lessThanNodeNum::operator()( const SwNodeNum* pNodeNumOne, 2548 const SwNodeNum* pNodeNumTwo ) const 2549 { 2550 return pNodeNumOne->LessThan( *pNodeNumTwo ); 2551 } 2552 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 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 2585 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 2595 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 2608 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> 2628 sal_Int32 SwDoc::getOutlineNodesCount() const 2629 { 2630 return GetNodes().GetOutLineNds().Count(); 2631 } 2632 2633 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 2640 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 2649 SwTxtNode* SwDoc::getOutlineNode( const sal_Int32 nIdx ) const 2650 { 2651 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->GetTxtNode(); 2652 } 2653 2654 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 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 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 2709 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 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 2759 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 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# 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 { 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 } 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