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