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