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( 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# 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 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 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 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! 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# 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 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 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 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 1467 ListStyleData() 1468 : pReplaceNumRule( 0 ), 1469 bCreateNewList( false ), 1470 sListId() 1471 {} 1472 }; 1473 } 1474 // <-- 1475 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 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 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 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 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 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 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 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> 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 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 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 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 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 2404 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 2420 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 2429 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# 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# 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 2518 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 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# 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 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# 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> 2647 bool SwDoc::lessThanNodeNum::operator()( const SwNodeNum* pNodeNumOne, 2648 const SwNodeNum* pNodeNumTwo ) const 2649 { 2650 return pNodeNumOne->LessThan( *pNodeNumTwo ); 2651 } 2652 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 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 2685 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 2695 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 2708 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> 2729 sal_Int32 SwDoc::getOutlineNodesCount() const 2730 { 2731 return GetNodes().GetOutLineNds().Count(); 2732 } 2733 2734 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 2741 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 2750 SwTxtNode* SwDoc::getOutlineNode( const sal_Int32 nIdx ) const 2751 { 2752 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->GetTxtNode(); 2753 } 2754 2755 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 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 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 2810 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 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 2860 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 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# 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 { 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 } 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