1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 #include <hintids.hxx> 32 #include <tools/date.hxx> 33 #include <tools/time.hxx> 34 #include <tools/resid.hxx> 35 #include <editeng/lrspitem.hxx> 36 #include <ftninfo.hxx> 37 #include <ftnidx.hxx> 38 #include <doc.hxx> 39 #include <IDocumentUndoRedo.hxx> 40 #include <pam.hxx> 41 #include <ndtxt.hxx> 42 #include <doctxm.hxx> // pTOXBaseRing 43 #include <poolfmt.hxx> 44 #include <UndoCore.hxx> 45 #include <UndoRedline.hxx> 46 #include <UndoNumbering.hxx> 47 #include <swundo.hxx> 48 #include <SwUndoFmt.hxx> 49 #include <rolbck.hxx> 50 #include <paratr.hxx> 51 #include <docary.hxx> 52 #include <mvsave.hxx> 53 #include <txtfrm.hxx> 54 #include <pamtyp.hxx> 55 #include <redline.hxx> 56 #include <comcore.hrc> 57 #include <editeng/adjitem.hxx> 58 #include <editeng/frmdiritem.hxx> 59 #include <frmatr.hxx> 60 #include <SwStyleNameMapper.hxx> 61 #include <SwNodeNum.hxx> 62 #include <list.hxx> 63 #include <listfunc.hxx> 64 #include <switerator.hxx> 65 66 #include <map> 67 68 inline sal_uInt8 GetUpperLvlChg( sal_uInt8 nCurLvl, sal_uInt8 nLevel, sal_uInt16 nMask ) 69 { 70 if( 1 < nLevel ) 71 { 72 if( nCurLvl + 1 >= nLevel ) 73 nCurLvl -= nLevel - 1; 74 else 75 nCurLvl = 0; 76 } 77 return static_cast<sal_uInt8>((nMask - 1) & ~(( 1 << nCurLvl ) - 1)); 78 } 79 80 void SwDoc::SetOutlineNumRule( const SwNumRule& rRule ) 81 { 82 if( pOutlineRule ) 83 (*pOutlineRule) = rRule; 84 else 85 { 86 pOutlineRule = new SwNumRule( rRule ); 87 88 AddNumRule(pOutlineRule); // #i36749# 89 } 90 91 pOutlineRule->SetRuleType( OUTLINE_RULE ); 92 // --> OD 2008-07-08 #i91400# 93 pOutlineRule->SetName( String::CreateFromAscii( 94 SwNumRule::GetOutlineRuleName() ), 95 *this); 96 // <-- 97 // --> OD 2006-09-21 #i69522# 98 // assure that the outline numbering rule is an automatic rule 99 pOutlineRule->SetAutoRule( sal_True ); 100 // <-- 101 102 // teste ob die evt. gesetzen CharFormate in diesem Document 103 // definiert sind 104 pOutlineRule->CheckCharFmts( this ); 105 106 // --> OD 2008-05-13 #refactorlists# 107 // notify text nodes, which are registered at the outline style, about the 108 // changed outline style 109 SwNumRule::tTxtNodeList aTxtNodeList; 110 pOutlineRule->GetTxtNodeList( aTxtNodeList ); 111 for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); 112 aIter != aTxtNodeList.end(); ++aIter ) 113 { 114 SwTxtNode* pTxtNd = *aIter; 115 pTxtNd->NumRuleChgd(); 116 // --> OD 2009-01-20 #i94152# 117 // assure that list level corresponds to outline level 118 if ( pTxtNd->GetTxtColl()->IsAssignedToListLevelOfOutlineStyle() && 119 pTxtNd->GetAttrListLevel() != pTxtNd->GetTxtColl()->GetAssignedOutlineStyleLevel() ) 120 { 121 pTxtNd->SetAttrListLevel( pTxtNd->GetTxtColl()->GetAssignedOutlineStyleLevel() ); 122 } 123 // <-- 124 } 125 // <-- 126 127 PropagateOutlineRule(); 128 pOutlineRule->SetInvalidRule(sal_True); 129 UpdateNumRule(); 130 131 // gibt es Fussnoten && gilt Kapitelweises Nummerieren, dann updaten 132 if( GetFtnIdxs().Count() && FTNNUM_CHAPTER == GetFtnInfo().eNum ) 133 GetFtnIdxs().UpdateAllFtn(); 134 135 UpdateExpFlds(NULL, true); 136 137 SetModified(); 138 } 139 140 void SwDoc::PropagateOutlineRule() 141 { 142 for (sal_uInt16 n = 0; n < pTxtFmtCollTbl->Count(); n++) 143 { 144 SwTxtFmtColl *pColl = (*pTxtFmtCollTbl)[n]; 145 146 // if (NO_NUMBERING != pColl->GetOutlineLevel())//#outline level,zhaojianwei 147 if(pColl->IsAssignedToListLevelOfOutlineStyle())//<-end,zhaojianwei 148 { 149 // --> OD 2006-11-20 #i71764# 150 // Check only the list style, which is set at the paragraph style 151 const SwNumRuleItem & rCollRuleItem = pColl->GetNumRule( sal_False ); 152 // <-- 153 154 // --> OD 2006-11-20 #i71764# 155 // Check on document setting OUTLINE_LEVEL_YIELDS_OUTLINE_RULE no longer needed. 156 if ( rCollRuleItem.GetValue().Len() == 0 ) 157 // <-- 158 { 159 SwNumRule * pMyOutlineRule = GetOutlineNumRule(); 160 161 if (pMyOutlineRule) 162 { 163 SwNumRuleItem aNumItem( pMyOutlineRule->GetName() ); 164 165 pColl->SetFmtAttr(aNumItem); 166 } 167 } 168 } 169 } 170 } 171 172 // Hoch-/Runterstufen 173 sal_Bool SwDoc::OutlineUpDown( const SwPaM& rPam, short nOffset ) 174 { 175 if( !GetNodes().GetOutLineNds().Count() || !nOffset ) 176 return sal_False; 177 178 // den Bereich feststellen 179 const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds(); 180 const SwNodePtr pSttNd = (SwNodePtr)&rPam.Start()->nNode.GetNode(); 181 const SwNodePtr pEndNd = (SwNodePtr)&rPam.End()->nNode.GetNode(); 182 sal_uInt16 nSttPos, nEndPos; 183 184 if( !rOutlNds.Seek_Entry( pSttNd, &nSttPos ) && 185 !nSttPos-- ) 186 // wir stehen in keiner "Outline-Section" 187 return sal_False; 188 189 if( rOutlNds.Seek_Entry( pEndNd, &nEndPos ) ) 190 ++nEndPos; 191 192 // jetzt haben wir unseren Bereich im OutlineNodes-Array 193 // dann prufe ersmal, ob nicht unterebenen aufgehoben werden 194 // (Stufung ueber die Grenzen) 195 sal_uInt16 n; 196 197 // so, dann koennen wir: 198 // 1. Vorlagen-Array anlegen 199 SwTxtFmtColl* aCollArr[ MAXLEVEL ]; 200 memset( aCollArr, 0, sizeof( SwTxtFmtColl* ) * MAXLEVEL ); 201 202 for( n = 0; n < pTxtFmtCollTbl->Count(); ++n ) 203 { 204 //sal_uInt8 nLevel = (*pTxtFmtCollTbl)[ n ]->GetOutlineLevel();//#outline level,zhaojianwei 205 //if( nLevel < MAXLEVEL ) 206 // aCollArr[ nLevel ] = (*pTxtFmtCollTbl)[ n ]; 207 if((*pTxtFmtCollTbl)[ n ]->IsAssignedToListLevelOfOutlineStyle()) 208 { 209 const int nLevel = (*pTxtFmtCollTbl)[ n ]->GetAssignedOutlineStyleLevel(); 210 aCollArr[ nLevel ] = (*pTxtFmtCollTbl)[ n ]; 211 }//<-end,zhaojianwei 212 } 213 214 /* --> #111107# */ 215 /* Find the last occupied level (backward). */ 216 for (n = MAXLEVEL - 1; n > 0; n--) 217 { 218 if (aCollArr[n] != 0) 219 break; 220 } 221 222 /* If an occupied level is found, choose next level (which IS 223 unoccupied) until a valid level is found. If no occupied level 224 was found n is 0 and aCollArr[0] is 0. In this case no demoting 225 is possible. */ 226 if (aCollArr[n] != 0) 227 { 228 while (n < MAXLEVEL - 1) 229 { 230 n++; 231 232 SwTxtFmtColl *aTmpColl = 233 GetTxtCollFromPool(static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + n)); 234 235 //if (aTmpColl->GetOutlineLevel() == n)//#outline level,zhaojianwei 236 if( aTmpColl->IsAssignedToListLevelOfOutlineStyle() && 237 aTmpColl->GetAssignedOutlineStyleLevel() == n )//<-end,zhaojianwei 238 { 239 aCollArr[n] = aTmpColl; 240 break; 241 } 242 } 243 } 244 245 /* Find the first occupied level (forward). */ 246 for (n = 0; n < MAXLEVEL - 1; n++) 247 { 248 if (aCollArr[n] != 0) 249 break; 250 } 251 252 /* If an occupied level is found, choose previous level (which IS 253 unoccupied) until a valid level is found. If no occupied level 254 was found n is MAXLEVEL - 1 and aCollArr[MAXLEVEL - 1] is 0. In 255 this case no demoting is possible. */ 256 if (aCollArr[n] != 0) 257 { 258 while (n > 0) 259 { 260 n--; 261 262 SwTxtFmtColl *aTmpColl = 263 GetTxtCollFromPool(static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + n)); 264 265 //if (aTmpColl->GetOutlineLevel() == n)//#outline level,zhaojianwei 266 if( aTmpColl->IsAssignedToListLevelOfOutlineStyle() && 267 aTmpColl->GetAssignedOutlineStyleLevel() == n )//<-end,zhaojianwei 268 { 269 aCollArr[n] = aTmpColl; 270 break; 271 } 272 } 273 } 274 /* <-- #111107# */ 275 276 /* --> #i13747# 277 278 Build a move table that states from which level an outline will 279 280 be moved to which other level. */ 281 282 /* the move table 283 284 aMoveArr[n] = m: replace aCollArr[n] with aCollArr[m] 285 */ 286 int aMoveArr[MAXLEVEL]; 287 int nStep; // step size for searching in aCollArr: -1 or 1 288 int nNum; // amount of steps for stepping in aCollArr 289 290 if (nOffset < 0) 291 { 292 nStep = -1; 293 nNum = -nOffset; 294 } 295 else 296 { 297 nStep = 1; 298 nNum = nOffset; 299 } 300 301 /* traverse aCollArr */ 302 for (n = 0; n < MAXLEVEL; n++) 303 { 304 /* If outline level n has an assigned paragraph style step 305 nNum steps forwards (nStep == 1) or backwards (nStep == 306 -1). One step is to go to the next non-null entry in 307 aCollArr in the selected direction. If nNum steps were 308 possible write the index of the entry found to aCollArr[n], 309 i.e. outline level n will be replaced by outline level 310 aCollArr[n]. 311 312 If outline level n has no assigned paragraph style 313 aMoveArr[n] is set to -1. 314 */ 315 if (aCollArr[n] != NULL) 316 { 317 sal_uInt16 m = n; 318 int nCount = nNum; 319 320 while (nCount > 0 && m + nStep >= 0 && m + nStep < MAXLEVEL) 321 { 322 m = static_cast<sal_uInt16>(m + nStep); 323 324 if (aCollArr[m] != NULL) 325 nCount--; 326 } 327 328 if (nCount == 0) 329 aMoveArr[n] = m; 330 else 331 aMoveArr[n] = -1; 332 333 } 334 else 335 aMoveArr[n] = -1; 336 } 337 338 /* If moving of the outline levels is applicable, i.e. for all 339 outline levels occuring in the document there has to be a valid 340 target outline level implied by aMoveArr. */ 341 bool bMoveApplicable = true; 342 for (n = nSttPos; n < nEndPos; n++) 343 { 344 SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode(); 345 SwTxtFmtColl* pColl = pTxtNd->GetTxtColl(); 346 // int nLevel = pColl->GetOutlineLevel();//#outline level,zhaojianwei 347 // if (aMoveArr[nLevel] == -1) 348 // bMoveApplicable = false; 349 if( pColl->IsAssignedToListLevelOfOutlineStyle() ) 350 { 351 const int nLevel = pColl->GetAssignedOutlineStyleLevel(); 352 if (aMoveArr[nLevel] == -1) 353 bMoveApplicable = false; 354 }//<-end,zhaojianwei 355 // --> OD 2008-12-16 #i70748# 356 // Check on outline level attribute of text node, if text node is 357 // not an outline via a to outline style assigned paragraph style. 358 else 359 { 360 const int nNewOutlineLevel = pTxtNd->GetAttrOutlineLevel() + nOffset; 361 if ( nNewOutlineLevel < 1 || nNewOutlineLevel > MAXLEVEL ) 362 { 363 bMoveApplicable = false; 364 } 365 } 366 // <-- 367 } 368 369 if (! bMoveApplicable ) 370 return sal_False; 371 372 /* <-- #i13747 # */ 373 if (GetIDocumentUndoRedo().DoesUndo()) 374 { 375 GetIDocumentUndoRedo().StartUndo(UNDO_OUTLINE_LR, NULL); 376 SwUndo *const pUndoOLR( new SwUndoOutlineLeftRight( rPam, nOffset ) ); 377 GetIDocumentUndoRedo().AppendUndo(pUndoOLR); 378 } 379 380 // 2. allen Nodes die neue Vorlage zuweisen 381 382 n = nSttPos; 383 while( n < nEndPos) 384 { 385 SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode(); 386 SwTxtFmtColl* pColl = pTxtNd->GetTxtColl(); 387 388 if( pColl->IsAssignedToListLevelOfOutlineStyle() ) 389 { 390 // ASSERT(pColl->GetOutlineLevel() < MAXLEVEL, //#outline level,removed by zhaojianwei 391 // "non outline node in outline nodes?"); 392 //int nLevel = pColl->GetOutlineLevel(); 393 const int nLevel = pColl->GetAssignedOutlineStyleLevel();//#outline level,add by zhaojianwei 394 395 ASSERT(aMoveArr[nLevel] >= 0, 396 "move table: current TxtColl not found when building table!"); 397 398 399 if (nLevel < MAXLEVEL && aMoveArr[nLevel] >= 0) 400 { 401 pColl = aCollArr[ aMoveArr[nLevel] ]; 402 403 if (pColl != NULL) 404 pColl = (SwTxtFmtColl*)pTxtNd->ChgFmtColl( pColl ); 405 } 406 407 } 408 else if( pTxtNd->GetAttrOutlineLevel() > 0) //#outline level,add by zhaojianwei 409 { 410 int nLevel = pTxtNd->GetAttrOutlineLevel() + nOffset; 411 if( 0 <= nLevel && nLevel <= MAXLEVEL) 412 pTxtNd->SetAttrOutlineLevel( nLevel ); 413 414 }//<-end,zhaojianwei 415 416 n++; 417 // Undo ??? 418 } 419 if (GetIDocumentUndoRedo().DoesUndo()) 420 { 421 GetIDocumentUndoRedo().EndUndo(UNDO_OUTLINE_LR, NULL); 422 } 423 424 ChkCondColls(); 425 SetModified(); 426 427 return sal_True; 428 } 429 430 431 432 // Hoch-/Runter - Verschieben ! 433 sal_Bool SwDoc::MoveOutlinePara( const SwPaM& rPam, short nOffset ) 434 { 435 // kein Verschiebung in den Sonderbereichen 436 const SwPosition& rStt = *rPam.Start(), 437 & rEnd = &rStt == rPam.GetPoint() ? *rPam.GetMark() 438 : *rPam.GetPoint(); 439 if( !GetNodes().GetOutLineNds().Count() || !nOffset || 440 (rStt.nNode.GetIndex() < GetNodes().GetEndOfExtras().GetIndex()) || 441 (rEnd.nNode.GetIndex() < GetNodes().GetEndOfExtras().GetIndex())) 442 { 443 return sal_False; 444 } 445 446 sal_uInt16 nAktPos = 0; 447 SwNodeIndex aSttRg( rStt.nNode ), aEndRg( rEnd.nNode ); 448 449 //sal_uInt8 nOutLineLevel = NO_NUMBERING; //#outline level,zhaojianwei 450 int nOutLineLevel = MAXLEVEL; //<-end,zhaojianwei 451 SwNode* pSrch = &aSttRg.GetNode(); 452 //if( pSrch->IsTxtNode() ) //#outline level,zhaojianwei 453 // nOutLineLevel = static_cast<sal_uInt8>(((SwTxtNode*)pSrch)->GetOutlineLevel()); 454 if( pSrch->IsTxtNode()) 455 nOutLineLevel = static_cast<sal_uInt8>(((SwTxtNode*)pSrch)->GetAttrOutlineLevel()-1);//<-end,zhaojianwei 456 SwNode* pEndSrch = &aEndRg.GetNode(); 457 if( !GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nAktPos ) ) 458 { 459 if( !nAktPos ) 460 return sal_False; // Promoting or demoting before the first outline => no. 461 if( --nAktPos ) 462 aSttRg = *GetNodes().GetOutLineNds()[ nAktPos ]; 463 else if( 0 > nOffset ) 464 return sal_False; // Promoting at the top of document?! 465 else 466 aSttRg = *GetNodes().GetEndOfContent().StartOfSectionNode(); 467 } 468 sal_uInt16 nTmpPos = 0; 469 // If the given range ends at an outlined text node we have to decide if it has to be a part of 470 // the moving range or not. Normally it will be a sub outline of our chapter 471 // and has to be moved, too. But if the chapter ends with a table(or a section end), 472 // the next text node will be choosen and this could be the next outline of the same level. 473 // The criteria has to be the outline level: sub level => incorporate, same/higher level => no. 474 if( GetNodes().GetOutLineNds().Seek_Entry( pEndSrch, &nTmpPos ) ) 475 { 476 if( !pEndSrch->IsTxtNode() || pEndSrch == pSrch || 477 //nOutLineLevel < ((SwTxtNode*)pEndSrch)->GetOutlineLevel() )//#outline level,zhaojianwei 478 nOutLineLevel < ((SwTxtNode*)pEndSrch)->GetAttrOutlineLevel()-1 )//<-end,zhaojianwei 479 ++nTmpPos; // For sub outlines only! 480 } 481 482 aEndRg = nTmpPos < GetNodes().GetOutLineNds().Count() 483 ? *GetNodes().GetOutLineNds()[ nTmpPos ] 484 : GetNodes().GetEndOfContent(); 485 if( nOffset >= 0 ) 486 nAktPos = nTmpPos; 487 if( aEndRg == aSttRg ) 488 { 489 ASSERT( false, "Moving outlines: Surprising selection" ); 490 aEndRg++; 491 } 492 493 const SwNode* pNd; 494 // The following code corrects the range to handle sections (start/end nodes) 495 // The range will be extended if the least node before the range is a start node 496 // which ends inside the range => The complete section will be moved. 497 // The range will be shrinked if the last position is a start node. 498 // The range will be shrinked if the last node is an end node which starts before the range. 499 aSttRg--; 500 while( aSttRg.GetNode().IsStartNode() ) 501 { 502 pNd = aSttRg.GetNode().EndOfSectionNode(); 503 if( pNd->GetIndex() >= aEndRg.GetIndex() ) 504 break; 505 aSttRg--; 506 } 507 aSttRg++; 508 509 aEndRg--; 510 while( aEndRg.GetNode().IsStartNode() ) 511 aEndRg--; 512 while( aEndRg.GetNode().IsEndNode() ) 513 { 514 pNd = aEndRg.GetNode().StartOfSectionNode(); 515 if( pNd->GetIndex() >= aSttRg.GetIndex() ) 516 break; 517 aEndRg--; 518 } 519 aEndRg++; 520 521 // calculation of the new position 522 if( nOffset < 0 && nAktPos < sal_uInt16(-nOffset) ) 523 pNd = GetNodes().GetEndOfContent().StartOfSectionNode(); 524 else if( nAktPos + nOffset >= GetNodes().GetOutLineNds().Count() ) 525 pNd = &GetNodes().GetEndOfContent(); 526 else 527 pNd = GetNodes().GetOutLineNds()[ nAktPos + nOffset ]; 528 529 sal_uLong nNewPos = pNd->GetIndex(); 530 531 // And now a correction of the insert position if necessary... 532 SwNodeIndex aInsertPos( *pNd, -1 ); 533 while( aInsertPos.GetNode().IsStartNode() ) 534 { 535 // Just before the insert position starts a section: 536 // when I'm moving forward I do not want to enter the section, 537 // when I'm moving backward I want to stay in the section if I'm already a part of, 538 // I want to stay outside if I was outside before. 539 if( nOffset < 0 ) 540 { 541 pNd = aInsertPos.GetNode().EndOfSectionNode(); 542 if( pNd->GetIndex() >= aEndRg.GetIndex() ) 543 break; 544 } 545 aInsertPos--; 546 --nNewPos; 547 } 548 if( nOffset >= 0 ) 549 { 550 // When just before the insert position a section ends, it is okay when I'm moving backward 551 // because I want to stay outside the section. 552 // When moving forward I've to check if I started inside or outside the section 553 // because I don't want to enter of leave such a section 554 while( aInsertPos.GetNode().IsEndNode() ) 555 { 556 pNd = aInsertPos.GetNode().StartOfSectionNode(); 557 if( pNd->GetIndex() >= aSttRg.GetIndex() ) 558 break; 559 aInsertPos--; 560 --nNewPos; 561 } 562 } 563 // We do not want to move into tables (at the moment) 564 aInsertPos++; 565 pNd = &aInsertPos.GetNode(); 566 if( pNd->IsTableNode() ) 567 pNd = pNd->StartOfSectionNode(); 568 if( pNd->FindTableNode() ) 569 return sal_False; 570 571 ASSERT( aSttRg.GetIndex() > nNewPos || nNewPos >= aEndRg.GetIndex(), 572 "Position liegt im MoveBereich" ); 573 574 // wurde ein Position in den Sonderbereichen errechnet, dann 575 // setze die Position auf den Dokumentanfang. 576 // Sollten da Bereiche oder Tabellen stehen, so werden sie nach 577 // hinten verschoben. 578 nNewPos = Max( nNewPos, GetNodes().GetEndOfExtras().GetIndex() + 2 ); 579 580 long nOffs = nNewPos - ( 0 < nOffset ? aEndRg.GetIndex() : aSttRg.GetIndex()); 581 SwPaM aPam( aSttRg, aEndRg, 0, -1 ); 582 return MoveParagraph( aPam, nOffs, sal_True ); 583 } 584 585 586 sal_uInt16 lcl_FindOutlineName( const SwNodes& rNds, const String& rName, 587 sal_Bool bExact ) 588 { 589 sal_uInt16 nSavePos = USHRT_MAX; 590 const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds(); 591 for( sal_uInt16 n = 0; n < rOutlNds.Count(); ++n ) 592 { 593 SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode(); 594 String sTxt( pTxtNd->GetExpandTxt() ); 595 if( sTxt.Equals( rName ) ) 596 { 597 // "exact" gefunden, setze Pos auf den Node 598 nSavePos = n; 599 break; 600 } 601 else if( !bExact && USHRT_MAX == nSavePos && 602 COMPARE_EQUAL == sTxt.CompareTo( rName, rName.Len()) ) 603 { 604 // dann vielleicht nur den den 1.Teil vom Text gefunden 605 nSavePos = n; 606 } 607 } 608 609 return nSavePos; 610 } 611 612 613 614 sal_uInt16 lcl_FindOutlineNum( const SwNodes& rNds, String& rName ) 615 { 616 // Gueltig Nummern sind (immer nur Offsets!!!): 617 // ([Nummer]+\.)+ (als regulaerer Ausdruck!) 618 // (Nummer gefolgt von Punkt, zum 5 Wiederholungen) 619 // also: "1.1.", "1.", "1.1.1." 620 xub_StrLen nPos = 0; 621 String sNum = rName.GetToken( 0, '.', nPos ); 622 if( STRING_NOTFOUND == nPos ) 623 return USHRT_MAX; // ungueltige Nummer!!! 624 625 sal_uInt16 nLevelVal[ MAXLEVEL ]; // Nummern aller Levels 626 memset( nLevelVal, 0, MAXLEVEL * sizeof( nLevelVal[0] )); 627 sal_uInt8 nLevel = 0; 628 String sName( rName ); 629 630 while( STRING_NOTFOUND != nPos ) 631 { 632 sal_uInt16 nVal = 0; 633 sal_Unicode c; 634 for( sal_uInt16 n = 0; n < sNum.Len(); ++n ) 635 if( '0' <= ( c = sNum.GetChar( n )) && c <= '9' ) 636 { 637 nVal *= 10; nVal += c - '0'; 638 } 639 else if( nLevel ) 640 break; // "fast" gueltige Nummer 641 else 642 return USHRT_MAX; // ungueltige Nummer!!! 643 644 if( MAXLEVEL > nLevel ) 645 nLevelVal[ nLevel++ ] = nVal; 646 647 sName.Erase( 0, nPos ); 648 nPos = 0; 649 sNum = sName.GetToken( 0, '.', nPos ); 650 // #i4533# without this check all parts delimited by a dot are treated as outline numbers 651 if(!ByteString(sNum, gsl_getSystemTextEncoding()).IsNumericAscii()) 652 nPos = STRING_NOTFOUND; 653 } 654 rName = sName; // das ist der nachfolgende Text. 655 656 // alle Levels gelesen, dann suche mal im Document nach dieser 657 // Gliederung: 658 const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds(); 659 // OS: ohne OutlineNodes lohnt die Suche nicht 660 // und man spart sich einen Absturz #42958# 661 if(!rOutlNds.Count()) 662 return USHRT_MAX; 663 SwTxtNode* pNd; 664 nPos = 0; 665 //search in the existing outline nodes for the required outline num array 666 for( ; nPos < rOutlNds.Count(); ++nPos ) 667 { 668 pNd = rOutlNds[ nPos ]->GetTxtNode(); 669 //sal_uInt8 nLvl = pNd->GetTxtColl()->GetOutlineLevel(); //#outline level,zhaojianwei 670 const int nLvl = pNd->GetAttrOutlineLevel()-1; //<-end,zhaojianwei 671 if( nLvl == nLevel - 1) 672 { 673 // check for the outline num 674 // --> OD 2005-11-02 #i51089 - TUNING# 675 // --> OD 2006-09-22 #i68289# 676 // Assure, that text node has the correct numbering level. Otherwise, 677 // its number vector will not fit to the searched level. 678 // if ( pNd->GetNum() ) 679 if ( pNd->GetNum() && 680 pNd->GetActualListLevel() == ( nLevel - 1 ) ) 681 // <-- 682 { 683 const SwNodeNum & rNdNum = *(pNd->GetNum()); 684 SwNumberTree::tNumberVector aLevelVal = rNdNum.GetNumberVector(); 685 //now compare with the one searched for 686 bool bEqual = true; 687 for( sal_uInt8 n = 0; (n < nLevel) && bEqual; ++n ) 688 { 689 bEqual = aLevelVal[n] == nLevelVal[n]; 690 } 691 if(bEqual) 692 { 693 break; 694 } 695 } 696 else 697 { 698 // --> OD 2006-01-12 #126588# 699 // A text node, which has an outline paragraph style applied and 700 // has as hard attribute 'no numbering' set, has an outline level, 701 // but no numbering tree node. Thus, consider this situation in 702 // the assertion condition. 703 ASSERT( !pNd->GetNumRule(), 704 "<lcl_FindOutlineNum(..)> - text node with outline level and numbering rule, but without numbering tree node. This is a serious defect -> inform OD" ); 705 } 706 } 707 } 708 if( nPos >= rOutlNds.Count() ) 709 nPos = USHRT_MAX; 710 return nPos; 711 } 712 713 // zu diesem Gliederungspunkt 714 715 716 // JP 13.06.96: 717 // im Namen kann eine Nummer oder/und der Text stehen. 718 // zuerst wird ueber die Nummer versucht den richtigen Eintrag zu finden. 719 // Gibt es diesen, dann wird ueber den Text verglichen, od es der 720 // gewuenschte ist. Ist das nicht der Fall, wird noch mal nur ueber den 721 // Text gesucht. Wird dieser gefunden ist es der Eintrag. Ansonsten der, 722 // der ueber die Nummer gefunden wurde. 723 // Ist keine Nummer angegeben, dann nur den Text suchen. 724 725 sal_Bool SwDoc::GotoOutline( SwPosition& rPos, const String& rName ) const 726 { 727 if( rName.Len() ) 728 { 729 const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds(); 730 731 // 1. Schritt: ueber die Nummer: 732 String sName( rName ); 733 sal_uInt16 nFndPos = ::lcl_FindOutlineNum( GetNodes(), sName ); 734 if( USHRT_MAX != nFndPos ) 735 { 736 SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode(); 737 String sExpandedText = pNd->GetExpandTxt(); 738 //#i4533# leading numbers followed by a dot have been remove while 739 //searching for the outline position 740 //to compensate this they must be removed from the paragraphs text content, too 741 sal_uInt16 nPos = 0; 742 String sTempNum; 743 while(sExpandedText.Len() && (sTempNum = sExpandedText.GetToken(0, '.', nPos)).Len() && 744 STRING_NOTFOUND != nPos && 745 ByteString(sTempNum, gsl_getSystemTextEncoding()).IsNumericAscii()) 746 { 747 sExpandedText.Erase(0, nPos); 748 nPos = 0; 749 } 750 751 if( !sExpandedText.Equals( sName ) ) 752 { 753 sal_uInt16 nTmp = ::lcl_FindOutlineName( GetNodes(), sName, sal_True ); 754 if( USHRT_MAX != nTmp ) // ueber den Namen gefunden 755 { 756 nFndPos = nTmp; 757 pNd = rOutlNds[ nFndPos ]->GetTxtNode(); 758 } 759 } 760 rPos.nNode = *pNd; 761 rPos.nContent.Assign( pNd, 0 ); 762 return sal_True; 763 } 764 765 nFndPos = ::lcl_FindOutlineName( GetNodes(), rName, sal_False ); 766 if( USHRT_MAX != nFndPos ) 767 { 768 SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode(); 769 rPos.nNode = *pNd; 770 rPos.nContent.Assign( pNd, 0 ); 771 return sal_True; 772 } 773 774 // --> OD 2006-09-22 #i68289# 775 // additional search on hyperlink URL without its outline numbering part 776 if ( !sName.Equals( rName ) ) 777 { 778 nFndPos = ::lcl_FindOutlineName( GetNodes(), sName, sal_False ); 779 if( USHRT_MAX != nFndPos ) 780 { 781 SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode(); 782 rPos.nNode = *pNd; 783 rPos.nContent.Assign( pNd, 0 ); 784 return sal_True; 785 } 786 } 787 // <-- 788 } 789 return sal_False; 790 } 791 792 /* */ 793 794 // --- Nummerierung ----------------------------------------- 795 796 // --> OD 2008-02-19 #refactorlists# 797 //void SwNumRuleInfo::MakeList( SwDoc& rDoc, sal_Bool ) 798 //{ 799 // SwNumRule* pRule = rDoc.FindNumRulePtr(rName); 800 801 // // no rule, no fun. 802 // if ( !pRule ) 803 // return; 804 805 // // 806 // // 1. Case: Information already available at pRule: 807 // // 808 // if (pRule->GetTxtNodeList()) 809 // { 810 // // copy list to own pList pointer: 811 // aList = *pRule->GetTxtNodeList(); 812 // return; 813 // } 814 815 // // 816 // // 2. Case: Information has to be generated from scratch: 817 // // 818 819 // if (pRule->IsOutlineRule()) 820 // { 821 // const SwOutlineNodes & rOutlineNodes = rDoc.GetNodes().GetOutLineNds(); 822 823 // for (sal_uInt16 i = 0; i < rOutlineNodes.Count(); ++i) 824 // { 825 // SwTxtNode & aNode = *((SwTxtNode *) rOutlineNodes[i]); 826 827 // if (pRule == aNode.GetNumRule()) 828 // AddNode(aNode); 829 // } 830 // } 831 // { 832 // SwModify* pMod; 833 // const SfxPoolItem* pItem; 834 // sal_uInt16 i, nMaxItems = rDoc.GetAttrPool().GetItemCount 835 // ( RES_PARATR_NUMRULE); 836 // for( i = 0; i < nMaxItems; ++i ) 837 // { 838 // pItem = rDoc.GetAttrPool().GetItem( RES_PARATR_NUMRULE, i ); 839 // if( 0 != pItem) 840 // { 841 // pMod = (SwModify*)((SwNumRuleItem*)pItem)->GetDefinedIn(); 842 // if (0 != pMod && 843 // ((SwNumRuleItem*)pItem)->GetValue().Len() && 844 // ((SwNumRuleItem*)pItem)->GetValue() == rName ) 845 // { 846 // if( pMod->IsA( TYPE( SwFmt )) ) 847 // pMod->GetInfo( *this ); 848 // else 849 // { 850 // SwTxtNode* pModTxtNode = (SwTxtNode*)pMod; 851 852 // // #115901# 853 // if( pModTxtNode->GetNodes().IsDocNodes()) 854 // { 855 // AddNode( *pModTxtNode ); 856 // } 857 // } 858 // } 859 // } 860 // } 861 // } 862 863 // // --> FME 2004-11-03 #i36571# The numrule and this info structure should 864 // // have different instances of the list: 865 // // --> OD 2006-09-12 #i69145# 866 // // method <SwNumRule::SetList(..)> copies content of list provided by the parameter 867 // pRule->SetTxtNodeList( aList ); 868 // // <-- 869 //} 870 // <-- 871 872 873 void lcl_ChgNumRule( SwDoc& rDoc, const SwNumRule& rRule ) 874 { 875 SwNumRule* pOld = rDoc.FindNumRulePtr( rRule.GetName() ); 876 ASSERT( pOld, "ohne die alte NumRule geht gar nichts" ); 877 878 sal_uInt16 nChgFmtLevel = 0, nMask = 1; 879 sal_uInt8 n; 880 881 for( n = 0; n < MAXLEVEL; ++n, nMask <<= 1 ) 882 { 883 const SwNumFmt& rOldFmt = pOld->Get( n ), 884 & rNewFmt = rRule.Get( n ); 885 886 if( rOldFmt != rNewFmt ) 887 { 888 nChgFmtLevel |= nMask; 889 } 890 else if( SVX_NUM_NUMBER_NONE > rNewFmt.GetNumberingType() && 1 < rNewFmt.GetIncludeUpperLevels() && 891 0 != (nChgFmtLevel & GetUpperLvlChg( n, rNewFmt.GetIncludeUpperLevels(),nMask )) ) 892 nChgFmtLevel |= nMask; 893 } 894 895 if( !nChgFmtLevel ) // es wurde nichts veraendert? 896 { 897 // --> OD 2006-04-27 #i64311# 898 const bool bInvalidateNumRule( pOld->IsContinusNum() != rRule.IsContinusNum() ); 899 // <-- 900 pOld->CheckCharFmts( &rDoc ); 901 pOld->SetContinusNum( rRule.IsContinusNum() ); 902 // --> OD 2008-06-17 #i87166# 903 // Do NOT change list style type 904 // pOld->SetRuleType( rRule.GetRuleType() ); 905 // <-- 906 // --> OD 2006-04-27 #i64311# 907 if ( bInvalidateNumRule ) 908 { 909 pOld->SetInvalidRule(sal_True); 910 } 911 // <-- 912 return ; 913 } 914 915 // --> OD 2008-02-19 #refactorlists# 916 // SwNumRuleInfo* pUpd = new SwNumRuleInfo( rRule.GetName() ); 917 // pUpd->MakeList( rDoc ); 918 919 // sal_uInt8 nLvl; 920 // for( sal_uLong nFirst = 0, nLast = pUpd->GetList().Count(); 921 // nFirst < nLast; ++nFirst ) 922 // { 923 // SwTxtNode* pTxtNd = pUpd->GetList().GetObject( nFirst ); 924 // nLvl = static_cast<sal_uInt8>(pTxtNd->GetLevel()); 925 926 // if( nLvl < MAXLEVEL ) 927 // { 928 // if( nChgFmtLevel & ( 1 << nLvl )) 929 // { 930 // pTxtNd->NumRuleChgd(); 931 // } 932 // } 933 // } 934 SwNumRule::tTxtNodeList aTxtNodeList; 935 pOld->GetTxtNodeList( aTxtNodeList ); 936 sal_uInt8 nLvl( 0 ); 937 for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); 938 aIter != aTxtNodeList.end(); ++aIter ) 939 { 940 SwTxtNode* pTxtNd = *aIter; 941 nLvl = static_cast<sal_uInt8>(pTxtNd->GetActualListLevel()); 942 943 if( nLvl < MAXLEVEL ) 944 { 945 if( nChgFmtLevel & ( 1 << nLvl )) 946 { 947 pTxtNd->NumRuleChgd(); 948 } 949 } 950 } 951 // <-- 952 953 for( n = 0; n < MAXLEVEL; ++n ) 954 if( nChgFmtLevel & ( 1 << n )) 955 pOld->Set( n, rRule.GetNumFmt( n )); 956 957 pOld->CheckCharFmts( &rDoc ); 958 pOld->SetInvalidRule(sal_True); 959 pOld->SetContinusNum( rRule.IsContinusNum() ); 960 // --> OD 2008-06-17 #i87166# 961 // Do NOT change list style type 962 // pOld->SetRuleType( rRule.GetRuleType() ); 963 // <-- 964 965 // --> OD 2008-02-19 #refactorlists# 966 // delete pUpd; 967 // <-- 968 969 rDoc.UpdateNumRule(); 970 } 971 972 // OD 2008-02-08 #newlistlevelattrs# - add handling of parameter <bResetIndentAttrs> 973 // --> OD 2008-03-17 #refactorlists# 974 void SwDoc::SetNumRule( const SwPaM& rPam, 975 const SwNumRule& rRule, 976 const bool bCreateNewList, 977 const String sContinuedListId, 978 sal_Bool bSetItem, 979 const bool bResetIndentAttrs ) 980 { 981 SwUndoInsNum * pUndo = NULL; 982 if (GetIDocumentUndoRedo().DoesUndo()) 983 { 984 // Start/End for attributes! 985 GetIDocumentUndoRedo().StartUndo( UNDO_INSNUM, NULL ); 986 pUndo = new SwUndoInsNum( rPam, rRule ); 987 GetIDocumentUndoRedo().AppendUndo(pUndo); 988 } 989 990 SwNumRule * pNew = FindNumRulePtr( rRule.GetName() ); 991 bool bUpdateRule = false; 992 993 if( !pNew ) 994 { 995 pNew = (*pNumRuleTbl)[ MakeNumRule( rRule.GetName(), &rRule ) ]; 996 } 997 else if (rRule != *pNew) 998 { 999 bUpdateRule = true; 1000 } 1001 1002 if (bUpdateRule) 1003 { 1004 if( pUndo ) 1005 { 1006 pUndo->SaveOldNumRule( *pNew ); 1007 ::lcl_ChgNumRule( *this, rRule ); 1008 pUndo->SetLRSpaceEndPos(); 1009 } 1010 else 1011 { 1012 ::lcl_ChgNumRule( *this, rRule ); 1013 } 1014 } 1015 1016 // --> OD 2008-03-17 #refactorlists# 1017 if ( bSetItem ) 1018 { 1019 if ( bCreateNewList ) 1020 { 1021 String sListId; 1022 if ( !bUpdateRule ) 1023 { 1024 // apply list id of list, which has been created for the new list style 1025 sListId = pNew->GetDefaultListId(); 1026 } 1027 else 1028 { 1029 // create new list and apply its list id 1030 SwList* pNewList = createList( String(), pNew->GetName() ); 1031 ASSERT( pNewList, 1032 "<SwDoc::SetNumRule(..)> - could not create new list. Serious defect -> please inform OD." ); 1033 sListId = pNewList->GetListId(); 1034 } 1035 InsertPoolItem( rPam, 1036 SfxStringItem( RES_PARATR_LIST_ID, sListId ), 0 ); 1037 } 1038 else if ( sContinuedListId.Len() > 0 ) 1039 { 1040 // apply given list id 1041 InsertPoolItem( rPam, 1042 SfxStringItem( RES_PARATR_LIST_ID, sContinuedListId ), 0 ); 1043 } 1044 } 1045 // <-- 1046 1047 if ( ! rPam.HasMark()) 1048 { 1049 SwTxtNode * pTxtNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode(); 1050 // --> OD 2006-10-19 #134160# 1051 // consider case that the PaM doesn't denote a text node - e.g. it denotes a graphic node 1052 if ( pTxtNd ) 1053 { 1054 SwNumRule * pRule = pTxtNd->GetNumRule(); 1055 1056 if (pRule && pRule->GetName() == pNew->GetName()) 1057 { 1058 bSetItem = sal_False; 1059 // --> OD 2008-06-02 #refactorlists# 1060 if ( !pTxtNd->IsInList() ) 1061 { 1062 pTxtNd->AddToList(); 1063 } 1064 // <-- 1065 } 1066 // --> OD 2005-10-26 #b6340308# - only clear numbering attribute at 1067 // text node, if at paragraph style the new numbering rule is found. 1068 else if ( !pRule ) 1069 { 1070 SwTxtFmtColl* pColl = pTxtNd->GetTxtColl(); 1071 if ( pColl ) 1072 { 1073 SwNumRule* pCollRule = FindNumRulePtr(pColl->GetNumRule().GetValue()); 1074 if ( pCollRule && pCollRule->GetName() == pNew->GetName() ) 1075 { 1076 pTxtNd->ResetAttr( RES_PARATR_NUMRULE ); 1077 bSetItem = sal_False; 1078 } 1079 } 1080 } 1081 // <-- 1082 } 1083 // <-- 1084 } 1085 1086 // --> OD 2009-08-18 #i103817# 1087 if ( bSetItem ) 1088 // <-- 1089 { 1090 InsertPoolItem( rPam, SwNumRuleItem( pNew->GetName() ), 0 ); 1091 } 1092 1093 // --> OD 2008-02-08 #newlistlevelattrs# 1094 if ( bResetIndentAttrs && 1095 pNew && pNew->Get( 0 ).GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) 1096 { 1097 SvUShortsSort aResetAttrsArray; 1098 aResetAttrsArray.Insert( RES_LR_SPACE ); 1099 // --> OD 2010-10-05 #i114929# 1100 // On a selection setup a corresponding Point-and-Mark in order to get 1101 // the indentation attribute reset on all paragraphs touched by the selection 1102 if ( rPam.HasMark() && 1103 rPam.End()->nNode.GetNode().GetTxtNode() ) 1104 { 1105 SwPaM aPam( rPam.Start()->nNode, 1106 rPam.End()->nNode ); 1107 aPam.Start()->nContent = 0; 1108 aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTxtNode()->Len(); 1109 ResetAttrs( aPam, sal_False, &aResetAttrsArray ); 1110 } 1111 else 1112 { 1113 ResetAttrs( rPam, sal_False, &aResetAttrsArray ); 1114 } 1115 // <-- 1116 } 1117 // <-- 1118 1119 if (GetIDocumentUndoRedo().DoesUndo()) 1120 { 1121 GetIDocumentUndoRedo().EndUndo( UNDO_INSNUM, NULL ); 1122 } 1123 1124 SetModified(); 1125 } 1126 1127 void SwDoc::SetCounted(const SwPaM & rPam, bool bCounted) 1128 { 1129 if ( bCounted ) 1130 { 1131 SvUShortsSort aResetAttrsArray; 1132 aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED ); 1133 // --> OD 2010-10-05 #i114929# 1134 // On a selection setup a corresponding Point-and-Mark in order to get 1135 // the list-is-counted attribute reset on all paragraphs touched by the selection 1136 if ( rPam.HasMark() && 1137 rPam.End()->nNode.GetNode().GetTxtNode() ) 1138 { 1139 SwPaM aPam( rPam.Start()->nNode, 1140 rPam.End()->nNode ); 1141 aPam.Start()->nContent = 0; 1142 aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTxtNode()->Len(); 1143 ResetAttrs( aPam, sal_False, &aResetAttrsArray ); 1144 } 1145 else 1146 { 1147 ResetAttrs( rPam, sal_False, &aResetAttrsArray ); 1148 } 1149 // <-- 1150 } 1151 else 1152 { 1153 InsertPoolItem( rPam, 1154 SfxBoolItem( RES_PARATR_LIST_ISCOUNTED, sal_False ), 0 ); 1155 } 1156 } 1157 1158 void SwDoc::SetNumRuleStart( const SwPosition& rPos, sal_Bool bFlag ) 1159 { 1160 SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); 1161 1162 if (pTxtNd) 1163 { 1164 const SwNumRule* pRule = pTxtNd->GetNumRule(); 1165 if( pRule && !bFlag != !pTxtNd->IsListRestart()) 1166 { 1167 if (GetIDocumentUndoRedo().DoesUndo()) 1168 { 1169 SwUndo *const pUndo( new SwUndoNumRuleStart(rPos, bFlag) ); 1170 GetIDocumentUndoRedo().AppendUndo(pUndo); 1171 } 1172 1173 pTxtNd->SetListRestart(bFlag ? true : false); 1174 1175 SetModified(); 1176 } 1177 } 1178 } 1179 1180 void SwDoc::SetNodeNumStart( const SwPosition& rPos, sal_uInt16 nStt ) 1181 { 1182 SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); 1183 1184 if (pTxtNd) 1185 { 1186 // --> OD 2008-02-27 #refactorlists# 1187 // const SwNumRule* pRule = pTxtNd->GetNumRule(); 1188 // if( pRule && nStt != pTxtNd->GetListRestartValue() ) 1189 // { 1190 // if( DoesUndo() ) 1191 // { 1192 // ClearRedo(); 1193 // AppendUndo( new SwUndoNumRuleStart( rPos, nStt )); 1194 // } 1195 // } 1196 // pTxtNd->SetListRestartValue(nStt); 1197 1198 // SetModified(); 1199 if ( !pTxtNd->HasAttrListRestartValue() || 1200 pTxtNd->GetAttrListRestartValue() != nStt ) 1201 { 1202 if (GetIDocumentUndoRedo().DoesUndo()) 1203 { 1204 SwUndo *const pUndo( new SwUndoNumRuleStart(rPos, nStt) ); 1205 GetIDocumentUndoRedo().AppendUndo(pUndo); 1206 } 1207 pTxtNd->SetAttrListRestartValue( nStt ); 1208 1209 SetModified(); 1210 } 1211 // <-- 1212 } 1213 } 1214 1215 // loeschen geht nur, wenn die Rule niemand benutzt! 1216 sal_Bool SwDoc::DelNumRule( const String& rName, sal_Bool bBroadcast ) 1217 { 1218 sal_uInt16 nPos = FindNumRule( rName ); 1219 1220 // --> OD 2007-12-17 #151213# 1221 if ( (*pNumRuleTbl)[ nPos ] == GetOutlineNumRule() ) 1222 { 1223 ASSERT( false, 1224 "<SwDoc::DelNumRule(..)> - No deletion of outline list style. This is serious defect - please inform OD" ); 1225 return sal_False; 1226 } 1227 // <-- 1228 1229 if( USHRT_MAX != nPos && !IsUsed( *(*pNumRuleTbl)[ nPos ] )) 1230 { 1231 if (GetIDocumentUndoRedo().DoesUndo()) 1232 { 1233 SwUndo * pUndo = 1234 new SwUndoNumruleDelete(*(*pNumRuleTbl)[nPos], this); 1235 GetIDocumentUndoRedo().AppendUndo(pUndo); 1236 } 1237 1238 if (bBroadcast) 1239 BroadcastStyleOperation(rName, SFX_STYLE_FAMILY_PSEUDO, 1240 SFX_STYLESHEET_ERASED); 1241 1242 // --> OD 2008-04-02 #refactorlists# 1243 deleteListForListStyle( rName ); 1244 { 1245 // delete further list, which have the deleted list style as default list style 1246 std::vector< SwList* > aListsForDeletion; 1247 tHashMapForLists::iterator aListIter = maLists.begin(); 1248 while ( aListIter != maLists.end() ) 1249 { 1250 SwList* pList = (*aListIter).second; 1251 if ( pList->GetDefaultListStyleName() == rName ) 1252 { 1253 aListsForDeletion.push_back( pList ); 1254 } 1255 1256 ++aListIter; 1257 } 1258 while ( aListsForDeletion.size() > 0 ) 1259 { 1260 SwList* pList = aListsForDeletion.back(); 1261 aListsForDeletion.pop_back(); 1262 deleteList( pList->GetListId() ); 1263 } 1264 } 1265 // <-- 1266 // --> FME 2004-11-02 #i34097# DeleteAndDestroy deletes rName if 1267 // rName is directly taken from the numrule. 1268 const String aTmpName( rName ); 1269 // <-- 1270 pNumRuleTbl->DeleteAndDestroy( nPos ); 1271 maNumRuleMap.erase(aTmpName); 1272 1273 SetModified(); 1274 return sal_True; 1275 } 1276 return sal_False; 1277 } 1278 1279 // #106897# 1280 void SwDoc::ChgNumRuleFmts( const SwNumRule& rRule, const String * pName ) 1281 { 1282 // #106897# 1283 SwNumRule* pRule = FindNumRulePtr( pName ? *pName : rRule.GetName() ); 1284 if( pRule ) 1285 { 1286 SwUndoInsNum* pUndo = 0; 1287 if (GetIDocumentUndoRedo().DoesUndo()) 1288 { 1289 pUndo = new SwUndoInsNum( *pRule, rRule ); 1290 pUndo->GetHistory(); 1291 GetIDocumentUndoRedo().AppendUndo( pUndo ); 1292 } 1293 ::lcl_ChgNumRule( *this, rRule ); 1294 1295 if( pUndo ) 1296 pUndo->SetLRSpaceEndPos(); 1297 1298 SetModified(); 1299 } 1300 } 1301 1302 sal_Bool SwDoc::RenameNumRule(const String & rOldName, const String & rNewName, 1303 sal_Bool bBroadcast) 1304 { 1305 sal_Bool bResult = sal_False; 1306 SwNumRule * pNumRule = FindNumRulePtr(rOldName); 1307 1308 if (pNumRule) 1309 { 1310 if (GetIDocumentUndoRedo().DoesUndo()) 1311 { 1312 SwUndo * pUndo = new SwUndoNumruleRename(rOldName, rNewName, this); 1313 GetIDocumentUndoRedo().AppendUndo(pUndo); 1314 } 1315 1316 // --> OD 2008-02-19 #refactorlists# 1317 // SwNumRuleInfo aInfo(rOldName); 1318 // aInfo.MakeList(*this); 1319 SwNumRule::tTxtNodeList aTxtNodeList; 1320 pNumRule->GetTxtNodeList( aTxtNodeList ); 1321 // <-- 1322 1323 // --> OD 2008-07-08 #i91400# 1324 pNumRule->SetName( rNewName, *this ); 1325 // <-- 1326 1327 SwNumRuleItem aItem(rNewName); 1328 // --> OD 2008-02-19 #refactorlists# 1329 // for (sal_uLong nI = 0; nI < aInfo.GetList().Count(); ++nI) 1330 // { 1331 // SwTxtNode * pTxtNd = aInfo.GetList().GetObject(nI); 1332 // pTxtNd->SwCntntNode::SetAttr(aItem); 1333 // } 1334 for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); 1335 aIter != aTxtNodeList.end(); ++aIter ) 1336 { 1337 SwTxtNode * pTxtNd = *aIter; 1338 pTxtNd->SetAttr(aItem); 1339 } 1340 // <-- 1341 1342 bResult = sal_True; 1343 1344 if (bBroadcast) 1345 BroadcastStyleOperation(rOldName, SFX_STYLE_FAMILY_PSEUDO, 1346 SFX_STYLESHEET_MODIFIED); 1347 } 1348 1349 return bResult; 1350 } 1351 1352 void SwDoc::StopNumRuleAnimations( OutputDevice* pOut ) 1353 { 1354 for( sal_uInt16 n = GetNumRuleTbl().Count(); n; ) 1355 { 1356 SwNumRule::tTxtNodeList aTxtNodeList; 1357 GetNumRuleTbl()[ --n ]->GetTxtNodeList( aTxtNodeList ); 1358 for ( SwNumRule::tTxtNodeList::iterator aTxtNodeIter = aTxtNodeList.begin(); 1359 aTxtNodeIter != aTxtNodeList.end(); ++aTxtNodeIter ) 1360 { 1361 SwTxtNode* pTNd = *aTxtNodeIter; 1362 SwIterator<SwTxtFrm,SwTxtNode> aIter(*pTNd); 1363 for(SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) 1364 if( pFrm->HasAnimation() ) 1365 pFrm->StopAnimation( pOut ); 1366 } 1367 } 1368 } 1369 1370 sal_Bool SwDoc::ReplaceNumRule( const SwPosition& rPos, 1371 const String& rOldRule, const String& rNewRule ) 1372 { 1373 sal_Bool bRet = sal_False; 1374 SwNumRule *pOldRule = FindNumRulePtr( rOldRule ), 1375 *pNewRule = FindNumRulePtr( rNewRule ); 1376 if( pOldRule && pNewRule && pOldRule != pNewRule ) 1377 { 1378 // --> OD 2008-02-19 #refactorlists# 1379 SwUndoInsNum* pUndo = 0; 1380 if (GetIDocumentUndoRedo().DoesUndo()) 1381 { 1382 // Start/End for attributes! 1383 GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL ); 1384 pUndo = new SwUndoInsNum( rPos, *pNewRule, rOldRule ); 1385 GetIDocumentUndoRedo().AppendUndo(pUndo); 1386 } 1387 1388 // --> OD 2008-02-19 #refactorlists# 1389 // apply new list style <pNewRule> to all text nodes, which have the 1390 // old list style <pOldNRule> applied and belong to the same list as 1391 // the text node of the given <SwPosition>. 1392 // SwNumRuleInfo aUpd( rOldRule ); 1393 // aUpd.MakeList( *this ); 1394 1395 // if (aUpd.GetList().Count() > 0) // #106897# 1396 SwNumRule::tTxtNodeList aTxtNodeList; 1397 pOldRule->GetTxtNodeList( aTxtNodeList ); 1398 if ( aTxtNodeList.size() > 0 ) 1399 { 1400 // // Position suchen und bestimme ob ein Node davor oder dahinter 1401 // // einen Start erzwingt 1402 // SwTxtNode* pTxtNd; 1403 // sal_uLong nFndPos, nFirst, nLast; 1404 1405 // if( TABLE_ENTRY_NOTFOUND != aUpd.GetList().SearchKey( 1406 // rPos.nNode.GetIndex(), &nFndPos )) 1407 // ++nFndPos; 1408 1409 // for( nLast = nFndPos; nLast < aUpd.GetList().Count(); ++nLast ) 1410 // { 1411 // pTxtNd = aUpd.GetList().GetObject( nLast ); 1412 // if(pTxtNd->IsRestart()) 1413 // break; 1414 // } 1415 // for( nFirst = nFndPos; nFirst; ) 1416 // { 1417 // pTxtNd = aUpd.GetList().GetObject( --nFirst ); 1418 // if( pTxtNd->IsRestart() ) 1419 // break; 1420 // } 1421 // // dann neue Numerierung ueber diesen Bereich 1422 // // definieren und den Start am Anfang/Ende zurueck setzen 1423 // pTxtNd = aUpd.GetList().GetObject( nFirst ); 1424 // if( pTxtNd->IsRestart() ) 1425 // { 1426 // pTxtNd->SetRestart(false); 1427 // if( pUndo ) 1428 // pUndo->SetSttNum( pTxtNd->GetIndex() ); 1429 // } 1430 1431 SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 ); 1432 sal_uInt16 nChgFmtLevel = 0; 1433 for( sal_uInt8 n = 0; n < MAXLEVEL; ++n ) 1434 { 1435 const SwNumFmt& rOldFmt = pOldRule->Get( n ), 1436 & rNewFmt = pNewRule->Get( n ); 1437 1438 if( rOldFmt.GetAbsLSpace() != rNewFmt.GetAbsLSpace() || 1439 rOldFmt.GetFirstLineOffset() != rNewFmt.GetFirstLineOffset() ) 1440 nChgFmtLevel |= ( 1 << n ); 1441 } 1442 1443 const SwTxtNode* pGivenTxtNode = rPos.nNode.GetNode().GetTxtNode(); 1444 SwNumRuleItem aRule( rNewRule ); 1445 // for( ; nFirst < nLast; ++nFirst ) 1446 // { 1447 // pTxtNd = aUpd.GetList().GetObject( nFirst ); 1448 1449 // aRegH.RegisterInModify( pTxtNd, *pTxtNd ); 1450 1451 // pTxtNd->SwCntntNode::SetAttr( aRule ); 1452 // pTxtNd->NumRuleChgd(); 1453 // } 1454 for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); 1455 aIter != aTxtNodeList.end(); ++aIter ) 1456 { 1457 SwTxtNode* pTxtNd = *aIter; 1458 1459 if ( pGivenTxtNode && 1460 pGivenTxtNode->GetListId() == pTxtNd->GetListId() ) 1461 { 1462 aRegH.RegisterInModify( pTxtNd, *pTxtNd ); 1463 1464 pTxtNd->SetAttr( aRule ); 1465 pTxtNd->NumRuleChgd(); 1466 } 1467 } 1468 GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); 1469 SetModified(); 1470 1471 bRet = sal_True; // #106897# 1472 } 1473 } 1474 1475 return bRet; 1476 } 1477 1478 // --> OD 2008-03-18 #refactorlists# 1479 namespace 1480 { 1481 struct ListStyleData 1482 { 1483 SwNumRule* pReplaceNumRule; 1484 bool bCreateNewList; 1485 String sListId; 1486 1487 ListStyleData() 1488 : pReplaceNumRule( 0 ), 1489 bCreateNewList( false ), 1490 sListId() 1491 {} 1492 }; 1493 } 1494 // <-- 1495 1496 void SwDoc::MakeUniqueNumRules(const SwPaM & rPaM) 1497 { 1498 ASSERT( rPaM.GetDoc() == this, "need same doc" ); 1499 1500 // --> OD 2008-03-18 #refactorlists# 1501 // map<SwNumRule *, SwNumRule *> aMyNumRuleMap; 1502 ::std::map<SwNumRule *, ListStyleData> aMyNumRuleMap; 1503 // <-- 1504 1505 sal_uLong nStt = rPaM.Start()->nNode.GetIndex(); 1506 sal_uLong nEnd = rPaM.End()->nNode.GetIndex(); 1507 1508 bool bFirst = true; 1509 1510 for (sal_uLong n = nStt; n <= nEnd; n++) 1511 { 1512 SwTxtNode * pCNd = GetNodes()[n]->GetTxtNode(); 1513 1514 if (pCNd) 1515 { 1516 SwNumRule * pRule = pCNd->GetNumRule(); 1517 1518 if (pRule && pRule->IsAutoRule() && ! pRule->IsOutlineRule()) 1519 { 1520 // --> OD 2008-03-18 #refactorlists# 1521 // SwNumRule * pReplaceNumRule = aMyNumRuleMap[pRule]; 1522 ListStyleData aListStyleData = aMyNumRuleMap[pRule]; 1523 1524 // if (! pReplaceNumRule) 1525 if ( aListStyleData.pReplaceNumRule == 0 ) 1526 { 1527 if (bFirst) 1528 { 1529 SwPosition aPos(*pCNd); 1530 aListStyleData.pReplaceNumRule = 1531 const_cast<SwNumRule *> 1532 (SearchNumRule( aPos, false, pCNd->HasNumber(), 1533 false, 0, 1534 aListStyleData.sListId, true )); 1535 } 1536 1537 // if (! pReplaceNumRule) 1538 if ( aListStyleData.pReplaceNumRule == 0 ) 1539 { 1540 // pReplaceNumRule = new SwNumRule(*pRule); 1541 // pReplaceNumRule->SetName(GetUniqueNumRuleName()); 1542 aListStyleData.pReplaceNumRule = new SwNumRule(*pRule); 1543 // --> OD 2008-07-08 #i91400# 1544 aListStyleData.pReplaceNumRule->SetName( 1545 GetUniqueNumRuleName(), *this ); 1546 // <-- 1547 aListStyleData.bCreateNewList = true; 1548 } 1549 1550 // aMyNumRuleMap[pRule] = pReplaceNumRule; 1551 aMyNumRuleMap[pRule] = aListStyleData; 1552 } 1553 1554 SwPaM aPam(*pCNd); 1555 1556 SetNumRule( aPam, *aListStyleData.pReplaceNumRule, 1557 aListStyleData.bCreateNewList, 1558 aListStyleData.sListId ); 1559 if ( aListStyleData.bCreateNewList ) 1560 { 1561 aListStyleData.bCreateNewList = false; 1562 aListStyleData.sListId = pCNd->GetListId(); 1563 aMyNumRuleMap[pRule] = aListStyleData; 1564 } 1565 // <-- 1566 1567 bFirst = false; 1568 } 1569 } 1570 } 1571 } 1572 1573 sal_Bool SwDoc::NoNum( const SwPaM& rPam ) 1574 { 1575 1576 sal_Bool bRet = SplitNode( *rPam.GetPoint(), false ); 1577 // ist ueberhaupt Nummerierung im Spiel ? 1578 if( bRet ) 1579 { 1580 // NoNum setzen und Upaten 1581 const SwNodeIndex& rIdx = rPam.GetPoint()->nNode; 1582 SwTxtNode* pNd = rIdx.GetNode().GetTxtNode(); 1583 const SwNumRule* pRule = pNd->GetNumRule(); 1584 if( pRule ) 1585 { 1586 pNd->SetCountedInList(false); 1587 1588 SetModified(); 1589 } 1590 else 1591 bRet = sal_False; // keine Nummerierung , ?? oder immer sal_True ?? 1592 } 1593 return bRet; 1594 } 1595 1596 void SwDoc::DelNumRules( const SwPaM& rPam ) 1597 { 1598 sal_uLong nStt = rPam.GetPoint()->nNode.GetIndex(), 1599 nEnd = rPam.GetMark()->nNode.GetIndex(); 1600 if( nStt > nEnd ) 1601 { 1602 sal_uLong nTmp = nStt; nStt = nEnd; nEnd = nTmp; 1603 } 1604 1605 SwUndoDelNum* pUndo; 1606 if (GetIDocumentUndoRedo().DoesUndo()) 1607 { 1608 pUndo = new SwUndoDelNum( rPam ); 1609 GetIDocumentUndoRedo().AppendUndo(pUndo); 1610 } 1611 else 1612 pUndo = 0; 1613 1614 SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 ); 1615 1616 SwNumRuleItem aEmptyRule( aEmptyStr ); 1617 const SwNode* pOutlNd = 0; 1618 for( ; nStt <= nEnd; ++nStt ) 1619 { 1620 SwTxtNode* pTNd = GetNodes()[ nStt ]->GetTxtNode(); 1621 // --> OD 2008-03-13 #refactorlists# 1622 // if( pTNd && 0 != ( pItem = pTNd->GetNoCondAttr( 1623 // RES_PARATR_NUMRULE, sal_True ) ) && 1624 // ( pName = &((SwNumRuleItem*)pItem)->GetValue())->Len() ) 1625 SwNumRule* pNumRuleOfTxtNode = pTNd ? pTNd->GetNumRule() : 0; 1626 if ( pTNd && pNumRuleOfTxtNode ) 1627 // <-- 1628 { 1629 // recognize changes of attribute for undo 1630 aRegH.RegisterInModify( pTNd, *pTNd ); 1631 1632 if( pUndo ) 1633 pUndo->AddNode( *pTNd, sal_False ); 1634 1635 // directly set list style attribute is reset, otherwise empty 1636 // list style is applied 1637 const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet(); 1638 if ( pAttrSet && 1639 pAttrSet->GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET ) 1640 pTNd->ResetAttr( RES_PARATR_NUMRULE ); 1641 else 1642 pTNd->SetAttr( aEmptyRule ); 1643 1644 // --> OD 2008-03-26 #refactorlists# 1645 pTNd->ResetAttr( RES_PARATR_LIST_ID ); 1646 pTNd->ResetAttr( RES_PARATR_LIST_LEVEL ); 1647 pTNd->ResetAttr( RES_PARATR_LIST_ISRESTART ); 1648 pTNd->ResetAttr( RES_PARATR_LIST_RESTARTVALUE ); 1649 pTNd->ResetAttr( RES_PARATR_LIST_ISCOUNTED ); 1650 // <-- 1651 1652 if( RES_CONDTXTFMTCOLL == pTNd->GetFmtColl()->Which() ) 1653 pTNd->ChkCondColl(); 1654 //else if( !pOutlNd && NO_NUMBERING != //#outline level,zhaojianwei 1655 // ((SwTxtFmtColl*)pTNd->GetFmtColl())->GetOutlineLevel() ) 1656 else if( !pOutlNd && 1657 ((SwTxtFmtColl*)pTNd->GetFmtColl())->IsAssignedToListLevelOfOutlineStyle() )//<-end,zhaojianwei 1658 pOutlNd = pTNd; 1659 } 1660 } 1661 1662 // dann noch alle Updaten 1663 UpdateNumRule(); 1664 1665 if( pOutlNd ) 1666 GetNodes().UpdtOutlineIdx( *pOutlNd ); 1667 } 1668 1669 void SwDoc::InvalidateNumRules() 1670 { 1671 for (sal_uInt16 n = 0; n < pNumRuleTbl->Count(); ++n) 1672 (*pNumRuleTbl)[n]->SetInvalidRule(sal_True); 1673 } 1674 1675 // zum naechsten/vorhergehenden Punkt auf gleicher Ebene 1676 1677 sal_Bool lcl_IsNumOk( sal_uInt8 nSrchNum, sal_uInt8& rLower, sal_uInt8& rUpper, 1678 sal_Bool bOverUpper, sal_uInt8 nNumber ) 1679 { 1680 // --> OD 2008-04-02 #refactorlists# 1681 ASSERT( nNumber < MAXLEVEL, 1682 "<lcl_IsNumOk(..)> - misusage of method" ); 1683 // <-- 1684 1685 sal_Bool bRet = sal_False; 1686 { 1687 if( bOverUpper ? nSrchNum == nNumber : nSrchNum >= nNumber ) 1688 bRet = sal_True; 1689 else if( nNumber > rLower ) 1690 rLower = nNumber; 1691 else if( nNumber < rUpper ) 1692 rUpper = nNumber; 1693 } 1694 return bRet; 1695 } 1696 1697 sal_Bool lcl_IsValidPrevNextNumNode( const SwNodeIndex& rIdx ) 1698 { 1699 sal_Bool bRet = sal_False; 1700 const SwNode& rNd = rIdx.GetNode(); 1701 switch( rNd.GetNodeType() ) 1702 { 1703 case ND_ENDNODE: 1704 bRet = SwTableBoxStartNode == rNd.StartOfSectionNode()->GetStartNodeType() || 1705 rNd.StartOfSectionNode()->IsSectionNode(); 1706 break; 1707 1708 case ND_STARTNODE: 1709 bRet = SwTableBoxStartNode == ((SwStartNode&)rNd).GetStartNodeType(); 1710 break; 1711 1712 case ND_SECTIONNODE: // der ist erlaubt, also weiter 1713 bRet = sal_True; 1714 break; 1715 } 1716 return bRet; 1717 } 1718 1719 sal_Bool lcl_GotoNextPrevNum( SwPosition& rPos, sal_Bool bNext, 1720 sal_Bool bOverUpper, sal_uInt8* pUpper, sal_uInt8* pLower ) 1721 { 1722 const SwTxtNode* pNd = rPos.nNode.GetNode().GetTxtNode(); 1723 const SwNumRule* pRule; 1724 if( !pNd || 0 == ( pRule = pNd->GetNumRule())) 1725 return sal_False; 1726 1727 sal_uInt8 nSrchNum = static_cast<sal_uInt8>(pNd->GetActualListLevel()); 1728 1729 SwNodeIndex aIdx( rPos.nNode ); 1730 if( ! pNd->IsCountedInList() ) 1731 { 1732 // falls gerade mal NO_NUMLEVEL an ist, so such den vorherigen Node 1733 // mit Nummerierung 1734 sal_Bool bError = sal_False; 1735 do { 1736 aIdx--; 1737 if( aIdx.GetNode().IsTxtNode() ) 1738 { 1739 pNd = aIdx.GetNode().GetTxtNode(); 1740 pRule = pNd->GetNumRule(); 1741 1742 sal_uInt8 nTmpNum; 1743 1744 if( pRule ) 1745 { 1746 nTmpNum = static_cast<sal_uInt8>(pNd->GetActualListLevel()); 1747 if( !( ! pNd->IsCountedInList() && 1748 (nTmpNum >= nSrchNum )) ) 1749 break; // gefunden 1750 } 1751 else 1752 bError = sal_True; 1753 } 1754 else 1755 bError = !lcl_IsValidPrevNextNumNode( aIdx ); 1756 1757 } while( !bError ); 1758 if( bError ) 1759 return sal_False; 1760 } 1761 1762 sal_uInt8 nLower = nSrchNum, nUpper = nSrchNum; 1763 sal_Bool bRet = sal_False; 1764 1765 const SwTxtNode* pLast; 1766 if( bNext ) 1767 aIdx++, pLast = pNd; 1768 else 1769 aIdx--, pLast = 0; 1770 1771 while( bNext ? ( aIdx.GetIndex() < aIdx.GetNodes().Count() - 1 ) 1772 : aIdx.GetIndex() ) 1773 { 1774 if( aIdx.GetNode().IsTxtNode() ) 1775 { 1776 pNd = aIdx.GetNode().GetTxtNode(); 1777 pRule = pNd->GetNumRule(); 1778 if( pRule ) 1779 { 1780 if( ::lcl_IsNumOk( nSrchNum, nLower, nUpper, bOverUpper, 1781 static_cast<sal_uInt8>(pNd->GetActualListLevel()) )) 1782 { 1783 rPos.nNode = aIdx; 1784 rPos.nContent.Assign( (SwTxtNode*)pNd, 0 ); 1785 bRet = sal_True; 1786 break; 1787 } 1788 else 1789 pLast = pNd; 1790 } 1791 else 1792 break; 1793 } 1794 else if( !lcl_IsValidPrevNextNumNode( aIdx )) 1795 break; 1796 1797 if( bNext ) 1798 aIdx++; 1799 else 1800 aIdx--; 1801 } 1802 1803 if( !bRet && !bOverUpper && pLast ) // nicht ueber hoehere Nummmern, aber bis Ende 1804 { 1805 if( bNext ) 1806 { 1807 rPos.nNode = aIdx; 1808 if( aIdx.GetNode().IsCntntNode() ) 1809 rPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 ); 1810 } 1811 else 1812 { 1813 rPos.nNode.Assign( *pLast ); 1814 rPos.nContent.Assign( (SwTxtNode*)pLast, 0 ); 1815 } 1816 bRet = sal_True; 1817 } 1818 1819 if( bRet ) 1820 { 1821 if( pUpper ) 1822 *pUpper = nUpper; 1823 if( pLower ) 1824 *pLower = nLower; 1825 } 1826 return bRet; 1827 } 1828 1829 sal_Bool SwDoc::GotoNextNum( SwPosition& rPos, sal_Bool bOverUpper, 1830 sal_uInt8* pUpper, sal_uInt8* pLower ) 1831 { 1832 return ::lcl_GotoNextPrevNum( rPos, sal_True, bOverUpper, pUpper, pLower ); 1833 } 1834 1835 // -> #i23731# 1836 // --> OD 2008-03-18 #refactorlists# - add output parameter <sListId> 1837 const SwNumRule * SwDoc::SearchNumRule(const SwPosition & rPos, 1838 const bool bForward, 1839 const bool bNum, 1840 const bool bOutline, 1841 int nNonEmptyAllowed, 1842 String& sListId, 1843 const bool bInvestigateStartNode) 1844 { 1845 const SwNumRule * pResult = NULL; 1846 SwTxtNode * pTxtNd = rPos.nNode.GetNode().GetTxtNode(); 1847 SwNode * pStartFromNode = pTxtNd; 1848 1849 if (pTxtNd) 1850 { 1851 SwNodeIndex aIdx(rPos.nNode); 1852 1853 // --> OD 2005-10-20 #i55391# 1854 // - the start node has also been investigated, if requested. 1855 const SwNode * pNode = NULL; 1856 do 1857 { 1858 // --> OD 2005-10-20 #i55391# 1859 if ( !bInvestigateStartNode ) 1860 { 1861 if (bForward) 1862 aIdx++; 1863 else 1864 aIdx--; 1865 } 1866 // <-- 1867 if (aIdx.GetNode().IsTxtNode()) 1868 { 1869 pTxtNd = aIdx.GetNode().GetTxtNode(); 1870 1871 const SwNumRule * pNumRule = pTxtNd->GetNumRule(); 1872 if (pNumRule) 1873 { 1874 if ( ( pNumRule->IsOutlineRule() == ( bOutline ? sal_True : sal_False ) ) && // #115901# 1875 ( ( bNum && pNumRule->Get(0).IsEnumeration()) || 1876 ( !bNum && pNumRule->Get(0).IsItemize() ) ) ) // #i22362#, #i29560# 1877 { 1878 pResult = pTxtNd->GetNumRule(); 1879 // --> OD 2008-03-18 #refactorlists# 1880 // provide also the list id, to which the text node belongs. 1881 sListId = pTxtNd->GetListId(); 1882 } 1883 1884 break; 1885 } 1886 else if (pTxtNd->Len() > 0 || NULL != pTxtNd->GetNumRule()) 1887 { 1888 if (nNonEmptyAllowed == 0) 1889 break; 1890 1891 nNonEmptyAllowed--; 1892 1893 if (nNonEmptyAllowed < 0) 1894 nNonEmptyAllowed = -1; 1895 } 1896 } 1897 1898 // --> OD 2005-10-20 #i55391# 1899 if ( bInvestigateStartNode ) 1900 { 1901 if (bForward) 1902 aIdx++; 1903 else 1904 aIdx--; 1905 } 1906 // <-- 1907 1908 pNode = &aIdx.GetNode(); 1909 } 1910 while (!(pNode == GetNodes().DocumentSectionStartNode(pStartFromNode) || 1911 pNode == GetNodes().DocumentSectionEndNode(pStartFromNode))); 1912 // <-- 1913 } 1914 1915 return pResult; 1916 } 1917 // <- #i23731# 1918 1919 sal_Bool SwDoc::GotoPrevNum( SwPosition& rPos, sal_Bool bOverUpper, 1920 sal_uInt8* pUpper, sal_uInt8* pLower ) 1921 { 1922 return ::lcl_GotoNextPrevNum( rPos, sal_False, bOverUpper, pUpper, pLower ); 1923 } 1924 1925 sal_Bool SwDoc::NumUpDown( const SwPaM& rPam, sal_Bool bDown ) 1926 { 1927 sal_uLong nStt = rPam.GetPoint()->nNode.GetIndex(), 1928 nEnd = rPam.GetMark()->nNode.GetIndex(); 1929 if( nStt > nEnd ) 1930 { 1931 sal_uLong nTmp = nStt; nStt = nEnd; nEnd = nTmp; 1932 } 1933 1934 // -> #115901# outline nodes are promoted or demoted differently 1935 bool bOnlyOutline = true; 1936 bool bOnlyNonOutline = true; 1937 for (sal_uLong n = nStt; n <= nEnd; n++) 1938 { 1939 SwTxtNode * pTxtNd = GetNodes()[n]->GetTxtNode(); 1940 1941 if (pTxtNd) 1942 { 1943 SwNumRule * pRule = pTxtNd->GetNumRule(); 1944 1945 if (pRule) 1946 { 1947 if (pRule->IsOutlineRule()) 1948 bOnlyNonOutline = false; 1949 else 1950 bOnlyOutline = false; 1951 } 1952 } 1953 } 1954 // <- #115901# 1955 1956 sal_Bool bRet = sal_True; 1957 char nDiff = bDown ? 1 : -1; 1958 1959 // ->#115901# 1960 if (bOnlyOutline) 1961 bRet = OutlineUpDown(rPam, nDiff); 1962 else if (bOnlyNonOutline) 1963 { 1964 /* --> #i24560# 1965 1966 Only promote or demote if all selected paragraphs are 1967 promotable resp. demotable. 1968 1969 */ 1970 for (sal_uLong nTmp = nStt; nTmp <= nEnd; ++nTmp) 1971 { 1972 SwTxtNode* pTNd = GetNodes()[ nTmp ]->GetTxtNode(); 1973 1974 // --> OD 2006-10-19 #134160# - make code robust: 1975 // consider case that the node doesn't denote a text node. 1976 if ( pTNd ) 1977 { 1978 SwNumRule * pRule = pTNd->GetNumRule(); 1979 1980 if (pRule) 1981 { 1982 sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel()); 1983 if( (-1 == nDiff && 0 >= nLevel) || 1984 (1 == nDiff && MAXLEVEL - 1 <= nLevel)) 1985 bRet = sal_False; 1986 } 1987 } 1988 // <-- 1989 } 1990 1991 if( bRet ) 1992 { 1993 /* <-- #i24560# */ 1994 if (GetIDocumentUndoRedo().DoesUndo()) 1995 { 1996 SwUndo *const pUndo( new SwUndoNumUpDown(rPam, nDiff) ); 1997 GetIDocumentUndoRedo().AppendUndo(pUndo); 1998 } 1999 2000 String sNumRule; 2001 2002 for(sal_uLong nTmp = nStt; nTmp <= nEnd; ++nTmp ) 2003 { 2004 SwTxtNode* pTNd = GetNodes()[ nTmp ]->GetTxtNode(); 2005 2006 if( pTNd) 2007 { 2008 SwNumRule * pRule = pTNd->GetNumRule(); 2009 2010 if (pRule) 2011 { 2012 sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel()); 2013 nLevel = nLevel + nDiff; 2014 2015 pTNd->SetAttrListLevel(nLevel); 2016 } 2017 } 2018 } 2019 2020 ChkCondColls(); 2021 SetModified(); 2022 } 2023 } 2024 2025 return bRet; 2026 } 2027 2028 sal_Bool SwDoc::MoveParagraph( const SwPaM& rPam, long nOffset, sal_Bool bIsOutlMv ) 2029 { 2030 const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End(); 2031 2032 sal_uLong nStIdx = pStt->nNode.GetIndex(); 2033 sal_uLong nEndIdx = pEnd->nNode.GetIndex(); 2034 2035 // Here are some sophisticated checks whether the wished PaM will be moved or not. 2036 // For moving outlines (bIsOutlMv) I've already done some checks, so here are two different 2037 // checks... 2038 SwNode *pTmp1; 2039 SwNode *pTmp2; 2040 if( bIsOutlMv ) 2041 { 2042 // For moving chapters (outline) the following reason will deny the move: 2043 // if a start node is inside the moved area and its end node outside or vice versa. 2044 // If a start node is the first moved paragraph, its end node has to be within the moved 2045 // area, too (e.g. as last node). 2046 // If an end node is the last node of the moved area, its start node has to be a part of 2047 // the moved section, too. 2048 pTmp1 = GetNodes()[ nStIdx ]; 2049 if( pTmp1->IsStartNode() ) 2050 { // First is a start node 2051 pTmp2 = pTmp1->EndOfSectionNode(); 2052 if( pTmp2->GetIndex() > nEndIdx ) 2053 return sal_False; // Its end node is behind the moved range 2054 } 2055 pTmp1 = pTmp1->StartOfSectionNode()->EndOfSectionNode(); 2056 if( pTmp1->GetIndex() <= nEndIdx ) 2057 return sal_False; // End node inside but start node before moved range => no. 2058 pTmp1 = GetNodes()[ nEndIdx ]; 2059 if( pTmp1->IsEndNode() ) 2060 { // The last one is an end node 2061 pTmp1 = pTmp1->StartOfSectionNode(); 2062 if( pTmp1->GetIndex() < nStIdx ) 2063 return sal_False; // Its start node is before the moved range. 2064 } 2065 pTmp1 = pTmp1->StartOfSectionNode(); 2066 if( pTmp1->GetIndex() >= nStIdx ) 2067 return sal_False; // A start node which ends behind the moved area => no. 2068 } 2069 2070 sal_uLong nInStIdx, nInEndIdx; 2071 long nOffs = nOffset; 2072 if( nOffset > 0 ) 2073 { 2074 nInEndIdx = nEndIdx; 2075 nEndIdx += nOffset; 2076 ++nOffs; 2077 } 2078 else 2079 { 2080 //Impossible to move to negative index 2081 if( sal_uLong(abs( nOffset )) > nStIdx) 2082 return sal_False; 2083 2084 nInEndIdx = nStIdx - 1; 2085 nStIdx += nOffset; 2086 } 2087 nInStIdx = nInEndIdx + 1; 2088 // Folgende Absatzbloecke sollen vertauscht werden: 2089 // [ nStIdx, nInEndIdx ] mit [ nInStIdx, nEndIdx ] 2090 2091 if( nEndIdx >= GetNodes().GetEndOfContent().GetIndex() ) 2092 return sal_False; 2093 2094 if( !bIsOutlMv ) 2095 { // And here the restrictions for moving paragraphs other than chapters (outlines) 2096 // The plan is to exchange [nStIdx,nInEndIdx] and [nStartIdx,nEndIdx] 2097 // It will checked if the both "start" nodes as well as the both "end" notes belongs to 2098 // the same start-end-section. This is more restrictive than the conditions checked above. 2099 // E.g. a paragraph will not escape from a section or be inserted to another section. 2100 pTmp1 = GetNodes()[ nStIdx ]->StartOfSectionNode(); 2101 pTmp2 = GetNodes()[ nInStIdx ]->StartOfSectionNode(); 2102 if( pTmp1 != pTmp2 ) 2103 return sal_False; // "start" nodes in different sections 2104 pTmp1 = GetNodes()[ nEndIdx ]; 2105 bool bIsEndNode = pTmp1->IsEndNode(); 2106 if( !pTmp1->IsStartNode() ) 2107 { 2108 pTmp1 = pTmp1->StartOfSectionNode(); 2109 if( bIsEndNode ) // For end nodes the first start node is of course inside the range, 2110 pTmp1 = pTmp1->StartOfSectionNode(); // I've to check the start node of the start node. 2111 } 2112 pTmp1 = pTmp1->EndOfSectionNode(); 2113 pTmp2 = GetNodes()[ nInEndIdx ]; 2114 if( !pTmp2->IsStartNode() ) 2115 { 2116 bIsEndNode = pTmp2->IsEndNode(); 2117 pTmp2 = pTmp2->StartOfSectionNode(); 2118 if( bIsEndNode ) 2119 pTmp2 = pTmp2->StartOfSectionNode(); 2120 } 2121 pTmp2 = pTmp2->EndOfSectionNode(); 2122 if( pTmp1 != pTmp2 ) 2123 return sal_False; // The "end" notes are in different sections 2124 } 2125 2126 // auf Redlining testen - darf die Selektion ueberhaupt verschoben 2127 // werden? 2128 if( !IsIgnoreRedline() ) 2129 { 2130 sal_uInt16 nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), nsRedlineType_t::REDLINE_DELETE ); 2131 if( USHRT_MAX != nRedlPos ) 2132 { 2133 SwPosition aStPos( *pStt ), aEndPos( *pEnd ); 2134 aStPos.nContent = 0; 2135 SwCntntNode* pCNd = pEnd->nNode.GetNode().GetCntntNode(); 2136 aEndPos.nContent = pCNd ? pCNd->Len() : 1; 2137 sal_Bool bCheckDel = sal_True; 2138 2139 // es existiert fuer den Bereich irgendein Redline-Delete-Object 2140 for( ; nRedlPos < GetRedlineTbl().Count(); ++nRedlPos ) 2141 { 2142 const SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ]; 2143 if( !bCheckDel || nsRedlineType_t::REDLINE_DELETE == pTmp->GetType() ) 2144 { 2145 const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End(); 2146 switch( ComparePosition( *pRStt, *pREnd, aStPos, aEndPos )) 2147 { 2148 case POS_COLLIDE_START: 2149 case POS_BEHIND: // Pos1 liegt hinter Pos2 2150 nRedlPos = GetRedlineTbl().Count(); 2151 break; 2152 2153 case POS_COLLIDE_END: 2154 case POS_BEFORE: // Pos1 liegt vor Pos2 2155 break; 2156 case POS_INSIDE: // Pos1 liegt vollstaendig in Pos2 2157 // ist erlaubt, aber checke dann alle nachfolgenden 2158 // auf Ueberlappungen 2159 bCheckDel = sal_False; 2160 break; 2161 2162 case POS_OUTSIDE: // Pos2 liegt vollstaendig in Pos1 2163 case POS_EQUAL: // Pos1 ist genauso gross wie Pos2 2164 case POS_OVERLAP_BEFORE: // Pos1 ueberlappt Pos2 am Anfang 2165 case POS_OVERLAP_BEHIND: // Pos1 ueberlappt Pos2 am Ende 2166 return sal_False; 2167 } 2168 } 2169 } 2170 } 2171 } 2172 2173 { 2174 // DataChanged vorm verschieben verschicken, dann bekommt 2175 // man noch mit, welche Objecte sich im Bereich befinden. 2176 // Danach koennen sie vor/hinter der Position befinden. 2177 SwDataChanged aTmp( rPam, 0 ); 2178 } 2179 2180 SwNodeIndex aIdx( nOffset > 0 ? pEnd->nNode : pStt->nNode, nOffs ); 2181 SwNodeRange aMvRg( pStt->nNode, 0, pEnd->nNode, +1 ); 2182 2183 SwRedline* pOwnRedl = 0; 2184 if( IsRedlineOn() ) 2185 { 2186 // wenn der Bereich komplett im eigenen Redline liegt, kann es 2187 // verschoben werden! 2188 sal_uInt16 nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), nsRedlineType_t::REDLINE_INSERT ); 2189 if( USHRT_MAX != nRedlPos ) 2190 { 2191 SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ]; 2192 const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End(); 2193 SwRedline aTmpRedl( nsRedlineType_t::REDLINE_INSERT, rPam ); 2194 const SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode(); 2195 // liegt komplett im Bereich, und ist auch der eigene Redline? 2196 if( aTmpRedl.IsOwnRedline( *pTmp ) && 2197 (pRStt->nNode < pStt->nNode || 2198 (pRStt->nNode == pStt->nNode && !pRStt->nContent.GetIndex()) ) && 2199 (pEnd->nNode < pREnd->nNode || 2200 (pEnd->nNode == pREnd->nNode && 2201 pCEndNd ? pREnd->nContent.GetIndex() == pCEndNd->Len() 2202 : !pREnd->nContent.GetIndex() )) ) 2203 { 2204 pOwnRedl = pTmp; 2205 if( nRedlPos + 1 < GetRedlineTbl().Count() ) 2206 { 2207 pTmp = GetRedlineTbl()[ nRedlPos+1 ]; 2208 if( *pTmp->Start() == *pREnd ) 2209 // dann doch nicht! 2210 pOwnRedl = 0; 2211 } 2212 2213 if( pOwnRedl && 2214 !( pRStt->nNode <= aIdx && aIdx <= pREnd->nNode )) 2215 { 2216 // nicht in sich selbst, dann auch nicht moven 2217 pOwnRedl = 0; 2218 } 2219 } 2220 } 2221 2222 if( !pOwnRedl ) 2223 { 2224 GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL ); 2225 2226 // zuerst das Insert, dann das Loeschen 2227 SwPosition aInsPos( aIdx ); 2228 aInsPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 ); 2229 2230 SwPaM aPam( pStt->nNode, aMvRg.aEnd ); 2231 2232 SwPaM& rOrigPam = (SwPaM&)rPam; 2233 rOrigPam.DeleteMark(); 2234 rOrigPam.GetPoint()->nNode = aIdx.GetIndex() - 1; 2235 2236 sal_Bool bDelLastPara = !aInsPos.nNode.GetNode().IsCntntNode(); 2237 2238 /* #101076# When copying to a non-content node Copy will 2239 insert a paragraph before that node and insert before 2240 that inserted node. Copy creates an SwUndoInserts that 2241 does not cover the extra paragraph. Thus we insert the 2242 extra paragraph ourselves, _with_ correct undo 2243 information. */ 2244 if (bDelLastPara) 2245 { 2246 /* aInsPos points to the non-content node. Move it to 2247 the previous content node. */ 2248 SwPaM aInsPam(aInsPos); 2249 sal_Bool bMoved = aInsPam.Move(fnMoveBackward); 2250 ASSERT(bMoved, "No content node found!"); 2251 2252 if (bMoved) 2253 { 2254 /* Append the new node after the content node 2255 found. The new position to insert the moved 2256 paragraph at is before the inserted 2257 paragraph. */ 2258 AppendTxtNode(*aInsPam.GetPoint()); 2259 aInsPos = *aInsPam.GetPoint(); 2260 } 2261 } 2262 2263 CopyRange( aPam, aInsPos, false ); 2264 if( bDelLastPara ) 2265 { 2266 // dann muss der letzte leere Node wieder entfernt werden 2267 aIdx = aInsPos.nNode; 2268 SwCntntNode* pCNd = GetNodes().GoPrevious( &aInsPos.nNode ); 2269 xub_StrLen nCLen = 0; if( pCNd ) nCLen = pCNd->Len(); 2270 aInsPos.nContent.Assign( pCNd, nCLen ); 2271 2272 // alle die im zu loeschenden Node stehen, mussen auf den 2273 // naechsten umgestezt werden 2274 SwPosition* pPos; 2275 for( sal_uInt16 n = 0; n < GetRedlineTbl().Count(); ++n ) 2276 { 2277 SwRedline* pTmp = GetRedlineTbl()[ n ]; 2278 if( ( pPos = &pTmp->GetBound(sal_True))->nNode == aIdx ) 2279 { 2280 pPos->nNode++; 2281 pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0); 2282 } 2283 if( ( pPos = &pTmp->GetBound(sal_False))->nNode == aIdx ) 2284 { 2285 pPos->nNode++; 2286 pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0); 2287 } 2288 } 2289 CorrRel( aIdx, aInsPos, 0, sal_False ); 2290 2291 pCNd->JoinNext(); 2292 } 2293 2294 rOrigPam.GetPoint()->nNode++; 2295 rOrigPam.GetPoint()->nContent.Assign( rOrigPam.GetCntntNode(), 0 ); 2296 2297 RedlineMode_t eOld = GetRedlineMode(); 2298 checkRedlining(eOld); 2299 if (GetIDocumentUndoRedo().DoesUndo()) 2300 { 2301 //JP 06.01.98: MUSS noch optimiert werden!!! 2302 SetRedlineMode( 2303 (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 2304 SwUndo *const pUndo(new SwUndoRedlineDelete(aPam, UNDO_DELETE)); 2305 GetIDocumentUndoRedo().AppendUndo(pUndo); 2306 } 2307 2308 SwRedline* pNewRedline = new SwRedline( nsRedlineType_t::REDLINE_DELETE, aPam ); 2309 2310 // #101654# prevent assertion from aPam's target being deleted 2311 // (Alternatively, one could just let aPam go out of scope, but 2312 // that requires touching a lot of code.) 2313 aPam.GetBound(sal_True).nContent.Assign( NULL, 0 ); 2314 aPam.GetBound(sal_False).nContent.Assign( NULL, 0 ); 2315 2316 AppendRedline( pNewRedline, true ); 2317 2318 //JP 06.01.98: MUSS noch optimiert werden!!! 2319 SetRedlineMode( eOld ); 2320 GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); 2321 SetModified(); 2322 2323 return sal_True; 2324 } 2325 } 2326 2327 if( !pOwnRedl && !IsIgnoreRedline() && GetRedlineTbl().Count() ) 2328 { 2329 SwPaM aTemp(aIdx); 2330 SplitRedline(aTemp); 2331 } 2332 2333 sal_uLong nRedlSttNd(0), nRedlEndNd(0); 2334 if( pOwnRedl ) 2335 { 2336 const SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End(); 2337 nRedlSttNd = pRStt->nNode.GetIndex(); 2338 nRedlEndNd = pREnd->nNode.GetIndex(); 2339 } 2340 2341 SwUndoMoveNum* pUndo = 0; 2342 sal_uLong nMoved = 0; 2343 if (GetIDocumentUndoRedo().DoesUndo()) 2344 { 2345 pUndo = new SwUndoMoveNum( rPam, nOffset, bIsOutlMv ); 2346 nMoved = rPam.End()->nNode.GetIndex() - rPam.Start()->nNode.GetIndex() + 1; 2347 } 2348 2349 2350 MoveNodeRange( aMvRg, aIdx, DOC_MOVEREDLINES ); 2351 2352 if( pUndo ) 2353 { 2354 // i57907: Under circumstances (sections at the end of a chapter) 2355 // the rPam.Start() is not moved to the new position. 2356 // But aIdx should be at the new end position and as long as the number of moved paragraphs 2357 // is nMoved, I know, where the new position is. 2358 pUndo->SetStartNode( aIdx.GetIndex() - nMoved ); 2359 GetIDocumentUndoRedo().AppendUndo(pUndo); 2360 } 2361 2362 if( pOwnRedl ) 2363 { 2364 SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End(); 2365 if( pRStt->nNode.GetIndex() != nRedlSttNd ) 2366 { 2367 pRStt->nNode = nRedlSttNd; 2368 pRStt->nContent.Assign( pRStt->nNode.GetNode().GetCntntNode(),0); 2369 } 2370 if( pREnd->nNode.GetIndex() != nRedlEndNd ) 2371 { 2372 pREnd->nNode = nRedlEndNd; 2373 SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode(); 2374 xub_StrLen nL = 0; if( pCNd ) nL = pCNd->Len(); 2375 pREnd->nContent.Assign( pCNd, nL ); 2376 } 2377 } 2378 2379 SetModified(); 2380 return sal_True; 2381 } 2382 2383 sal_Bool SwDoc::NumOrNoNum( const SwNodeIndex& rIdx, sal_Bool bDel ) 2384 { 2385 sal_Bool bResult = sal_False; 2386 SwTxtNode * pTxtNd = rIdx.GetNode().GetTxtNode(); 2387 2388 if (pTxtNd && pTxtNd->GetNumRule() != NULL && 2389 (pTxtNd->HasNumber() || pTxtNd->HasBullet())) 2390 { 2391 if ( !pTxtNd->IsCountedInList() == !bDel) 2392 { 2393 sal_Bool bOldNum = bDel; // == pTxtNd->IsCounted(); 2394 sal_Bool bNewNum = bDel ? sal_False : sal_True; 2395 pTxtNd->SetCountedInList(bNewNum ? true : false); 2396 2397 SetModified(); 2398 2399 bResult = sal_True; 2400 2401 if (GetIDocumentUndoRedo().DoesUndo()) 2402 { 2403 SwUndoNumOrNoNum * pUndo = 2404 new SwUndoNumOrNoNum(rIdx, bOldNum, bNewNum); 2405 2406 GetIDocumentUndoRedo().AppendUndo(pUndo); 2407 } 2408 } 2409 else if (bDel && pTxtNd->GetNumRule(sal_False) && 2410 pTxtNd->GetActualListLevel() >= 0 && 2411 pTxtNd->GetActualListLevel() < MAXLEVEL) 2412 { 2413 SwPaM aPam(*pTxtNd); 2414 2415 DelNumRules(aPam); 2416 2417 bResult = sal_True; 2418 } 2419 } 2420 2421 return bResult; 2422 } 2423 2424 SwNumRule* SwDoc::GetCurrNumRule( const SwPosition& rPos ) const 2425 { 2426 SwNumRule* pRet = 0; 2427 SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode(); 2428 2429 if( pTNd ) 2430 { 2431 // --> OD 2008-02-20 #refactorlists# 2432 // pTNd->SyncNumberAndNumRule(); 2433 // <-- 2434 pRet = pTNd->GetNumRule(); 2435 } 2436 2437 return pRet; 2438 } 2439 2440 sal_uInt16 SwDoc::FindNumRule( const String& rName ) const 2441 { 2442 for( sal_uInt16 n = pNumRuleTbl->Count(); n; ) 2443 if( (*pNumRuleTbl)[ --n ]->GetName() == rName ) 2444 return n; 2445 2446 return USHRT_MAX; 2447 } 2448 2449 SwNumRule* SwDoc::FindNumRulePtr( const String& rName ) const 2450 { 2451 SwNumRule * pResult = 0; 2452 2453 pResult = maNumRuleMap[rName]; 2454 2455 if ( !pResult ) 2456 { 2457 for (sal_uInt16 n = 0; n < pNumRuleTbl->Count(); ++n) 2458 { 2459 if ((*pNumRuleTbl)[n]->GetName() == rName) 2460 { 2461 pResult = (*pNumRuleTbl)[n]; 2462 2463 break; 2464 } 2465 } 2466 } 2467 2468 return pResult; 2469 } 2470 2471 // #i36749# 2472 void SwDoc::AddNumRule(SwNumRule * pRule) 2473 { 2474 pNumRuleTbl->Insert(pRule, pNumRuleTbl->Count()); 2475 maNumRuleMap[pRule->GetName()] = pRule; 2476 pRule->SetNumRuleMap(&maNumRuleMap); 2477 2478 // --> OD 2008-03-26 #refactorlists# 2479 createListForListStyle( pRule->GetName() ); 2480 // <-- 2481 } 2482 2483 // --> OD 2008-02-11 #newlistlevelattrs# 2484 sal_uInt16 SwDoc::MakeNumRule( const String &rName, 2485 const SwNumRule* pCpy, 2486 sal_Bool bBroadcast, 2487 const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode ) 2488 { 2489 SwNumRule* pNew; 2490 if( pCpy ) 2491 { 2492 pNew = new SwNumRule( *pCpy ); 2493 2494 // --> OD 2008-07-08 #i91400# 2495 pNew->SetName( GetUniqueNumRuleName( &rName ), *this ); 2496 // <-- 2497 if( pNew->GetName() != rName ) 2498 { 2499 pNew->SetPoolFmtId( USHRT_MAX ); 2500 pNew->SetPoolHelpId( USHRT_MAX ); 2501 pNew->SetPoolHlpFileId( UCHAR_MAX ); 2502 // --> OD 2008-04-03 #refactorlists# 2503 pNew->SetDefaultListId( String() ); 2504 // <-- 2505 } 2506 pNew->CheckCharFmts( this ); 2507 } 2508 else 2509 { 2510 // --> OD 2008-02-11 #newlistlevelattrs# 2511 pNew = new SwNumRule( GetUniqueNumRuleName( &rName ), 2512 eDefaultNumberFormatPositionAndSpaceMode ); 2513 // <-- 2514 } 2515 2516 sal_uInt16 nRet = pNumRuleTbl->Count(); 2517 2518 AddNumRule(pNew); // #i36749# 2519 2520 if (GetIDocumentUndoRedo().DoesUndo()) 2521 { 2522 SwUndo * pUndo = new SwUndoNumruleCreate(pNew, this); 2523 GetIDocumentUndoRedo().AppendUndo(pUndo); 2524 } 2525 2526 if (bBroadcast) 2527 BroadcastStyleOperation(pNew->GetName(), SFX_STYLE_FAMILY_PSEUDO, 2528 SFX_STYLESHEET_CREATED); 2529 2530 return nRet; 2531 } 2532 2533 String SwDoc::GetUniqueNumRuleName( const String* pChkStr, sal_Bool bAutoNum ) const 2534 { 2535 String aName; 2536 if( bAutoNum ) 2537 { 2538 long n = Time().GetTime(); 2539 n += Date().GetDate(); 2540 aName = String::CreateFromInt32( n ); 2541 if( pChkStr && !pChkStr->Len() ) 2542 pChkStr = 0; 2543 } 2544 else if( pChkStr && pChkStr->Len() ) 2545 aName = *pChkStr; 2546 else 2547 { 2548 pChkStr = 0; 2549 aName = SW_RESSTR( STR_NUMRULE_DEFNAME ); 2550 } 2551 2552 sal_uInt16 nNum(0), nTmp, nFlagSize = ( pNumRuleTbl->Count() / 8 ) +2; 2553 sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ]; 2554 memset( pSetFlags, 0, nFlagSize ); 2555 2556 xub_StrLen nNmLen = aName.Len(); 2557 if( !bAutoNum && pChkStr ) 2558 { 2559 while( nNmLen-- && '0' <= aName.GetChar( nNmLen ) && 2560 '9' >= aName.GetChar( nNmLen ) ) 2561 ; //nop 2562 2563 if( ++nNmLen < aName.Len() ) 2564 { 2565 aName.Erase( nNmLen ); 2566 pChkStr = 0; 2567 } 2568 } 2569 2570 const SwNumRule* pNumRule; 2571 sal_uInt16 n; 2572 2573 for( n = 0; n < pNumRuleTbl->Count(); ++n ) 2574 if( 0 != ( pNumRule = (*pNumRuleTbl)[ n ] ) ) 2575 { 2576 const String& rNm = pNumRule->GetName(); 2577 if( rNm.Match( aName ) == nNmLen ) 2578 { 2579 // Nummer bestimmen und das Flag setzen 2580 nNum = (sal_uInt16)rNm.Copy( nNmLen ).ToInt32(); 2581 if( nNum-- && nNum < pNumRuleTbl->Count() ) 2582 pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 )); 2583 } 2584 if( pChkStr && pChkStr->Equals( rNm ) ) 2585 pChkStr = 0; 2586 } 2587 2588 if( !pChkStr ) 2589 { 2590 // alle Nummern entsprechend geflag, also bestimme die richtige Nummer 2591 nNum = pNumRuleTbl->Count(); 2592 for( n = 0; n < nFlagSize; ++n ) 2593 if( 0xff != ( nTmp = pSetFlags[ n ] )) 2594 { 2595 // also die Nummer bestimmen 2596 nNum = n * 8; 2597 while( nTmp & 1 ) 2598 ++nNum, nTmp >>= 1; 2599 break; 2600 } 2601 2602 } 2603 delete [] pSetFlags; 2604 if( pChkStr && pChkStr->Len() ) 2605 return *pChkStr; 2606 return aName += String::CreateFromInt32( ++nNum ); 2607 } 2608 2609 void SwDoc::UpdateNumRule() 2610 { 2611 const SwNumRuleTbl& rNmTbl = GetNumRuleTbl(); 2612 for( sal_uInt16 n = 0; n < rNmTbl.Count(); ++n ) 2613 if( rNmTbl[ n ]->IsInvalidRule() ) 2614 rNmTbl[ n ]->Validate(); 2615 } 2616 2617 // --> OD 2008-04-02 #refactorlists# 2618 void SwDoc::MarkListLevel( const String& sListId, 2619 const int nListLevel, 2620 const sal_Bool bValue ) 2621 { 2622 SwList* pList = getListByName( sListId ); 2623 2624 if ( pList ) 2625 { 2626 MarkListLevel( *pList, nListLevel, bValue ); 2627 } 2628 } 2629 2630 void SwDoc::MarkListLevel( SwList& rList, 2631 const int nListLevel, 2632 const sal_Bool bValue ) 2633 { 2634 // Set new marked list level and notify all affected nodes of the changed mark. 2635 rList.MarkListLevel( nListLevel, bValue ); 2636 } 2637 // <- #i27615# 2638 // <-- 2639 2640 // #i23726# 2641 sal_Bool SwDoc::IsFirstOfNumRule(SwPosition & rPos) 2642 { 2643 sal_Bool bResult = sal_False; 2644 SwTxtNode * pTxtNode = rPos.nNode.GetNode().GetTxtNode(); 2645 2646 if (pTxtNode) 2647 { 2648 SwNumRule * pNumRule = pTxtNode->GetNumRule(); 2649 2650 if (pNumRule) 2651 bResult = pTxtNode->IsFirstOfNumRule(); 2652 } 2653 2654 return bResult; 2655 } 2656 2657 // --> OD 2007-10-26 #i83479# 2658 // implementation for interface <IDocumentListItems> 2659 bool SwDoc::lessThanNodeNum::operator()( const SwNodeNum* pNodeNumOne, 2660 const SwNodeNum* pNodeNumTwo ) const 2661 { 2662 return pNodeNumOne->LessThan( *pNodeNumTwo ); 2663 } 2664 2665 void SwDoc::addListItem( const SwNodeNum& rNodeNum ) 2666 { 2667 if ( mpListItemsList == 0 ) 2668 { 2669 return; 2670 } 2671 2672 const bool bAlreadyInserted( 2673 mpListItemsList->find( &rNodeNum ) != mpListItemsList->end() ); 2674 ASSERT( !bAlreadyInserted, 2675 "<SwDoc::InsertListItem(..)> - <SwNodeNum> instance already registered as numbered item!" ); 2676 if ( !bAlreadyInserted ) 2677 { 2678 mpListItemsList->insert( &rNodeNum ); 2679 } 2680 } 2681 2682 void SwDoc::removeListItem( const SwNodeNum& rNodeNum ) 2683 { 2684 if ( mpListItemsList == 0 ) 2685 { 2686 return; 2687 } 2688 2689 const tImplSortedNodeNumList::size_type nDeleted = mpListItemsList->erase( &rNodeNum ); 2690 if ( nDeleted > 1 ) 2691 { 2692 ASSERT( false, 2693 "<SwDoc::RemoveListItem(..)> - <SwNodeNum> was registered more than once as numbered item!" ); 2694 } 2695 } 2696 2697 String SwDoc::getListItemText( const SwNodeNum& rNodeNum, 2698 const bool bWithNumber, 2699 const bool bWithSpacesForLevel ) const 2700 { 2701 return rNodeNum.GetTxtNode() 2702 ? rNodeNum.GetTxtNode()->GetExpandTxt( 0, STRING_LEN, bWithNumber, 2703 bWithNumber, bWithSpacesForLevel ) 2704 : String(); 2705 } 2706 2707 void SwDoc::getListItems( tSortedNodeNumList& orNodeNumList ) const 2708 { 2709 orNodeNumList.clear(); 2710 orNodeNumList.reserve( mpListItemsList->size() ); 2711 2712 tImplSortedNodeNumList::iterator aIter; 2713 tImplSortedNodeNumList::iterator aEndIter = mpListItemsList->end(); 2714 for ( aIter = mpListItemsList->begin(); aIter != aEndIter; ++aIter ) 2715 { 2716 orNodeNumList.push_back( (*aIter) ); 2717 } 2718 } 2719 2720 void SwDoc::getNumItems( tSortedNodeNumList& orNodeNumList ) const 2721 { 2722 orNodeNumList.clear(); 2723 orNodeNumList.reserve( mpListItemsList->size() ); 2724 2725 tImplSortedNodeNumList::iterator aIter; 2726 tImplSortedNodeNumList::iterator aEndIter = mpListItemsList->end(); 2727 for ( aIter = mpListItemsList->begin(); aIter != aEndIter; ++aIter ) 2728 { 2729 const SwNodeNum* pNodeNum = (*aIter); 2730 if ( pNodeNum->IsCounted() && 2731 pNodeNum->GetTxtNode() && pNodeNum->GetTxtNode()->HasNumber() ) 2732 { 2733 orNodeNumList.push_back( pNodeNum ); 2734 } 2735 } 2736 } 2737 // <-- 2738 2739 // --> OD 2007-11-15 #i83479# 2740 // implementation for interface <IDocumentOutlineNodes> 2741 sal_Int32 SwDoc::getOutlineNodesCount() const 2742 { 2743 return GetNodes().GetOutLineNds().Count(); 2744 } 2745 2746 int SwDoc::getOutlineLevel( const sal_Int32 nIdx ) const 2747 { 2748 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]-> 2749 // GetTxtNode()->GetOutlineLevel(); //#outline level,zhaojianwei 2750 GetTxtNode()->GetAttrOutlineLevel()-1; //<-end,zhaojianwei 2751 } 2752 2753 String SwDoc::getOutlineText( const sal_Int32 nIdx, 2754 const bool bWithNumber, 2755 const bool bWithSpacesForLevel ) const 2756 { 2757 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]-> 2758 GetTxtNode()->GetExpandTxt( 0, STRING_LEN, bWithNumber, 2759 bWithNumber, bWithSpacesForLevel ); 2760 } 2761 2762 SwTxtNode* SwDoc::getOutlineNode( const sal_Int32 nIdx ) const 2763 { 2764 return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->GetTxtNode(); 2765 } 2766 2767 void SwDoc::getOutlineNodes( IDocumentOutlineNodes::tSortedOutlineNodeList& orOutlineNodeList ) const 2768 { 2769 orOutlineNodeList.clear(); 2770 orOutlineNodeList.reserve( getOutlineNodesCount() ); 2771 2772 const sal_uInt16 nOutlCount( static_cast<sal_uInt16>(getOutlineNodesCount()) ); 2773 for ( sal_uInt16 i = 0; i < nOutlCount; ++i ) 2774 { 2775 orOutlineNodeList.push_back( 2776 GetNodes().GetOutLineNds()[i]->GetTxtNode() ); 2777 } 2778 } 2779 // <-- 2780 2781 // --> OD 2008-03-26 #refactorlists# 2782 // implementation of interface IDocumentListsAccess 2783 SwList* SwDoc::createList( String sListId, 2784 const String sDefaultListStyleName ) 2785 { 2786 if ( sListId.Len() == 0 ) 2787 { 2788 sListId = listfunc::CreateUniqueListId( *this ); 2789 } 2790 2791 if ( getListByName( sListId ) ) 2792 { 2793 ASSERT( false, 2794 "<SwDoc::createList(..)> - provided list id already used. Serious defect -> please inform OD." ); 2795 return 0; 2796 } 2797 2798 SwNumRule* pDefaultNumRuleForNewList = FindNumRulePtr( sDefaultListStyleName ); 2799 if ( !pDefaultNumRuleForNewList ) 2800 { 2801 ASSERT( false, 2802 "<SwDoc::createList(..)> - for provided default list style name no list style is found. Serious defect -> please inform OD." ); 2803 return 0; 2804 } 2805 2806 SwList* pNewList = new SwList( sListId, *pDefaultNumRuleForNewList, GetNodes() ); 2807 maLists[sListId] = pNewList; 2808 2809 return pNewList; 2810 } 2811 2812 void SwDoc::deleteList( const String sListId ) 2813 { 2814 SwList* pList = getListByName( sListId ); 2815 if ( pList ) 2816 { 2817 maLists.erase( sListId ); 2818 delete pList; 2819 } 2820 } 2821 2822 SwList* SwDoc::getListByName( const String sListId ) const 2823 { 2824 SwList* pList = 0; 2825 2826 std::hash_map< String, SwList*, StringHash >::const_iterator 2827 aListIter = maLists.find( sListId ); 2828 if ( aListIter != maLists.end() ) 2829 { 2830 pList = (*aListIter).second; 2831 } 2832 2833 return pList; 2834 } 2835 2836 SwList* SwDoc::createListForListStyle( const String sListStyleName ) 2837 { 2838 if ( sListStyleName.Len() == 0 ) 2839 { 2840 ASSERT( false, 2841 "<SwDoc::createListForListStyle(..)> - no list style name provided. Serious defect -> please inform OD." ); 2842 return 0; 2843 } 2844 2845 if ( getListForListStyle( sListStyleName ) ) 2846 { 2847 ASSERT( false, 2848 "<SwDoc::createListForListStyle(..)> - a list for the provided list style name already exists. Serious defect -> please inform OD." ); 2849 return 0; 2850 } 2851 2852 SwNumRule* pNumRule = FindNumRulePtr( sListStyleName ); 2853 if ( !pNumRule ) 2854 { 2855 ASSERT( false, 2856 "<SwDoc::createListForListStyle(..)> - for provided list style name no list style is found. Serious defect -> please inform OD." ); 2857 return 0; 2858 } 2859 2860 String sListId( pNumRule->GetDefaultListId() ); // can be empty String 2861 if ( getListByName( sListId ) ) 2862 { 2863 sListId = String(); 2864 } 2865 SwList* pNewList = createList( sListId, sListStyleName ); 2866 maListStyleLists[sListStyleName] = pNewList; 2867 pNumRule->SetDefaultListId( pNewList->GetListId() ); 2868 2869 return pNewList; 2870 } 2871 2872 SwList* SwDoc::getListForListStyle( const String sListStyleName ) const 2873 { 2874 SwList* pList = 0; 2875 2876 std::hash_map< String, SwList*, StringHash >::const_iterator 2877 aListIter = maListStyleLists.find( sListStyleName ); 2878 if ( aListIter != maListStyleLists.end() ) 2879 { 2880 pList = (*aListIter).second; 2881 } 2882 2883 return pList; 2884 } 2885 2886 void SwDoc::deleteListForListStyle( const String sListStyleName ) 2887 { 2888 String sListId; 2889 { 2890 SwList* pList = getListForListStyle( sListStyleName ); 2891 ASSERT( pList, 2892 "<SwDoc::deleteListForListStyle(..)> - misusage of method: no list found for given list style name" ); 2893 if ( pList ) 2894 { 2895 sListId = pList->GetListId(); 2896 } 2897 } 2898 if ( sListId.Len() > 0 ) 2899 { 2900 maListStyleLists.erase( sListStyleName ); 2901 deleteList( sListId ); 2902 } 2903 } 2904 // <-- 2905 // --> OD 2008-07-08 #i91400# 2906 void SwDoc::trackChangeOfListStyleName( const String sListStyleName, 2907 const String sNewListStyleName ) 2908 { 2909 SwList* pList = getListForListStyle( sListStyleName ); 2910 ASSERT( pList, 2911 "<SwDoc::changeOfListStyleName(..)> - misusage of method: no list found for given list style name" ); 2912 2913 if ( pList != 0 ) 2914 { 2915 maListStyleLists.erase( sListStyleName ); 2916 maListStyleLists[sNewListStyleName] = pList; 2917 } 2918 } 2919 // <-- 2920 2921 // --> OD 2008-03-13 #refactorlists# 2922 namespace listfunc 2923 { 2924 const String MakeListIdUnique( const SwDoc& rDoc, 2925 const String aSuggestedUniqueListId ) 2926 { 2927 long nHitCount = 0; 2928 String aTmpStr = aSuggestedUniqueListId; 2929 while ( rDoc.getListByName( aTmpStr ) ) 2930 { 2931 ++nHitCount; 2932 aTmpStr = aSuggestedUniqueListId; 2933 aTmpStr += String::CreateFromInt32( nHitCount ); 2934 } 2935 2936 return aTmpStr; 2937 } 2938 const String CreateUniqueListId( const SwDoc& rDoc ) 2939 { 2940 // --> OD 2008-08-06 #i92478# 2941 String aNewListId = String::CreateFromAscii( "list" ); 2942 // <-- 2943 sal_Int64 n = Time().GetTime(); 2944 n += Date().GetDate(); 2945 n += rand(); 2946 // --> OD 2008-08-06 #i92478# 2947 aNewListId += String::CreateFromInt64( n ); 2948 // <-- 2949 2950 return MakeListIdUnique( rDoc, aNewListId ); 2951 } 2952 } 2953 // <-- 2954