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