1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sc.hxx" 26 27 28 #include <tools/debug.hxx> 29 #include <tools/shl.hxx> // SHL_CALC 30 #include <tools/stack.hxx> 31 #include <tools/rtti.hxx> 32 #include <svl/zforlist.hxx> 33 #include <svl/itemset.hxx> 34 #include <svl/isethint.hxx> 35 #include <svl/itempool.hxx> 36 #include <sfx2/app.hxx> 37 #include <unotools/useroptions.hxx> 38 #include <sfx2/sfxsids.hrc> 39 40 #include "cell.hxx" 41 #include "document.hxx" 42 #include "dociter.hxx" 43 #include "global.hxx" 44 #include "rechead.hxx" 45 #include "scerrors.hxx" 46 #include "scmod.hxx" // SC_MOD 47 #include "inputopt.hxx" // GetExpandRefs 48 #include "patattr.hxx" 49 #include "hints.hxx" 50 51 #include "globstr.hrc" 52 53 #include <stack> 54 55 #define SC_CHGTRACK_CXX 56 #include "chgtrack.hxx" 57 58 DECLARE_STACK( ScChangeActionStack, ScChangeAction* ) 59 60 const sal_uInt16 nMemPoolChangeActionCellListEntry = (0x2000 - 64) / sizeof(ScChangeActionCellListEntry); 61 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionCellListEntry, nMemPoolChangeActionCellListEntry, nMemPoolChangeActionCellListEntry ) 62 63 const sal_uInt16 nMemPoolChangeActionLinkEntry = (0x8000 - 64) / sizeof(ScChangeActionLinkEntry); 64 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionLinkEntry, nMemPoolChangeActionLinkEntry, nMemPoolChangeActionLinkEntry ) 65 66 // loaded MSB > eigenes => inkompatibel 67 #define SC_CHGTRACK_FILEFORMAT_FIRST 0x0001 68 #define SC_CHGTRACK_FILEFORMAT 0x0001 69 70 // --- ScChangeActionLinkEntry --------------------------------------------- 71 72 #if DEBUG_CHANGETRACK 73 String ScChangeActionLinkEntry::ToString() const 74 { 75 String aReturn; 76 if ( pAction ) 77 { 78 aReturn = String::CreateFromInt64( static_cast< sal_Int64 >( pAction->GetActionNumber() ) ); 79 } 80 else if ( pLink && pLink->pAction ) 81 { 82 aReturn = String::CreateFromAscii( "*" ); 83 aReturn += String::CreateFromInt64( static_cast< sal_Int64 >( pLink->pAction->GetActionNumber() ) ); 84 } 85 else 86 { 87 aReturn = String::CreateFromAscii( "-" ); 88 } 89 90 return aReturn; 91 } 92 #endif // DEBUG_CHANGETRACK 93 94 // --- ScChangeAction ------------------------------------------------------ 95 96 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScRange& rRange ) 97 : 98 aBigRange( rRange ), 99 pNext( NULL ), 100 pPrev( NULL ), 101 pLinkAny( NULL ), 102 pLinkDeletedIn( NULL ), 103 pLinkDeleted( NULL ), 104 pLinkDependent( NULL ), 105 nAction( 0 ), 106 nRejectAction( 0 ), 107 eType( eTypeP ), 108 eState( SC_CAS_VIRGIN ) 109 { 110 aDateTime.ConvertToUTC(); 111 } 112 113 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange, 114 const sal_uLong nTempAction, const sal_uLong nTempRejectAction, 115 const ScChangeActionState eTempState, const DateTime& aTempDateTime, 116 const String& aTempUser, const String& aTempComment) 117 : 118 aBigRange( rRange ), 119 aDateTime( aTempDateTime ), 120 aUser( aTempUser ), 121 aComment( aTempComment ), 122 pNext( NULL ), 123 pPrev( NULL ), 124 pLinkAny( NULL ), 125 pLinkDeletedIn( NULL ), 126 pLinkDeleted( NULL ), 127 pLinkDependent( NULL ), 128 nAction( nTempAction ), 129 nRejectAction( nTempRejectAction ), 130 eType( eTypeP ), 131 eState( eTempState ) 132 { 133 } 134 135 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange, 136 const sal_uLong nTempAction) 137 : 138 aBigRange( rRange ), 139 pNext( NULL ), 140 pPrev( NULL ), 141 pLinkAny( NULL ), 142 pLinkDeletedIn( NULL ), 143 pLinkDeleted( NULL ), 144 pLinkDependent( NULL ), 145 nAction( nTempAction ), 146 nRejectAction( 0 ), 147 eType( eTypeP ), 148 eState( SC_CAS_VIRGIN ) 149 { 150 aDateTime.ConvertToUTC(); 151 } 152 153 154 ScChangeAction::~ScChangeAction() 155 { 156 RemoveAllLinks(); 157 } 158 159 160 sal_Bool ScChangeAction::IsVisible() const 161 { 162 //! sequence order of execution is significant 163 if ( IsRejected() || GetType() == SC_CAT_DELETE_TABS || IsDeletedIn() ) 164 return sal_False; 165 if ( GetType() == SC_CAT_CONTENT ) 166 return ((ScChangeActionContent*)this)->IsTopContent(); 167 return sal_True; 168 } 169 170 171 sal_Bool ScChangeAction::IsTouchable() const 172 { 173 //! sequence order of execution is significant 174 if ( IsRejected() || GetType() == SC_CAT_REJECT || IsDeletedIn() ) 175 return sal_False; 176 // content may reject and be touchable if on top 177 if ( GetType() == SC_CAT_CONTENT ) 178 return ((ScChangeActionContent*)this)->IsTopContent(); 179 if ( IsRejecting() ) 180 return sal_False; 181 return sal_True; 182 } 183 184 185 sal_Bool ScChangeAction::IsClickable() const 186 { 187 //! sequence order of execution is significant 188 if ( !IsVirgin() ) 189 return sal_False; 190 if ( IsDeletedIn() ) 191 return sal_False; 192 if ( GetType() == SC_CAT_CONTENT ) 193 { 194 ScChangeActionContentCellType eCCT = 195 ScChangeActionContent::GetContentCellType( 196 ((ScChangeActionContent*)this)->GetNewCell() ); 197 if ( eCCT == SC_CACCT_MATREF ) 198 return sal_False; 199 if ( eCCT == SC_CACCT_MATORG ) 200 { // no Accept-Select if one of the references is in a deleted col/row 201 const ScChangeActionLinkEntry* pL = 202 ((ScChangeActionContent*)this)->GetFirstDependentEntry(); 203 while ( pL ) 204 { 205 ScChangeAction* p = (ScChangeAction*) pL->GetAction(); 206 if ( p && p->IsDeletedIn() ) 207 return sal_False; 208 pL = pL->GetNext(); 209 } 210 } 211 return sal_True; // for Select() a content doesn't have to be touchable 212 } 213 return IsTouchable(); // Accept()/Reject() only on touchables 214 } 215 216 217 sal_Bool ScChangeAction::IsRejectable() const 218 { 219 //! sequence order of execution is significant 220 if ( !IsClickable() ) 221 return sal_False; 222 if ( GetType() == SC_CAT_CONTENT ) 223 { 224 if ( ((ScChangeActionContent*)this)->IsOldMatrixReference() ) 225 return sal_False; 226 ScChangeActionContent* pNextContent = 227 ((ScChangeActionContent*)this)->GetNextContent(); 228 if ( pNextContent == NULL ) 229 return sal_True; // *this is TopContent 230 return pNextContent->IsRejected(); // *this is next rejectable 231 } 232 return IsTouchable(); 233 } 234 235 236 sal_Bool ScChangeAction::IsInternalRejectable() const 237 { 238 //! sequence order of execution is significant 239 if ( !IsVirgin() ) 240 return sal_False; 241 if ( IsDeletedIn() ) 242 return sal_False; 243 if ( GetType() == SC_CAT_CONTENT ) 244 { 245 ScChangeActionContent* pNextContent = 246 ((ScChangeActionContent*)this)->GetNextContent(); 247 if ( pNextContent == NULL ) 248 return sal_True; // *this is TopContent 249 return pNextContent->IsRejected(); // *this is next rejectable 250 } 251 return IsTouchable(); 252 } 253 254 255 sal_Bool ScChangeAction::IsDialogRoot() const 256 { 257 return IsInternalRejectable(); // only rejectables in root 258 } 259 260 261 sal_Bool ScChangeAction::IsDialogParent() const 262 { 263 //! sequence order of execution is significant 264 if ( GetType() == SC_CAT_CONTENT ) 265 { 266 if ( !IsDialogRoot() ) 267 return sal_False; 268 if ( ((ScChangeActionContent*)this)->IsMatrixOrigin() && HasDependent() ) 269 return sal_True; 270 ScChangeActionContent* pPrevContent = 271 ((ScChangeActionContent*)this)->GetPrevContent(); 272 return pPrevContent && pPrevContent->IsVirgin(); 273 } 274 if ( HasDependent() ) 275 return IsDeleteType() ? sal_True : !IsDeletedIn(); 276 if ( HasDeleted() ) 277 { 278 if ( IsDeleteType() ) 279 { 280 if ( IsDialogRoot() ) 281 return sal_True; 282 ScChangeActionLinkEntry* pL = pLinkDeleted; 283 while ( pL ) 284 { 285 ScChangeAction* p = pL->GetAction(); 286 if ( p && p->GetType() != eType ) 287 return sal_True; 288 pL = pL->GetNext(); 289 } 290 } 291 else 292 return sal_True; 293 } 294 return sal_False; 295 } 296 297 298 sal_Bool ScChangeAction::IsMasterDelete() const 299 { 300 if ( !IsDeleteType() ) 301 return sal_False; 302 ScChangeActionDel* pDel = (ScChangeActionDel*) this; 303 return pDel->IsMultiDelete() && (pDel->IsTopDelete() || pDel->IsRejectable()); 304 } 305 306 307 void ScChangeAction::RemoveAllLinks() 308 { 309 RemoveAllAnyLinks(); 310 RemoveAllDeletedIn(); 311 RemoveAllDeleted(); 312 RemoveAllDependent(); 313 } 314 315 316 void ScChangeAction::RemoveAllAnyLinks() 317 { 318 while ( pLinkAny ) 319 delete pLinkAny; // rueckt sich selbst hoch 320 } 321 322 323 sal_Bool ScChangeAction::RemoveDeletedIn( const ScChangeAction* p ) 324 { 325 sal_Bool bRemoved = sal_False; 326 ScChangeActionLinkEntry* pL = GetDeletedIn(); 327 while ( pL ) 328 { 329 ScChangeActionLinkEntry* pNextLink = pL->GetNext(); 330 if ( pL->GetAction() == p ) 331 { 332 delete pL; 333 bRemoved = sal_True; 334 } 335 pL = pNextLink; 336 } 337 return bRemoved; 338 } 339 340 341 sal_Bool ScChangeAction::IsDeletedIn( const ScChangeAction* p ) const 342 { 343 ScChangeActionLinkEntry* pL = GetDeletedIn(); 344 while ( pL ) 345 { 346 if ( pL->GetAction() == p ) 347 return sal_True; 348 pL = pL->GetNext(); 349 } 350 return sal_False; 351 } 352 353 354 void ScChangeAction::RemoveAllDeletedIn() 355 { 356 //! nicht vom evtl. TopContent sondern wirklich dieser 357 while ( pLinkDeletedIn ) 358 delete pLinkDeletedIn; // rueckt sich selbst hoch 359 } 360 361 362 sal_Bool ScChangeAction::IsDeletedInDelType( ScChangeActionType eDelType ) const 363 { 364 ScChangeAction* p; 365 ScChangeActionLinkEntry* pL = GetDeletedIn(); 366 if ( pL ) 367 { 368 // InsertType fuer MergePrepare/MergeOwn 369 ScChangeActionType eInsType; 370 switch ( eDelType ) 371 { 372 case SC_CAT_DELETE_COLS : 373 eInsType = SC_CAT_INSERT_COLS; 374 break; 375 case SC_CAT_DELETE_ROWS : 376 eInsType = SC_CAT_INSERT_ROWS; 377 break; 378 case SC_CAT_DELETE_TABS : 379 eInsType = SC_CAT_INSERT_TABS; 380 break; 381 default: 382 eInsType = SC_CAT_NONE; 383 } 384 while ( pL ) 385 { 386 if ( (p = pL->GetAction()) != NULL && 387 (p->GetType() == eDelType || p->GetType() == eInsType) ) 388 return sal_True; 389 pL = pL->GetNext(); 390 } 391 } 392 return sal_False; 393 } 394 395 396 void ScChangeAction::SetDeletedIn( ScChangeAction* p ) 397 { 398 ScChangeActionLinkEntry* pLink1 = AddDeletedIn( p ); 399 ScChangeActionLinkEntry* pLink2; 400 if ( GetType() == SC_CAT_CONTENT ) 401 pLink2 = p->AddDeleted( ((ScChangeActionContent*)this)->GetTopContent() ); 402 else 403 pLink2 = p->AddDeleted( this ); 404 pLink1->SetLink( pLink2 ); 405 } 406 407 408 void ScChangeAction::RemoveAllDeleted() 409 { 410 while ( pLinkDeleted ) 411 delete pLinkDeleted; // rueckt sich selbst hoch 412 } 413 414 415 void ScChangeAction::RemoveAllDependent() 416 { 417 while ( pLinkDependent ) 418 delete pLinkDependent; // rueckt sich selbst hoch 419 } 420 421 422 DateTime ScChangeAction::GetDateTime() const 423 { 424 DateTime aDT( aDateTime ); 425 aDT.ConvertToLocalTime(); 426 return aDT; 427 } 428 429 430 void ScChangeAction::UpdateReference( const ScChangeTrack* /* pTrack */, 431 UpdateRefMode eMode, const ScBigRange& rRange, 432 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) 433 { 434 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() ); 435 } 436 437 438 void ScChangeAction::GetDescription( String& rStr, ScDocument* /* pDoc */, 439 sal_Bool /* bSplitRange */, bool bWarning ) const 440 { 441 if ( IsRejecting() && bWarning ) 442 { 443 // #112261# Add comment if rejection may have resulted in references 444 // not properly restored in formulas. See specification at 445 // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw 446 if (GetType() == SC_CAT_MOVE) 447 { 448 rStr += ScGlobal::GetRscString( 449 STR_CHANGED_MOVE_REJECTION_WARNING); 450 rStr += ' '; 451 } 452 else if (IsInsertType()) 453 { 454 rStr += ScGlobal::GetRscString( 455 STR_CHANGED_DELETE_REJECTION_WARNING); 456 rStr += ' '; 457 } 458 else 459 { 460 const ScChangeTrack* pCT = GetChangeTrack(); 461 if (pCT) 462 { 463 ScChangeAction* pReject = pCT->GetActionOrGenerated( 464 GetRejectAction()); 465 if (pReject) 466 { 467 if (pReject->GetType() == SC_CAT_MOVE) 468 { 469 rStr += ScGlobal::GetRscString( 470 STR_CHANGED_MOVE_REJECTION_WARNING); 471 rStr += ' '; 472 } 473 else if (pReject->IsDeleteType()) 474 { 475 rStr += ScGlobal::GetRscString( 476 STR_CHANGED_DELETE_REJECTION_WARNING); 477 rStr += ' '; 478 } 479 else if (pReject->HasDependent()) 480 { 481 ScChangeActionTable aTable; 482 pCT->GetDependents( pReject, aTable, sal_False, sal_True ); 483 for ( const ScChangeAction* p = aTable.First(); p; 484 p = aTable.Next() ) 485 { 486 if (p->GetType() == SC_CAT_MOVE) 487 { 488 rStr += ScGlobal::GetRscString( 489 STR_CHANGED_MOVE_REJECTION_WARNING); 490 rStr += ' '; 491 break; // for 492 } 493 else if (pReject->IsDeleteType()) 494 { 495 rStr += ScGlobal::GetRscString( 496 STR_CHANGED_DELETE_REJECTION_WARNING); 497 rStr += ' '; 498 break; // for 499 } 500 } 501 } 502 } 503 } 504 } 505 } 506 } 507 508 509 String ScChangeAction::GetRefString( const ScBigRange& rRange, 510 ScDocument* pDoc, sal_Bool bFlag3D ) const 511 { 512 String aStr; 513 sal_uInt16 nFlags = ( rRange.IsValid( pDoc ) ? SCA_VALID : 0 ); 514 if ( !nFlags ) 515 aStr = ScGlobal::GetRscString( STR_NOREF_STR ); 516 else 517 { 518 ScRange aTmpRange( rRange.MakeRange() ); 519 switch ( GetType() ) 520 { 521 case SC_CAT_INSERT_COLS : 522 case SC_CAT_DELETE_COLS : 523 if ( bFlag3D ) 524 { 525 pDoc->GetName( aTmpRange.aStart.Tab(), aStr ); 526 aStr += '.'; 527 } 528 aStr += ::ScColToAlpha( aTmpRange.aStart.Col() ); 529 aStr += ':'; 530 aStr += ::ScColToAlpha( aTmpRange.aEnd.Col() ); 531 break; 532 case SC_CAT_INSERT_ROWS : 533 case SC_CAT_DELETE_ROWS : 534 if ( bFlag3D ) 535 { 536 pDoc->GetName( aTmpRange.aStart.Tab(), aStr ); 537 aStr += '.'; 538 } 539 aStr += String::CreateFromInt32( aTmpRange.aStart.Row() + 1 ); 540 aStr += ':'; 541 aStr += String::CreateFromInt32( aTmpRange.aEnd.Row() + 1 ); 542 break; 543 default: 544 if ( bFlag3D || GetType() == SC_CAT_INSERT_TABS ) 545 nFlags |= SCA_TAB_3D; 546 aTmpRange.Format( aStr, nFlags, pDoc, pDoc->GetAddressConvention() ); 547 } 548 if ( (bFlag3D && IsDeleteType()) || IsDeletedIn() ) 549 { 550 aStr.Insert( '(', 0 ); 551 aStr += ')'; 552 } 553 } 554 return aStr; 555 } 556 557 558 void ScChangeAction::GetRefString( String& rStr, ScDocument* pDoc, 559 sal_Bool bFlag3D ) const 560 { 561 rStr = GetRefString( GetBigRange(), pDoc, bFlag3D ); 562 } 563 564 565 void ScChangeAction::Accept() 566 { 567 if ( IsVirgin() ) 568 { 569 SetState( SC_CAS_ACCEPTED ); 570 DeleteCellEntries(); 571 } 572 } 573 574 575 void ScChangeAction::SetRejected() 576 { 577 if ( IsVirgin() ) 578 { 579 SetState( SC_CAS_REJECTED ); 580 RemoveAllLinks(); 581 DeleteCellEntries(); 582 } 583 } 584 585 586 void ScChangeAction::RejectRestoreContents( ScChangeTrack* pTrack, 587 SCsCOL nDx, SCsROW nDy ) 588 { 589 // Liste der Contents aufbauen 590 ScChangeActionCellListEntry* pListContents = NULL; 591 for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() ) 592 { 593 ScChangeAction* p = pL->GetAction(); 594 if ( p && p->GetType() == SC_CAT_CONTENT ) 595 { 596 ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry( 597 (ScChangeActionContent*) p, pListContents ); 598 pListContents = pE; 599 } 600 } 601 SetState( SC_CAS_REJECTED ); // vor UpdateReference fuer Move 602 pTrack->UpdateReference( this, sal_True ); // LinkDeleted freigeben 603 DBG_ASSERT( !pLinkDeleted, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" ); 604 // Liste der Contents abarbeiten und loeschen 605 ScDocument* pDoc = pTrack->GetDocument(); 606 ScChangeActionCellListEntry* pE = pListContents; 607 while ( pE ) 608 { 609 if ( !pE->pContent->IsDeletedIn() && 610 pE->pContent->GetBigRange().aStart.IsValid( pDoc ) ) 611 pE->pContent->PutNewValueToDoc( pDoc, nDx, nDy ); 612 ScChangeActionCellListEntry* pNextEntry; 613 pNextEntry = pE->pNext; 614 delete pE; 615 pE = pNextEntry; 616 } 617 DeleteCellEntries(); // weg mit den generierten 618 } 619 620 621 void ScChangeAction::SetDeletedInThis( sal_uLong nActionNumber, 622 const ScChangeTrack* pTrack ) 623 { 624 if ( nActionNumber ) 625 { 626 ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber ); 627 DBG_ASSERT( pAct, "ScChangeAction::SetDeletedInThis: missing Action" ); 628 if ( pAct ) 629 pAct->SetDeletedIn( this ); 630 } 631 } 632 633 634 void ScChangeAction::AddDependent( sal_uLong nActionNumber, 635 const ScChangeTrack* pTrack ) 636 { 637 if ( nActionNumber ) 638 { 639 ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber ); 640 DBG_ASSERT( pAct, "ScChangeAction::AddDependent: missing Action" ); 641 if ( pAct ) 642 { 643 ScChangeActionLinkEntry* pLink = AddDependent( pAct ); 644 pAct->AddLink( this, pLink ); 645 } 646 } 647 } 648 649 650 #if DEBUG_CHANGETRACK 651 String ScChangeAction::ToString( ScDocument* pDoc ) const 652 { 653 String aReturn; 654 655 String aNumber = String::CreateFromInt64( static_cast< sal_Int64 >( GetActionNumber() ) ); 656 657 String aActionState; 658 ScChangeActionState eActionState = GetState(); 659 switch ( eActionState ) 660 { 661 case SC_CAS_VIRGIN: 662 { 663 aActionState = String::CreateFromAscii( " " ); 664 } 665 break; 666 case SC_CAS_ACCEPTED: 667 { 668 aActionState = String::CreateFromAscii( "+" ); 669 } 670 break; 671 case SC_CAS_REJECTED: 672 { 673 aActionState = String::CreateFromAscii( "-" ); 674 } 675 break; 676 } 677 678 String aRejectAction; 679 if ( IsRejecting() ) 680 { 681 aRejectAction += 'r'; 682 aRejectAction += String::CreateFromInt64( static_cast< sal_Int64 >( GetRejectAction() ) ); 683 } 684 685 String aReference; 686 GetRefString( aReference, pDoc, sal_True ); 687 688 String aAuthor = GetUser(); 689 690 DateTime aDT = GetDateTime(); 691 String aDate = ScGlobal::pLocaleData->getDate( aDT ); 692 aDate += ' '; 693 aDate += ScGlobal::pLocaleData->getTime( aDT, sal_False, sal_False ); 694 695 String aDescription; 696 GetDescription( aDescription, pDoc ); 697 698 String aLinkAny; 699 const ScChangeActionLinkEntry* pLinkA = pLinkAny; 700 while ( pLinkA ) 701 { 702 if ( !aLinkAny.Len() ) 703 { 704 aLinkAny = String::CreateFromAscii( "(Any:" ); 705 } 706 aLinkAny += String::CreateFromAscii( " ->" ); 707 aLinkAny += pLinkA->ToString(); 708 pLinkA = pLinkA->GetNext(); 709 } 710 if ( aLinkAny.Len() ) 711 { 712 aLinkAny += ')'; 713 } 714 715 String aLinkDeletedIn; 716 const ScChangeActionLinkEntry* pLinkDI = pLinkDeletedIn; 717 while ( pLinkDI ) 718 { 719 if ( !aLinkDeletedIn.Len() ) 720 { 721 aLinkDeletedIn = String::CreateFromAscii( "(DeletedIn:" ); 722 } 723 aLinkDeletedIn += String::CreateFromAscii( " ->" ); 724 aLinkDeletedIn += pLinkDI->ToString(); 725 pLinkDI = pLinkDI->GetNext(); 726 } 727 if ( aLinkDeletedIn.Len() ) 728 { 729 aLinkDeletedIn += ')'; 730 } 731 732 String aLinkDeleted; 733 const ScChangeActionLinkEntry* pLinkD = pLinkDeleted; 734 while ( pLinkD ) 735 { 736 if ( !aLinkDeleted.Len() ) 737 { 738 aLinkDeleted = String::CreateFromAscii( "(Deleted:" ); 739 } 740 aLinkDeleted += String::CreateFromAscii( " ->" ); 741 aLinkDeleted += pLinkD->ToString(); 742 pLinkD = pLinkD->GetNext(); 743 } 744 if ( aLinkDeleted.Len() ) 745 { 746 aLinkDeleted += ')'; 747 } 748 749 String aLinkDependent; 750 const ScChangeActionLinkEntry* pLinkDp = pLinkDependent; 751 while ( pLinkDp ) 752 { 753 if ( !aLinkDependent.Len() ) 754 { 755 aLinkDependent = String::CreateFromAscii( "(Dependent:" ); 756 } 757 aLinkDependent += String::CreateFromAscii( " ->" ); 758 aLinkDependent += pLinkDp->ToString(); 759 pLinkDp = pLinkDp->GetNext(); 760 } 761 if ( aLinkDependent.Len() ) 762 { 763 aLinkDependent += ')'; 764 } 765 766 aReturn += aNumber; 767 aReturn += aActionState; 768 aReturn += aRejectAction; 769 aReturn += String::CreateFromAscii( ": " ); 770 aReturn += aReference; 771 aReturn += ' '; 772 aReturn += aAuthor; 773 aReturn += ' '; 774 aReturn += aDate; 775 aReturn += ' '; 776 aReturn += aDescription; 777 aReturn += ' '; 778 aReturn += aLinkAny; 779 aReturn += ' '; 780 aReturn += aLinkDeletedIn; 781 aReturn += ' '; 782 aReturn += aLinkDeleted; 783 aReturn += ' '; 784 aReturn += aLinkDependent; 785 786 return aReturn; 787 } 788 #endif // DEBUG_CHANGETRACK 789 790 791 // --- ScChangeActionIns --------------------------------------------------- 792 793 ScChangeActionIns::ScChangeActionIns( const ScRange& rRange ) 794 : ScChangeAction( SC_CAT_NONE, rRange ) 795 { 796 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL ) 797 { 798 aBigRange.aStart.SetCol( nInt32Min ); 799 aBigRange.aEnd.SetCol( nInt32Max ); 800 if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW ) 801 { 802 SetType( SC_CAT_INSERT_TABS ); 803 aBigRange.aStart.SetRow( nInt32Min ); 804 aBigRange.aEnd.SetRow( nInt32Max ); 805 } 806 else 807 SetType( SC_CAT_INSERT_ROWS ); 808 } 809 else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW ) 810 { 811 SetType( SC_CAT_INSERT_COLS ); 812 aBigRange.aStart.SetRow( nInt32Min ); 813 aBigRange.aEnd.SetRow( nInt32Max ); 814 } 815 else 816 { 817 DBG_ERROR( "ScChangeActionIns: Block not supported!" ); 818 } 819 } 820 821 822 ScChangeActionIns::ScChangeActionIns(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, 823 const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String& sComment, 824 const ScChangeActionType eTypeP) 825 : 826 ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment) 827 { 828 } 829 830 ScChangeActionIns::~ScChangeActionIns() 831 { 832 } 833 834 835 void ScChangeActionIns::GetDescription( String& rStr, ScDocument* pDoc, 836 sal_Bool bSplitRange, bool bWarning ) const 837 { 838 ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning ); 839 840 sal_uInt16 nWhatId; 841 switch ( GetType() ) 842 { 843 case SC_CAT_INSERT_COLS : 844 nWhatId = STR_COLUMN; 845 break; 846 case SC_CAT_INSERT_ROWS : 847 nWhatId = STR_ROW; 848 break; 849 default: 850 nWhatId = STR_AREA; 851 } 852 853 String aRsc( ScGlobal::GetRscString( STR_CHANGED_INSERT ) ); 854 xub_StrLen nPos = aRsc.SearchAscii( "#1" ); 855 rStr += aRsc.Copy( 0, nPos ); 856 rStr += ScGlobal::GetRscString( nWhatId ); 857 rStr += ' '; 858 rStr += GetRefString( GetBigRange(), pDoc ); 859 rStr += aRsc.Copy( nPos+2 ); 860 } 861 862 863 sal_Bool ScChangeActionIns::Reject( ScDocument* pDoc ) 864 { 865 if ( !aBigRange.IsValid( pDoc ) ) 866 return sal_False; 867 868 ScRange aRange( aBigRange.MakeRange() ); 869 if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(), 870 aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) ) 871 return sal_False; 872 873 switch ( GetType() ) 874 { 875 case SC_CAT_INSERT_COLS : 876 pDoc->DeleteCol( aRange ); 877 break; 878 case SC_CAT_INSERT_ROWS : 879 pDoc->DeleteRow( aRange ); 880 break; 881 case SC_CAT_INSERT_TABS : 882 pDoc->DeleteTab( aRange.aStart.Tab() ); 883 break; 884 default: 885 { 886 // added to avoid warnings 887 } 888 } 889 SetState( SC_CAS_REJECTED ); 890 RemoveAllLinks(); 891 return sal_True; 892 } 893 894 895 // --- ScChangeActionDel --------------------------------------------------- 896 897 ScChangeActionDel::ScChangeActionDel( const ScRange& rRange, 898 SCsCOL nDxP, SCsROW nDyP, ScChangeTrack* pTrackP ) 899 : 900 ScChangeAction( SC_CAT_NONE, rRange ), 901 pTrack( pTrackP ), 902 pFirstCell( NULL ), 903 pCutOff( NULL ), 904 nCutOff( 0 ), 905 pLinkMove( NULL ), 906 nDx( nDxP ), 907 nDy( nDyP ) 908 { 909 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL ) 910 { 911 aBigRange.aStart.SetCol( nInt32Min ); 912 aBigRange.aEnd.SetCol( nInt32Max ); 913 if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW ) 914 { 915 SetType( SC_CAT_DELETE_TABS ); 916 aBigRange.aStart.SetRow( nInt32Min ); 917 aBigRange.aEnd.SetRow( nInt32Max ); 918 } 919 else 920 SetType( SC_CAT_DELETE_ROWS ); 921 } 922 else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW ) 923 { 924 SetType( SC_CAT_DELETE_COLS ); 925 aBigRange.aStart.SetRow( nInt32Min ); 926 aBigRange.aEnd.SetRow( nInt32Max ); 927 } 928 else 929 { 930 DBG_ERROR( "ScChangeActionDel: Block not supported!" ); 931 } 932 } 933 934 935 ScChangeActionDel::ScChangeActionDel(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, 936 const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String &sComment, 937 const ScChangeActionType eTypeP, const SCsCOLROW nD, ScChangeTrack* pTrackP) // wich of nDx and nDy is set is depend on the type 938 : 939 ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), 940 pTrack( pTrackP ), 941 pFirstCell( NULL ), 942 pCutOff( NULL ), 943 nCutOff( 0 ), 944 pLinkMove( NULL ), 945 nDx( 0 ), 946 nDy( 0 ) 947 { 948 if (eType == SC_CAT_DELETE_COLS) 949 nDx = static_cast<SCsCOL>(nD); 950 else if (eType == SC_CAT_DELETE_ROWS) 951 nDy = static_cast<SCsROW>(nD); 952 } 953 954 ScChangeActionDel::~ScChangeActionDel() 955 { 956 DeleteCellEntries(); 957 while ( pLinkMove ) 958 delete pLinkMove; 959 } 960 961 void ScChangeActionDel::AddContent( ScChangeActionContent* pContent ) 962 { 963 ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry( 964 pContent, pFirstCell ); 965 pFirstCell = pE; 966 } 967 968 969 void ScChangeActionDel::DeleteCellEntries() 970 { 971 pTrack->DeleteCellEntries( pFirstCell, this ); 972 } 973 974 975 sal_Bool ScChangeActionDel::IsBaseDelete() const 976 { 977 return !GetDx() && !GetDy(); 978 } 979 980 981 sal_Bool ScChangeActionDel::IsTopDelete() const 982 { 983 const ScChangeAction* p = GetNext(); 984 if ( !p || p->GetType() != GetType() ) 985 return sal_True; 986 return ((ScChangeActionDel*)p)->IsBaseDelete(); 987 } 988 989 990 sal_Bool ScChangeActionDel::IsMultiDelete() const 991 { 992 if ( GetDx() || GetDy() ) 993 return sal_True; 994 const ScChangeAction* p = GetNext(); 995 if ( !p || p->GetType() != GetType() ) 996 return sal_False; 997 const ScChangeActionDel* pDel = (const ScChangeActionDel*) p; 998 if ( (pDel->GetDx() > GetDx() || pDel->GetDy() > GetDy()) && 999 pDel->GetBigRange() == aBigRange ) 1000 return sal_True; 1001 return sal_False; 1002 } 1003 1004 1005 sal_Bool ScChangeActionDel::IsTabDeleteCol() const 1006 { 1007 if ( GetType() != SC_CAT_DELETE_COLS ) 1008 return sal_False; 1009 const ScChangeAction* p = this; 1010 while ( p && p->GetType() == SC_CAT_DELETE_COLS && 1011 !((const ScChangeActionDel*)p)->IsTopDelete() ) 1012 p = p->GetNext(); 1013 return p && p->GetType() == SC_CAT_DELETE_TABS; 1014 } 1015 1016 1017 void ScChangeActionDel::UpdateReference( const ScChangeTrack* /* pTrack */, 1018 UpdateRefMode eMode, const ScBigRange& rRange, 1019 sal_Int32 nDxP, sal_Int32 nDyP, sal_Int32 nDz ) 1020 { 1021 ScRefUpdate::Update( eMode, rRange, nDxP, nDyP, nDz, GetBigRange() ); 1022 if ( !IsDeletedIn() ) 1023 return ; 1024 // evtl. in "druntergerutschten" anpassen 1025 for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() ) 1026 { 1027 ScChangeAction* p = pL->GetAction(); 1028 if ( p && p->GetType() == SC_CAT_CONTENT && 1029 !GetBigRange().In( p->GetBigRange() ) ) 1030 { 1031 switch ( GetType() ) 1032 { 1033 case SC_CAT_DELETE_COLS : 1034 p->GetBigRange().aStart.SetCol( GetBigRange().aStart.Col() ); 1035 p->GetBigRange().aEnd.SetCol( GetBigRange().aStart.Col() ); 1036 break; 1037 case SC_CAT_DELETE_ROWS : 1038 p->GetBigRange().aStart.SetRow( GetBigRange().aStart.Row() ); 1039 p->GetBigRange().aEnd.SetRow( GetBigRange().aStart.Row() ); 1040 break; 1041 case SC_CAT_DELETE_TABS : 1042 p->GetBigRange().aStart.SetTab( GetBigRange().aStart.Tab() ); 1043 p->GetBigRange().aEnd.SetTab( GetBigRange().aStart.Tab() ); 1044 break; 1045 default: 1046 { 1047 // added to avoid warnings 1048 } 1049 } 1050 } 1051 } 1052 } 1053 1054 1055 ScBigRange ScChangeActionDel::GetOverAllRange() const 1056 { 1057 ScBigRange aTmpRange( GetBigRange() ); 1058 aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() ); 1059 aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() ); 1060 return aTmpRange; 1061 } 1062 1063 1064 void ScChangeActionDel::GetDescription( String& rStr, ScDocument* pDoc, 1065 sal_Bool bSplitRange, bool bWarning ) const 1066 { 1067 ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning ); 1068 1069 sal_uInt16 nWhatId; 1070 switch ( GetType() ) 1071 { 1072 case SC_CAT_DELETE_COLS : 1073 nWhatId = STR_COLUMN; 1074 break; 1075 case SC_CAT_DELETE_ROWS : 1076 nWhatId = STR_ROW; 1077 break; 1078 default: 1079 nWhatId = STR_AREA; 1080 } 1081 1082 ScBigRange aTmpRange( GetBigRange() ); 1083 if ( !IsRejected() ) 1084 { 1085 if ( bSplitRange ) 1086 { 1087 aTmpRange.aStart.SetCol( aTmpRange.aStart.Col() + GetDx() ); 1088 aTmpRange.aStart.SetRow( aTmpRange.aStart.Row() + GetDy() ); 1089 } 1090 aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() ); 1091 aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() ); 1092 } 1093 1094 String aRsc( ScGlobal::GetRscString( STR_CHANGED_DELETE ) ); 1095 xub_StrLen nPos = aRsc.SearchAscii( "#1" ); 1096 rStr += aRsc.Copy( 0, nPos ); 1097 rStr += ScGlobal::GetRscString( nWhatId ); 1098 rStr += ' '; 1099 rStr += GetRefString( aTmpRange, pDoc ); 1100 rStr += aRsc.Copy( nPos+2 ); 1101 } 1102 1103 1104 sal_Bool ScChangeActionDel::Reject( ScDocument* pDoc ) 1105 { 1106 if ( !aBigRange.IsValid( pDoc ) && GetType() != SC_CAT_DELETE_TABS ) 1107 return sal_False; 1108 1109 sal_Bool bOk = sal_True; 1110 1111 if ( IsTopDelete() ) 1112 { // den kompletten Bereich in einem Rutsch restaurieren 1113 ScBigRange aTmpRange( GetOverAllRange() ); 1114 if ( !aTmpRange.IsValid( pDoc ) ) 1115 { 1116 if ( GetType() == SC_CAT_DELETE_TABS ) 1117 { // wird Tab angehaengt? 1118 if ( aTmpRange.aStart.Tab() > pDoc->GetMaxTableNumber() ) 1119 bOk = sal_False; 1120 } 1121 else 1122 bOk = sal_False; 1123 } 1124 if ( bOk ) 1125 { 1126 ScRange aRange( aTmpRange.MakeRange() ); 1127 // InDelete... fuer Formel UpdateReference in Document 1128 pTrack->SetInDeleteRange( aRange ); 1129 pTrack->SetInDeleteTop( sal_True ); 1130 pTrack->SetInDeleteUndo( sal_True ); 1131 pTrack->SetInDelete( sal_True ); 1132 switch ( GetType() ) 1133 { 1134 case SC_CAT_DELETE_COLS : 1135 if ( !(aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL) ) 1136 { // nur wenn nicht TabDelete 1137 if ( ( bOk = pDoc->CanInsertCol( aRange ) ) != sal_False ) 1138 bOk = pDoc->InsertCol( aRange ); 1139 } 1140 break; 1141 case SC_CAT_DELETE_ROWS : 1142 if ( ( bOk = pDoc->CanInsertRow( aRange ) ) != sal_False ) 1143 bOk = pDoc->InsertRow( aRange ); 1144 break; 1145 case SC_CAT_DELETE_TABS : 1146 { 1147 //2do: Tabellennamen merken? 1148 String aName; 1149 pDoc->CreateValidTabName( aName ); 1150 if ( ( bOk = pDoc->ValidNewTabName( aName ) ) != sal_False ) 1151 bOk = pDoc->InsertTab( aRange.aStart.Tab(), aName ); 1152 } 1153 break; 1154 default: 1155 { 1156 // added to avoid warnings 1157 } 1158 } 1159 pTrack->SetInDelete( sal_False ); 1160 pTrack->SetInDeleteUndo( sal_False ); 1161 } 1162 if ( !bOk ) 1163 { 1164 pTrack->SetInDeleteTop( sal_False ); 1165 return sal_False; 1166 } 1167 // InDeleteTop fuer UpdateReference-Undo behalten 1168 } 1169 1170 // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries 1171 RejectRestoreContents( pTrack, GetDx(), GetDy() ); 1172 1173 pTrack->SetInDeleteTop( sal_False ); 1174 RemoveAllLinks(); 1175 return sal_True; 1176 } 1177 1178 1179 void ScChangeActionDel::UndoCutOffMoves() 1180 { // abgeschnittene Moves wiederherstellen, Entries/Links deleten 1181 while ( pLinkMove ) 1182 { 1183 ScChangeActionMove* pMove = pLinkMove->GetMove(); 1184 short nFrom = pLinkMove->GetCutOffFrom(); 1185 short nTo = pLinkMove->GetCutOffTo(); 1186 switch ( GetType() ) 1187 { 1188 case SC_CAT_DELETE_COLS : 1189 if ( nFrom > 0 ) 1190 pMove->GetFromRange().aStart.IncCol( -nFrom ); 1191 else if ( nFrom < 0 ) 1192 pMove->GetFromRange().aEnd.IncCol( -nFrom ); 1193 if ( nTo > 0 ) 1194 pMove->GetBigRange().aStart.IncCol( -nTo ); 1195 else if ( nTo < 0 ) 1196 pMove->GetBigRange().aEnd.IncCol( -nTo ); 1197 break; 1198 case SC_CAT_DELETE_ROWS : 1199 if ( nFrom > 0 ) 1200 pMove->GetFromRange().aStart.IncRow( -nFrom ); 1201 else if ( nFrom < 0 ) 1202 pMove->GetFromRange().aEnd.IncRow( -nFrom ); 1203 if ( nTo > 0 ) 1204 pMove->GetBigRange().aStart.IncRow( -nTo ); 1205 else if ( nTo < 0 ) 1206 pMove->GetBigRange().aEnd.IncRow( -nTo ); 1207 break; 1208 case SC_CAT_DELETE_TABS : 1209 if ( nFrom > 0 ) 1210 pMove->GetFromRange().aStart.IncTab( -nFrom ); 1211 else if ( nFrom < 0 ) 1212 pMove->GetFromRange().aEnd.IncTab( -nFrom ); 1213 if ( nTo > 0 ) 1214 pMove->GetBigRange().aStart.IncTab( -nTo ); 1215 else if ( nTo < 0 ) 1216 pMove->GetBigRange().aEnd.IncTab( -nTo ); 1217 break; 1218 default: 1219 { 1220 // added to avoid warnings 1221 } 1222 } 1223 delete pLinkMove; // rueckt sich selbst hoch 1224 } 1225 } 1226 1227 void ScChangeActionDel::UndoCutOffInsert() 1228 { // abgeschnittenes Insert wiederherstellen 1229 if ( pCutOff ) 1230 { 1231 switch ( pCutOff->GetType() ) 1232 { 1233 case SC_CAT_INSERT_COLS : 1234 if ( nCutOff < 0 ) 1235 pCutOff->GetBigRange().aEnd.IncCol( -nCutOff ); 1236 else 1237 pCutOff->GetBigRange().aStart.IncCol( -nCutOff ); 1238 break; 1239 case SC_CAT_INSERT_ROWS : 1240 if ( nCutOff < 0 ) 1241 pCutOff->GetBigRange().aEnd.IncRow( -nCutOff ); 1242 else 1243 pCutOff->GetBigRange().aStart.IncRow( -nCutOff ); 1244 break; 1245 case SC_CAT_INSERT_TABS : 1246 if ( nCutOff < 0 ) 1247 pCutOff->GetBigRange().aEnd.IncTab( -nCutOff ); 1248 else 1249 pCutOff->GetBigRange().aStart.IncTab( -nCutOff ); 1250 break; 1251 default: 1252 { 1253 // added to avoid warnings 1254 } 1255 } 1256 SetCutOffInsert( NULL, 0 ); 1257 } 1258 } 1259 1260 1261 // --- ScChangeActionMove -------------------------------------------------- 1262 1263 ScChangeActionMove::ScChangeActionMove(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, 1264 const ScBigRange& aToBigRange, const String& aUserP, const DateTime& aDateTimeP, const String &sComment, 1265 const ScBigRange& aFromBigRange, ScChangeTrack* pTrackP) // wich of nDx and nDy is set is depend on the type 1266 : 1267 ScChangeAction(SC_CAT_MOVE, aToBigRange, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), 1268 aFromRange(aFromBigRange), 1269 pTrack( pTrackP ), 1270 pFirstCell( NULL ), 1271 nStartLastCut(0), 1272 nEndLastCut(0) 1273 { 1274 } 1275 1276 ScChangeActionMove::~ScChangeActionMove() 1277 { 1278 DeleteCellEntries(); 1279 } 1280 1281 1282 void ScChangeActionMove::AddContent( ScChangeActionContent* pContent ) 1283 { 1284 ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry( 1285 pContent, pFirstCell ); 1286 pFirstCell = pE; 1287 } 1288 1289 1290 void ScChangeActionMove::DeleteCellEntries() 1291 { 1292 pTrack->DeleteCellEntries( pFirstCell, this ); 1293 } 1294 1295 1296 void ScChangeActionMove::UpdateReference( const ScChangeTrack* /* pTrack */, 1297 UpdateRefMode eMode, const ScBigRange& rRange, 1298 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) 1299 { 1300 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aFromRange ); 1301 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() ); 1302 } 1303 1304 1305 void ScChangeActionMove::GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const 1306 { 1307 const ScBigAddress& rToPos = GetBigRange().aStart; 1308 const ScBigAddress& rFromPos = GetFromRange().aStart; 1309 nDx = rToPos.Col() - rFromPos.Col(); 1310 nDy = rToPos.Row() - rFromPos.Row(); 1311 nDz = rToPos.Tab() - rFromPos.Tab(); 1312 } 1313 1314 1315 void ScChangeActionMove::GetDescription( String& rStr, ScDocument* pDoc, 1316 sal_Bool bSplitRange, bool bWarning ) const 1317 { 1318 ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning ); 1319 1320 sal_Bool bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() ); 1321 1322 String aRsc( ScGlobal::GetRscString( STR_CHANGED_MOVE ) ); 1323 1324 xub_StrLen nPos = 0; 1325 String aTmpStr = ScChangeAction::GetRefString( GetFromRange(), pDoc, bFlag3D ); 1326 nPos = aRsc.SearchAscii( "#1", nPos ); 1327 aRsc.Erase( nPos, 2 ); 1328 aRsc.Insert( aTmpStr, nPos ); 1329 nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() ); 1330 1331 aTmpStr = ScChangeAction::GetRefString( GetBigRange(), pDoc, bFlag3D ); 1332 nPos = aRsc.SearchAscii( "#2", nPos ); 1333 aRsc.Erase( nPos, 2 ); 1334 aRsc.Insert( aTmpStr, nPos ); 1335 nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() ); 1336 1337 rStr += aRsc; 1338 } 1339 1340 1341 void ScChangeActionMove::GetRefString( String& rStr, ScDocument* pDoc, 1342 sal_Bool bFlag3D ) const 1343 { 1344 if ( !bFlag3D ) 1345 bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() ); 1346 rStr = ScChangeAction::GetRefString( GetFromRange(), pDoc, bFlag3D ); 1347 rStr += ','; 1348 rStr += ' '; 1349 rStr += ScChangeAction::GetRefString( GetBigRange(), pDoc, bFlag3D ); 1350 } 1351 1352 1353 sal_Bool ScChangeActionMove::Reject( ScDocument* pDoc ) 1354 { 1355 if ( !(aBigRange.IsValid( pDoc ) && aFromRange.IsValid( pDoc )) ) 1356 return sal_False; 1357 1358 ScRange aToRange( aBigRange.MakeRange() ); 1359 ScRange aFrmRange( aFromRange.MakeRange() ); 1360 1361 sal_Bool bOk = pDoc->IsBlockEditable( aToRange.aStart.Tab(), 1362 aToRange.aStart.Col(), aToRange.aStart.Row(), 1363 aToRange.aEnd.Col(), aToRange.aEnd.Row() ); 1364 if ( bOk ) 1365 bOk = pDoc->IsBlockEditable( aFrmRange.aStart.Tab(), 1366 aFrmRange.aStart.Col(), aFrmRange.aStart.Row(), 1367 aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row() ); 1368 if ( !bOk ) 1369 return sal_False; 1370 1371 pTrack->LookUpContents( aToRange, pDoc, 0, 0, 0 ); // zu movende Contents 1372 1373 pDoc->DeleteAreaTab( aToRange, IDF_ALL ); 1374 pDoc->DeleteAreaTab( aFrmRange, IDF_ALL ); 1375 // Formeln im Dokument anpassen 1376 pDoc->UpdateReference( URM_MOVE, 1377 aFrmRange.aStart.Col(), aFrmRange.aStart.Row(), aFrmRange.aStart.Tab(), 1378 aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row(), aFrmRange.aEnd.Tab(), 1379 (SCsCOL) aFrmRange.aStart.Col() - aToRange.aStart.Col(), 1380 (SCsROW) aFrmRange.aStart.Row() - aToRange.aStart.Row(), 1381 (SCsTAB) aFrmRange.aStart.Tab() - aToRange.aStart.Tab(), NULL ); 1382 1383 // LinkDependent freigeben, nachfolgendes UpdateReference-Undo setzt 1384 // ToRange->FromRange Dependents 1385 RemoveAllDependent(); 1386 1387 // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries 1388 RejectRestoreContents( pTrack, 0, 0 ); 1389 1390 while ( pLinkDependent ) 1391 { 1392 ScChangeAction* p = pLinkDependent->GetAction(); 1393 if ( p && p->GetType() == SC_CAT_CONTENT ) 1394 { 1395 ScChangeActionContent* pContent = (ScChangeActionContent*) p; 1396 if ( !pContent->IsDeletedIn() && 1397 pContent->GetBigRange().aStart.IsValid( pDoc ) ) 1398 pContent->PutNewValueToDoc( pDoc, 0, 0 ); 1399 // in LookUpContents generierte loeschen 1400 if ( pTrack->IsGenerated( pContent->GetActionNumber() ) && 1401 !pContent->IsDeletedIn() ) 1402 { 1403 pLinkDependent->UnLink(); //! sonst wird der mitgeloescht 1404 pTrack->DeleteGeneratedDelContent( pContent ); 1405 } 1406 } 1407 delete pLinkDependent; 1408 } 1409 1410 RemoveAllLinks(); 1411 return sal_True; 1412 } 1413 1414 1415 // --- ScChangeActionContent ----------------------------------------------- 1416 1417 const sal_uInt16 nMemPoolChangeActionContent = (0x8000 - 64) / sizeof(ScChangeActionContent); 1418 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent, nMemPoolChangeActionContent, nMemPoolChangeActionContent ) 1419 1420 ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber, 1421 const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, 1422 const ScBigRange& aBigRangeP, const String& aUserP, 1423 const DateTime& aDateTimeP, const String& sComment, 1424 ScBaseCell* pTempOldCell, ScDocument* pDoc, const String& sOldValue ) 1425 : 1426 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), 1427 aOldValue(sOldValue), 1428 pOldCell(pTempOldCell), 1429 pNewCell(NULL), 1430 pNextContent(NULL), 1431 pPrevContent(NULL), 1432 pNextInSlot(NULL), 1433 ppPrevInSlot(NULL) 1434 1435 { 1436 if (pOldCell) 1437 ScChangeActionContent::SetCell( aOldValue, pOldCell, 0, pDoc ); 1438 if ( sOldValue.Len() ) // #i40704# don't overwrite SetCell result with empty string 1439 aOldValue = sOldValue; // set again, because SetCell removes it 1440 } 1441 1442 ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber, 1443 ScBaseCell* pTempNewCell, const ScBigRange& aBigRangeP, 1444 ScDocument* pDoc, const String& sNewValue ) 1445 : 1446 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber), 1447 aNewValue(sNewValue), 1448 pOldCell(NULL), 1449 pNewCell(pTempNewCell), 1450 pNextContent(NULL), 1451 pPrevContent(NULL), 1452 pNextInSlot(NULL), 1453 ppPrevInSlot(NULL) 1454 { 1455 if (pNewCell) 1456 ScChangeActionContent::SetCell( aNewValue, pNewCell, 0, pDoc ); 1457 if ( sNewValue.Len() ) // #i40704# don't overwrite SetCell result with empty string 1458 aNewValue = sNewValue; // set again, because SetCell removes it 1459 } 1460 1461 ScChangeActionContent::~ScChangeActionContent() 1462 { 1463 ClearTrack(); 1464 } 1465 1466 1467 void ScChangeActionContent::ClearTrack() 1468 { 1469 RemoveFromSlot(); 1470 if ( pPrevContent ) 1471 pPrevContent->pNextContent = pNextContent; 1472 if ( pNextContent ) 1473 pNextContent->pPrevContent = pPrevContent; 1474 } 1475 1476 1477 ScChangeActionContent* ScChangeActionContent::GetTopContent() const 1478 { 1479 if ( pNextContent ) 1480 { 1481 ScChangeActionContent* pContent = pNextContent; 1482 while ( pContent->pNextContent && pContent != pContent->pNextContent ) 1483 pContent = pContent->pNextContent; 1484 return pContent; 1485 } 1486 return (ScChangeActionContent*) this; 1487 } 1488 1489 1490 ScChangeActionLinkEntry* ScChangeActionContent::GetDeletedIn() const 1491 { 1492 if ( pNextContent ) 1493 return GetTopContent()->pLinkDeletedIn; 1494 return pLinkDeletedIn; 1495 } 1496 1497 1498 ScChangeActionLinkEntry** ScChangeActionContent::GetDeletedInAddress() 1499 { 1500 if ( pNextContent ) 1501 return GetTopContent()->GetDeletedInAddress(); 1502 return &pLinkDeletedIn; 1503 } 1504 1505 1506 void ScChangeActionContent::SetOldValue( const ScBaseCell* pCell, 1507 const ScDocument* pFromDoc, ScDocument* pToDoc, sal_uLong nFormat ) 1508 { 1509 ScChangeActionContent::SetValue( aOldValue, pOldCell, 1510 nFormat, pCell, pFromDoc, pToDoc ); 1511 } 1512 1513 1514 void ScChangeActionContent::SetOldValue( const ScBaseCell* pCell, 1515 const ScDocument* pFromDoc, ScDocument* pToDoc ) 1516 { 1517 ScChangeActionContent::SetValue( aOldValue, pOldCell, 1518 aBigRange.aStart.MakeAddress(), pCell, pFromDoc, pToDoc ); 1519 } 1520 1521 1522 void ScChangeActionContent::SetNewValue( const ScBaseCell* pCell, 1523 ScDocument* pDoc ) 1524 { 1525 ScChangeActionContent::SetValue( aNewValue, pNewCell, 1526 aBigRange.aStart.MakeAddress(), pCell, pDoc, pDoc ); 1527 } 1528 1529 1530 void ScChangeActionContent::SetOldNewCells( ScBaseCell* pOldCellP, 1531 sal_uLong nOldFormat, ScBaseCell* pNewCellP, 1532 sal_uLong nNewFormat, ScDocument* pDoc ) 1533 { 1534 pOldCell = pOldCellP; 1535 pNewCell = pNewCellP; 1536 ScChangeActionContent::SetCell( aOldValue, pOldCell, nOldFormat, pDoc ); 1537 ScChangeActionContent::SetCell( aNewValue, pNewCell, nNewFormat, pDoc ); 1538 } 1539 1540 void ScChangeActionContent::SetNewCell( ScBaseCell* pCell, ScDocument* pDoc, const String& rFormatted ) 1541 { 1542 DBG_ASSERT( !pNewCell, "ScChangeActionContent::SetNewCell: overwriting existing cell" ); 1543 pNewCell = pCell; 1544 ScChangeActionContent::SetCell( aNewValue, pNewCell, 0, pDoc ); 1545 1546 // #i40704# allow to set formatted text here - don't call SetNewValue with String from XML filter 1547 if ( rFormatted.Len() ) 1548 aNewValue = rFormatted; 1549 } 1550 1551 void ScChangeActionContent::SetValueString( String& rValue, ScBaseCell*& pCell, 1552 const String& rStr, ScDocument* pDoc ) 1553 { 1554 if ( pCell ) 1555 { 1556 pCell->Delete(); 1557 pCell = NULL; 1558 } 1559 if ( rStr.Len() > 1 && rStr.GetChar(0) == '=' ) 1560 { 1561 rValue.Erase(); 1562 pCell = new ScFormulaCell( 1563 pDoc, aBigRange.aStart.MakeAddress(), rStr, formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::CONV_OOO ); 1564 ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True ); 1565 } 1566 else 1567 rValue = rStr; 1568 } 1569 1570 1571 void ScChangeActionContent::SetOldValue( const String& rOld, ScDocument* pDoc ) 1572 { 1573 SetValueString( aOldValue, pOldCell, rOld, pDoc ); 1574 } 1575 1576 1577 void ScChangeActionContent::SetNewValue( const String& rNew, ScDocument* pDoc ) 1578 { 1579 SetValueString( aNewValue, pNewCell, rNew, pDoc ); 1580 } 1581 1582 1583 void ScChangeActionContent::GetOldString( String& rStr ) const 1584 { 1585 GetValueString( rStr, aOldValue, pOldCell ); 1586 } 1587 1588 1589 void ScChangeActionContent::GetNewString( String& rStr ) const 1590 { 1591 GetValueString( rStr, aNewValue, pNewCell ); 1592 } 1593 1594 1595 void ScChangeActionContent::GetDescription( String& rStr, ScDocument* pDoc, 1596 sal_Bool bSplitRange, bool bWarning ) const 1597 { 1598 ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning ); 1599 1600 String aRsc( ScGlobal::GetRscString( STR_CHANGED_CELL ) ); 1601 1602 String aTmpStr; 1603 GetRefString( aTmpStr, pDoc ); 1604 1605 xub_StrLen nPos = 0; 1606 nPos = aRsc.SearchAscii( "#1", nPos ); 1607 aRsc.Erase( nPos, 2 ); 1608 aRsc.Insert( aTmpStr, nPos ); 1609 nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() ); 1610 1611 GetOldString( aTmpStr ); 1612 if ( !aTmpStr.Len() ) 1613 aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK ); 1614 nPos = aRsc.SearchAscii( "#2", nPos ); 1615 aRsc.Erase( nPos, 2 ); 1616 aRsc.Insert( aTmpStr, nPos ); 1617 nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() ); 1618 1619 GetNewString( aTmpStr ); 1620 if ( !aTmpStr.Len() ) 1621 aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK ); 1622 nPos = aRsc.SearchAscii( "#3", nPos ); 1623 aRsc.Erase( nPos, 2 ); 1624 aRsc.Insert( aTmpStr, nPos ); 1625 1626 rStr += aRsc; 1627 } 1628 1629 1630 void ScChangeActionContent::GetRefString( String& rStr, ScDocument* pDoc, 1631 sal_Bool bFlag3D ) const 1632 { 1633 sal_uInt16 nFlags = ( GetBigRange().IsValid( pDoc ) ? SCA_VALID : 0 ); 1634 if ( nFlags ) 1635 { 1636 const ScBaseCell* pCell = GetNewCell(); 1637 if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATORG ) 1638 { 1639 ScBigRange aLocalBigRange( GetBigRange() ); 1640 SCCOL nC; 1641 SCROW nR; 1642 ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR ); 1643 aLocalBigRange.aEnd.IncCol( nC-1 ); 1644 aLocalBigRange.aEnd.IncRow( nR-1 ); 1645 rStr = ScChangeAction::GetRefString( aLocalBigRange, pDoc, bFlag3D ); 1646 1647 return ; 1648 } 1649 1650 ScAddress aTmpAddress( GetBigRange().aStart.MakeAddress() ); 1651 if ( bFlag3D ) 1652 nFlags |= SCA_TAB_3D; 1653 aTmpAddress.Format( rStr, nFlags, pDoc, pDoc->GetAddressConvention() ); 1654 if ( IsDeletedIn() ) 1655 { 1656 rStr.Insert( '(', 0 ); 1657 rStr += ')'; 1658 } 1659 } 1660 else 1661 rStr = ScGlobal::GetRscString( STR_NOREF_STR ); 1662 } 1663 1664 1665 sal_Bool ScChangeActionContent::Reject( ScDocument* pDoc ) 1666 { 1667 if ( !aBigRange.IsValid( pDoc ) ) 1668 return sal_False; 1669 1670 PutOldValueToDoc( pDoc, 0, 0 ); 1671 1672 SetState( SC_CAS_REJECTED ); 1673 RemoveAllLinks(); 1674 1675 return sal_True; 1676 } 1677 1678 1679 sal_Bool ScChangeActionContent::Select( ScDocument* pDoc, ScChangeTrack* pTrack, 1680 sal_Bool bOldest, Stack* pRejectActions ) 1681 { 1682 if ( !aBigRange.IsValid( pDoc ) ) 1683 return sal_False; 1684 1685 ScChangeActionContent* pContent = this; 1686 // accept previous contents 1687 while ( ( pContent = pContent->pPrevContent ) != NULL ) 1688 { 1689 if ( pContent->IsVirgin() ) 1690 pContent->SetState( SC_CAS_ACCEPTED ); 1691 } 1692 ScChangeActionContent* pEnd = pContent = this; 1693 // reject subsequent contents 1694 while ( ( pContent = pContent->pNextContent ) != NULL ) 1695 { 1696 // MatrixOrigin may have dependents, no dependency recursion needed 1697 const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry(); 1698 while ( pL ) 1699 { 1700 ScChangeAction* p = (ScChangeAction*) pL->GetAction(); 1701 if ( p ) 1702 p->SetRejected(); 1703 pL = pL->GetNext(); 1704 } 1705 pContent->SetRejected(); 1706 pEnd = pContent; 1707 } 1708 1709 if ( bOldest || pEnd != this ) 1710 { // wenn nicht aeltester: ist es ueberhaupt ein anderer als der letzte? 1711 ScRange aRange( aBigRange.aStart.MakeAddress() ); 1712 const ScAddress& rPos = aRange.aStart; 1713 1714 ScChangeActionContent* pNew = new ScChangeActionContent( aRange ); 1715 pNew->SetOldValue( pDoc->GetCell( rPos ), pDoc, pDoc ); 1716 1717 if ( bOldest ) 1718 PutOldValueToDoc( pDoc, 0, 0 ); 1719 else 1720 PutNewValueToDoc( pDoc, 0, 0 ); 1721 1722 pNew->SetRejectAction( bOldest ? GetActionNumber() : pEnd->GetActionNumber() ); 1723 pNew->SetState( SC_CAS_ACCEPTED ); 1724 if ( pRejectActions ) 1725 pRejectActions->Push( pNew ); 1726 else 1727 { 1728 pNew->SetNewValue( pDoc->GetCell( rPos ), pDoc ); 1729 pTrack->Append( pNew ); 1730 } 1731 } 1732 1733 if ( bOldest ) 1734 SetRejected(); 1735 else 1736 SetState( SC_CAS_ACCEPTED ); 1737 1738 return sal_True; 1739 } 1740 1741 1742 // static 1743 void ScChangeActionContent::GetStringOfCell( String& rStr, 1744 const ScBaseCell* pCell, const ScDocument* pDoc, const ScAddress& rPos ) 1745 { 1746 if ( pCell ) 1747 { 1748 if ( ScChangeActionContent::NeedsNumberFormat( pCell ) ) 1749 GetStringOfCell( rStr, pCell, pDoc, pDoc->GetNumberFormat( rPos ) ); 1750 else 1751 GetStringOfCell( rStr, pCell, pDoc, 0 ); 1752 } 1753 else 1754 rStr.Erase(); 1755 } 1756 1757 1758 // static 1759 void ScChangeActionContent::GetStringOfCell( String& rStr, 1760 const ScBaseCell* pCell, const ScDocument* pDoc, sal_uLong nFormat ) 1761 { 1762 if ( ScChangeActionContent::GetContentCellType( pCell ) ) 1763 { 1764 switch ( pCell->GetCellType() ) 1765 { 1766 case CELLTYPE_VALUE : 1767 { 1768 double nValue = ((ScValueCell*)pCell)->GetValue(); 1769 pDoc->GetFormatTable()->GetInputLineString( nValue, nFormat, 1770 rStr ); 1771 } 1772 break; 1773 case CELLTYPE_STRING : 1774 ((ScStringCell*)pCell)->GetString( rStr ); 1775 break; 1776 case CELLTYPE_EDIT : 1777 ((ScEditCell*)pCell)->GetString( rStr ); 1778 break; 1779 case CELLTYPE_FORMULA : 1780 ((ScFormulaCell*)pCell)->GetFormula( rStr ); 1781 break; 1782 default: 1783 rStr.Erase(); 1784 } 1785 } 1786 else 1787 rStr.Erase(); 1788 } 1789 1790 1791 // static 1792 ScChangeActionContentCellType ScChangeActionContent::GetContentCellType( const ScBaseCell* pCell ) 1793 { 1794 if ( pCell ) 1795 { 1796 switch ( pCell->GetCellType() ) 1797 { 1798 case CELLTYPE_VALUE : 1799 case CELLTYPE_STRING : 1800 case CELLTYPE_EDIT : 1801 return SC_CACCT_NORMAL; 1802 //break; 1803 case CELLTYPE_FORMULA : 1804 switch ( ((const ScFormulaCell*)pCell)->GetMatrixFlag() ) 1805 { 1806 case MM_NONE : 1807 return SC_CACCT_NORMAL; 1808 //break; 1809 case MM_FORMULA : 1810 case MM_FAKE : 1811 return SC_CACCT_MATORG; 1812 //break; 1813 case MM_REFERENCE : 1814 return SC_CACCT_MATREF; 1815 //break; 1816 } 1817 return SC_CACCT_NORMAL; 1818 //break; 1819 default: 1820 return SC_CACCT_NONE; 1821 } 1822 } 1823 return SC_CACCT_NONE; 1824 } 1825 1826 1827 // static 1828 sal_Bool ScChangeActionContent::NeedsNumberFormat( const ScBaseCell* pCell ) 1829 { 1830 return pCell && pCell->GetCellType() == CELLTYPE_VALUE; 1831 } 1832 1833 1834 // static 1835 void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell, 1836 const ScAddress& rPos, const ScBaseCell* pOrgCell, 1837 const ScDocument* pFromDoc, ScDocument* pToDoc ) 1838 { 1839 sal_uLong nFormat = NeedsNumberFormat( pOrgCell ) ? pFromDoc->GetNumberFormat( rPos ) : 0; 1840 SetValue( rStr, pCell, nFormat, pOrgCell, pFromDoc, pToDoc ); 1841 } 1842 1843 1844 // static 1845 void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell, 1846 sal_uLong nFormat, const ScBaseCell* pOrgCell, 1847 const ScDocument* pFromDoc, ScDocument* pToDoc ) 1848 { 1849 rStr.Erase(); 1850 if ( pCell ) 1851 pCell->Delete(); 1852 if ( ScChangeActionContent::GetContentCellType( pOrgCell ) ) 1853 { 1854 pCell = pOrgCell->CloneWithoutNote( *pToDoc ); 1855 switch ( pOrgCell->GetCellType() ) 1856 { 1857 case CELLTYPE_VALUE : 1858 { // z.B. Datum auch als solches merken 1859 double nValue = ((ScValueCell*)pOrgCell)->GetValue(); 1860 pFromDoc->GetFormatTable()->GetInputLineString( nValue, 1861 nFormat, rStr ); 1862 } 1863 break; 1864 case CELLTYPE_FORMULA : 1865 ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True ); 1866 break; 1867 default: 1868 { 1869 // added to avoid warnings 1870 } 1871 } 1872 } 1873 else 1874 pCell = NULL; 1875 } 1876 1877 1878 // static 1879 void ScChangeActionContent::SetCell( String& rStr, ScBaseCell* pCell, 1880 sal_uLong nFormat, const ScDocument* pDoc ) 1881 { 1882 rStr.Erase(); 1883 if ( pCell ) 1884 { 1885 switch ( pCell->GetCellType() ) 1886 { 1887 case CELLTYPE_VALUE : 1888 { // e.g. remember date as date string 1889 double nValue = ((ScValueCell*)pCell)->GetValue(); 1890 pDoc->GetFormatTable()->GetInputLineString( nValue, 1891 nFormat, rStr ); 1892 } 1893 break; 1894 case CELLTYPE_FORMULA : 1895 ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True ); 1896 break; 1897 default: 1898 { 1899 // added to avoid warnings 1900 } 1901 } 1902 } 1903 } 1904 1905 1906 void ScChangeActionContent::GetValueString( String& rStr, 1907 const String& rValue, const ScBaseCell* pCell ) const 1908 { 1909 if ( !rValue.Len() ) 1910 { 1911 if ( pCell ) 1912 { 1913 switch ( pCell->GetCellType() ) 1914 { 1915 case CELLTYPE_STRING : 1916 ((ScStringCell*)pCell)->GetString( rStr ); 1917 break; 1918 case CELLTYPE_EDIT : 1919 ((ScEditCell*)pCell)->GetString( rStr ); 1920 break; 1921 case CELLTYPE_VALUE : // ist immer in rValue 1922 rStr = rValue; 1923 break; 1924 case CELLTYPE_FORMULA : 1925 GetFormulaString( rStr, (ScFormulaCell*) pCell ); 1926 break; 1927 default: 1928 { 1929 // added to avoid warnings 1930 } 1931 } 1932 } 1933 else 1934 rStr.Erase(); 1935 } 1936 else 1937 rStr = rValue; 1938 } 1939 1940 1941 void ScChangeActionContent::GetFormulaString( String& rStr, 1942 const ScFormulaCell* pCell ) const 1943 { 1944 ScAddress aPos( aBigRange.aStart.MakeAddress() ); 1945 if ( aPos == pCell->aPos || IsDeletedIn() ) 1946 pCell->GetFormula( rStr ); 1947 else 1948 { 1949 DBG_ERROR( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" ); 1950 ScFormulaCell* pNew = new ScFormulaCell( *pCell, *pCell->GetDocument(), aPos ); 1951 pNew->GetFormula( rStr ); 1952 delete pNew; 1953 } 1954 } 1955 1956 1957 void ScChangeActionContent::PutOldValueToDoc( ScDocument* pDoc, 1958 SCsCOL nDx, SCsROW nDy ) const 1959 { 1960 PutValueToDoc( pOldCell, aOldValue, pDoc, nDx, nDy ); 1961 } 1962 1963 1964 void ScChangeActionContent::PutNewValueToDoc( ScDocument* pDoc, 1965 SCsCOL nDx, SCsROW nDy ) const 1966 { 1967 PutValueToDoc( pNewCell, aNewValue, pDoc, nDx, nDy ); 1968 } 1969 1970 1971 void ScChangeActionContent::PutValueToDoc( ScBaseCell* pCell, 1972 const String& rValue, ScDocument* pDoc, SCsCOL nDx, SCsROW nDy ) const 1973 { 1974 ScAddress aPos( aBigRange.aStart.MakeAddress() ); 1975 if ( nDx ) 1976 aPos.IncCol( nDx ); 1977 if ( nDy ) 1978 aPos.IncRow( nDy ); 1979 if ( !rValue.Len() ) 1980 { 1981 if ( pCell ) 1982 { 1983 switch ( pCell->GetCellType() ) 1984 { 1985 case CELLTYPE_VALUE : // ist immer in rValue 1986 pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue ); 1987 break; 1988 default: 1989 switch ( ScChangeActionContent::GetContentCellType( pCell ) ) 1990 { 1991 case SC_CACCT_MATORG : 1992 { 1993 SCCOL nC; 1994 SCROW nR; 1995 ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR ); 1996 DBG_ASSERT( nC>0 && nR>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" ); 1997 ScRange aRange( aPos ); 1998 if ( nC > 1 ) 1999 aRange.aEnd.IncCol( nC-1 ); 2000 if ( nR > 1 ) 2001 aRange.aEnd.IncRow( nR-1 ); 2002 ScMarkData aDestMark; 2003 aDestMark.SelectOneTable( aPos.Tab() ); 2004 aDestMark.SetMarkArea( aRange ); 2005 pDoc->InsertMatrixFormula( aPos.Col(), aPos.Row(), 2006 aRange.aEnd.Col(), aRange.aEnd.Row(), 2007 aDestMark, EMPTY_STRING, 2008 ((const ScFormulaCell*)pCell)->GetCode() ); 2009 } 2010 break; 2011 case SC_CACCT_MATREF : 2012 // nothing 2013 break; 2014 default: 2015 pDoc->PutCell( aPos, pCell->CloneWithoutNote( *pDoc ) ); 2016 } 2017 } 2018 } 2019 else 2020 pDoc->PutCell( aPos, NULL ); 2021 } 2022 else 2023 pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue ); 2024 } 2025 2026 2027 void lcl_InvalidateReference( ScToken& rTok, const ScBigAddress& rPos ) 2028 { 2029 ScSingleRefData& rRef1 = rTok.GetSingleRef(); 2030 if ( rPos.Col() < 0 || MAXCOL < rPos.Col() ) 2031 { 2032 rRef1.nCol = SCCOL_MAX; 2033 rRef1.nRelCol = SCCOL_MAX; 2034 rRef1.SetColDeleted( sal_True ); 2035 } 2036 if ( rPos.Row() < 0 || MAXROW < rPos.Row() ) 2037 { 2038 rRef1.nRow = SCROW_MAX; 2039 rRef1.nRelRow = SCROW_MAX; 2040 rRef1.SetRowDeleted( sal_True ); 2041 } 2042 if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() ) 2043 { 2044 rRef1.nTab = SCTAB_MAX; 2045 rRef1.nRelTab = SCTAB_MAX; 2046 rRef1.SetTabDeleted( sal_True ); 2047 } 2048 if ( rTok.GetType() == formula::svDoubleRef ) 2049 { 2050 ScSingleRefData& rRef2 = rTok.GetDoubleRef().Ref2; 2051 if ( rPos.Col() < 0 || MAXCOL < rPos.Col() ) 2052 { 2053 rRef2.nCol = SCCOL_MAX; 2054 rRef2.nRelCol = SCCOL_MAX; 2055 rRef2.SetColDeleted( sal_True ); 2056 } 2057 if ( rPos.Row() < 0 || MAXROW < rPos.Row() ) 2058 { 2059 rRef2.nRow = SCROW_MAX; 2060 rRef2.nRelRow = SCROW_MAX; 2061 rRef2.SetRowDeleted( sal_True ); 2062 } 2063 if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() ) 2064 { 2065 rRef2.nTab = SCTAB_MAX; 2066 rRef2.nRelTab = SCTAB_MAX; 2067 rRef2.SetTabDeleted( sal_True ); 2068 } 2069 } 2070 } 2071 2072 2073 void ScChangeActionContent::UpdateReference( const ScChangeTrack* pTrack, 2074 UpdateRefMode eMode, const ScBigRange& rRange, 2075 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) 2076 { 2077 SCSIZE nOldSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() ); 2078 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aBigRange ); 2079 SCSIZE nNewSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() ); 2080 if ( nNewSlot != nOldSlot ) 2081 { 2082 RemoveFromSlot(); 2083 InsertInSlot( &(pTrack->GetContentSlots()[nNewSlot]) ); 2084 } 2085 2086 if ( pTrack->IsInDelete() && !pTrack->IsInDeleteTop() ) 2087 return ; // Formeln nur kompletten Bereich updaten 2088 2089 sal_Bool bOldFormula = ( pOldCell && pOldCell->GetCellType() == CELLTYPE_FORMULA ); 2090 sal_Bool bNewFormula = ( pNewCell && pNewCell->GetCellType() == CELLTYPE_FORMULA ); 2091 if ( bOldFormula || bNewFormula ) 2092 { // via ScFormulaCell UpdateReference anpassen (dort) 2093 if ( pTrack->IsInDelete() ) 2094 { 2095 const ScRange& rDelRange = pTrack->GetInDeleteRange(); 2096 if ( nDx > 0 ) 2097 nDx = rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1; 2098 else if ( nDx < 0 ) 2099 nDx = -(rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1); 2100 if ( nDy > 0 ) 2101 nDy = rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1; 2102 else if ( nDy < 0 ) 2103 nDy = -(rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1); 2104 if ( nDz > 0 ) 2105 nDz = rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1; 2106 else if ( nDz < 0 ) 2107 nDz = -(rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1); 2108 } 2109 ScBigRange aTmpRange( rRange ); 2110 switch ( eMode ) 2111 { 2112 case URM_INSDEL : 2113 if ( nDx < 0 || nDy < 0 || nDz < 0 ) 2114 { // Delete startet dort hinter geloeschtem Bereich, 2115 // Position wird dort angepasst. 2116 if ( nDx ) 2117 aTmpRange.aStart.IncCol( -nDx ); 2118 if ( nDy ) 2119 aTmpRange.aStart.IncRow( -nDy ); 2120 if ( nDz ) 2121 aTmpRange.aStart.IncTab( -nDz ); 2122 } 2123 break; 2124 case URM_MOVE : 2125 // Move ist hier Quelle, dort Ziel, 2126 // Position muss vorher angepasst sein. 2127 if ( bOldFormula ) 2128 ((ScFormulaCell*)pOldCell)->aPos = aBigRange.aStart.MakeAddress(); 2129 if ( bNewFormula ) 2130 ((ScFormulaCell*)pNewCell)->aPos = aBigRange.aStart.MakeAddress(); 2131 if ( nDx ) 2132 { 2133 aTmpRange.aStart.IncCol( nDx ); 2134 aTmpRange.aEnd.IncCol( nDx ); 2135 } 2136 if ( nDy ) 2137 { 2138 aTmpRange.aStart.IncRow( nDy ); 2139 aTmpRange.aEnd.IncRow( nDy ); 2140 } 2141 if ( nDz ) 2142 { 2143 aTmpRange.aStart.IncTab( nDz ); 2144 aTmpRange.aEnd.IncTab( nDz ); 2145 } 2146 break; 2147 default: 2148 { 2149 // added to avoid warnings 2150 } 2151 } 2152 ScRange aRange( aTmpRange.MakeRange() ); 2153 if ( bOldFormula ) 2154 ((ScFormulaCell*)pOldCell)->UpdateReference( eMode, aRange, 2155 (SCsCOL) nDx, (SCsROW) nDy, (SCsTAB) nDz, NULL ); 2156 if ( bNewFormula ) 2157 ((ScFormulaCell*)pNewCell)->UpdateReference( eMode, aRange, 2158 (SCsCOL) nDx, (SCsROW) nDy, (SCsTAB) nDz, NULL ); 2159 if ( !aBigRange.aStart.IsValid( pTrack->GetDocument() ) ) 2160 { //! HACK! 2161 //! UpdateReference kann nicht mit Positionen ausserhalb des 2162 //! Dokuments umgehen, deswegen alles auf #REF! setzen 2163 //2do: make it possible! das bedeutet grossen Umbau von ScAddress etc.! 2164 const ScBigAddress& rPos = aBigRange.aStart; 2165 if ( bOldFormula ) 2166 { 2167 ScToken* t; 2168 ScTokenArray* pArr = ((ScFormulaCell*)pOldCell)->GetCode(); 2169 pArr->Reset(); 2170 while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL ) 2171 lcl_InvalidateReference( *t, rPos ); 2172 pArr->Reset(); 2173 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL ) 2174 lcl_InvalidateReference( *t, rPos ); 2175 } 2176 if ( bNewFormula ) 2177 { 2178 ScToken* t; 2179 ScTokenArray* pArr = ((ScFormulaCell*)pNewCell)->GetCode(); 2180 pArr->Reset(); 2181 while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL ) 2182 lcl_InvalidateReference( *t, rPos ); 2183 pArr->Reset(); 2184 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL ) 2185 lcl_InvalidateReference( *t, rPos ); 2186 } 2187 } 2188 } 2189 } 2190 2191 2192 // --- ScChangeActionReject ------------------------------------------------ 2193 2194 ScChangeActionReject::ScChangeActionReject(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, 2195 const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String& sComment) 2196 : 2197 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment) 2198 { 2199 } 2200 2201 2202 // --- ScChangeTrack ------------------------------------------------------- 2203 2204 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeTrackMsgInfo, 16, 16 ) 2205 2206 const SCROW ScChangeTrack::nContentRowsPerSlot = InitContentRowsPerSlot(); 2207 const SCSIZE ScChangeTrack::nContentSlots = 2208 (MAXROWCOUNT) / InitContentRowsPerSlot() + 2; 2209 2210 // static 2211 SCROW ScChangeTrack::InitContentRowsPerSlot() 2212 { 2213 const SCSIZE nMaxSlots = 0xffe0 / sizeof( ScChangeActionContent* ) - 2; 2214 SCROW nRowsPerSlot = (MAXROWCOUNT) / nMaxSlots; 2215 if ( nRowsPerSlot * nMaxSlots < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) ) 2216 ++nRowsPerSlot; 2217 return nRowsPerSlot; 2218 } 2219 2220 2221 ScChangeTrack::ScChangeTrack( ScDocument* pDocP ) : 2222 pDoc( pDocP ) 2223 { 2224 Init(); 2225 SC_MOD()->GetUserOptions().AddListener(this); 2226 2227 ppContentSlots = new ScChangeActionContent* [ nContentSlots ]; 2228 memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) ); 2229 } 2230 2231 ScChangeTrack::ScChangeTrack( ScDocument* pDocP, const ScStrCollection& aTempUserCollection) : 2232 aUserCollection(aTempUserCollection), 2233 pDoc( pDocP ) 2234 { 2235 Init(); 2236 SC_MOD()->GetUserOptions().AddListener(this); 2237 ppContentSlots = new ScChangeActionContent* [ nContentSlots ]; 2238 memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) ); 2239 } 2240 2241 ScChangeTrack::~ScChangeTrack() 2242 { 2243 SC_MOD()->GetUserOptions().RemoveListener(this); 2244 DtorClear(); 2245 delete [] ppContentSlots; 2246 } 2247 2248 2249 void ScChangeTrack::Init() 2250 { 2251 pFirst = NULL; 2252 pLast = NULL; 2253 pFirstGeneratedDelContent = NULL; 2254 pLastCutMove = NULL; 2255 pLinkInsertCol = NULL; 2256 pLinkInsertRow = NULL; 2257 pLinkInsertTab = NULL; 2258 pLinkMove = NULL; 2259 pBlockModifyMsg = NULL; 2260 nActionMax = 0; 2261 nGeneratedMin = SC_CHGTRACK_GENERATED_START; 2262 nMarkLastSaved = 0; 2263 nStartLastCut = 0; 2264 nEndLastCut = 0; 2265 nLastMerge = 0; 2266 eMergeState = SC_CTMS_NONE; 2267 nLoadedFileFormatVersion = SC_CHGTRACK_FILEFORMAT; 2268 bLoadSave = sal_False; 2269 bInDelete = sal_False; 2270 bInDeleteTop = sal_False; 2271 bInDeleteUndo = sal_False; 2272 bInPasteCut = sal_False; 2273 bUseFixDateTime = sal_False; 2274 bTime100thSeconds = sal_True; 2275 2276 const SvtUserOptions& rUserOpt = SC_MOD()->GetUserOptions(); 2277 aUser = rUserOpt.GetFirstName(); 2278 aUser += ' '; 2279 aUser += (String)rUserOpt.GetLastName(); 2280 aUserCollection.Insert( new StrData( aUser ) ); 2281 } 2282 2283 2284 void ScChangeTrack::DtorClear() 2285 { 2286 ScChangeAction* p; 2287 ScChangeAction* pNext; 2288 for ( p = GetFirst(); p; p = pNext ) 2289 { 2290 pNext = p->GetNext(); 2291 delete p; 2292 } 2293 for ( p = pFirstGeneratedDelContent; p; p = pNext ) 2294 { 2295 pNext = p->GetNext(); 2296 delete p; 2297 } 2298 for ( p = aPasteCutTable.First(); p; p = aPasteCutTable.Next() ) 2299 { 2300 delete p; 2301 } 2302 delete pLastCutMove; 2303 ClearMsgQueue(); 2304 } 2305 2306 2307 void ScChangeTrack::ClearMsgQueue() 2308 { 2309 if ( pBlockModifyMsg ) 2310 { 2311 delete pBlockModifyMsg; 2312 pBlockModifyMsg = NULL; 2313 } 2314 ScChangeTrackMsgInfo* pMsgInfo; 2315 while ( ( pMsgInfo = aMsgStackTmp.Pop() ) != NULL ) 2316 delete pMsgInfo; 2317 while ( ( pMsgInfo = aMsgStackFinal.Pop() ) != NULL ) 2318 delete pMsgInfo; 2319 while ( ( pMsgInfo = aMsgQueue.Get() ) != NULL ) 2320 delete pMsgInfo; 2321 } 2322 2323 2324 void ScChangeTrack::Clear() 2325 { 2326 DtorClear(); 2327 aTable.Clear(); 2328 aGeneratedTable.Clear(); 2329 aPasteCutTable.Clear(); 2330 aUserCollection.FreeAll(); 2331 aUser.Erase(); 2332 Init(); 2333 } 2334 2335 2336 void __EXPORT ScChangeTrack::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 ) 2337 { 2338 if ( !pDoc->IsInDtorClear() ) 2339 { 2340 const SvtUserOptions& rUserOptions = SC_MOD()->GetUserOptions(); 2341 sal_uInt16 nOldCount = aUserCollection.GetCount(); 2342 2343 String aStr( rUserOptions.GetFirstName() ); 2344 aStr += ' '; 2345 aStr += (String)rUserOptions.GetLastName(); 2346 SetUser( aStr ); 2347 2348 if ( aUserCollection.GetCount() != nOldCount ) 2349 { 2350 // New user in collection -> have to repaint because 2351 // colors may be different now (#106697#). 2352 // (Has to be done in the Notify handler, to be sure 2353 // the user collection has already been updated) 2354 2355 SfxObjectShell* pDocSh = pDoc->GetDocumentShell(); 2356 if (pDocSh) 2357 pDocSh->Broadcast( ScPaintHint( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB), PAINT_GRID ) ); 2358 } 2359 } 2360 } 2361 2362 2363 void ScChangeTrack::SetUser( const String& rUser ) 2364 { 2365 if ( IsLoadSave() ) 2366 return ; // nicht die Collection zerschiessen 2367 2368 aUser = rUser; 2369 StrData* pStrData = new StrData( aUser ); 2370 if ( !aUserCollection.Insert( pStrData ) ) 2371 delete pStrData; 2372 } 2373 2374 2375 void ScChangeTrack::StartBlockModify( ScChangeTrackMsgType eMsgType, 2376 sal_uLong nStartAction ) 2377 { 2378 if ( aModifiedLink.IsSet() ) 2379 { 2380 if ( pBlockModifyMsg ) 2381 aMsgStackTmp.Push( pBlockModifyMsg ); // Block im Block 2382 pBlockModifyMsg = new ScChangeTrackMsgInfo; 2383 pBlockModifyMsg->eMsgType = eMsgType; 2384 pBlockModifyMsg->nStartAction = nStartAction; 2385 } 2386 } 2387 2388 2389 void ScChangeTrack::EndBlockModify( sal_uLong nEndAction ) 2390 { 2391 if ( aModifiedLink.IsSet() ) 2392 { 2393 if ( pBlockModifyMsg ) 2394 { 2395 if ( pBlockModifyMsg->nStartAction <= nEndAction ) 2396 { 2397 pBlockModifyMsg->nEndAction = nEndAction; 2398 // Blocks in Blocks aufgeloest 2399 aMsgStackFinal.Push( pBlockModifyMsg ); 2400 } 2401 else 2402 delete pBlockModifyMsg; 2403 pBlockModifyMsg = aMsgStackTmp.Pop(); // evtl. Block im Block 2404 } 2405 if ( !pBlockModifyMsg ) 2406 { 2407 sal_Bool bNew = sal_False; 2408 ScChangeTrackMsgInfo* pMsg; 2409 while ( ( pMsg = aMsgStackFinal.Pop() ) != NULL ) 2410 { 2411 aMsgQueue.Put( pMsg ); 2412 bNew = sal_True; 2413 } 2414 if ( bNew ) 2415 aModifiedLink.Call( this ); 2416 } 2417 } 2418 } 2419 2420 2421 void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType, 2422 sal_uLong nStartAction, sal_uLong nEndAction ) 2423 { 2424 if ( aModifiedLink.IsSet() ) 2425 { 2426 if ( !pBlockModifyMsg || pBlockModifyMsg->eMsgType != eMsgType || 2427 (IsGenerated( nStartAction ) && 2428 (eMsgType == SC_CTM_APPEND || eMsgType == SC_CTM_REMOVE)) ) 2429 { // Append innerhalb von Append z.B. nicht 2430 StartBlockModify( eMsgType, nStartAction ); 2431 EndBlockModify( nEndAction ); 2432 } 2433 } 2434 } 2435 2436 2437 void ScChangeTrack::MasterLinks( ScChangeAction* pAppend ) 2438 { 2439 ScChangeActionType eType = pAppend->GetType(); 2440 2441 if ( eType == SC_CAT_CONTENT ) 2442 { 2443 if ( !IsGenerated( pAppend->GetActionNumber() ) ) 2444 { 2445 SCSIZE nSlot = ComputeContentSlot( 2446 pAppend->GetBigRange().aStart.Row() ); 2447 ((ScChangeActionContent*)pAppend)->InsertInSlot( 2448 &ppContentSlots[nSlot] ); 2449 } 2450 return ; 2451 } 2452 2453 if ( pAppend->IsRejecting() ) 2454 return ; // Rejects haben keine Abhaengigkeiten 2455 2456 switch ( eType ) 2457 { 2458 case SC_CAT_INSERT_COLS : 2459 { 2460 ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( 2461 &pLinkInsertCol, pAppend ); 2462 pAppend->AddLink( NULL, pLink ); 2463 } 2464 break; 2465 case SC_CAT_INSERT_ROWS : 2466 { 2467 ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( 2468 &pLinkInsertRow, pAppend ); 2469 pAppend->AddLink( NULL, pLink ); 2470 } 2471 break; 2472 case SC_CAT_INSERT_TABS : 2473 { 2474 ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( 2475 &pLinkInsertTab, pAppend ); 2476 pAppend->AddLink( NULL, pLink ); 2477 } 2478 break; 2479 case SC_CAT_MOVE : 2480 { 2481 ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( 2482 &pLinkMove, pAppend ); 2483 pAppend->AddLink( NULL, pLink ); 2484 } 2485 break; 2486 default: 2487 { 2488 // added to avoid warnings 2489 } 2490 } 2491 } 2492 2493 2494 void ScChangeTrack::AppendLoaded( ScChangeAction* pAppend ) 2495 { 2496 aTable.Insert( pAppend->GetActionNumber(), pAppend ); 2497 if ( !pLast ) 2498 pFirst = pLast = pAppend; 2499 else 2500 { 2501 pLast->pNext = pAppend; 2502 pAppend->pPrev = pLast; 2503 pLast = pAppend; 2504 } 2505 MasterLinks( pAppend ); 2506 } 2507 2508 2509 void ScChangeTrack::Append( ScChangeAction* pAppend, sal_uLong nAction ) 2510 { 2511 if ( nActionMax < nAction ) 2512 nActionMax = nAction; 2513 pAppend->SetUser( aUser ); 2514 if ( bUseFixDateTime ) 2515 pAppend->SetDateTimeUTC( aFixDateTime ); 2516 pAppend->SetActionNumber( nAction ); 2517 aTable.Insert( nAction, pAppend ); 2518 // UpdateReference Inserts vor Dependencies. 2519 // Delete rejectendes Insert hatte UpdateReference mit Delete-Undo. 2520 // UpdateReference auch wenn pLast==NULL, weil pAppend ein Delete sein 2521 // kann, dass DelContents generiert haben kann 2522 if ( pAppend->IsInsertType() && !pAppend->IsRejecting() ) 2523 UpdateReference( pAppend, sal_False ); 2524 if ( !pLast ) 2525 pFirst = pLast = pAppend; 2526 else 2527 { 2528 pLast->pNext = pAppend; 2529 pAppend->pPrev = pLast; 2530 pLast = pAppend; 2531 Dependencies( pAppend ); 2532 } 2533 // UpdateReference Inserts nicht nach Dependencies. 2534 // Move rejectendes Move hatte UpdateReference mit Move-Undo, Inhalt in 2535 // ToRange nicht deleten. 2536 if ( !pAppend->IsInsertType() && 2537 !(pAppend->GetType() == SC_CAT_MOVE && pAppend->IsRejecting()) ) 2538 UpdateReference( pAppend, sal_False ); 2539 MasterLinks( pAppend ); 2540 2541 if ( aModifiedLink.IsSet() ) 2542 { 2543 NotifyModified( SC_CTM_APPEND, nAction, nAction ); 2544 if ( pAppend->GetType() == SC_CAT_CONTENT ) 2545 { 2546 ScChangeActionContent* pContent = (ScChangeActionContent*) pAppend; 2547 if ( ( pContent = pContent->GetPrevContent() ) != NULL ) 2548 { 2549 sal_uLong nMod = pContent->GetActionNumber(); 2550 NotifyModified( SC_CTM_CHANGE, nMod, nMod ); 2551 } 2552 } 2553 else 2554 NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(), 2555 pLast->GetActionNumber() ); 2556 } 2557 } 2558 2559 2560 void ScChangeTrack::Append( ScChangeAction* pAppend ) 2561 { 2562 Append( pAppend, ++nActionMax ); 2563 } 2564 2565 2566 void ScChangeTrack::AppendDeleteRange( const ScRange& rRange, 2567 ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, SCsTAB nDz ) 2568 { 2569 nStartAction = GetActionMax() + 1; 2570 AppendDeleteRange( rRange, pRefDoc, nDz, 0 ); 2571 nEndAction = GetActionMax(); 2572 } 2573 2574 2575 void ScChangeTrack::AppendDeleteRange( const ScRange& rRange, 2576 ScDocument* pRefDoc, SCsTAB nDz, sal_uLong nRejectingInsert ) 2577 { 2578 SetInDeleteRange( rRange ); 2579 StartBlockModify( SC_CTM_APPEND, GetActionMax() + 1 ); 2580 SCCOL nCol1; 2581 SCROW nRow1; 2582 SCTAB nTab1; 2583 SCCOL nCol2; 2584 SCROW nRow2; 2585 SCTAB nTab2; 2586 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 2587 for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ ) 2588 { 2589 if ( !pRefDoc || nTab < pRefDoc->GetTableCount() ) 2590 { 2591 if ( nCol1 == 0 && nCol2 == MAXCOL ) 2592 { // ganze Zeilen und/oder Tabellen 2593 if ( nRow1 == 0 && nRow2 == MAXROW ) 2594 { // ganze Tabellen 2595 //2do: geht nicht auch komplette Tabelle als ganzes? 2596 ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab ); 2597 for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) 2598 { // spaltenweise ist weniger als zeilenweise 2599 aRange.aStart.SetCol( nCol ); 2600 aRange.aEnd.SetCol( nCol ); 2601 if ( nCol == nCol2 ) 2602 SetInDeleteTop( sal_True ); 2603 AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0, 2604 nTab-nTab1 + nDz, nRejectingInsert ); 2605 } 2606 //! immer noch InDeleteTop 2607 AppendOneDeleteRange( rRange, pRefDoc, 0, 0, 2608 nTab-nTab1 + nDz, nRejectingInsert ); 2609 } 2610 else 2611 { // ganze Zeilen 2612 ScRange aRange( 0, 0, nTab, MAXCOL, 0, nTab ); 2613 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ ) 2614 { 2615 aRange.aStart.SetRow( nRow ); 2616 aRange.aEnd.SetRow( nRow ); 2617 if ( nRow == nRow2 ) 2618 SetInDeleteTop( sal_True ); 2619 AppendOneDeleteRange( aRange, pRefDoc, 0, nRow-nRow1, 2620 0, nRejectingInsert ); 2621 } 2622 } 2623 } 2624 else if ( nRow1 == 0 && nRow2 == MAXROW ) 2625 { // ganze Spalten 2626 ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab ); 2627 for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) 2628 { 2629 aRange.aStart.SetCol( nCol ); 2630 aRange.aEnd.SetCol( nCol ); 2631 if ( nCol == nCol2 ) 2632 SetInDeleteTop( sal_True ); 2633 AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0, 2634 0, nRejectingInsert ); 2635 } 2636 } 2637 else 2638 { 2639 DBG_ERROR( "ScChangeTrack::AppendDeleteRange: Block not supported!" ); 2640 } 2641 SetInDeleteTop( sal_False ); 2642 } 2643 } 2644 EndBlockModify( GetActionMax() ); 2645 } 2646 2647 2648 void ScChangeTrack::AppendOneDeleteRange( const ScRange& rOrgRange, 2649 ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, 2650 sal_uLong nRejectingInsert ) 2651 { 2652 ScRange aTrackRange( rOrgRange ); 2653 if ( nDx ) 2654 { 2655 aTrackRange.aStart.IncCol( -nDx ); 2656 aTrackRange.aEnd.IncCol( -nDx ); 2657 } 2658 if ( nDy ) 2659 { 2660 aTrackRange.aStart.IncRow( -nDy ); 2661 aTrackRange.aEnd.IncRow( -nDy ); 2662 } 2663 if ( nDz ) 2664 { 2665 aTrackRange.aStart.IncTab( -nDz ); 2666 aTrackRange.aEnd.IncTab( -nDz ); 2667 } 2668 ScChangeActionDel* pAct = new ScChangeActionDel( aTrackRange, nDx, nDy, 2669 this ); 2670 // TabDelete keine Contents, sind in einzelnen Spalten 2671 if ( !(rOrgRange.aStart.Col() == 0 && rOrgRange.aStart.Row() == 0 && 2672 rOrgRange.aEnd.Col() == MAXCOL && rOrgRange.aEnd.Row() == MAXROW) ) 2673 LookUpContents( rOrgRange, pRefDoc, -nDx, -nDy, -nDz ); 2674 if ( nRejectingInsert ) 2675 { 2676 pAct->SetRejectAction( nRejectingInsert ); 2677 pAct->SetState( SC_CAS_ACCEPTED ); 2678 } 2679 Append( pAct ); 2680 } 2681 2682 2683 void ScChangeTrack::LookUpContents( const ScRange& rOrgRange, 2684 ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 2685 { 2686 if ( pRefDoc ) 2687 { 2688 ScAddress aPos; 2689 ScBigAddress aBigPos; 2690 ScCellIterator aIter( pRefDoc, rOrgRange ); 2691 ScBaseCell* pCell = aIter.GetFirst(); 2692 while ( pCell ) 2693 { 2694 if ( ScChangeActionContent::GetContentCellType( pCell ) ) 2695 { 2696 aBigPos.Set( aIter.GetCol() + nDx, aIter.GetRow() + nDy, 2697 aIter.GetTab() + nDz ); 2698 ScChangeActionContent* pContent = SearchContentAt( aBigPos, NULL ); 2699 if ( !pContent ) 2700 { // nicht getrackte Contents 2701 aPos.Set( aIter.GetCol() + nDx, aIter.GetRow() + nDy, 2702 aIter.GetTab() + nDz ); 2703 GenerateDelContent( aPos, pCell, pRefDoc ); 2704 //! der Content wird hier _nicht_ per AddContent hinzugefuegt, 2705 //! sondern in UpdateReference, um z.B. auch kreuzende Deletes 2706 //! korrekt zu erfassen 2707 } 2708 } 2709 pCell = aIter.GetNext(); 2710 } 2711 } 2712 } 2713 2714 2715 void ScChangeTrack::AppendMove( const ScRange& rFromRange, 2716 const ScRange& rToRange, ScDocument* pRefDoc ) 2717 { 2718 ScChangeActionMove* pAct = new ScChangeActionMove( rFromRange, rToRange, this ); 2719 LookUpContents( rToRange, pRefDoc, 0, 0, 0 ); // ueberschriebene Contents 2720 Append( pAct ); 2721 } 2722 2723 2724 // static 2725 sal_Bool ScChangeTrack::IsMatrixFormulaRangeDifferent( const ScBaseCell* pOldCell, 2726 const ScBaseCell* pNewCell ) 2727 { 2728 SCCOL nC1, nC2; 2729 SCROW nR1, nR2; 2730 nC1 = nC2 = 0; 2731 nR1 = nR2 = 0; 2732 if ( pOldCell && (pOldCell->GetCellType() == CELLTYPE_FORMULA) && 2733 ((const ScFormulaCell*)pOldCell)->GetMatrixFlag() == MM_FORMULA ) 2734 ((const ScFormulaCell*)pOldCell)->GetMatColsRows( nC1, nR1 ); 2735 if ( pNewCell && (pNewCell->GetCellType() == CELLTYPE_FORMULA) && 2736 ((const ScFormulaCell*)pNewCell)->GetMatrixFlag() == MM_FORMULA ) 2737 ((const ScFormulaCell*)pNewCell)->GetMatColsRows( nC1, nR1 ); 2738 return nC1 != nC2 || nR1 != nR2; 2739 } 2740 2741 2742 void ScChangeTrack::AppendContent( const ScAddress& rPos, 2743 const String& rNewValue, ScBaseCell* pOldCell ) 2744 { 2745 String aOldValue; 2746 ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pDoc, rPos ); 2747 if ( aOldValue != rNewValue || 2748 IsMatrixFormulaRangeDifferent( pOldCell, NULL ) ) 2749 { // nur wirkliche Aenderung tracken 2750 ScRange aRange( rPos ); 2751 ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); 2752 pAct->SetOldValue( pOldCell, pDoc, pDoc ); 2753 pAct->SetNewValue( rNewValue, pDoc ); 2754 Append( pAct ); 2755 } 2756 } 2757 2758 2759 void ScChangeTrack::AppendContent( const ScAddress& rPos, 2760 const ScBaseCell* pOldCell, sal_uLong nOldFormat, ScDocument* pRefDoc ) 2761 { 2762 if ( !pRefDoc ) 2763 pRefDoc = pDoc; 2764 String aOldValue; 2765 ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pRefDoc, nOldFormat ); 2766 String aNewValue; 2767 ScBaseCell* pNewCell = pDoc->GetCell( rPos ); 2768 ScChangeActionContent::GetStringOfCell( aNewValue, pNewCell, pDoc, rPos ); 2769 if ( aOldValue != aNewValue || 2770 IsMatrixFormulaRangeDifferent( pOldCell, pNewCell ) ) 2771 { // nur wirkliche Aenderung tracken 2772 ScRange aRange( rPos ); 2773 ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); 2774 pAct->SetOldValue( pOldCell, pRefDoc, pDoc, nOldFormat ); 2775 pAct->SetNewValue( pNewCell, pDoc ); 2776 Append( pAct ); 2777 } 2778 } 2779 2780 2781 void ScChangeTrack::AppendContent( const ScAddress& rPos, 2782 ScDocument* pRefDoc ) 2783 { 2784 String aOldValue; 2785 ScBaseCell* pOldCell = pRefDoc->GetCell( rPos ); 2786 ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pRefDoc, rPos ); 2787 String aNewValue; 2788 ScBaseCell* pNewCell = pDoc->GetCell( rPos ); 2789 ScChangeActionContent::GetStringOfCell( aNewValue, pNewCell, pDoc, rPos ); 2790 if ( aOldValue != aNewValue || 2791 IsMatrixFormulaRangeDifferent( pOldCell, pNewCell ) ) 2792 { // nur wirkliche Aenderung tracken 2793 ScRange aRange( rPos ); 2794 ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); 2795 pAct->SetOldValue( pOldCell, pRefDoc, pDoc ); 2796 pAct->SetNewValue( pNewCell, pDoc ); 2797 Append( pAct ); 2798 } 2799 } 2800 2801 2802 void ScChangeTrack::AppendContent( const ScAddress& rPos, 2803 const ScBaseCell* pOldCell ) 2804 { 2805 if ( ScChangeActionContent::NeedsNumberFormat( pOldCell ) ) 2806 AppendContent( rPos, pOldCell, pDoc->GetNumberFormat( rPos ), pDoc ); 2807 else 2808 AppendContent( rPos, pOldCell, 0, pDoc ); 2809 } 2810 2811 2812 void ScChangeTrack::SetLastCutMoveRange( const ScRange& rRange, 2813 ScDocument* pRefDoc ) 2814 { 2815 if ( pLastCutMove ) 2816 { 2817 // ToRange nicht mit Deletes linken und nicht in der Groesse aendern, 2818 // eigentlich unnoetig, da ein Delete vorher in 2819 // ScViewFunc::PasteFromClip ein ResetLastCut ausloest 2820 ScBigRange& r = pLastCutMove->GetBigRange(); 2821 r.aEnd.SetCol( -1 ); 2822 r.aEnd.SetRow( -1 ); 2823 r.aEnd.SetTab( -1 ); 2824 r.aStart.SetCol( -1 - (rRange.aEnd.Col() - rRange.aStart.Col()) ); 2825 r.aStart.SetRow( -1 - (rRange.aEnd.Row() - rRange.aStart.Row()) ); 2826 r.aStart.SetTab( -1 - (rRange.aEnd.Tab() - rRange.aStart.Tab()) ); 2827 // zu ueberschreibende Contents im FromRange 2828 LookUpContents( rRange, pRefDoc, 0, 0, 0 ); 2829 } 2830 } 2831 2832 2833 void ScChangeTrack::AppendContentRange( const ScRange& rRange, 2834 ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, 2835 ScChangeActionClipMode eClipMode ) 2836 { 2837 if ( eClipMode == SC_CACM_CUT ) 2838 { 2839 ResetLastCut(); 2840 pLastCutMove = new ScChangeActionMove( rRange, rRange, this ); 2841 SetLastCutMoveRange( rRange, pRefDoc ); 2842 } 2843 SCCOL nCol1; 2844 SCROW nRow1; 2845 SCTAB nTab1; 2846 SCCOL nCol2; 2847 SCROW nRow2; 2848 SCTAB nTab2; 2849 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 2850 sal_Bool bDoContents; 2851 if ( eClipMode == SC_CACM_PASTE && HasLastCut() ) 2852 { 2853 bDoContents = sal_False; 2854 SetInPasteCut( sal_True ); 2855 // Paste und Cut abstimmen, Paste kann groesserer Range sein 2856 ScRange aRange( rRange ); 2857 ScBigRange& r = pLastCutMove->GetBigRange(); 2858 SCCOL nTmpCol; 2859 if ( (nTmpCol = (SCCOL) (r.aEnd.Col() - r.aStart.Col())) != (nCol2 - nCol1) ) 2860 { 2861 aRange.aEnd.SetCol( aRange.aStart.Col() + nTmpCol ); 2862 nCol1 += nTmpCol + 1; 2863 bDoContents = sal_True; 2864 } 2865 SCROW nTmpRow; 2866 if ( (nTmpRow = (SCROW) (r.aEnd.Row() - r.aStart.Row())) != (nRow2 - nRow1) ) 2867 { 2868 aRange.aEnd.SetRow( aRange.aStart.Row() + nTmpRow ); 2869 nRow1 += nTmpRow + 1; 2870 bDoContents = sal_True; 2871 } 2872 SCTAB nTmpTab; 2873 if ( (nTmpTab = (SCTAB) (r.aEnd.Tab() - r.aStart.Tab())) != (nTab2 - nTab1) ) 2874 { 2875 aRange.aEnd.SetTab( aRange.aStart.Tab() + nTmpTab ); 2876 nTab1 += nTmpTab + 1; 2877 bDoContents = sal_True; 2878 } 2879 r = aRange; 2880 Undo( nStartLastCut, nEndLastCut ); // hier werden sich die Cuts gemerkt 2881 //! StartAction erst nach Undo 2882 nStartAction = GetActionMax() + 1; 2883 StartBlockModify( SC_CTM_APPEND, nStartAction ); 2884 // zu ueberschreibende Contents im ToRange 2885 LookUpContents( aRange, pRefDoc, 0, 0, 0 ); 2886 pLastCutMove->SetStartLastCut( nStartLastCut ); 2887 pLastCutMove->SetEndLastCut( nEndLastCut ); 2888 Append( pLastCutMove ); 2889 pLastCutMove = NULL; 2890 ResetLastCut(); 2891 SetInPasteCut( sal_False ); 2892 } 2893 else 2894 { 2895 bDoContents = sal_True; 2896 nStartAction = GetActionMax() + 1; 2897 StartBlockModify( SC_CTM_APPEND, nStartAction ); 2898 } 2899 if ( bDoContents ) 2900 { 2901 ScAddress aPos; 2902 for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ ) 2903 { 2904 aPos.SetTab( nTab ); 2905 for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) 2906 { 2907 aPos.SetCol( nCol ); 2908 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ ) 2909 { 2910 aPos.SetRow( nRow ); 2911 AppendContent( aPos, pRefDoc ); 2912 } 2913 } 2914 } 2915 } 2916 nEndAction = GetActionMax(); 2917 EndBlockModify( nEndAction ); 2918 if ( eClipMode == SC_CACM_CUT ) 2919 { 2920 nStartLastCut = nStartAction; 2921 nEndLastCut = nEndAction; 2922 } 2923 } 2924 2925 2926 void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument* pRefDoc, 2927 sal_uLong& nStartAction, sal_uLong& nEndAction ) 2928 { 2929 ScDocumentIterator aIter( pRefDoc, 0, MAXTAB ); 2930 if ( aIter.GetFirst() ) 2931 { 2932 nStartAction = GetActionMax() + 1; 2933 StartBlockModify( SC_CTM_APPEND, nStartAction ); 2934 SvNumberFormatter* pFormatter = pRefDoc->GetFormatTable(); 2935 do 2936 { 2937 SCCOL nCol; 2938 SCROW nRow; 2939 SCTAB nTab; 2940 aIter.GetPos( nCol, nRow, nTab ); 2941 ScAddress aPos( nCol, nRow, nTab ); 2942 AppendContent( aPos, aIter.GetCell(), 2943 aIter.GetPattern()->GetNumberFormat( pFormatter ), pRefDoc ); 2944 } while ( aIter.GetNext() ); 2945 nEndAction = GetActionMax(); 2946 EndBlockModify( nEndAction ); 2947 } 2948 else 2949 nStartAction = nEndAction = 0; 2950 } 2951 2952 2953 ScChangeActionContent* ScChangeTrack::AppendContentOnTheFly( 2954 const ScAddress& rPos, ScBaseCell* pOldCell, ScBaseCell* pNewCell, 2955 sal_uLong nOldFormat, sal_uLong nNewFormat ) 2956 { 2957 ScRange aRange( rPos ); 2958 ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); 2959 pAct->SetOldNewCells( pOldCell, nOldFormat, pNewCell, nNewFormat, pDoc ); 2960 Append( pAct ); 2961 return pAct; 2962 } 2963 2964 2965 void ScChangeTrack::AppendInsert( const ScRange& rRange ) 2966 { 2967 ScChangeActionIns* pAct = new ScChangeActionIns( rRange ); 2968 Append( pAct ); 2969 } 2970 2971 2972 void ScChangeTrack::DeleteCellEntries( ScChangeActionCellListEntry*& pCellList, 2973 ScChangeAction* pDeletor ) 2974 { 2975 ScChangeActionCellListEntry* pE = pCellList; 2976 while ( pE ) 2977 { 2978 ScChangeActionCellListEntry* pNext = pE->pNext; 2979 pE->pContent->RemoveDeletedIn( pDeletor ); 2980 if ( IsGenerated( pE->pContent->GetActionNumber() ) && 2981 !pE->pContent->IsDeletedIn() ) 2982 DeleteGeneratedDelContent( pE->pContent ); 2983 delete pE; 2984 pE = pNext; 2985 } 2986 pCellList = NULL; 2987 } 2988 2989 2990 ScChangeActionContent* ScChangeTrack::GenerateDelContent( 2991 const ScAddress& rPos, const ScBaseCell* pCell, 2992 const ScDocument* pFromDoc ) 2993 { 2994 ScChangeActionContent* pContent = new ScChangeActionContent( 2995 ScRange( rPos ) ); 2996 pContent->SetActionNumber( --nGeneratedMin ); 2997 // nur NewValue 2998 ScChangeActionContent::SetValue( pContent->aNewValue, pContent->pNewCell, 2999 rPos, pCell, pFromDoc, pDoc ); 3000 // pNextContent und pPrevContent werden nicht gesetzt 3001 if ( pFirstGeneratedDelContent ) 3002 { // vorne reinhaengen 3003 pFirstGeneratedDelContent->pPrev = pContent; 3004 pContent->pNext = pFirstGeneratedDelContent; 3005 } 3006 pFirstGeneratedDelContent = pContent; 3007 aGeneratedTable.Insert( nGeneratedMin, pContent ); 3008 NotifyModified( SC_CTM_APPEND, nGeneratedMin, nGeneratedMin ); 3009 return pContent; 3010 } 3011 3012 3013 void ScChangeTrack::DeleteGeneratedDelContent( ScChangeActionContent* pContent ) 3014 { 3015 sal_uLong nAct = pContent->GetActionNumber(); 3016 aGeneratedTable.Remove( nAct ); 3017 if ( pFirstGeneratedDelContent == pContent ) 3018 pFirstGeneratedDelContent = (ScChangeActionContent*) pContent->pNext; 3019 if ( pContent->pNext ) 3020 pContent->pNext->pPrev = pContent->pPrev; 3021 if ( pContent->pPrev ) 3022 pContent->pPrev->pNext = pContent->pNext; 3023 delete pContent; 3024 NotifyModified( SC_CTM_REMOVE, nAct, nAct ); 3025 if ( nAct == nGeneratedMin ) 3026 ++nGeneratedMin; //! erst nach NotifyModified wg. IsGenerated 3027 } 3028 3029 3030 ScChangeActionContent* ScChangeTrack::SearchContentAt( 3031 const ScBigAddress& rPos, ScChangeAction* pButNotThis ) const 3032 { 3033 SCSIZE nSlot = ComputeContentSlot( rPos.Row() ); 3034 for ( ScChangeActionContent* p = ppContentSlots[nSlot]; p; 3035 p = p->GetNextInSlot() ) 3036 { 3037 if ( p != pButNotThis && !p->IsDeletedIn() && 3038 p->GetBigRange().aStart == rPos ) 3039 { 3040 ScChangeActionContent* pContent = p->GetTopContent(); 3041 if ( !pContent->IsDeletedIn() ) 3042 return pContent; 3043 } 3044 } 3045 return NULL; 3046 } 3047 3048 3049 void ScChangeTrack::AddDependentWithNotify( ScChangeAction* pParent, 3050 ScChangeAction* pDependent ) 3051 { 3052 ScChangeActionLinkEntry* pLink = pParent->AddDependent( pDependent ); 3053 pDependent->AddLink( pParent, pLink ); 3054 if ( aModifiedLink.IsSet() ) 3055 { 3056 sal_uLong nMod = pParent->GetActionNumber(); 3057 NotifyModified( SC_CTM_PARENT, nMod, nMod ); 3058 } 3059 } 3060 3061 3062 void ScChangeTrack::Dependencies( ScChangeAction* pAct ) 3063 { 3064 // Finde die letzte Abhaengigkeit fuer jeweils Col/Row/Tab. 3065 // Content an gleicher Position verketten. 3066 // Move Abhaengigkeiten. 3067 ScChangeActionType eActType = pAct->GetType(); 3068 if ( eActType == SC_CAT_REJECT || 3069 (eActType == SC_CAT_MOVE && pAct->IsRejecting()) ) 3070 return ; // diese Rejects sind nicht abhaengig 3071 3072 if ( eActType == SC_CAT_CONTENT ) 3073 { 3074 if ( !(((ScChangeActionContent*)pAct)->GetNextContent() || 3075 ((ScChangeActionContent*)pAct)->GetPrevContent()) ) 3076 { // Contents an gleicher Position verketten 3077 ScChangeActionContent* pContent = SearchContentAt( 3078 pAct->GetBigRange().aStart, pAct ); 3079 if ( pContent ) 3080 { 3081 pContent->SetNextContent( (ScChangeActionContent*) pAct ); 3082 ((ScChangeActionContent*)pAct)->SetPrevContent( pContent ); 3083 } 3084 } 3085 const ScBaseCell* pCell = ((ScChangeActionContent*)pAct)->GetNewCell(); 3086 if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATREF ) 3087 { 3088 ScAddress aOrg; 3089 ((const ScFormulaCell*)pCell)->GetMatrixOrigin( aOrg ); 3090 ScChangeActionContent* pContent = SearchContentAt( aOrg, pAct ); 3091 if ( pContent && pContent->IsMatrixOrigin() ) 3092 { 3093 AddDependentWithNotify( pContent, pAct ); 3094 } 3095 else 3096 { 3097 DBG_ERRORFILE( "ScChangeTrack::Dependencies: MatOrg not found" ); 3098 } 3099 } 3100 } 3101 3102 if ( !(pLinkInsertCol || pLinkInsertRow || pLinkInsertTab || pLinkMove) ) 3103 return ; // keine Dependencies 3104 if ( pAct->IsRejecting() ) 3105 return ; // ausser Content keine Dependencies 3106 3107 // Insert in einem entsprechenden Insert haengt davon ab, sonst muesste 3108 // der vorherige Insert gesplittet werden. 3109 // Sich kreuzende Inserts und Deletes sind nicht abhaengig. 3110 // Alles andere ist abhaengig. 3111 3112 // Der zuletzt eingelinkte Insert steht am Anfang einer Kette, 3113 // also genau richtig 3114 3115 const ScBigRange& rRange = pAct->GetBigRange(); 3116 sal_Bool bActNoInsert = !pAct->IsInsertType(); 3117 sal_Bool bActColDel = ( eActType == SC_CAT_DELETE_COLS ); 3118 sal_Bool bActRowDel = ( eActType == SC_CAT_DELETE_ROWS ); 3119 sal_Bool bActTabDel = ( eActType == SC_CAT_DELETE_TABS ); 3120 3121 if ( pLinkInsertCol && (eActType == SC_CAT_INSERT_COLS || 3122 (bActNoInsert && !bActRowDel && !bActTabDel)) ) 3123 { 3124 for ( ScChangeActionLinkEntry* pL = pLinkInsertCol; pL; pL = pL->GetNext() ) 3125 { 3126 ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction(); 3127 if ( !pTest->IsRejected() && 3128 pTest->GetBigRange().Intersects( rRange ) ) 3129 { 3130 AddDependentWithNotify( pTest, pAct ); 3131 break; // for 3132 } 3133 } 3134 } 3135 if ( pLinkInsertRow && (eActType == SC_CAT_INSERT_ROWS || 3136 (bActNoInsert && !bActColDel && !bActTabDel)) ) 3137 { 3138 for ( ScChangeActionLinkEntry* pL = pLinkInsertRow; pL; pL = pL->GetNext() ) 3139 { 3140 ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction(); 3141 if ( !pTest->IsRejected() && 3142 pTest->GetBigRange().Intersects( rRange ) ) 3143 { 3144 AddDependentWithNotify( pTest, pAct ); 3145 break; // for 3146 } 3147 } 3148 } 3149 if ( pLinkInsertTab && (eActType == SC_CAT_INSERT_TABS || 3150 (bActNoInsert && !bActColDel && !bActRowDel)) ) 3151 { 3152 for ( ScChangeActionLinkEntry* pL = pLinkInsertTab; pL; pL = pL->GetNext() ) 3153 { 3154 ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction(); 3155 if ( !pTest->IsRejected() && 3156 pTest->GetBigRange().Intersects( rRange ) ) 3157 { 3158 AddDependentWithNotify( pTest, pAct ); 3159 break; // for 3160 } 3161 } 3162 } 3163 3164 if ( pLinkMove ) 3165 { 3166 if ( eActType == SC_CAT_CONTENT ) 3167 { // Content ist von FromRange abhaengig 3168 const ScBigAddress& rPos = rRange.aStart; 3169 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) 3170 { 3171 ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction(); 3172 if ( !pTest->IsRejected() && 3173 pTest->GetFromRange().In( rPos ) ) 3174 { 3175 AddDependentWithNotify( pTest, pAct ); 3176 } 3177 } 3178 } 3179 else if ( eActType == SC_CAT_MOVE ) 3180 { // Move FromRange ist von ToRange abhaengig 3181 const ScBigRange& rFromRange = ((ScChangeActionMove*)pAct)->GetFromRange(); 3182 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) 3183 { 3184 ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction(); 3185 if ( !pTest->IsRejected() && 3186 pTest->GetBigRange().Intersects( rFromRange ) ) 3187 { 3188 AddDependentWithNotify( pTest, pAct ); 3189 } 3190 } 3191 } 3192 else 3193 { // Inserts und Deletes sind abhaengig, sobald sie FromRange oder 3194 // ToRange kreuzen 3195 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) 3196 { 3197 ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction(); 3198 if ( !pTest->IsRejected() && 3199 (pTest->GetFromRange().Intersects( rRange ) || 3200 pTest->GetBigRange().Intersects( rRange )) ) 3201 { 3202 AddDependentWithNotify( pTest, pAct ); 3203 } 3204 } 3205 } 3206 } 3207 } 3208 3209 3210 void ScChangeTrack::Remove( ScChangeAction* pRemove ) 3211 { 3212 // aus Track ausklinken 3213 sal_uLong nAct = pRemove->GetActionNumber(); 3214 aTable.Remove( nAct ); 3215 if ( nAct == nActionMax ) 3216 --nActionMax; 3217 if ( pRemove == pLast ) 3218 pLast = pRemove->pPrev; 3219 if ( pRemove == pFirst ) 3220 pFirst = pRemove->pNext; 3221 if ( nAct == nMarkLastSaved ) 3222 nMarkLastSaved = 3223 ( pRemove->pPrev ? pRemove->pPrev->GetActionNumber() : 0 ); 3224 3225 // aus der globalen Kette ausklinken 3226 if ( pRemove->pNext ) 3227 pRemove->pNext->pPrev = pRemove->pPrev; 3228 if ( pRemove->pPrev ) 3229 pRemove->pPrev->pNext = pRemove->pNext; 3230 3231 // Dependencies nicht loeschen, passiert on delete automatisch durch 3232 // LinkEntry, ohne Listen abzuklappern 3233 3234 if ( aModifiedLink.IsSet() ) 3235 { 3236 NotifyModified( SC_CTM_REMOVE, nAct, nAct ); 3237 if ( pRemove->GetType() == SC_CAT_CONTENT ) 3238 { 3239 ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove; 3240 if ( ( pContent = pContent->GetPrevContent() ) != NULL ) 3241 { 3242 sal_uLong nMod = pContent->GetActionNumber(); 3243 NotifyModified( SC_CTM_CHANGE, nMod, nMod ); 3244 } 3245 } 3246 else if ( pLast ) 3247 NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(), 3248 pLast->GetActionNumber() ); 3249 } 3250 3251 if ( IsInPasteCut() && pRemove->GetType() == SC_CAT_CONTENT ) 3252 { //! Content wird wiederverwertet 3253 ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove; 3254 pContent->RemoveAllLinks(); 3255 pContent->ClearTrack(); 3256 pContent->pNext = pContent->pPrev = NULL; 3257 pContent->pNextContent = pContent->pPrevContent = NULL; 3258 } 3259 } 3260 3261 3262 void ScChangeTrack::Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge ) 3263 { 3264 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 3265 if ( bMerge ) 3266 { 3267 SetMergeState( SC_CTMS_UNDO ); 3268 } 3269 3270 if ( nStartAction == 0 ) 3271 ++nStartAction; 3272 if ( nEndAction > nActionMax ) 3273 nEndAction = nActionMax; 3274 if ( nEndAction && nStartAction <= nEndAction ) 3275 { 3276 if ( nStartAction == nStartLastCut && nEndAction == nEndLastCut && 3277 !IsInPasteCut() ) 3278 ResetLastCut(); 3279 StartBlockModify( SC_CTM_REMOVE, nStartAction ); 3280 for ( sal_uLong j = nEndAction; j >= nStartAction; --j ) 3281 { // rueckwaerts um evtl. nActionMax zu recyclen und schnelleren 3282 // Zugriff via pLast, Deletes in richtiger Reihenfolge 3283 ScChangeAction* pAct = ( (j == nActionMax && pLast && 3284 pLast->GetActionNumber() == j) ? pLast : GetAction( j ) ); 3285 if ( pAct ) 3286 { 3287 if ( pAct->IsDeleteType() ) 3288 { 3289 if ( j == nEndAction || (pAct != pLast && 3290 ((ScChangeActionDel*)pAct)->IsTopDelete()) ) 3291 { 3292 SetInDeleteTop( sal_True ); 3293 SetInDeleteRange( ((ScChangeActionDel*)pAct)-> 3294 GetOverAllRange().MakeRange() ); 3295 } 3296 } 3297 UpdateReference( pAct, sal_True ); 3298 SetInDeleteTop( sal_False ); 3299 Remove( pAct ); 3300 if ( IsInPasteCut() ) 3301 aPasteCutTable.Insert( pAct->GetActionNumber(), pAct ); 3302 else 3303 { 3304 if ( j == nStartAction && pAct->GetType() == SC_CAT_MOVE ) 3305 { 3306 ScChangeActionMove* pMove = (ScChangeActionMove*) pAct; 3307 sal_uLong nStart = pMove->GetStartLastCut(); 3308 sal_uLong nEnd = pMove->GetEndLastCut(); 3309 if ( nStart && nStart <= nEnd ) 3310 { // LastCut wiederherstellen 3311 //! Links vor Cut-Append aufloesen 3312 pMove->RemoveAllLinks(); 3313 StartBlockModify( SC_CTM_APPEND, nStart ); 3314 for ( sal_uLong nCut = nStart; nCut <= nEnd; nCut++ ) 3315 { 3316 ScChangeAction* pCut = aPasteCutTable.Remove( nCut ); 3317 if ( pCut ) 3318 { 3319 DBG_ASSERT( !aTable.Get( nCut ), "ScChangeTrack::Undo: nCut dup" ); 3320 Append( pCut, nCut ); 3321 } 3322 else 3323 { 3324 DBG_ERROR( "ScChangeTrack::Undo: nCut not found" ); 3325 } 3326 } 3327 EndBlockModify( nEnd ); 3328 ResetLastCut(); 3329 nStartLastCut = nStart; 3330 nEndLastCut = nEnd; 3331 pLastCutMove = pMove; 3332 SetLastCutMoveRange( 3333 pMove->GetFromRange().MakeRange(), pDoc ); 3334 } 3335 else 3336 delete pMove; 3337 } 3338 else 3339 delete pAct; 3340 } 3341 } 3342 } 3343 EndBlockModify( nEndAction ); 3344 } 3345 3346 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 3347 if ( bMerge ) 3348 { 3349 SetMergeState( SC_CTMS_OTHER ); 3350 } 3351 } 3352 3353 3354 // static 3355 sal_Bool ScChangeTrack::MergeIgnore( const ScChangeAction& rAction, sal_uLong nFirstMerge ) 3356 { 3357 if ( rAction.IsRejected() ) 3358 return sal_True; // da kommt noch eine passende Reject-Action 3359 3360 if ( rAction.IsRejecting() && rAction.GetRejectAction() >= nFirstMerge ) 3361 return sal_True; // da ist sie 3362 3363 return sal_False; // alles andere 3364 } 3365 3366 3367 void ScChangeTrack::MergePrepare( ScChangeAction* pFirstMerge, bool bShared ) 3368 { 3369 SetMergeState( SC_CTMS_PREPARE ); 3370 sal_uLong nFirstMerge = pFirstMerge->GetActionNumber(); 3371 ScChangeAction* pAct = GetLast(); 3372 if ( pAct ) 3373 { 3374 SetLastMerge( pAct->GetActionNumber() ); 3375 while ( pAct ) 3376 { // rueckwaerts, Deletes in richtiger Reihenfolge 3377 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 3378 if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) ) 3379 { 3380 if ( pAct->IsDeleteType() ) 3381 { 3382 if ( ((ScChangeActionDel*)pAct)->IsTopDelete() ) 3383 { 3384 SetInDeleteTop( sal_True ); 3385 SetInDeleteRange( ((ScChangeActionDel*)pAct)-> 3386 GetOverAllRange().MakeRange() ); 3387 } 3388 } 3389 UpdateReference( pAct, sal_True ); 3390 SetInDeleteTop( sal_False ); 3391 pAct->DeleteCellEntries(); // sonst GPF bei Track Clear() 3392 } 3393 pAct = ( pAct == pFirstMerge ? NULL : pAct->GetPrev() ); 3394 } 3395 } 3396 SetMergeState( SC_CTMS_OTHER ); //! nachfolgende per default MergeOther 3397 } 3398 3399 3400 void ScChangeTrack::MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared ) 3401 { 3402 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 3403 if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) ) 3404 { 3405 SetMergeState( SC_CTMS_OWN ); 3406 if ( pAct->IsDeleteType() ) 3407 { 3408 if ( ((ScChangeActionDel*)pAct)->IsTopDelete() ) 3409 { 3410 SetInDeleteTop( sal_True ); 3411 SetInDeleteRange( ((ScChangeActionDel*)pAct)-> 3412 GetOverAllRange().MakeRange() ); 3413 } 3414 } 3415 UpdateReference( pAct, sal_False ); 3416 SetInDeleteTop( sal_False ); 3417 SetMergeState( SC_CTMS_OTHER ); //! nachfolgende per default MergeOther 3418 } 3419 } 3420 3421 3422 void ScChangeTrack::UpdateReference( ScChangeAction* pAct, sal_Bool bUndo ) 3423 { 3424 ScChangeActionType eActType = pAct->GetType(); 3425 if ( eActType == SC_CAT_CONTENT || eActType == SC_CAT_REJECT ) 3426 return ; 3427 3428 //! Formelzellen haengen nicht im Dokument 3429 sal_Bool bOldAutoCalc = pDoc->GetAutoCalc(); 3430 pDoc->SetAutoCalc( sal_False ); 3431 sal_Bool bOldNoListening = pDoc->GetNoListening(); 3432 pDoc->SetNoListening( sal_True ); 3433 //! Formelzellen ExpandRefs synchronisiert zu denen im Dokument 3434 sal_Bool bOldExpandRefs = pDoc->IsExpandRefs(); 3435 if ( (!bUndo && pAct->IsInsertType()) || (bUndo && pAct->IsDeleteType()) ) 3436 pDoc->SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() ); 3437 3438 if ( pAct->IsDeleteType() ) 3439 { 3440 SetInDeleteUndo( bUndo ); 3441 SetInDelete( sal_True ); 3442 } 3443 else if ( GetMergeState() == SC_CTMS_OWN ) 3444 { 3445 // Referenzen von Formelzellen wiederherstellen, 3446 // vorheriges MergePrepare war bei einem Insert wie ein Delete 3447 if ( pAct->IsInsertType() ) 3448 SetInDeleteUndo( sal_True ); 3449 } 3450 3451 //! erst die generated, als waeren sie vorher getrackt worden 3452 if ( pFirstGeneratedDelContent ) 3453 UpdateReference( (ScChangeAction**)&pFirstGeneratedDelContent, pAct, 3454 bUndo ); 3455 UpdateReference( &pFirst, pAct, bUndo ); 3456 3457 SetInDelete( sal_False ); 3458 SetInDeleteUndo( sal_False ); 3459 3460 pDoc->SetExpandRefs( bOldExpandRefs ); 3461 pDoc->SetNoListening( bOldNoListening ); 3462 pDoc->SetAutoCalc( bOldAutoCalc ); 3463 } 3464 3465 3466 void ScChangeTrack::UpdateReference( ScChangeAction** ppFirstAction, 3467 ScChangeAction* pAct, sal_Bool bUndo ) 3468 { 3469 ScChangeActionType eActType = pAct->GetType(); 3470 sal_Bool bGeneratedDelContents = 3471 ( ppFirstAction == (ScChangeAction**)&pFirstGeneratedDelContent ); 3472 const ScBigRange& rOrgRange = pAct->GetBigRange(); 3473 ScBigRange aRange( rOrgRange ); 3474 ScBigRange aDelRange( rOrgRange ); 3475 sal_Int32 nDx, nDy, nDz; 3476 nDx = nDy = nDz = 0; 3477 UpdateRefMode eMode = URM_INSDEL; 3478 sal_Bool bDel = sal_False; 3479 switch ( eActType ) 3480 { 3481 case SC_CAT_INSERT_COLS : 3482 aRange.aEnd.SetCol( nInt32Max ); 3483 nDx = rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1; 3484 break; 3485 case SC_CAT_INSERT_ROWS : 3486 aRange.aEnd.SetRow( nInt32Max ); 3487 nDy = rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1; 3488 break; 3489 case SC_CAT_INSERT_TABS : 3490 aRange.aEnd.SetTab( nInt32Max ); 3491 nDz = rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1; 3492 break; 3493 case SC_CAT_DELETE_COLS : 3494 aRange.aEnd.SetCol( nInt32Max ); 3495 nDx = -(rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1); 3496 aDelRange.aEnd.SetCol( aDelRange.aStart.Col() - nDx - 1 ); 3497 bDel = sal_True; 3498 break; 3499 case SC_CAT_DELETE_ROWS : 3500 aRange.aEnd.SetRow( nInt32Max ); 3501 nDy = -(rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1); 3502 aDelRange.aEnd.SetRow( aDelRange.aStart.Row() - nDy - 1 ); 3503 bDel = sal_True; 3504 break; 3505 case SC_CAT_DELETE_TABS : 3506 aRange.aEnd.SetTab( nInt32Max ); 3507 nDz = -(rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1); 3508 aDelRange.aEnd.SetTab( aDelRange.aStart.Tab() - nDz - 1 ); 3509 bDel = sal_True; 3510 break; 3511 case SC_CAT_MOVE : 3512 eMode = URM_MOVE; 3513 ((ScChangeActionMove*)pAct)->GetDelta( nDx, nDy, nDz ); 3514 break; 3515 default: 3516 DBG_ERROR( "ScChangeTrack::UpdateReference: unknown Type" ); 3517 } 3518 if ( bUndo ) 3519 { 3520 nDx = -nDx; 3521 nDy = -nDy; 3522 nDz = -nDz; 3523 } 3524 if ( bDel ) 3525 { //! fuer diesen Mechanismus gilt: 3526 //! es gibt nur ganze, einfache geloeschte Spalten/Zeilen 3527 ScChangeActionDel* pActDel = (ScChangeActionDel*) pAct; 3528 if ( !bUndo ) 3529 { // Delete 3530 ScChangeActionType eInsType = SC_CAT_NONE; // for Insert-Undo-"Deletes" 3531 switch ( eActType ) 3532 { 3533 case SC_CAT_DELETE_COLS : 3534 eInsType = SC_CAT_INSERT_COLS; 3535 break; 3536 case SC_CAT_DELETE_ROWS : 3537 eInsType = SC_CAT_INSERT_ROWS; 3538 break; 3539 case SC_CAT_DELETE_TABS : 3540 eInsType = SC_CAT_INSERT_TABS; 3541 break; 3542 default: 3543 { 3544 // added to avoid warnings 3545 } 3546 } 3547 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3548 { 3549 if ( p == pAct ) 3550 continue; // for 3551 sal_Bool bUpdate = sal_True; 3552 if ( GetMergeState() == SC_CTMS_OTHER && 3553 p->GetActionNumber() <= GetLastMerge() ) 3554 { // Delete in mergendem Dokument, Action im zu mergenden 3555 if ( p->IsInsertType() ) 3556 { 3557 // Bei Insert Referenzen nur anpassen, wenn das Delete 3558 // das Insert nicht schneidet. 3559 if ( !aDelRange.Intersects( p->GetBigRange() ) ) 3560 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); 3561 bUpdate = sal_False; 3562 } 3563 else if ( p->GetType() == SC_CAT_CONTENT && 3564 p->IsDeletedInDelType( eInsType ) ) 3565 { // Content in Insert-Undo-"Delete" 3566 // Nicht anpassen, wenn dieses Delete in dem 3567 // Insert-"Delete" sein wuerde (ist nur verschoben). 3568 if ( aDelRange.In( p->GetBigRange().aStart ) ) 3569 bUpdate = sal_False; 3570 else 3571 { 3572 const ScChangeActionLinkEntry* pLink = p->GetDeletedIn(); 3573 while ( pLink && bUpdate ) 3574 { 3575 const ScChangeAction* pDel = pLink->GetAction(); 3576 if ( pDel && pDel->GetType() == eInsType && 3577 pDel->GetBigRange().In( aDelRange ) ) 3578 bUpdate = sal_False; 3579 pLink = pLink->GetNext(); 3580 } 3581 } 3582 } 3583 if ( !bUpdate ) 3584 continue; // for 3585 } 3586 if ( aDelRange.In( p->GetBigRange() ) ) 3587 { 3588 // Innerhalb eines gerade geloeschten Bereiches nicht 3589 // anpassen, stattdessen dem Bereich zuordnen. 3590 // Mehrfache geloeschte Bereiche "stapeln". 3591 // Kreuzende Deletes setzen mehrfach geloescht. 3592 if ( !p->IsDeletedInDelType( eActType ) ) 3593 { 3594 p->SetDeletedIn( pActDel ); 3595 // GeneratedDelContent in zu loeschende Liste aufnehmen 3596 if ( bGeneratedDelContents ) 3597 pActDel->AddContent( (ScChangeActionContent*) p ); 3598 } 3599 bUpdate = sal_False; 3600 } 3601 else 3602 { 3603 // Eingefuegte Bereiche abschneiden, wenn Start/End im 3604 // Delete liegt, aber das Insert nicht komplett innerhalb 3605 // des Delete liegt bzw. das Delete nicht komplett im 3606 // Insert. Das Delete merkt sich, welchem Insert es was 3607 // abgeschnitten hat, es kann auch nur ein einziges Insert 3608 // sein (weil Delete einspaltig/einzeilig ist). 3609 // Abgeschnittene Moves kann es viele geben. 3610 //! Ein Delete ist immer einspaltig/einzeilig, deswegen 1 3611 //! ohne die Ueberlappung auszurechnen. 3612 switch ( p->GetType() ) 3613 { 3614 case SC_CAT_INSERT_COLS : 3615 if ( eActType == SC_CAT_DELETE_COLS ) 3616 { 3617 if ( aDelRange.In( p->GetBigRange().aStart ) ) 3618 { 3619 pActDel->SetCutOffInsert( 3620 (ScChangeActionIns*) p, 1 ); 3621 p->GetBigRange().aStart.IncCol( 1 ); 3622 } 3623 else if ( aDelRange.In( p->GetBigRange().aEnd ) ) 3624 { 3625 pActDel->SetCutOffInsert( 3626 (ScChangeActionIns*) p, -1 ); 3627 p->GetBigRange().aEnd.IncCol( -1 ); 3628 } 3629 } 3630 break; 3631 case SC_CAT_INSERT_ROWS : 3632 if ( eActType == SC_CAT_DELETE_ROWS ) 3633 { 3634 if ( aDelRange.In( p->GetBigRange().aStart ) ) 3635 { 3636 pActDel->SetCutOffInsert( 3637 (ScChangeActionIns*) p, 1 ); 3638 p->GetBigRange().aStart.IncRow( 1 ); 3639 } 3640 else if ( aDelRange.In( p->GetBigRange().aEnd ) ) 3641 { 3642 pActDel->SetCutOffInsert( 3643 (ScChangeActionIns*) p, -1 ); 3644 p->GetBigRange().aEnd.IncRow( -1 ); 3645 } 3646 } 3647 break; 3648 case SC_CAT_INSERT_TABS : 3649 if ( eActType == SC_CAT_DELETE_TABS ) 3650 { 3651 if ( aDelRange.In( p->GetBigRange().aStart ) ) 3652 { 3653 pActDel->SetCutOffInsert( 3654 (ScChangeActionIns*) p, 1 ); 3655 p->GetBigRange().aStart.IncTab( 1 ); 3656 } 3657 else if ( aDelRange.In( p->GetBigRange().aEnd ) ) 3658 { 3659 pActDel->SetCutOffInsert( 3660 (ScChangeActionIns*) p, -1 ); 3661 p->GetBigRange().aEnd.IncTab( -1 ); 3662 } 3663 } 3664 break; 3665 case SC_CAT_MOVE : 3666 { 3667 ScChangeActionMove* pMove = (ScChangeActionMove*) p; 3668 short nFrom = 0; 3669 short nTo = 0; 3670 if ( aDelRange.In( pMove->GetBigRange().aStart ) ) 3671 nTo = 1; 3672 else if ( aDelRange.In( pMove->GetBigRange().aEnd ) ) 3673 nTo = -1; 3674 if ( aDelRange.In( pMove->GetFromRange().aStart ) ) 3675 nFrom = 1; 3676 else if ( aDelRange.In( pMove->GetFromRange().aEnd ) ) 3677 nFrom = -1; 3678 if ( nFrom ) 3679 { 3680 switch ( eActType ) 3681 { 3682 case SC_CAT_DELETE_COLS : 3683 if ( nFrom > 0 ) 3684 pMove->GetFromRange().aStart.IncCol( nFrom ); 3685 else 3686 pMove->GetFromRange().aEnd.IncCol( nFrom ); 3687 break; 3688 case SC_CAT_DELETE_ROWS : 3689 if ( nFrom > 0 ) 3690 pMove->GetFromRange().aStart.IncRow( nFrom ); 3691 else 3692 pMove->GetFromRange().aEnd.IncRow( nFrom ); 3693 break; 3694 case SC_CAT_DELETE_TABS : 3695 if ( nFrom > 0 ) 3696 pMove->GetFromRange().aStart.IncTab( nFrom ); 3697 else 3698 pMove->GetFromRange().aEnd.IncTab( nFrom ); 3699 break; 3700 default: 3701 { 3702 // added to avoid warnings 3703 } 3704 } 3705 } 3706 if ( nTo ) 3707 { 3708 switch ( eActType ) 3709 { 3710 case SC_CAT_DELETE_COLS : 3711 if ( nTo > 0 ) 3712 pMove->GetBigRange().aStart.IncCol( nTo ); 3713 else 3714 pMove->GetBigRange().aEnd.IncCol( nTo ); 3715 break; 3716 case SC_CAT_DELETE_ROWS : 3717 if ( nTo > 0 ) 3718 pMove->GetBigRange().aStart.IncRow( nTo ); 3719 else 3720 pMove->GetBigRange().aEnd.IncRow( nTo ); 3721 break; 3722 case SC_CAT_DELETE_TABS : 3723 if ( nTo > 0 ) 3724 pMove->GetBigRange().aStart.IncTab( nTo ); 3725 else 3726 pMove->GetBigRange().aEnd.IncTab( nTo ); 3727 break; 3728 default: 3729 { 3730 // added to avoid warnings 3731 } 3732 } 3733 } 3734 if ( nFrom || nTo ) 3735 { 3736 ScChangeActionDelMoveEntry* pLink = 3737 pActDel->AddCutOffMove( pMove, nFrom, nTo ); 3738 pMove->AddLink( pActDel, pLink ); 3739 } 3740 } 3741 break; 3742 default: 3743 { 3744 // added to avoid warnings 3745 } 3746 } 3747 } 3748 if ( bUpdate ) 3749 { 3750 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); 3751 if ( p->GetType() == eActType && !p->IsRejected() && 3752 !pActDel->IsDeletedIn() && 3753 p->GetBigRange().In( aDelRange ) ) 3754 pActDel->SetDeletedIn( p ); // "druntergerutscht" 3755 } 3756 } 3757 } 3758 else 3759 { // Undo Delete 3760 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3761 { 3762 if ( p == pAct ) 3763 continue; // for 3764 sal_Bool bUpdate = sal_True; 3765 if ( aDelRange.In( p->GetBigRange() ) ) 3766 { 3767 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 3768 if ( GetMergeState() == SC_CTMS_UNDO && !p->IsDeletedIn( pAct ) && pAct->IsDeleteType() && 3769 ( p->GetType() == SC_CAT_CONTENT || 3770 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || 3771 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) ) 3772 { 3773 p->SetDeletedIn( pAct ); 3774 } 3775 3776 if ( p->IsDeletedInDelType( eActType ) ) 3777 { 3778 if ( p->IsDeletedIn( pActDel ) ) 3779 { 3780 if ( p->GetType() != SC_CAT_CONTENT || 3781 ((ScChangeActionContent*)p)->IsTopContent() ) 3782 { // erst der TopContent wird wirklich entfernt 3783 p->RemoveDeletedIn( pActDel ); 3784 // GeneratedDelContent _nicht_ aus Liste loeschen, 3785 // wir brauchen ihn evtl. noch fuer Reject, 3786 // geloescht wird in DeleteCellEntries 3787 } 3788 } 3789 bUpdate = sal_False; 3790 } 3791 else if ( eActType != SC_CAT_DELETE_TABS && 3792 p->IsDeletedInDelType( SC_CAT_DELETE_TABS ) ) 3793 { // in geloeschten Tabellen nicht updaten, 3794 // ausser wenn Tabelle verschoben wird 3795 bUpdate = sal_False; 3796 } 3797 if ( p->GetType() == eActType && pActDel->IsDeletedIn( p ) ) 3798 { 3799 pActDel->RemoveDeletedIn( p ); // "druntergerutscht" 3800 bUpdate = sal_True; 3801 } 3802 } 3803 if ( bUpdate ) 3804 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); 3805 } 3806 if ( !bGeneratedDelContents ) 3807 { // die werden sonst noch fuer das echte Undo gebraucht 3808 pActDel->UndoCutOffInsert(); 3809 pActDel->UndoCutOffMoves(); 3810 } 3811 } 3812 } 3813 else if ( eActType == SC_CAT_MOVE ) 3814 { 3815 ScChangeActionMove* pActMove = (ScChangeActionMove*) pAct; 3816 sal_Bool bLastCutMove = ( pActMove == pLastCutMove ); 3817 const ScBigRange& rTo = pActMove->GetBigRange(); 3818 const ScBigRange& rFrom = pActMove->GetFromRange(); 3819 if ( !bUndo ) 3820 { // Move 3821 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3822 { 3823 if ( p == pAct ) 3824 continue; // for 3825 if ( p->GetType() == SC_CAT_CONTENT ) 3826 { 3827 // Inhalt in Ziel deleten (Inhalt in Quelle moven) 3828 if ( rTo.In( p->GetBigRange() ) ) 3829 { 3830 if ( !p->IsDeletedIn( pActMove ) ) 3831 { 3832 p->SetDeletedIn( pActMove ); 3833 // GeneratedDelContent in zu loeschende Liste aufnehmen 3834 if ( bGeneratedDelContents ) 3835 pActMove->AddContent( (ScChangeActionContent*) p ); 3836 } 3837 } 3838 else if ( bLastCutMove && 3839 p->GetActionNumber() > nEndLastCut && 3840 rFrom.In( p->GetBigRange() ) ) 3841 { // Paste Cut: neuer Content nach Cut eingefuegt, bleibt. 3842 // Aufsplitten der ContentChain 3843 ScChangeActionContent *pHere, *pTmp; 3844 pHere = (ScChangeActionContent*) p; 3845 while ( (pTmp = pHere->GetPrevContent()) != NULL && 3846 pTmp->GetActionNumber() > nEndLastCut ) 3847 pHere = pTmp; 3848 if ( pTmp ) 3849 { // wird TopContent des Move 3850 pTmp->SetNextContent( NULL ); 3851 pHere->SetPrevContent( NULL ); 3852 } 3853 do 3854 { // Abhaengigkeit vom FromRange herstellen 3855 AddDependentWithNotify( pActMove, pHere ); 3856 } while ( ( pHere = pHere->GetNextContent() ) != NULL ); 3857 } 3858 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly 3859 else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() ) 3860 p->UpdateReference( this, eMode, rFrom, nDx, nDy, nDz ); 3861 } 3862 } 3863 } 3864 else 3865 { // Undo Move 3866 sal_Bool bActRejected = pActMove->IsRejected(); 3867 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3868 { 3869 if ( p == pAct ) 3870 continue; // for 3871 if ( p->GetType() == SC_CAT_CONTENT ) 3872 { 3873 // Inhalt in Ziel moven, wenn nicht deleted, sonst undelete 3874 if ( p->IsDeletedIn( pActMove ) ) 3875 { 3876 if ( ((ScChangeActionContent*)p)->IsTopContent() ) 3877 { // erst der TopContent wird wirklich entfernt 3878 p->RemoveDeletedIn( pActMove ); 3879 // GeneratedDelContent _nicht_ aus Liste loeschen, 3880 // wir brauchen ihn evtl. noch fuer Reject, 3881 // geloescht wird in DeleteCellEntries 3882 } 3883 } 3884 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly 3885 else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() ) 3886 p->UpdateReference( this, eMode, rTo, nDx, nDy, nDz ); 3887 if ( bActRejected && 3888 ((ScChangeActionContent*)p)->IsTopContent() && 3889 rFrom.In( p->GetBigRange() ) ) 3890 { // Abhaengigkeit herstellen, um Content zu schreiben 3891 ScChangeActionLinkEntry* pLink = 3892 pActMove->AddDependent( p ); 3893 p->AddLink( pActMove, pLink ); 3894 } 3895 } 3896 } 3897 } 3898 } 3899 else 3900 { // Insert / Undo Insert 3901 switch ( GetMergeState() ) 3902 { 3903 case SC_CTMS_NONE : 3904 case SC_CTMS_OTHER : 3905 { 3906 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3907 { 3908 if ( p == pAct ) 3909 continue; // for 3910 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); 3911 } 3912 } 3913 break; 3914 case SC_CTMS_PREPARE : 3915 { 3916 // in Insert-Undo "Deleten" 3917 const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry(); 3918 while ( pLink ) 3919 { 3920 ScChangeAction* p = (ScChangeAction*) pLink->GetAction(); 3921 if ( p ) 3922 p->SetDeletedIn( pAct ); 3923 pLink = pLink->GetNext(); 3924 } 3925 3926 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly 3927 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3928 { 3929 if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() && 3930 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 3931 ( p->GetType() == SC_CAT_CONTENT || 3932 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || 3933 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && 3934 pAct->GetBigRange().Intersects( p->GetBigRange() ) ) 3935 { 3936 p->SetDeletedIn( pAct ); 3937 } 3938 } 3939 3940 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3941 { 3942 if ( p == pAct ) 3943 continue; // for 3944 if ( !p->IsDeletedIn( pAct ) 3945 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet 3946 && p->GetActionNumber() <= pAct->GetActionNumber() ) 3947 { 3948 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); 3949 } 3950 } 3951 } 3952 break; 3953 case SC_CTMS_OWN : 3954 { 3955 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3956 { 3957 if ( p == pAct ) 3958 continue; // for 3959 if ( !p->IsDeletedIn( pAct ) 3960 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet 3961 && p->GetActionNumber() <= pAct->GetActionNumber() ) 3962 { 3963 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); 3964 } 3965 } 3966 // in Insert-Undo "Delete" rueckgaengig 3967 const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry(); 3968 while ( pLink ) 3969 { 3970 ScChangeAction* p = (ScChangeAction*) pLink->GetAction(); 3971 if ( p ) 3972 p->RemoveDeletedIn( pAct ); 3973 pLink = pLink->GetNext(); 3974 } 3975 3976 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly 3977 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3978 { 3979 if ( p->IsDeletedIn( pAct ) && pAct->IsInsertType() && 3980 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 3981 ( p->GetType() == SC_CAT_CONTENT || 3982 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || 3983 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && 3984 pAct->GetBigRange().Intersects( p->GetBigRange() ) ) 3985 { 3986 p->RemoveDeletedIn( pAct ); 3987 } 3988 } 3989 } 3990 break; 3991 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong 3992 case SC_CTMS_UNDO : 3993 { 3994 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 3995 { 3996 if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() && 3997 ( p->GetType() == SC_CAT_CONTENT || 3998 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || 3999 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && 4000 pAct->GetBigRange().Intersects( p->GetBigRange() ) ) 4001 { 4002 p->SetDeletedIn( pAct ); 4003 } 4004 } 4005 4006 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) 4007 { 4008 if ( p == pAct ) 4009 { 4010 continue; 4011 } 4012 if ( !p->IsDeletedIn( pAct ) && p->GetActionNumber() <= pAct->GetActionNumber() ) 4013 { 4014 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); 4015 } 4016 } 4017 } 4018 break; 4019 } 4020 } 4021 } 4022 4023 4024 void ScChangeTrack::GetDependents( ScChangeAction* pAct, 4025 ScChangeActionTable& rTable, sal_Bool bListMasterDelete, sal_Bool bAllFlat ) const 4026 { 4027 //! bAllFlat==TRUE: intern aus Accept oder Reject gerufen, 4028 //! => Generated werden nicht aufgenommen 4029 4030 sal_Bool bIsDelete = pAct->IsDeleteType(); 4031 sal_Bool bIsMasterDelete = ( bListMasterDelete && pAct->IsMasterDelete() ); 4032 4033 const ScChangeAction* pCur = pAct; 4034 ScChangeActionStack* pStack = new ScChangeActionStack; 4035 do 4036 { 4037 if ( pCur->IsInsertType() ) 4038 { 4039 const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry(); 4040 while ( pL ) 4041 { 4042 ScChangeAction* p = (ScChangeAction*) pL->GetAction(); 4043 if ( p != pAct ) 4044 { 4045 if ( bAllFlat ) 4046 { 4047 sal_uLong n = p->GetActionNumber(); 4048 if ( !IsGenerated( n ) && rTable.Insert( n, p ) ) 4049 if ( p->HasDependent() ) 4050 pStack->Push( p ); 4051 } 4052 else 4053 { 4054 if ( p->GetType() == SC_CAT_CONTENT ) 4055 { 4056 if ( ((ScChangeActionContent*)p)->IsTopContent() ) 4057 rTable.Insert( p->GetActionNumber(), p ); 4058 } 4059 else 4060 rTable.Insert( p->GetActionNumber(), p ); 4061 } 4062 } 4063 pL = pL->GetNext(); 4064 } 4065 } 4066 else if ( pCur->IsDeleteType() ) 4067 { 4068 if ( bIsDelete ) 4069 { // Inhalte geloeschter Bereiche interessieren nur bei Delete 4070 ScChangeActionDel* pDel = (ScChangeActionDel*) pCur; 4071 if ( !bAllFlat && bIsMasterDelete && pCur == pAct ) 4072 { 4073 // zu diesem Delete gehoerende Deletes in gleiche Ebene, 4074 // wenn dieses Delete das momentan oberste einer Reihe ist, 4075 ScChangeActionType eType = pDel->GetType(); 4076 ScChangeAction* p = pDel; 4077 while ( (p = p->GetPrev()) != NULL && p->GetType() == eType && 4078 !((ScChangeActionDel*)p)->IsTopDelete() ) 4079 rTable.Insert( p->GetActionNumber(), p ); 4080 // dieses Delete auch in Table! 4081 rTable.Insert( pAct->GetActionNumber(), pAct ); 4082 } 4083 else 4084 { 4085 const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry(); 4086 while ( pL ) 4087 { 4088 ScChangeAction* p = (ScChangeAction*) pL->GetAction(); 4089 if ( p != pAct ) 4090 { 4091 if ( bAllFlat ) 4092 { 4093 // nur ein TopContent einer Kette ist in LinkDeleted 4094 sal_uLong n = p->GetActionNumber(); 4095 if ( !IsGenerated( n ) && rTable.Insert( n, p ) ) 4096 if ( p->HasDeleted() || 4097 p->GetType() == SC_CAT_CONTENT ) 4098 pStack->Push( p ); 4099 } 4100 else 4101 { 4102 if ( p->IsDeleteType() ) 4103 { // weiteres TopDelete in gleiche Ebene, 4104 // es ist nicht rejectable 4105 if ( ((ScChangeActionDel*)p)->IsTopDelete() ) 4106 rTable.Insert( p->GetActionNumber(), p ); 4107 } 4108 else 4109 rTable.Insert( p->GetActionNumber(), p ); 4110 } 4111 } 4112 pL = pL->GetNext(); 4113 } 4114 } 4115 } 4116 } 4117 else if ( pCur->GetType() == SC_CAT_MOVE ) 4118 { 4119 // geloeschte Contents im ToRange 4120 const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry(); 4121 while ( pL ) 4122 { 4123 ScChangeAction* p = (ScChangeAction*) pL->GetAction(); 4124 if ( p != pAct && rTable.Insert( p->GetActionNumber(), p ) ) 4125 { 4126 // nur ein TopContent einer Kette ist in LinkDeleted 4127 if ( bAllFlat && (p->HasDeleted() || 4128 p->GetType() == SC_CAT_CONTENT) ) 4129 pStack->Push( p ); 4130 } 4131 pL = pL->GetNext(); 4132 } 4133 // neue Contents im FromRange oder neuer FromRange im ToRange 4134 // oder Inserts/Deletes in FromRange/ToRange 4135 pL = pCur->GetFirstDependentEntry(); 4136 while ( pL ) 4137 { 4138 ScChangeAction* p = (ScChangeAction*) pL->GetAction(); 4139 if ( p != pAct ) 4140 { 4141 if ( bAllFlat ) 4142 { 4143 sal_uLong n = p->GetActionNumber(); 4144 if ( !IsGenerated( n ) && rTable.Insert( n, p ) ) 4145 if ( p->HasDependent() || p->HasDeleted() ) 4146 pStack->Push( p ); 4147 } 4148 else 4149 { 4150 if ( p->GetType() == SC_CAT_CONTENT ) 4151 { 4152 if ( ((ScChangeActionContent*)p)->IsTopContent() ) 4153 rTable.Insert( p->GetActionNumber(), p ); 4154 } 4155 else 4156 rTable.Insert( p->GetActionNumber(), p ); 4157 } 4158 } 4159 pL = pL->GetNext(); 4160 } 4161 } 4162 else if ( pCur->GetType() == SC_CAT_CONTENT ) 4163 { // alle Aenderungen an gleicher Position 4164 ScChangeActionContent* pContent = (ScChangeActionContent*) pCur; 4165 // alle vorherigen 4166 while ( ( pContent = pContent->GetPrevContent() ) != NULL ) 4167 { 4168 if ( !pContent->IsRejected() ) 4169 rTable.Insert( pContent->GetActionNumber(), pContent ); 4170 } 4171 pContent = (ScChangeActionContent*) pCur; 4172 // alle nachfolgenden 4173 while ( ( pContent = pContent->GetNextContent() ) != NULL ) 4174 { 4175 if ( !pContent->IsRejected() ) 4176 rTable.Insert( pContent->GetActionNumber(), pContent ); 4177 } 4178 // all MatrixReferences of a MatrixOrigin 4179 const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry(); 4180 while ( pL ) 4181 { 4182 ScChangeAction* p = (ScChangeAction*) pL->GetAction(); 4183 if ( p != pAct ) 4184 { 4185 if ( bAllFlat ) 4186 { 4187 sal_uLong n = p->GetActionNumber(); 4188 if ( !IsGenerated( n ) && rTable.Insert( n, p ) ) 4189 if ( p->HasDependent() ) 4190 pStack->Push( p ); 4191 } 4192 else 4193 rTable.Insert( p->GetActionNumber(), p ); 4194 } 4195 pL = pL->GetNext(); 4196 } 4197 } 4198 else if ( pCur->GetType() == SC_CAT_REJECT ) 4199 { 4200 if ( bAllFlat ) 4201 { 4202 ScChangeAction* p = GetAction( 4203 ((ScChangeActionReject*)pCur)->GetRejectAction() ); 4204 if ( p != pAct && !rTable.Get( p->GetActionNumber() ) ) 4205 pStack->Push( p ); 4206 } 4207 } 4208 } while ( ( pCur = pStack->Pop() ) != NULL ); 4209 delete pStack; 4210 } 4211 4212 4213 sal_Bool ScChangeTrack::SelectContent( ScChangeAction* pAct, sal_Bool bOldest ) 4214 { 4215 if ( pAct->GetType() != SC_CAT_CONTENT ) 4216 return sal_False; 4217 4218 ScChangeActionContent* pContent = (ScChangeActionContent*) pAct; 4219 if ( bOldest ) 4220 { 4221 pContent = pContent->GetTopContent(); 4222 ScChangeActionContent* pPrevContent; 4223 while ( (pPrevContent = pContent->GetPrevContent()) != NULL && 4224 pPrevContent->IsVirgin() ) 4225 pContent = pPrevContent; 4226 } 4227 4228 if ( !pContent->IsClickable() ) 4229 return sal_False; 4230 4231 ScBigRange aBigRange( pContent->GetBigRange() ); 4232 const ScBaseCell* pCell = (bOldest ? pContent->GetOldCell() : 4233 pContent->GetNewCell()); 4234 if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATORG ) 4235 { 4236 SCCOL nC; 4237 SCROW nR; 4238 ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR ); 4239 aBigRange.aEnd.IncCol( nC-1 ); 4240 aBigRange.aEnd.IncRow( nR-1 ); 4241 } 4242 4243 if ( !aBigRange.IsValid( pDoc ) ) 4244 return sal_False; 4245 4246 ScRange aRange( aBigRange.MakeRange() ); 4247 if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(), 4248 aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) ) 4249 return sal_False; 4250 4251 if ( pContent->HasDependent() ) 4252 { 4253 sal_Bool bOk = sal_True; 4254 Stack aRejectActions; 4255 const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry(); 4256 while ( pL ) 4257 { 4258 ScChangeAction* p = (ScChangeAction*) pL->GetAction(); 4259 if ( p != pContent ) 4260 { 4261 if ( p->GetType() == SC_CAT_CONTENT ) 4262 { 4263 // we don't need no recursion here, do we? 4264 bOk &= ((ScChangeActionContent*)p)->Select( pDoc, this, 4265 bOldest, &aRejectActions ); 4266 } 4267 else 4268 { 4269 DBG_ERRORFILE( "ScChangeTrack::SelectContent: content dependent no content" ); 4270 } 4271 } 4272 pL = pL->GetNext(); 4273 } 4274 4275 bOk &= pContent->Select( pDoc, this, bOldest, NULL ); 4276 // now the matrix is inserted and new content values are ready 4277 4278 ScChangeActionContent* pNew; 4279 while ( ( pNew = (ScChangeActionContent*) aRejectActions.Pop() ) != NULL ) 4280 { 4281 ScAddress aPos( pNew->GetBigRange().aStart.MakeAddress() ); 4282 pNew->SetNewValue( pDoc->GetCell( aPos ), pDoc ); 4283 Append( pNew ); 4284 } 4285 return bOk; 4286 } 4287 else 4288 return pContent->Select( pDoc, this, bOldest, NULL ); 4289 } 4290 4291 4292 void ScChangeTrack::AcceptAll() 4293 { 4294 for ( ScChangeAction* p = GetFirst(); p; p = p->GetNext() ) 4295 { 4296 p->Accept(); 4297 } 4298 } 4299 4300 4301 sal_Bool ScChangeTrack::Accept( ScChangeAction* pAct ) 4302 { 4303 if ( !pAct->IsClickable() ) 4304 return sal_False; 4305 4306 if ( pAct->IsDeleteType() || pAct->GetType() == SC_CAT_CONTENT ) 4307 { 4308 ScChangeActionTable aActionTable; 4309 GetDependents( pAct, aActionTable, sal_False, sal_True ); 4310 for ( ScChangeAction* p = aActionTable.First(); p; p = aActionTable.Next() ) 4311 { 4312 p->Accept(); 4313 } 4314 } 4315 pAct->Accept(); 4316 return sal_True; 4317 } 4318 4319 4320 sal_Bool ScChangeTrack::RejectAll() 4321 { 4322 sal_Bool bOk = sal_True; 4323 for ( ScChangeAction* p = GetLast(); p && bOk; p = p->GetPrev() ) 4324 { //! rueckwaerts, weil abhaengige hinten und RejectActions angehaengt 4325 if ( p->IsInternalRejectable() ) 4326 bOk = Reject( p ); 4327 } 4328 return bOk; 4329 } 4330 4331 4332 sal_Bool ScChangeTrack::Reject( ScChangeAction* pAct, bool bShared ) 4333 { 4334 // #i100895# When collaboration changes are reversed, it must be possible 4335 // to reject a deleted row above another deleted row. 4336 if ( bShared && pAct->IsDeletedIn() ) 4337 pAct->RemoveAllDeletedIn(); 4338 4339 if ( !pAct->IsRejectable() ) 4340 return sal_False; 4341 4342 ScChangeActionTable* pTable = NULL; 4343 if ( pAct->HasDependent() ) 4344 { 4345 pTable = new ScChangeActionTable; 4346 GetDependents( pAct, *pTable, sal_False, sal_True ); 4347 } 4348 sal_Bool bRejected = Reject( pAct, pTable, sal_False ); 4349 if ( pTable ) 4350 delete pTable; 4351 return bRejected; 4352 } 4353 4354 4355 sal_Bool ScChangeTrack::Reject( ScChangeAction* pAct, ScChangeActionTable* pTable, 4356 sal_Bool bRecursion ) 4357 { 4358 if ( !pAct->IsInternalRejectable() ) 4359 return sal_False; 4360 4361 sal_Bool bOk = sal_True; 4362 sal_Bool bRejected = sal_False; 4363 if ( pAct->IsInsertType() ) 4364 { 4365 if ( pAct->HasDependent() && !bRecursion ) 4366 { 4367 DBG_ASSERT( pTable, "ScChangeTrack::Reject: Insert ohne Table" ); 4368 for ( ScChangeAction* p = pTable->Last(); p && bOk; p = pTable->Prev() ) 4369 { 4370 // keine Contents restoren, die eh geloescht werden wuerden 4371 if ( p->GetType() == SC_CAT_CONTENT ) 4372 p->SetRejected(); 4373 else if ( p->IsDeleteType() ) 4374 p->Accept(); // geloeschtes ins Nirvana 4375 else 4376 bOk = Reject( p, NULL, sal_True ); //! rekursiv 4377 } 4378 } 4379 if ( bOk && (bRejected = pAct->Reject( pDoc )) != sal_False ) 4380 { 4381 // pRefDoc NULL := geloeschte Zellen nicht speichern 4382 AppendDeleteRange( pAct->GetBigRange().MakeRange(), NULL, (short) 0, 4383 pAct->GetActionNumber() ); 4384 } 4385 } 4386 else if ( pAct->IsDeleteType() ) 4387 { 4388 DBG_ASSERT( !pTable, "ScChangeTrack::Reject: Delete mit Table" ); 4389 ScBigRange aDelRange; 4390 sal_uLong nRejectAction = pAct->GetActionNumber(); 4391 sal_Bool bTabDel, bTabDelOk; 4392 if ( pAct->GetType() == SC_CAT_DELETE_TABS ) 4393 { 4394 bTabDel = sal_True; 4395 aDelRange = pAct->GetBigRange(); 4396 bOk = bTabDelOk = pAct->Reject( pDoc ); 4397 if ( bOk ) 4398 { 4399 pAct = pAct->GetPrev(); 4400 bOk = ( pAct && pAct->GetType() == SC_CAT_DELETE_COLS ); 4401 } 4402 } 4403 else 4404 bTabDel = bTabDelOk = sal_False; 4405 ScChangeActionDel* pDel = (ScChangeActionDel*) pAct; 4406 if ( bOk ) 4407 { 4408 aDelRange = pDel->GetOverAllRange(); 4409 bOk = aDelRange.IsValid( pDoc ); 4410 } 4411 sal_Bool bOneOk = sal_False; 4412 if ( bOk ) 4413 { 4414 ScChangeActionType eActType = pAct->GetType(); 4415 switch ( eActType ) 4416 { 4417 case SC_CAT_DELETE_COLS : 4418 aDelRange.aStart.SetCol( aDelRange.aEnd.Col() ); 4419 break; 4420 case SC_CAT_DELETE_ROWS : 4421 aDelRange.aStart.SetRow( aDelRange.aEnd.Row() ); 4422 break; 4423 case SC_CAT_DELETE_TABS : 4424 aDelRange.aStart.SetTab( aDelRange.aEnd.Tab() ); 4425 break; 4426 default: 4427 { 4428 // added to avoid warnings 4429 } 4430 } 4431 ScChangeAction* p = pAct; 4432 sal_Bool bLoop = sal_True; 4433 do 4434 { 4435 pDel = (ScChangeActionDel*) p; 4436 bOk = pDel->Reject( pDoc ); 4437 if ( bOk ) 4438 { 4439 if ( bOneOk ) 4440 { 4441 switch ( pDel->GetType() ) 4442 { 4443 case SC_CAT_DELETE_COLS : 4444 aDelRange.aStart.IncCol( -1 ); 4445 break; 4446 case SC_CAT_DELETE_ROWS : 4447 aDelRange.aStart.IncRow( -1 ); 4448 break; 4449 case SC_CAT_DELETE_TABS : 4450 aDelRange.aStart.IncTab( -1 ); 4451 break; 4452 default: 4453 { 4454 // added to avoid warnings 4455 } 4456 } 4457 } 4458 else 4459 bOneOk = sal_True; 4460 } 4461 if ( pDel->IsBaseDelete() ) 4462 bLoop = sal_False; 4463 else 4464 p = p->GetPrev(); 4465 } while ( bOk && bLoop && p && p->GetType() == eActType && 4466 !((ScChangeActionDel*)p)->IsTopDelete() ); 4467 } 4468 bRejected = bOk; 4469 if ( bOneOk || (bTabDel && bTabDelOk) ) 4470 { 4471 // Delete-Reject machte UpdateReference Undo 4472 ScChangeActionIns* pReject = new ScChangeActionIns( 4473 aDelRange.MakeRange() ); 4474 pReject->SetRejectAction( nRejectAction ); 4475 pReject->SetState( SC_CAS_ACCEPTED ); 4476 Append( pReject ); 4477 } 4478 } 4479 else if ( pAct->GetType() == SC_CAT_MOVE ) 4480 { 4481 if ( pAct->HasDependent() && !bRecursion ) 4482 { 4483 DBG_ASSERT( pTable, "ScChangeTrack::Reject: Move ohne Table" ); 4484 for ( ScChangeAction* p = pTable->Last(); p && bOk; p = pTable->Prev() ) 4485 { 4486 bOk = Reject( p, NULL, sal_True ); //! rekursiv 4487 } 4488 } 4489 if ( bOk && (bRejected = pAct->Reject( pDoc )) != sal_False ) 4490 { 4491 ScChangeActionMove* pReject = new ScChangeActionMove( 4492 pAct->GetBigRange().MakeRange(), 4493 ((ScChangeActionMove*)pAct)->GetFromRange().MakeRange(), this ); 4494 pReject->SetRejectAction( pAct->GetActionNumber() ); 4495 pReject->SetState( SC_CAS_ACCEPTED ); 4496 Append( pReject ); 4497 } 4498 } 4499 else if ( pAct->GetType() == SC_CAT_CONTENT ) 4500 { 4501 ScRange aRange; 4502 ScChangeActionContent* pReject; 4503 if ( bRecursion ) 4504 pReject = NULL; 4505 else 4506 { 4507 aRange = pAct->GetBigRange().aStart.MakeAddress(); 4508 pReject = new ScChangeActionContent( aRange ); 4509 pReject->SetOldValue( pDoc->GetCell( aRange.aStart ), pDoc, pDoc ); 4510 } 4511 if ( (bRejected = pAct->Reject( pDoc )) != sal_False && !bRecursion ) 4512 { 4513 pReject->SetNewValue( pDoc->GetCell( aRange.aStart ), pDoc ); 4514 pReject->SetRejectAction( pAct->GetActionNumber() ); 4515 pReject->SetState( SC_CAS_ACCEPTED ); 4516 Append( pReject ); 4517 } 4518 else if ( pReject ) 4519 delete pReject; 4520 } 4521 else 4522 { 4523 DBG_ERROR( "ScChangeTrack::Reject: say what?" ); 4524 } 4525 4526 return bRejected; 4527 } 4528 4529 4530 sal_uLong ScChangeTrack::AddLoadedGenerated(ScBaseCell* pNewCell, const ScBigRange& aBigRange, const String& sNewValue ) 4531 { 4532 ScChangeActionContent* pAct = new ScChangeActionContent( --nGeneratedMin, pNewCell, aBigRange, pDoc, sNewValue ); 4533 if ( pAct ) 4534 { 4535 if ( pFirstGeneratedDelContent ) 4536 pFirstGeneratedDelContent->pPrev = pAct; 4537 pAct->pNext = pFirstGeneratedDelContent; 4538 pFirstGeneratedDelContent = pAct; 4539 aGeneratedTable.Insert( pAct->GetActionNumber(), pAct ); 4540 return pAct->GetActionNumber(); 4541 } 4542 return 0; 4543 } 4544 4545 void ScChangeTrack::AppendCloned( ScChangeAction* pAppend ) 4546 { 4547 aTable.Insert( pAppend->GetActionNumber(), pAppend ); 4548 if ( !pLast ) 4549 pFirst = pLast = pAppend; 4550 else 4551 { 4552 pLast->pNext = pAppend; 4553 pAppend->pPrev = pLast; 4554 pLast = pAppend; 4555 } 4556 } 4557 4558 ScChangeTrack* ScChangeTrack::Clone( ScDocument* pDocument ) const 4559 { 4560 if ( !pDocument ) 4561 { 4562 return NULL; 4563 } 4564 4565 ScChangeTrack* pClonedTrack = new ScChangeTrack( pDocument ); 4566 pClonedTrack->SetTime100thSeconds( IsTime100thSeconds() ); 4567 4568 // clone generated actions 4569 ::std::stack< const ScChangeAction* > aGeneratedStack; 4570 const ScChangeAction* pGenerated = GetFirstGenerated(); 4571 while ( pGenerated ) 4572 { 4573 aGeneratedStack.push( pGenerated ); 4574 pGenerated = pGenerated->GetNext(); 4575 } 4576 while ( !aGeneratedStack.empty() ) 4577 { 4578 pGenerated = aGeneratedStack.top(); 4579 aGeneratedStack.pop(); 4580 const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pGenerated ); 4581 DBG_ASSERT( pContent, "ScChangeTrack::Clone: pContent is null!" ); 4582 const ScBaseCell* pNewCell = pContent->GetNewCell(); 4583 if ( pNewCell ) 4584 { 4585 ScBaseCell* pClonedNewCell = pNewCell->CloneWithoutNote( *pDocument ); 4586 String aNewValue; 4587 pContent->GetNewString( aNewValue ); 4588 pClonedTrack->nGeneratedMin = pGenerated->GetActionNumber() + 1; 4589 pClonedTrack->AddLoadedGenerated( pClonedNewCell, pGenerated->GetBigRange(), aNewValue ); 4590 } 4591 } 4592 4593 // clone actions 4594 const ScChangeAction* pAction = GetFirst(); 4595 while ( pAction ) 4596 { 4597 ScChangeAction* pClonedAction = NULL; 4598 4599 switch ( pAction->GetType() ) 4600 { 4601 case SC_CAT_INSERT_COLS: 4602 case SC_CAT_INSERT_ROWS: 4603 case SC_CAT_INSERT_TABS: 4604 { 4605 pClonedAction = new ScChangeActionIns( 4606 pAction->GetActionNumber(), 4607 pAction->GetState(), 4608 pAction->GetRejectAction(), 4609 pAction->GetBigRange(), 4610 pAction->GetUser(), 4611 pAction->GetDateTimeUTC(), 4612 pAction->GetComment(), 4613 pAction->GetType() ); 4614 } 4615 break; 4616 case SC_CAT_DELETE_COLS: 4617 case SC_CAT_DELETE_ROWS: 4618 case SC_CAT_DELETE_TABS: 4619 { 4620 const ScChangeActionDel* pDelete = dynamic_cast< const ScChangeActionDel* >( pAction ); 4621 DBG_ASSERT( pDelete, "ScChangeTrack::Clone: pDelete is null!" ); 4622 4623 SCsCOLROW nD = 0; 4624 ScChangeActionType eType = pAction->GetType(); 4625 if ( eType == SC_CAT_DELETE_COLS ) 4626 { 4627 nD = static_cast< SCsCOLROW >( pDelete->GetDx() ); 4628 } 4629 else if ( eType == SC_CAT_DELETE_ROWS ) 4630 { 4631 nD = static_cast< SCsCOLROW >( pDelete->GetDy() ); 4632 } 4633 4634 pClonedAction = new ScChangeActionDel( 4635 pAction->GetActionNumber(), 4636 pAction->GetState(), 4637 pAction->GetRejectAction(), 4638 pAction->GetBigRange(), 4639 pAction->GetUser(), 4640 pAction->GetDateTimeUTC(), 4641 pAction->GetComment(), 4642 eType, 4643 nD, 4644 pClonedTrack ); 4645 } 4646 break; 4647 case SC_CAT_MOVE: 4648 { 4649 const ScChangeActionMove* pMove = dynamic_cast< const ScChangeActionMove* >( pAction ); 4650 DBG_ASSERT( pMove, "ScChangeTrack::Clone: pMove is null!" ); 4651 4652 pClonedAction = new ScChangeActionMove( 4653 pAction->GetActionNumber(), 4654 pAction->GetState(), 4655 pAction->GetRejectAction(), 4656 pAction->GetBigRange(), 4657 pAction->GetUser(), 4658 pAction->GetDateTimeUTC(), 4659 pAction->GetComment(), 4660 pMove->GetFromRange(), 4661 pClonedTrack ); 4662 } 4663 break; 4664 case SC_CAT_CONTENT: 4665 { 4666 const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pAction ); 4667 DBG_ASSERT( pContent, "ScChangeTrack::Clone: pContent is null!" ); 4668 const ScBaseCell* pOldCell = pContent->GetOldCell(); 4669 ScBaseCell* pClonedOldCell = pOldCell ? pOldCell->CloneWithoutNote( *pDocument ) : 0; 4670 String aOldValue; 4671 pContent->GetOldString( aOldValue ); 4672 4673 ScChangeActionContent* pClonedContent = new ScChangeActionContent( 4674 pAction->GetActionNumber(), 4675 pAction->GetState(), 4676 pAction->GetRejectAction(), 4677 pAction->GetBigRange(), 4678 pAction->GetUser(), 4679 pAction->GetDateTimeUTC(), 4680 pAction->GetComment(), 4681 pClonedOldCell, 4682 pDocument, 4683 aOldValue ); 4684 4685 const ScBaseCell* pNewCell = pContent->GetNewCell(); 4686 if ( pNewCell ) 4687 { 4688 ScBaseCell* pClonedNewCell = pNewCell->CloneWithoutNote( *pDocument ); 4689 pClonedContent->SetNewValue( pClonedNewCell, pDocument ); 4690 } 4691 4692 pClonedAction = pClonedContent; 4693 } 4694 break; 4695 case SC_CAT_REJECT: 4696 { 4697 pClonedAction = new ScChangeActionReject( 4698 pAction->GetActionNumber(), 4699 pAction->GetState(), 4700 pAction->GetRejectAction(), 4701 pAction->GetBigRange(), 4702 pAction->GetUser(), 4703 pAction->GetDateTimeUTC(), 4704 pAction->GetComment() ); 4705 } 4706 break; 4707 default: 4708 { 4709 } 4710 break; 4711 } 4712 4713 if ( pClonedAction ) 4714 { 4715 pClonedTrack->AppendCloned( pClonedAction ); 4716 } 4717 4718 pAction = pAction->GetNext(); 4719 } 4720 4721 if ( pClonedTrack->GetLast() ) 4722 { 4723 pClonedTrack->SetActionMax( pClonedTrack->GetLast()->GetActionNumber() ); 4724 } 4725 4726 // set dependencies for Deleted/DeletedIn 4727 pAction = GetFirst(); 4728 while ( pAction ) 4729 { 4730 if ( pAction->HasDeleted() ) 4731 { 4732 ::std::stack< sal_uLong > aStack; 4733 const ScChangeActionLinkEntry* pL = pAction->GetFirstDeletedEntry(); 4734 while ( pL ) 4735 { 4736 const ScChangeAction* pDeleted = pL->GetAction(); 4737 if ( pDeleted ) 4738 { 4739 aStack.push( pDeleted->GetActionNumber() ); 4740 } 4741 pL = pL->GetNext(); 4742 } 4743 ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() ); 4744 if ( pClonedAction ) 4745 { 4746 while ( !aStack.empty() ) 4747 { 4748 ScChangeAction* pClonedDeleted = pClonedTrack->GetActionOrGenerated( aStack.top() ); 4749 aStack.pop(); 4750 if ( pClonedDeleted ) 4751 { 4752 pClonedDeleted->SetDeletedIn( pClonedAction ); 4753 } 4754 } 4755 } 4756 } 4757 pAction = pAction->GetNext(); 4758 } 4759 4760 // set dependencies for Dependent/Any 4761 pAction = GetLast(); 4762 while ( pAction ) 4763 { 4764 if ( pAction->HasDependent() ) 4765 { 4766 ::std::stack< sal_uLong > aStack; 4767 const ScChangeActionLinkEntry* pL = pAction->GetFirstDependentEntry(); 4768 while ( pL ) 4769 { 4770 const ScChangeAction* pDependent = pL->GetAction(); 4771 if ( pDependent ) 4772 { 4773 aStack.push( pDependent->GetActionNumber() ); 4774 } 4775 pL = pL->GetNext(); 4776 } 4777 ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() ); 4778 if ( pClonedAction ) 4779 { 4780 while ( !aStack.empty() ) 4781 { 4782 ScChangeAction* pClonedDependent = pClonedTrack->GetActionOrGenerated( aStack.top() ); 4783 aStack.pop(); 4784 if ( pClonedDependent ) 4785 { 4786 ScChangeActionLinkEntry* pLink = pClonedAction->AddDependent( pClonedDependent ); 4787 pClonedDependent->AddLink( pClonedAction, pLink ); 4788 } 4789 } 4790 } 4791 } 4792 pAction = pAction->GetPrev(); 4793 } 4794 4795 // masterlinks 4796 ScChangeAction* pClonedAction = pClonedTrack->GetFirst(); 4797 while ( pClonedAction ) 4798 { 4799 pClonedTrack->MasterLinks( pClonedAction ); 4800 pClonedAction = pClonedAction->GetNext(); 4801 } 4802 4803 if ( IsProtected() ) 4804 { 4805 pClonedTrack->SetProtection( GetProtection() ); 4806 } 4807 4808 if ( pClonedTrack->GetLast() ) 4809 { 4810 pClonedTrack->SetLastSavedActionNumber( pClonedTrack->GetLast()->GetActionNumber() ); 4811 } 4812 4813 pDocument->SetChangeTrack( pClonedTrack ); 4814 4815 return pClonedTrack; 4816 } 4817 4818 void ScChangeTrack::MergeActionState( ScChangeAction* pAct, const ScChangeAction* pOtherAct ) 4819 { 4820 if ( pAct->IsVirgin() ) 4821 { 4822 if ( pOtherAct->IsAccepted() ) 4823 { 4824 pAct->Accept(); 4825 if ( pOtherAct->IsRejecting() ) 4826 { 4827 pAct->SetRejectAction( pOtherAct->GetRejectAction() ); 4828 } 4829 } 4830 else if ( pOtherAct->IsRejected() ) 4831 { 4832 pAct->SetRejected(); 4833 } 4834 } 4835 } 4836 4837 #if DEBUG_CHANGETRACK 4838 String ScChangeTrack::ToString() const 4839 { 4840 String aReturn; 4841 4842 aReturn += String::CreateFromAscii( "============================================================\n" ); 4843 4844 const ScChangeAction* pGenerated = GetFirstGenerated(); 4845 while ( pGenerated ) 4846 { 4847 aReturn += pGenerated->ToString( pDoc ); 4848 aReturn += '\n'; 4849 pGenerated = pGenerated->GetNext(); 4850 } 4851 4852 aReturn += String::CreateFromAscii( "------------------------------------------------------------\n" ); 4853 4854 const ScChangeAction* pAction = GetFirst(); 4855 while ( pAction ) 4856 { 4857 aReturn += pAction->ToString( pDoc ); 4858 aReturn += '\n'; 4859 pAction = pAction->GetNext(); 4860 } 4861 aReturn += String::CreateFromAscii( "============================================================\n" ); 4862 4863 return aReturn; 4864 } 4865 #endif // DEBUG_CHANGETRACK 4866