Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / tool / chgtrack.cxx
blob87d0cdb640f8ae316d259bd602ba3f1f2f29ee5e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "chgtrack.hxx"
21 #include "formulacell.hxx"
22 #include "document.hxx"
23 #include "dociter.hxx"
24 #include "global.hxx"
25 #include "rechead.hxx"
26 #include "scerrors.hxx"
27 #include "scmod.hxx"
28 #include "inputopt.hxx"
29 #include "patattr.hxx"
30 #include "hints.hxx"
31 #include "markdata.hxx"
32 #include "globstr.hrc"
33 #include "editutil.hxx"
34 #include "tokenarray.hxx"
35 #include "refupdatecontext.hxx"
37 #include <tools/shl.hxx>
38 #include <tools/rtti.hxx>
39 #include <svl/zforlist.hxx>
40 #include <svl/itemset.hxx>
41 #include <svl/isethint.hxx>
42 #include <svl/itempool.hxx>
43 #include <sfx2/app.hxx>
44 #include <unotools/useroptions.hxx>
45 #include <sfx2/sfxsids.hrc>
47 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionCellListEntry )
48 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionLinkEntry )
50 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScRange& rRange )
52 aBigRange( rRange ),
53 aDateTime( DateTime::SYSTEM ),
54 pNext( NULL ),
55 pPrev( NULL ),
56 pLinkAny( NULL ),
57 pLinkDeletedIn( NULL ),
58 pLinkDeleted( NULL ),
59 pLinkDependent( NULL ),
60 nAction( 0 ),
61 nRejectAction( 0 ),
62 eType( eTypeP ),
63 eState( SC_CAS_VIRGIN )
65 aDateTime.ConvertToUTC();
68 ScChangeAction::ScChangeAction(
69 ScChangeActionType eTypeP, const ScBigRange& rRange,
70 const sal_uLong nTempAction, const sal_uLong nTempRejectAction,
71 const ScChangeActionState eTempState, const DateTime& aTempDateTime,
72 const OUString& aTempUser, const OUString& aTempComment) :
73 aBigRange( rRange ),
74 aDateTime( aTempDateTime ),
75 aUser( aTempUser ),
76 aComment( aTempComment ),
77 pNext( NULL ),
78 pPrev( NULL ),
79 pLinkAny( NULL ),
80 pLinkDeletedIn( NULL ),
81 pLinkDeleted( NULL ),
82 pLinkDependent( NULL ),
83 nAction( nTempAction ),
84 nRejectAction( nTempRejectAction ),
85 eType( eTypeP ),
86 eState( eTempState )
90 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange,
91 const sal_uLong nTempAction)
93 aBigRange( rRange ),
94 aDateTime( DateTime::SYSTEM ),
95 pNext( NULL ),
96 pPrev( NULL ),
97 pLinkAny( NULL ),
98 pLinkDeletedIn( NULL ),
99 pLinkDeleted( NULL ),
100 pLinkDependent( NULL ),
101 nAction( nTempAction ),
102 nRejectAction( 0 ),
103 eType( eTypeP ),
104 eState( SC_CAS_VIRGIN )
106 aDateTime.ConvertToUTC();
109 ScChangeAction::~ScChangeAction()
111 RemoveAllLinks();
114 bool ScChangeAction::IsInsertType() const
116 return eType == SC_CAT_INSERT_COLS || eType == SC_CAT_INSERT_ROWS || eType == SC_CAT_INSERT_TABS;
119 bool ScChangeAction::IsDeleteType() const
121 return eType == SC_CAT_DELETE_COLS || eType == SC_CAT_DELETE_ROWS || eType == SC_CAT_DELETE_TABS;
124 bool ScChangeAction::IsVirgin() const
126 return eState == SC_CAS_VIRGIN;
129 bool ScChangeAction::IsAccepted() const
131 return eState == SC_CAS_ACCEPTED;
134 bool ScChangeAction::IsRejected() const
136 return eState == SC_CAS_REJECTED;
139 bool ScChangeAction::IsRejecting() const
141 return nRejectAction != 0;
144 bool ScChangeAction::IsVisible() const
146 //! sequence order of execution is significant
147 if ( IsRejected() || GetType() == SC_CAT_DELETE_TABS || IsDeletedIn() )
148 return false;
149 if ( GetType() == SC_CAT_CONTENT )
150 return ((ScChangeActionContent*)this)->IsTopContent();
151 return true;
154 bool ScChangeAction::IsTouchable() const
156 //! sequence order of execution is significant
157 if ( IsRejected() || GetType() == SC_CAT_REJECT || IsDeletedIn() )
158 return false;
159 // content may reject and be touchable if on top
160 if ( GetType() == SC_CAT_CONTENT )
161 return ((ScChangeActionContent*)this)->IsTopContent();
162 if ( IsRejecting() )
163 return false;
164 return true;
167 bool ScChangeAction::IsClickable() const
169 //! sequence order of execution is significant
170 if ( !IsVirgin() )
171 return false;
172 if ( IsDeletedIn() )
173 return false;
174 if ( GetType() == SC_CAT_CONTENT )
176 ScChangeActionContentCellType eCCT =
177 ScChangeActionContent::GetContentCellType(
178 ((ScChangeActionContent*)this)->GetNewCell() );
179 if ( eCCT == SC_CACCT_MATREF )
180 return false;
181 if ( eCCT == SC_CACCT_MATORG )
182 { // no Accept-Select if one of the references is in a deleted col/row
183 const ScChangeActionLinkEntry* pL =
184 ((ScChangeActionContent*)this)->GetFirstDependentEntry();
185 while ( pL )
187 ScChangeAction* p = (ScChangeAction*) pL->GetAction();
188 if ( p && p->IsDeletedIn() )
189 return false;
190 pL = pL->GetNext();
193 return true; // for Select() a content doesn't have to be touchable
195 return IsTouchable(); // Accept()/Reject() only on touchables
198 bool ScChangeAction::IsRejectable() const
200 //! sequence order of execution is significant
201 if ( !IsClickable() )
202 return false;
203 if ( GetType() == SC_CAT_CONTENT )
205 if ( ((ScChangeActionContent*)this)->IsOldMatrixReference() )
206 return false;
207 ScChangeActionContent* pNextContent =
208 ((ScChangeActionContent*)this)->GetNextContent();
209 if ( pNextContent == NULL )
210 return true; // *this is TopContent
211 return pNextContent->IsRejected(); // *this is next rejectable
213 return IsTouchable();
216 bool ScChangeAction::IsInternalRejectable() const
218 //! sequence order of execution is significant
219 if ( !IsVirgin() )
220 return false;
221 if ( IsDeletedIn() )
222 return false;
223 if ( GetType() == SC_CAT_CONTENT )
225 ScChangeActionContent* pNextContent =
226 ((ScChangeActionContent*)this)->GetNextContent();
227 if ( pNextContent == NULL )
228 return true; // *this is TopContent
229 return pNextContent->IsRejected(); // *this is next rejectable
231 return IsTouchable();
234 bool ScChangeAction::IsDialogRoot() const
236 return IsInternalRejectable(); // only rejectables in root
239 bool ScChangeAction::IsDialogParent() const
241 //! sequence order of execution is significant
242 if ( GetType() == SC_CAT_CONTENT )
244 if ( !IsDialogRoot() )
245 return false;
246 if ( ((ScChangeActionContent*)this)->IsMatrixOrigin() && HasDependent() )
247 return true;
248 ScChangeActionContent* pPrevContent =
249 ((ScChangeActionContent*)this)->GetPrevContent();
250 return pPrevContent && pPrevContent->IsVirgin();
252 if ( HasDependent() )
253 return IsDeleteType() ? true : !IsDeletedIn();
254 if ( HasDeleted() )
256 if ( IsDeleteType() )
258 if ( IsDialogRoot() )
259 return true;
260 ScChangeActionLinkEntry* pL = pLinkDeleted;
261 while ( pL )
263 ScChangeAction* p = pL->GetAction();
264 if ( p && p->GetType() != eType )
265 return true;
266 pL = pL->GetNext();
269 else
270 return true;
272 return false;
275 bool ScChangeAction::IsMasterDelete() const
277 if ( !IsDeleteType() )
278 return false;
279 ScChangeActionDel* pDel = (ScChangeActionDel*) this;
280 return pDel->IsMultiDelete() && (pDel->IsTopDelete() || pDel->IsRejectable());
283 void ScChangeAction::RemoveAllLinks()
285 RemoveAllAnyLinks();
286 RemoveAllDeletedIn();
287 RemoveAllDeleted();
288 RemoveAllDependent();
291 void ScChangeAction::RemoveAllAnyLinks()
293 while ( pLinkAny )
294 delete pLinkAny; // Moves up by itself
297 bool ScChangeAction::RemoveDeletedIn( const ScChangeAction* p )
299 bool bRemoved = false;
300 ScChangeActionLinkEntry* pL = GetDeletedIn();
301 while ( pL )
303 ScChangeActionLinkEntry* pNextLink = pL->GetNext();
304 if ( pL->GetAction() == p )
306 delete pL;
307 bRemoved = true;
309 pL = pNextLink;
311 return bRemoved;
314 bool ScChangeAction::IsDeletedIn() const
316 return GetDeletedIn() != NULL;
319 bool ScChangeAction::IsDeletedIn( const ScChangeAction* p ) const
321 ScChangeActionLinkEntry* pL = GetDeletedIn();
322 while ( pL )
324 if ( pL->GetAction() == p )
325 return true;
326 pL = pL->GetNext();
328 return false;
331 void ScChangeAction::RemoveAllDeletedIn()
333 //! Not from TopContent, but really this one
334 while ( pLinkDeletedIn )
335 delete pLinkDeletedIn; // Moves up by itself
338 bool ScChangeAction::IsDeletedInDelType( ScChangeActionType eDelType ) const
340 ScChangeActionLinkEntry* pL = GetDeletedIn();
341 if ( pL )
343 // InsertType for MergePrepare/MergeOwn
344 ScChangeActionType eInsType;
345 switch ( eDelType )
347 case SC_CAT_DELETE_COLS :
348 eInsType = SC_CAT_INSERT_COLS;
349 break;
350 case SC_CAT_DELETE_ROWS :
351 eInsType = SC_CAT_INSERT_ROWS;
352 break;
353 case SC_CAT_DELETE_TABS :
354 eInsType = SC_CAT_INSERT_TABS;
355 break;
356 default:
357 eInsType = SC_CAT_NONE;
359 ScChangeAction* p;
360 while ( pL )
362 if ( (p = pL->GetAction()) != NULL &&
363 (p->GetType() == eDelType || p->GetType() == eInsType) )
364 return true;
365 pL = pL->GetNext();
368 return false;
371 bool ScChangeAction::HasDependent() const
373 return pLinkDependent != NULL;
376 bool ScChangeAction::HasDeleted() const
378 return pLinkDeleted != NULL;
381 void ScChangeAction::SetDeletedIn( ScChangeAction* p )
383 ScChangeActionLinkEntry* pLink1 = AddDeletedIn( p );
384 ScChangeActionLinkEntry* pLink2;
385 if ( GetType() == SC_CAT_CONTENT )
386 pLink2 = p->AddDeleted( ((ScChangeActionContent*)this)->GetTopContent() );
387 else
388 pLink2 = p->AddDeleted( this );
389 pLink1->SetLink( pLink2 );
392 void ScChangeAction::RemoveAllDeleted()
394 while ( pLinkDeleted )
395 delete pLinkDeleted; // Moves up by itself
398 void ScChangeAction::RemoveAllDependent()
400 while ( pLinkDependent )
401 delete pLinkDependent; // Moves up by itself
404 DateTime ScChangeAction::GetDateTime() const
406 DateTime aDT( aDateTime );
407 aDT.ConvertToLocalTime();
408 return aDT;
411 void ScChangeAction::UpdateReference( const ScChangeTrack* /* pTrack */,
412 UpdateRefMode eMode, const ScBigRange& rRange,
413 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
415 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
418 void ScChangeAction::GetDescription(
419 OUString& rStr, ScDocument* /* pDoc */, bool /* bSplitRange */, bool bWarning ) const
421 if (!IsRejecting() || !bWarning)
422 return;
424 // Add comment if rejection may have resulted in references
425 // not properly restored in formulas. See specification at
426 // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw
428 OUStringBuffer aBuf(rStr); // Take the original string.
429 if (GetType() == SC_CAT_MOVE)
431 aBuf.append(
432 ScGlobal::GetRscString(STR_CHANGED_MOVE_REJECTION_WARNING) + " ");
433 rStr = aBuf.makeStringAndClear();
434 return;
437 if (IsInsertType())
439 aBuf.append(
440 ScGlobal::GetRscString(STR_CHANGED_DELETE_REJECTION_WARNING) + " ");
441 rStr = aBuf.makeStringAndClear();
442 return;
445 const ScChangeTrack* pCT = GetChangeTrack();
446 if (!pCT)
447 return;
449 ScChangeAction* pReject = pCT->GetActionOrGenerated(GetRejectAction());
451 if (!pReject)
452 return;
454 if (pReject->GetType() == SC_CAT_MOVE)
456 aBuf.append(
457 ScGlobal::GetRscString(STR_CHANGED_MOVE_REJECTION_WARNING));
458 aBuf.append(' ');
459 rStr = aBuf.makeStringAndClear();
460 return;
463 if (pReject->IsDeleteType())
465 aBuf.append(
466 ScGlobal::GetRscString(STR_CHANGED_DELETE_REJECTION_WARNING));
467 aBuf.append(' ');
468 rStr = aBuf.makeStringAndClear();
469 return;
472 if (pReject->HasDependent())
474 ScChangeActionMap aMap;
475 pCT->GetDependents( pReject, aMap, false, true );
476 ScChangeActionMap::iterator itChangeAction;
477 for( itChangeAction = aMap.begin(); itChangeAction != aMap.end(); ++itChangeAction )
479 if( itChangeAction->second->GetType() == SC_CAT_MOVE)
481 aBuf.append(
482 ScGlobal::GetRscString(STR_CHANGED_MOVE_REJECTION_WARNING));
483 aBuf.append(' ');
484 rStr = aBuf.makeStringAndClear();
485 return;
488 if (pReject->IsDeleteType())
490 aBuf.append(
491 ScGlobal::GetRscString(STR_CHANGED_DELETE_REJECTION_WARNING));
492 aBuf.append(' ');
493 rStr = aBuf.makeStringAndClear();
494 return;
500 OUString ScChangeAction::GetRefString(
501 const ScBigRange& rRange, ScDocument* pDoc, bool bFlag3D ) const
503 OUStringBuffer aBuf;
504 sal_uInt16 nFlags = ( rRange.IsValid( pDoc ) ? SCA_VALID : 0 );
505 if ( !nFlags )
506 aBuf.append(ScGlobal::GetRscString(STR_NOREF_STR));
507 else
509 ScRange aTmpRange( rRange.MakeRange() );
510 switch ( GetType() )
512 case SC_CAT_INSERT_COLS :
513 case SC_CAT_DELETE_COLS :
514 if ( bFlag3D )
516 OUString aTmp;
517 pDoc->GetName( aTmpRange.aStart.Tab(), aTmp );
518 aBuf.append(aTmp);
519 aBuf.append('.');
521 aBuf.append(ScColToAlpha(aTmpRange.aStart.Col()));
522 aBuf.append(':');
523 aBuf.append(ScColToAlpha(aTmpRange.aEnd.Col()));
524 break;
525 case SC_CAT_INSERT_ROWS :
526 case SC_CAT_DELETE_ROWS :
527 if ( bFlag3D )
529 OUString aTmp;
530 pDoc->GetName( aTmpRange.aStart.Tab(), aTmp );
531 aBuf.append(aTmp);
532 aBuf.append('.');
534 aBuf.append(static_cast<sal_Int32>(aTmpRange.aStart.Row()+1));
535 aBuf.append(':');
536 aBuf.append(static_cast<sal_Int32>(aTmpRange.aEnd.Row()+1));
537 break;
538 default:
540 if ( bFlag3D || GetType() == SC_CAT_INSERT_TABS )
541 nFlags |= SCA_TAB_3D;
543 aBuf.append(aTmpRange.Format(nFlags, pDoc, pDoc->GetAddressConvention()));
546 if ( (bFlag3D && IsDeleteType()) || IsDeletedIn() )
548 aBuf.insert(0, '(');
549 aBuf.append(')');
552 return aBuf.makeStringAndClear();
555 const OUString& ScChangeAction::GetUser() const
557 return aUser;
560 void ScChangeAction::SetUser( const OUString& r )
562 aUser = r;
565 const OUString& ScChangeAction::GetComment() const
567 return aComment;
570 void ScChangeAction::SetComment( const OUString& rStr )
572 aComment = rStr;
575 void ScChangeAction::GetRefString(
576 OUString& rStr, ScDocument* pDoc, bool bFlag3D ) const
578 rStr = GetRefString( GetBigRange(), pDoc, bFlag3D );
581 void ScChangeAction::Accept()
583 if ( IsVirgin() )
585 SetState( SC_CAS_ACCEPTED );
586 DeleteCellEntries();
590 void ScChangeAction::SetRejected()
592 if ( IsVirgin() )
594 SetState( SC_CAS_REJECTED );
595 RemoveAllLinks();
596 DeleteCellEntries();
600 void ScChangeAction::RejectRestoreContents( ScChangeTrack* pTrack,
601 SCsCOL nDx, SCsROW nDy )
603 // Construct list of Contents
604 ScChangeActionCellListEntry* pListContents = NULL;
605 for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() )
607 ScChangeAction* p = pL->GetAction();
608 if ( p && p->GetType() == SC_CAT_CONTENT )
610 ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
611 (ScChangeActionContent*) p, pListContents );
612 pListContents = pE;
615 SetState( SC_CAS_REJECTED ); // Before UpdateReference for Move
616 pTrack->UpdateReference( this, true ); // Free LinkDeleted
617 OSL_ENSURE( !pLinkDeleted, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" );
619 // Work through list of Contents and delete
620 ScDocument* pDoc = pTrack->GetDocument();
621 ScChangeActionCellListEntry* pE = pListContents;
622 while ( pE )
624 if ( !pE->pContent->IsDeletedIn() &&
625 pE->pContent->GetBigRange().aStart.IsValid( pDoc ) )
626 pE->pContent->PutNewValueToDoc( pDoc, nDx, nDy );
627 ScChangeActionCellListEntry* pNextEntry;
628 pNextEntry = pE->pNext;
629 delete pE;
630 pE = pNextEntry;
632 DeleteCellEntries(); // Remove generated ones
635 void ScChangeAction::SetDeletedInThis( sal_uLong nActionNumber,
636 const ScChangeTrack* pTrack )
638 if ( nActionNumber )
640 ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber );
641 OSL_ENSURE( pAct, "ScChangeAction::SetDeletedInThis: missing Action" );
642 if ( pAct )
643 pAct->SetDeletedIn( this );
647 void ScChangeAction::AddDependent( sal_uLong nActionNumber,
648 const ScChangeTrack* pTrack )
650 if ( nActionNumber )
652 ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber );
653 OSL_ENSURE( pAct, "ScChangeAction::AddDependent: missing Action" );
654 if ( pAct )
656 ScChangeActionLinkEntry* pLink = AddDependent( pAct );
657 pAct->AddLink( this, pLink );
662 // ScChangeActionIns
663 ScChangeActionIns::ScChangeActionIns( const ScRange& rRange )
664 : ScChangeAction( SC_CAT_NONE, rRange )
666 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL )
668 aBigRange.aStart.SetCol( nInt32Min );
669 aBigRange.aEnd.SetCol( nInt32Max );
670 if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
672 SetType( SC_CAT_INSERT_TABS );
673 aBigRange.aStart.SetRow( nInt32Min );
674 aBigRange.aEnd.SetRow( nInt32Max );
676 else
677 SetType( SC_CAT_INSERT_ROWS );
679 else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
681 SetType( SC_CAT_INSERT_COLS );
682 aBigRange.aStart.SetRow( nInt32Min );
683 aBigRange.aEnd.SetRow( nInt32Max );
685 else
687 OSL_FAIL( "ScChangeActionIns: Block not supported!" );
691 ScChangeActionIns::ScChangeActionIns(
692 const sal_uLong nActionNumber, const ScChangeActionState eStateP,
693 const sal_uLong nRejectingNumber, const ScBigRange& aBigRangeP,
694 const OUString& aUserP, const DateTime& aDateTimeP,
695 const OUString& sComment, const ScChangeActionType eTypeP) :
696 ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment)
700 ScChangeActionIns::~ScChangeActionIns()
704 void ScChangeActionIns::GetDescription(
705 OUString& rStr, ScDocument* pDoc, bool bSplitRange, bool bWarning ) const
707 ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
709 sal_uInt16 nWhatId;
710 switch ( GetType() )
712 case SC_CAT_INSERT_COLS :
713 nWhatId = STR_COLUMN;
714 break;
715 case SC_CAT_INSERT_ROWS :
716 nWhatId = STR_ROW;
717 break;
718 default:
719 nWhatId = STR_AREA;
722 OUString aRsc = ScGlobal::GetRscString(STR_CHANGED_INSERT);
723 sal_Int32 nPos = aRsc.indexOfAsciiL("#1", 2);
724 if (nPos >= 0)
726 // Construct a range string to replace '#1' first.
727 OUStringBuffer aBuf(ScGlobal::GetRscString(nWhatId));
728 aBuf.append(' ');
729 aBuf.append(GetRefString(GetBigRange(), pDoc));
730 OUString aRangeStr = aBuf.makeStringAndClear();
732 aRsc = aRsc.replaceAt(nPos, 2, aRangeStr); // replace '#1' with the range string.
734 aBuf.append(rStr).append(aRsc);
735 rStr = aBuf.makeStringAndClear();
739 bool ScChangeActionIns::Reject( ScDocument* pDoc )
741 if ( !aBigRange.IsValid( pDoc ) )
742 return false;
744 ScRange aRange( aBigRange.MakeRange() );
745 if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
746 aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
747 return false;
749 switch ( GetType() )
751 case SC_CAT_INSERT_COLS :
752 pDoc->DeleteCol( aRange );
753 break;
754 case SC_CAT_INSERT_ROWS :
755 pDoc->DeleteRow( aRange );
756 break;
757 case SC_CAT_INSERT_TABS :
758 pDoc->DeleteTab( aRange.aStart.Tab() );
759 break;
760 default:
762 // added to avoid warnings
765 SetState( SC_CAS_REJECTED );
766 RemoveAllLinks();
767 return true;
770 // ScChangeActionDel
771 ScChangeActionDel::ScChangeActionDel( const ScRange& rRange,
772 SCsCOL nDxP, SCsROW nDyP, ScChangeTrack* pTrackP )
774 ScChangeAction( SC_CAT_NONE, rRange ),
775 pTrack( pTrackP ),
776 pFirstCell( NULL ),
777 pCutOff( NULL ),
778 nCutOff( 0 ),
779 pLinkMove( NULL ),
780 nDx( nDxP ),
781 nDy( nDyP )
783 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL )
785 aBigRange.aStart.SetCol( nInt32Min );
786 aBigRange.aEnd.SetCol( nInt32Max );
787 if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
789 SetType( SC_CAT_DELETE_TABS );
790 aBigRange.aStart.SetRow( nInt32Min );
791 aBigRange.aEnd.SetRow( nInt32Max );
793 else
794 SetType( SC_CAT_DELETE_ROWS );
796 else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
798 SetType( SC_CAT_DELETE_COLS );
799 aBigRange.aStart.SetRow( nInt32Min );
800 aBigRange.aEnd.SetRow( nInt32Max );
802 else
804 OSL_FAIL( "ScChangeActionDel: Block not supported!" );
808 ScChangeActionDel::ScChangeActionDel(
809 const sal_uLong nActionNumber, const ScChangeActionState eStateP,
810 const sal_uLong nRejectingNumber, const ScBigRange& aBigRangeP,
811 const OUString& aUserP, const DateTime& aDateTimeP, const OUString &sComment,
812 const ScChangeActionType eTypeP, const SCsCOLROW nD, ScChangeTrack* pTrackP) : // which of nDx and nDy is set depends on the type
813 ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
814 pTrack( pTrackP ),
815 pFirstCell( NULL ),
816 pCutOff( NULL ),
817 nCutOff( 0 ),
818 pLinkMove( NULL ),
819 nDx( 0 ),
820 nDy( 0 )
822 if (eType == SC_CAT_DELETE_COLS)
823 nDx = static_cast<SCsCOL>(nD);
824 else if (eType == SC_CAT_DELETE_ROWS)
825 nDy = static_cast<SCsROW>(nD);
828 ScChangeActionDel::~ScChangeActionDel()
830 DeleteCellEntries();
831 while ( pLinkMove )
832 delete pLinkMove;
835 void ScChangeActionDel::AddContent( ScChangeActionContent* pContent )
837 ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
838 pContent, pFirstCell );
839 pFirstCell = pE;
842 void ScChangeActionDel::DeleteCellEntries()
844 pTrack->DeleteCellEntries( pFirstCell, this );
847 bool ScChangeActionDel::IsBaseDelete() const
849 return !GetDx() && !GetDy();
852 bool ScChangeActionDel::IsTopDelete() const
854 const ScChangeAction* p = GetNext();
855 if ( !p || p->GetType() != GetType() )
856 return true;
857 return ((ScChangeActionDel*)p)->IsBaseDelete();
860 bool ScChangeActionDel::IsMultiDelete() const
862 if ( GetDx() || GetDy() )
863 return true;
864 const ScChangeAction* p = GetNext();
865 if ( !p || p->GetType() != GetType() )
866 return false;
867 const ScChangeActionDel* pDel = (const ScChangeActionDel*) p;
868 if ( (pDel->GetDx() > GetDx() || pDel->GetDy() > GetDy()) &&
869 pDel->GetBigRange() == aBigRange )
870 return true;
871 return false;
874 bool ScChangeActionDel::IsTabDeleteCol() const
876 if ( GetType() != SC_CAT_DELETE_COLS )
877 return false;
878 const ScChangeAction* p = this;
879 while ( p && p->GetType() == SC_CAT_DELETE_COLS &&
880 !((const ScChangeActionDel*)p)->IsTopDelete() )
881 p = p->GetNext();
882 return p && p->GetType() == SC_CAT_DELETE_TABS;
885 SCsCOL ScChangeActionDel::GetDx() const { return nDx; }
886 SCsROW ScChangeActionDel::GetDy() const { return nDy; }
888 ScChangeActionDelMoveEntry* ScChangeActionDel::AddCutOffMove(
889 ScChangeActionMove* pMove, short nFrom, short nTo )
891 return new ScChangeActionDelMoveEntry(&pLinkMove, pMove, nFrom, nTo);
894 void ScChangeActionDel::UpdateReference( const ScChangeTrack* /* pTrack */,
895 UpdateRefMode eMode, const ScBigRange& rRange,
896 sal_Int32 nDxP, sal_Int32 nDyP, sal_Int32 nDz )
898 ScRefUpdate::Update( eMode, rRange, nDxP, nDyP, nDz, GetBigRange() );
900 if ( !IsDeletedIn() )
901 return ;
903 // Correct in the ones who slipped through
904 for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() )
906 ScChangeAction* p = pL->GetAction();
907 if ( p && p->GetType() == SC_CAT_CONTENT &&
908 !GetBigRange().In( p->GetBigRange() ) )
910 switch ( GetType() )
912 case SC_CAT_DELETE_COLS :
913 p->GetBigRange().aStart.SetCol( GetBigRange().aStart.Col() );
914 p->GetBigRange().aEnd.SetCol( GetBigRange().aStart.Col() );
915 break;
916 case SC_CAT_DELETE_ROWS :
917 p->GetBigRange().aStart.SetRow( GetBigRange().aStart.Row() );
918 p->GetBigRange().aEnd.SetRow( GetBigRange().aStart.Row() );
919 break;
920 case SC_CAT_DELETE_TABS :
921 p->GetBigRange().aStart.SetTab( GetBigRange().aStart.Tab() );
922 p->GetBigRange().aEnd.SetTab( GetBigRange().aStart.Tab() );
923 break;
924 default:
926 // added to avoid warnings
933 ScBigRange ScChangeActionDel::GetOverAllRange() const
935 ScBigRange aTmpRange( GetBigRange() );
936 aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() );
937 aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() );
938 return aTmpRange;
941 void ScChangeActionDel::GetDescription(
942 OUString& rStr, ScDocument* pDoc, bool bSplitRange, bool bWarning ) const
944 ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
946 sal_uInt16 nWhatId;
947 switch ( GetType() )
949 case SC_CAT_DELETE_COLS :
950 nWhatId = STR_COLUMN;
951 break;
952 case SC_CAT_DELETE_ROWS :
953 nWhatId = STR_ROW;
954 break;
955 default:
956 nWhatId = STR_AREA;
959 ScBigRange aTmpRange( GetBigRange() );
960 if ( !IsRejected() )
962 if ( bSplitRange )
964 aTmpRange.aStart.SetCol( aTmpRange.aStart.Col() + GetDx() );
965 aTmpRange.aStart.SetRow( aTmpRange.aStart.Row() + GetDy() );
967 aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() );
968 aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() );
971 OUString aRsc = ScGlobal::GetRscString(STR_CHANGED_DELETE);
972 sal_Int32 nPos = aRsc.indexOfAsciiL("#1", 2);
973 if (nPos >= 0)
975 // Build a string to replace with.
976 OUStringBuffer aBuf;
977 aBuf.append(ScGlobal::GetRscString(nWhatId));
978 aBuf.append(' ');
979 aBuf.append(GetRefString(aTmpRange, pDoc));
980 OUString aRangeStr = aBuf.makeStringAndClear();
981 aRsc = aRsc.replaceAt(nPos, 2, aRangeStr); // replace '#1' with the string.
983 aBuf.append(rStr).append(aRsc);
984 rStr = aBuf.makeStringAndClear(); // append to the original.
988 bool ScChangeActionDel::Reject( ScDocument* pDoc )
990 if ( !aBigRange.IsValid( pDoc ) && GetType() != SC_CAT_DELETE_TABS )
991 return false;
993 if ( IsTopDelete() )
994 { // Restore whole section in one go
995 bool bOk = true;
996 ScBigRange aTmpRange( GetOverAllRange() );
997 if ( !aTmpRange.IsValid( pDoc ) )
999 if ( GetType() == SC_CAT_DELETE_TABS )
1000 { // Do we attach a Tab?
1001 if ( aTmpRange.aStart.Tab() > pDoc->GetMaxTableNumber() )
1002 bOk = false;
1004 else
1005 bOk = false;
1007 if ( bOk )
1009 ScRange aRange( aTmpRange.MakeRange() );
1010 // InDelete... for formula UpdateReference in Document
1011 pTrack->SetInDeleteRange( aRange );
1012 pTrack->SetInDeleteTop( true );
1013 pTrack->SetInDeleteUndo( true );
1014 pTrack->SetInDelete( true );
1015 switch ( GetType() )
1017 case SC_CAT_DELETE_COLS :
1018 if ( !(aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL) )
1019 { // Only if not TabDelete
1020 if ( ( bOk = pDoc->CanInsertCol( aRange ) ) != false )
1021 bOk = pDoc->InsertCol( aRange );
1023 break;
1024 case SC_CAT_DELETE_ROWS :
1025 if ( ( bOk = pDoc->CanInsertRow( aRange ) ) != false )
1026 bOk = pDoc->InsertRow( aRange );
1027 break;
1028 case SC_CAT_DELETE_TABS :
1030 //TODO: Remember table names?
1031 OUString aName;
1032 pDoc->CreateValidTabName( aName );
1033 if ( ( bOk = pDoc->ValidNewTabName( aName ) ) != false )
1034 bOk = pDoc->InsertTab( aRange.aStart.Tab(), aName );
1036 break;
1037 default:
1039 // added to avoid warnings
1042 pTrack->SetInDelete( false );
1043 pTrack->SetInDeleteUndo( false );
1045 if ( !bOk )
1047 pTrack->SetInDeleteTop( false );
1048 return false;
1050 // Keep InDeleteTop for UpdateReference Undo
1053 // Sets rejected and calls UpdateReference-Undo and DeleteCellEntries
1054 RejectRestoreContents( pTrack, GetDx(), GetDy() );
1056 pTrack->SetInDeleteTop( false );
1057 RemoveAllLinks();
1058 return true;
1061 void ScChangeActionDel::UndoCutOffMoves()
1062 { // Restore cut off Moves; delete Entries/Links
1063 while ( pLinkMove )
1065 ScChangeActionMove* pMove = pLinkMove->GetMove();
1066 short nFrom = pLinkMove->GetCutOffFrom();
1067 short nTo = pLinkMove->GetCutOffTo();
1068 switch ( GetType() )
1070 case SC_CAT_DELETE_COLS :
1071 if ( nFrom > 0 )
1072 pMove->GetFromRange().aStart.IncCol( -nFrom );
1073 else if ( nFrom < 0 )
1074 pMove->GetFromRange().aEnd.IncCol( -nFrom );
1075 if ( nTo > 0 )
1076 pMove->GetBigRange().aStart.IncCol( -nTo );
1077 else if ( nTo < 0 )
1078 pMove->GetBigRange().aEnd.IncCol( -nTo );
1079 break;
1080 case SC_CAT_DELETE_ROWS :
1081 if ( nFrom > 0 )
1082 pMove->GetFromRange().aStart.IncRow( -nFrom );
1083 else if ( nFrom < 0 )
1084 pMove->GetFromRange().aEnd.IncRow( -nFrom );
1085 if ( nTo > 0 )
1086 pMove->GetBigRange().aStart.IncRow( -nTo );
1087 else if ( nTo < 0 )
1088 pMove->GetBigRange().aEnd.IncRow( -nTo );
1089 break;
1090 case SC_CAT_DELETE_TABS :
1091 if ( nFrom > 0 )
1092 pMove->GetFromRange().aStart.IncTab( -nFrom );
1093 else if ( nFrom < 0 )
1094 pMove->GetFromRange().aEnd.IncTab( -nFrom );
1095 if ( nTo > 0 )
1096 pMove->GetBigRange().aStart.IncTab( -nTo );
1097 else if ( nTo < 0 )
1098 pMove->GetBigRange().aEnd.IncTab( -nTo );
1099 break;
1100 default:
1102 // added to avoid warnings
1105 delete pLinkMove; // Moves up by itself
1109 void ScChangeActionDel::UndoCutOffInsert()
1110 { //Restore cut off Insert
1111 if ( pCutOff )
1113 switch ( pCutOff->GetType() )
1115 case SC_CAT_INSERT_COLS :
1116 if ( nCutOff < 0 )
1117 pCutOff->GetBigRange().aEnd.IncCol( -nCutOff );
1118 else
1119 pCutOff->GetBigRange().aStart.IncCol( -nCutOff );
1120 break;
1121 case SC_CAT_INSERT_ROWS :
1122 if ( nCutOff < 0 )
1123 pCutOff->GetBigRange().aEnd.IncRow( -nCutOff );
1124 else
1125 pCutOff->GetBigRange().aStart.IncRow( -nCutOff );
1126 break;
1127 case SC_CAT_INSERT_TABS :
1128 if ( nCutOff < 0 )
1129 pCutOff->GetBigRange().aEnd.IncTab( -nCutOff );
1130 else
1131 pCutOff->GetBigRange().aStart.IncTab( -nCutOff );
1132 break;
1133 default:
1135 // added to avoid warnings
1138 SetCutOffInsert( NULL, 0 );
1142 // ScChangeActionMove
1143 ScChangeActionMove::ScChangeActionMove(
1144 const sal_uLong nActionNumber, const ScChangeActionState eStateP,
1145 const sal_uLong nRejectingNumber, const ScBigRange& aToBigRange,
1146 const OUString& aUserP, const DateTime& aDateTimeP,
1147 const OUString &sComment, const ScBigRange& aFromBigRange,
1148 ScChangeTrack* pTrackP) : // which of nDx and nDy is set depends on the type
1149 ScChangeAction(SC_CAT_MOVE, aToBigRange, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
1150 aFromRange(aFromBigRange),
1151 pTrack( pTrackP ),
1152 pFirstCell( NULL ),
1153 nStartLastCut(0),
1154 nEndLastCut(0)
1158 ScChangeActionMove::~ScChangeActionMove()
1160 DeleteCellEntries();
1163 void ScChangeActionMove::AddContent( ScChangeActionContent* pContent )
1165 ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
1166 pContent, pFirstCell );
1167 pFirstCell = pE;
1170 void ScChangeActionMove::DeleteCellEntries()
1172 pTrack->DeleteCellEntries( pFirstCell, this );
1175 void ScChangeActionMove::UpdateReference( const ScChangeTrack* /* pTrack */,
1176 UpdateRefMode eMode, const ScBigRange& rRange,
1177 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
1179 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aFromRange );
1180 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
1183 void ScChangeActionMove::GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const
1185 const ScBigAddress& rToPos = GetBigRange().aStart;
1186 const ScBigAddress& rFromPos = GetFromRange().aStart;
1187 nDx = rToPos.Col() - rFromPos.Col();
1188 nDy = rToPos.Row() - rFromPos.Row();
1189 nDz = rToPos.Tab() - rFromPos.Tab();
1192 void ScChangeActionMove::GetDescription(
1193 OUString& rStr, ScDocument* pDoc, bool bSplitRange, bool bWarning ) const
1195 ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
1197 bool bFlag3D = GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab();
1199 OUString aRsc = ScGlobal::GetRscString(STR_CHANGED_MOVE);
1201 OUString aTmpStr = ScChangeAction::GetRefString(GetFromRange(), pDoc, bFlag3D);
1202 sal_Int32 nPos = aRsc.indexOfAsciiL("#1", 2);
1203 if (nPos >= 0)
1205 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1206 nPos += aTmpStr.getLength();
1209 aTmpStr = ScChangeAction::GetRefString(GetBigRange(), pDoc, bFlag3D);
1210 nPos = aRsc.indexOfAsciiL("#2", 2, nPos);
1211 if (nPos >= 0)
1213 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1214 nPos += aTmpStr.getLength();
1217 OUStringBuffer aBuf(rStr); // append to the original string.
1218 aBuf.append(aRsc);
1219 rStr = aBuf.makeStringAndClear();
1222 void ScChangeActionMove::GetRefString(
1223 OUString& rStr, ScDocument* pDoc, bool bFlag3D ) const
1225 if ( !bFlag3D )
1226 bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() );
1228 // overwrite existing string value.
1229 rStr = ScChangeAction::GetRefString(GetFromRange(), pDoc, bFlag3D)
1230 + ", "
1231 + ScChangeAction::GetRefString(GetBigRange(), pDoc, bFlag3D);
1234 bool ScChangeActionMove::Reject( ScDocument* pDoc )
1236 if ( !(aBigRange.IsValid( pDoc ) && aFromRange.IsValid( pDoc )) )
1237 return false;
1239 ScRange aToRange( aBigRange.MakeRange() );
1240 ScRange aFrmRange( aFromRange.MakeRange() );
1242 bool bOk = pDoc->IsBlockEditable( aToRange.aStart.Tab(),
1243 aToRange.aStart.Col(), aToRange.aStart.Row(),
1244 aToRange.aEnd.Col(), aToRange.aEnd.Row() );
1245 if ( bOk )
1246 bOk = pDoc->IsBlockEditable( aFrmRange.aStart.Tab(),
1247 aFrmRange.aStart.Col(), aFrmRange.aStart.Row(),
1248 aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row() );
1249 if ( !bOk )
1250 return false;
1252 pTrack->LookUpContents( aToRange, pDoc, 0, 0, 0 ); // Contents to be moved
1254 pDoc->DeleteAreaTab( aToRange, IDF_ALL );
1255 pDoc->DeleteAreaTab( aFrmRange, IDF_ALL );
1256 // Adjust formula in the Document
1257 sc::RefUpdateContext aCxt(*pDoc);
1258 aCxt.meMode = URM_MOVE;
1259 aCxt.maRange = aFrmRange;
1260 aCxt.mnColDelta = aFrmRange.aStart.Col() - aToRange.aStart.Col();
1261 aCxt.mnRowDelta = aFrmRange.aStart.Row() - aToRange.aStart.Row();
1262 aCxt.mnTabDelta = aFrmRange.aStart.Tab() - aToRange.aStart.Tab();
1263 pDoc->UpdateReference(aCxt, NULL);
1265 // Free LinkDependent, set succeeding UpdateReference Undo
1266 // ToRange->FromRange Dependents
1267 RemoveAllDependent();
1269 // Sets rejected and calls UpdateReference Undo and DeleteCellEntries
1270 RejectRestoreContents( pTrack, 0, 0 );
1272 while ( pLinkDependent )
1274 ScChangeAction* p = pLinkDependent->GetAction();
1275 if ( p && p->GetType() == SC_CAT_CONTENT )
1277 ScChangeActionContent* pContent = (ScChangeActionContent*) p;
1278 if ( !pContent->IsDeletedIn() &&
1279 pContent->GetBigRange().aStart.IsValid( pDoc ) )
1280 pContent->PutNewValueToDoc( pDoc, 0, 0 );
1281 // Delete the ones created in LookUpContents
1282 if ( pTrack->IsGenerated( pContent->GetActionNumber() ) &&
1283 !pContent->IsDeletedIn() )
1285 pLinkDependent->UnLink(); //! Else this one is also deleted
1286 pTrack->DeleteGeneratedDelContent( pContent );
1289 delete pLinkDependent;
1292 RemoveAllLinks();
1293 return true;
1296 // ScChangeActionContent
1297 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent )
1299 ScChangeActionContent::ScChangeActionContent( const ScRange& rRange ) :
1300 ScChangeAction(SC_CAT_CONTENT, rRange),
1301 pNextContent(NULL),
1302 pPrevContent(NULL),
1303 pNextInSlot(NULL),
1304 ppPrevInSlot(NULL)
1307 ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber,
1308 const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
1309 const ScBigRange& aBigRangeP, const OUString& aUserP,
1310 const DateTime& aDateTimeP, const OUString& sComment,
1311 const ScCellValue& rOldCell, ScDocument* pDoc, const OUString& sOldValue ) :
1312 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
1313 maOldCell(rOldCell),
1314 maOldValue(sOldValue),
1315 pNextContent(NULL),
1316 pPrevContent(NULL),
1317 pNextInSlot(NULL),
1318 ppPrevInSlot(NULL)
1320 if (!maOldCell.isEmpty())
1321 SetCell(maOldValue, maOldCell, 0, pDoc);
1323 if (!sOldValue.isEmpty()) // #i40704# don't overwrite SetCell result with empty string
1324 maOldValue = sOldValue; // set again, because SetCell removes it
1327 ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber,
1328 const ScCellValue& rNewCell, const ScBigRange& aBigRangeP,
1329 ScDocument* pDoc, const OUString& sNewValue ) :
1330 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber),
1331 maNewCell(rNewCell),
1332 maNewValue(sNewValue),
1333 pNextContent(NULL),
1334 pPrevContent(NULL),
1335 pNextInSlot(NULL),
1336 ppPrevInSlot(NULL)
1338 if (!maNewCell.isEmpty())
1339 SetCell(maNewValue, maNewCell, 0, pDoc);
1341 if (!sNewValue.isEmpty()) // #i40704# don't overwrite SetCell result with empty string
1342 maNewValue = sNewValue; // set again, because SetCell removes it
1345 ScChangeActionContent::~ScChangeActionContent()
1347 ClearTrack();
1350 void ScChangeActionContent::ClearTrack()
1352 RemoveFromSlot();
1353 if ( pPrevContent )
1354 pPrevContent->pNextContent = pNextContent;
1355 if ( pNextContent )
1356 pNextContent->pPrevContent = pPrevContent;
1359 ScChangeActionContent* ScChangeActionContent::GetTopContent() const
1361 if ( pNextContent )
1363 ScChangeActionContent* pContent = pNextContent;
1364 while ( pContent->pNextContent && pContent != pContent->pNextContent )
1365 pContent = pContent->pNextContent;
1366 return pContent;
1368 return (ScChangeActionContent*) this;
1371 ScChangeActionLinkEntry* ScChangeActionContent::GetDeletedIn() const
1373 if ( pNextContent )
1374 return GetTopContent()->pLinkDeletedIn;
1375 return pLinkDeletedIn;
1378 ScChangeActionLinkEntry** ScChangeActionContent::GetDeletedInAddress()
1380 if ( pNextContent )
1381 return GetTopContent()->GetDeletedInAddress();
1382 return &pLinkDeletedIn;
1385 void ScChangeActionContent::SetOldValue(
1386 const ScCellValue& rCell, const ScDocument* pFromDoc, ScDocument* pToDoc, sal_uLong nFormat )
1388 SetValue(maOldValue, maOldCell, nFormat, rCell, pFromDoc, pToDoc);
1391 void ScChangeActionContent::SetOldValue(
1392 const ScCellValue& rCell, const ScDocument* pFromDoc, ScDocument* pToDoc )
1394 SetValue(maOldValue, maOldCell, aBigRange.aStart.MakeAddress(), rCell, pFromDoc, pToDoc);
1397 void ScChangeActionContent::SetNewValue( const ScCellValue& rCell, ScDocument* pDoc )
1399 SetValue(maNewValue, maNewCell, aBigRange.aStart.MakeAddress(), rCell, pDoc, pDoc);
1402 void ScChangeActionContent::SetOldNewCells(
1403 const ScCellValue& rOldCell, sal_uLong nOldFormat, const ScCellValue& rNewCell,
1404 sal_uLong nNewFormat, ScDocument* pDoc )
1406 maOldCell = rOldCell;
1407 maNewCell = rNewCell;
1408 SetCell(maOldValue, maOldCell, nOldFormat, pDoc);
1409 SetCell(maNewValue, maNewCell, nNewFormat, pDoc);
1412 void ScChangeActionContent::SetNewCell(
1413 const ScCellValue& rCell, ScDocument* pDoc, const OUString& rFormatted )
1415 maNewCell = rCell;
1416 SetCell(maNewValue, maNewCell, 0, pDoc);
1418 // #i40704# allow to set formatted text here - don't call SetNewValue with string from XML filter
1419 if (!rFormatted.isEmpty())
1420 maNewValue = rFormatted;
1423 void ScChangeActionContent::SetValueString(
1424 OUString& rValue, ScCellValue& rCell, const OUString& rStr, ScDocument* pDoc )
1426 rCell.clear();
1427 if ( rStr.getLength() > 1 && rStr[0] == '=' )
1429 rValue = EMPTY_OUSTRING;
1430 rCell.meType = CELLTYPE_FORMULA;
1431 rCell.mpFormula = new ScFormulaCell(
1432 pDoc, aBigRange.aStart.MakeAddress(), rStr,
1433 formula::FormulaGrammar::GRAM_DEFAULT, pDoc->GetGrammar() );
1434 rCell.mpFormula->SetInChangeTrack(true);
1436 else
1437 rValue = rStr;
1440 void ScChangeActionContent::SetOldValue( const OUString& rOld, ScDocument* pDoc )
1442 SetValueString(maOldValue, maOldCell, rOld, pDoc);
1445 void ScChangeActionContent::GetOldString( OUString& rStr, const ScDocument* pDoc ) const
1447 GetValueString(rStr, maOldValue, maOldCell, pDoc);
1450 void ScChangeActionContent::GetNewString( OUString& rStr, const ScDocument* pDoc ) const
1452 GetValueString(rStr, maNewValue, maNewCell, pDoc);
1455 const ScCellValue& ScChangeActionContent::GetOldCell() const
1457 return maOldCell;
1460 const ScCellValue& ScChangeActionContent::GetNewCell() const
1462 return maNewCell;
1465 void ScChangeActionContent::GetDescription(
1466 OUString& rStr, ScDocument* pDoc, bool bSplitRange, bool bWarning ) const
1468 ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
1470 OUString aRsc = ScGlobal::GetRscString(STR_CHANGED_CELL);
1472 OUString aTmpStr;
1473 GetRefString(aTmpStr, pDoc);
1475 sal_Int32 nPos = 0;
1476 nPos = aRsc.indexOfAsciiL("#1", 2, nPos);
1477 if (nPos >= 0)
1479 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1480 nPos += aTmpStr.getLength();
1483 GetOldString( aTmpStr, pDoc );
1484 if (aTmpStr.isEmpty())
1485 aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK );
1487 nPos = aRsc.indexOfAsciiL("#2", 2, nPos);
1488 if (nPos >= 0)
1490 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1491 nPos += aTmpStr.getLength();
1494 GetNewString( aTmpStr, pDoc );
1495 if (aTmpStr.isEmpty())
1496 aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK );
1498 nPos = aRsc.indexOfAsciiL("#3", 2, nPos);
1499 if (nPos >= 0)
1501 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1502 nPos += aTmpStr.getLength();
1505 OUStringBuffer aBuf(rStr); // append to the original string.
1506 aBuf.append(aRsc);
1507 rStr = aBuf.makeStringAndClear();
1510 void ScChangeActionContent::GetRefString(
1511 OUString& rStr, ScDocument* pDoc, bool bFlag3D ) const
1513 sal_uInt16 nFlags = ( GetBigRange().IsValid( pDoc ) ? SCA_VALID : 0 );
1514 if ( nFlags )
1516 const ScCellValue& rCell = GetNewCell();
1517 if ( GetContentCellType(rCell) == SC_CACCT_MATORG )
1519 ScBigRange aLocalBigRange( GetBigRange() );
1520 SCCOL nC;
1521 SCROW nR;
1522 rCell.mpFormula->GetMatColsRows( nC, nR );
1523 aLocalBigRange.aEnd.IncCol( nC-1 );
1524 aLocalBigRange.aEnd.IncRow( nR-1 );
1525 rStr = ScChangeAction::GetRefString( aLocalBigRange, pDoc, bFlag3D );
1527 return ;
1530 ScAddress aTmpAddress( GetBigRange().aStart.MakeAddress() );
1531 if ( bFlag3D )
1532 nFlags |= SCA_TAB_3D;
1533 rStr = aTmpAddress.Format(nFlags, pDoc, pDoc->GetAddressConvention());
1534 if ( IsDeletedIn() )
1536 // Insert the parentheses.
1537 OUStringBuffer aBuf;
1538 aBuf.append('(');
1539 aBuf.append(rStr);
1540 aBuf.append(')');
1541 rStr = aBuf.makeStringAndClear();
1544 else
1545 rStr = ScGlobal::GetRscString( STR_NOREF_STR );
1548 bool ScChangeActionContent::Reject( ScDocument* pDoc )
1550 if ( !aBigRange.IsValid( pDoc ) )
1551 return false;
1553 PutOldValueToDoc( pDoc, 0, 0 );
1555 SetState( SC_CAS_REJECTED );
1556 RemoveAllLinks();
1558 return true;
1561 bool ScChangeActionContent::Select( ScDocument* pDoc, ScChangeTrack* pTrack,
1562 bool bOldest, ::std::stack<ScChangeActionContent*>* pRejectActions )
1564 if ( !aBigRange.IsValid( pDoc ) )
1565 return false;
1567 ScChangeActionContent* pContent = this;
1568 // accept previous contents
1569 while ( ( pContent = pContent->pPrevContent ) != NULL )
1571 if ( pContent->IsVirgin() )
1572 pContent->SetState( SC_CAS_ACCEPTED );
1574 ScChangeActionContent* pEnd = pContent = this;
1575 // reject subsequent contents
1576 while ( ( pContent = pContent->pNextContent ) != NULL )
1578 // MatrixOrigin may have dependents, no dependency recursion needed
1579 const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry();
1580 while ( pL )
1582 ScChangeAction* p = (ScChangeAction*) pL->GetAction();
1583 if ( p )
1584 p->SetRejected();
1585 pL = pL->GetNext();
1587 pContent->SetRejected();
1588 pEnd = pContent;
1591 // If not oldest: Is it anyone else than the last one?
1592 if ( bOldest || pEnd != this )
1593 { ScRange aRange( aBigRange.aStart.MakeAddress() );
1594 const ScAddress& rPos = aRange.aStart;
1596 ScChangeActionContent* pNew = new ScChangeActionContent( aRange );
1597 ScCellValue aCell;
1598 aCell.assign(*pDoc, rPos);
1599 pNew->SetOldValue(aCell, pDoc, pDoc);
1601 if ( bOldest )
1602 PutOldValueToDoc( pDoc, 0, 0 );
1603 else
1604 PutNewValueToDoc( pDoc, 0, 0 );
1606 pNew->SetRejectAction( bOldest ? GetActionNumber() : pEnd->GetActionNumber() );
1607 pNew->SetState( SC_CAS_ACCEPTED );
1608 if ( pRejectActions )
1609 pRejectActions->push( pNew );
1610 else
1612 aCell.assign(*pDoc, rPos);
1613 pNew->SetNewValue(aCell, pDoc);
1614 pTrack->Append( pNew );
1618 if ( bOldest )
1619 SetRejected();
1620 else
1621 SetState( SC_CAS_ACCEPTED );
1623 return true;
1626 void ScChangeActionContent::GetStringOfCell(
1627 OUString& rStr, const ScCellValue& rCell, const ScDocument* pDoc, const ScAddress& rPos )
1629 if (NeedsNumberFormat(rCell))
1630 GetStringOfCell(rStr, rCell, pDoc, pDoc->GetNumberFormat(rPos));
1631 else
1632 GetStringOfCell(rStr, rCell, pDoc, 0);
1635 void ScChangeActionContent::GetStringOfCell(
1636 OUString& rStr, const ScCellValue& rCell, const ScDocument* pDoc, sal_uLong nFormat )
1638 rStr = EMPTY_OUSTRING;
1640 if (!GetContentCellType(rCell))
1641 return;
1643 switch (rCell.meType)
1645 case CELLTYPE_VALUE:
1646 pDoc->GetFormatTable()->GetInputLineString(rCell.mfValue, nFormat, rStr);
1647 break;
1648 case CELLTYPE_STRING:
1649 rStr = rCell.mpString->getString();
1650 break;
1651 case CELLTYPE_EDIT:
1652 if (rCell.mpEditText)
1653 rStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc);
1654 break;
1655 case CELLTYPE_FORMULA:
1656 rCell.mpFormula->GetFormula(rStr);
1657 break;
1658 default:
1663 ScChangeActionContentCellType ScChangeActionContent::GetContentCellType( const ScCellValue& rCell )
1665 switch (rCell.meType)
1667 case CELLTYPE_VALUE :
1668 case CELLTYPE_STRING :
1669 case CELLTYPE_EDIT :
1670 return SC_CACCT_NORMAL;
1671 case CELLTYPE_FORMULA :
1672 switch (rCell.mpFormula->GetMatrixFlag())
1674 case MM_NONE :
1675 return SC_CACCT_NORMAL;
1676 case MM_FORMULA :
1677 case MM_FAKE :
1678 return SC_CACCT_MATORG;
1679 case MM_REFERENCE :
1680 return SC_CACCT_MATREF;
1682 return SC_CACCT_NORMAL;
1683 default:
1684 return SC_CACCT_NONE;
1688 ScChangeActionContentCellType ScChangeActionContent::GetContentCellType( const ScRefCellValue& rCell )
1690 switch (rCell.meType)
1692 case CELLTYPE_VALUE:
1693 case CELLTYPE_STRING:
1694 case CELLTYPE_EDIT:
1695 return SC_CACCT_NORMAL;
1696 case CELLTYPE_FORMULA:
1698 const ScFormulaCell* pCell = rCell.mpFormula;
1699 switch (pCell->GetMatrixFlag())
1701 case MM_NONE :
1702 return SC_CACCT_NORMAL;
1703 case MM_FORMULA :
1704 case MM_FAKE :
1705 return SC_CACCT_MATORG;
1706 case MM_REFERENCE :
1707 return SC_CACCT_MATREF;
1708 default:
1711 return SC_CACCT_NORMAL;
1713 default:
1717 return SC_CACCT_NONE;
1720 bool ScChangeActionContent::NeedsNumberFormat( const ScCellValue& rVal )
1722 return rVal.meType == CELLTYPE_VALUE;
1725 void ScChangeActionContent::SetValue(
1726 OUString& rStr, ScCellValue& rCell, const ScAddress& rPos, const ScCellValue& rOrgCell,
1727 const ScDocument* pFromDoc, ScDocument* pToDoc )
1729 sal_uLong nFormat = NeedsNumberFormat(rOrgCell) ? pFromDoc->GetNumberFormat(rPos) : 0;
1730 SetValue(rStr, rCell, nFormat, rOrgCell, pFromDoc, pToDoc);
1733 void ScChangeActionContent::SetValue(
1734 OUString& rStr, ScCellValue& rCell, sal_uLong nFormat, const ScCellValue& rOrgCell,
1735 const ScDocument* pFromDoc, ScDocument* pToDoc )
1737 rStr = OUString();
1739 if (GetContentCellType(rOrgCell))
1741 rCell.assign(rOrgCell, *pToDoc);
1742 switch (rOrgCell.meType)
1744 case CELLTYPE_VALUE :
1745 { // E.g.: Remember date as such
1746 pFromDoc->GetFormatTable()->GetInputLineString(
1747 rOrgCell.mfValue, nFormat, rStr);
1749 break;
1750 case CELLTYPE_FORMULA :
1751 rCell.mpFormula->SetInChangeTrack(true);
1752 break;
1753 default:
1755 // added to avoid warnings
1759 else
1760 rCell.clear();
1763 void ScChangeActionContent::SetCell( OUString& rStr, ScCellValue& rCell, sal_uLong nFormat, const ScDocument* pDoc )
1765 rStr = OUString();
1766 if (rCell.isEmpty())
1767 return;
1769 switch (rCell.meType)
1771 case CELLTYPE_VALUE :
1772 // e.g. remember date as date string
1773 pDoc->GetFormatTable()->GetInputLineString(rCell.mfValue, nFormat, rStr);
1774 break;
1775 case CELLTYPE_FORMULA :
1776 rCell.mpFormula->SetInChangeTrack(true);
1777 break;
1778 default:
1780 // added to avoid warnings
1785 void ScChangeActionContent::GetValueString(
1786 OUString& rStr, const OUString& rValue, const ScCellValue& rCell, const ScDocument* pDoc ) const
1788 if (!rValue.isEmpty())
1790 rStr = rValue;
1791 return;
1794 switch (rCell.meType)
1796 case CELLTYPE_STRING :
1797 rStr = rCell.mpString->getString();
1798 break;
1799 case CELLTYPE_EDIT :
1800 if (rCell.mpEditText)
1801 rStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc);
1802 break;
1803 case CELLTYPE_VALUE : // Is always in rValue
1804 rStr = rValue;
1805 break;
1806 case CELLTYPE_FORMULA :
1807 GetFormulaString(rStr, rCell.mpFormula);
1808 break;
1809 default:
1811 // added to avoid warnings
1816 void ScChangeActionContent::GetFormulaString(
1817 OUString& rStr, const ScFormulaCell* pCell ) const
1819 ScAddress aPos( aBigRange.aStart.MakeAddress() );
1820 if ( aPos == pCell->aPos || IsDeletedIn() )
1821 pCell->GetFormula( rStr );
1822 else
1824 OSL_FAIL( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" );
1825 ScFormulaCell* pNew = new ScFormulaCell( *pCell, *pCell->GetDocument(), aPos );
1826 pNew->GetFormula( rStr );
1827 delete pNew;
1831 void ScChangeActionContent::PutOldValueToDoc( ScDocument* pDoc,
1832 SCsCOL nDx, SCsROW nDy ) const
1834 PutValueToDoc(maOldCell, maOldValue, pDoc, nDx, nDy);
1837 void ScChangeActionContent::PutNewValueToDoc( ScDocument* pDoc,
1838 SCsCOL nDx, SCsROW nDy ) const
1840 PutValueToDoc(maNewCell, maNewValue, pDoc, nDx, nDy);
1843 void ScChangeActionContent::PutValueToDoc(
1844 const ScCellValue& rCell, const OUString& rValue, ScDocument* pDoc,
1845 SCsCOL nDx, SCsROW nDy ) const
1847 ScAddress aPos( aBigRange.aStart.MakeAddress() );
1848 if ( nDx )
1849 aPos.IncCol( nDx );
1850 if ( nDy )
1851 aPos.IncRow( nDy );
1853 if (!rValue.isEmpty())
1855 pDoc->SetString(aPos, rValue);
1856 return;
1859 if (rCell.isEmpty())
1861 pDoc->SetEmptyCell(aPos);
1862 return;
1865 if (rCell.meType == CELLTYPE_VALUE)
1867 pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue );
1868 return;
1871 switch (GetContentCellType(rCell))
1873 case SC_CACCT_MATORG :
1875 SCCOL nC;
1876 SCROW nR;
1877 rCell.mpFormula->GetMatColsRows(nC, nR);
1878 OSL_ENSURE( nC>0 && nR>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" );
1879 ScRange aRange( aPos );
1880 if ( nC > 1 )
1881 aRange.aEnd.IncCol( nC-1 );
1882 if ( nR > 1 )
1883 aRange.aEnd.IncRow( nR-1 );
1884 ScMarkData aDestMark;
1885 aDestMark.SelectOneTable( aPos.Tab() );
1886 aDestMark.SetMarkArea( aRange );
1887 pDoc->InsertMatrixFormula( aPos.Col(), aPos.Row(),
1888 aRange.aEnd.Col(), aRange.aEnd.Row(),
1889 aDestMark, EMPTY_OUSTRING, rCell.mpFormula->GetCode());
1891 break;
1892 case SC_CACCT_MATREF :
1893 // nothing
1894 break;
1895 default:
1896 rCell.commit(*pDoc, aPos);
1900 static void lcl_InvalidateReference( ScToken& rTok, const ScBigAddress& rPos )
1902 ScSingleRefData& rRef1 = rTok.GetSingleRef();
1903 if ( rPos.Col() < 0 || MAXCOL < rPos.Col() )
1905 rRef1.SetColDeleted( true );
1907 if ( rPos.Row() < 0 || MAXROW < rPos.Row() )
1909 rRef1.SetRowDeleted( true );
1911 if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
1913 rRef1.SetTabDeleted( true );
1915 if ( rTok.GetType() == formula::svDoubleRef )
1917 ScSingleRefData& rRef2 = rTok.GetDoubleRef().Ref2;
1918 if ( rPos.Col() < 0 || MAXCOL < rPos.Col() )
1920 rRef2.SetColDeleted( true );
1922 if ( rPos.Row() < 0 || MAXROW < rPos.Row() )
1924 rRef2.SetRowDeleted( true );
1926 if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
1928 rRef2.SetTabDeleted( true );
1933 void ScChangeActionContent::UpdateReference( const ScChangeTrack* pTrack,
1934 UpdateRefMode eMode, const ScBigRange& rRange,
1935 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
1937 SCSIZE nOldSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() );
1938 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aBigRange );
1939 SCSIZE nNewSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() );
1940 if ( nNewSlot != nOldSlot )
1942 RemoveFromSlot();
1943 InsertInSlot( &(pTrack->GetContentSlots()[nNewSlot]) );
1946 if ( pTrack->IsInDelete() && !pTrack->IsInDeleteTop() )
1947 return ; // Formula only update whole range
1949 bool bOldFormula = maOldCell.meType == CELLTYPE_FORMULA;
1950 bool bNewFormula = maNewCell.meType == CELLTYPE_FORMULA;
1951 if ( bOldFormula || bNewFormula )
1952 { // Adjust UpdateReference via ScFormulaCell (there)
1953 if ( pTrack->IsInDelete() )
1955 const ScRange& rDelRange = pTrack->GetInDeleteRange();
1956 if ( nDx > 0 )
1957 nDx = rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1;
1958 else if ( nDx < 0 )
1959 nDx = -(rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1);
1960 if ( nDy > 0 )
1961 nDy = rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1;
1962 else if ( nDy < 0 )
1963 nDy = -(rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1);
1964 if ( nDz > 0 )
1965 nDz = rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1;
1966 else if ( nDz < 0 )
1967 nDz = -(rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1);
1969 ScBigRange aTmpRange( rRange );
1970 switch ( eMode )
1972 case URM_INSDEL :
1973 if ( nDx < 0 || nDy < 0 || nDz < 0 )
1974 { // Delete starts there after removed range
1975 // Position is changed there
1976 if ( nDx )
1977 aTmpRange.aStart.IncCol( -nDx );
1978 if ( nDy )
1979 aTmpRange.aStart.IncRow( -nDy );
1980 if ( nDz )
1981 aTmpRange.aStart.IncTab( -nDz );
1983 break;
1984 case URM_MOVE :
1985 // Move is Source here and Target there
1986 // Position needs to be adjusted before that
1987 if ( bOldFormula )
1988 maOldCell.mpFormula->aPos = aBigRange.aStart.MakeAddress();
1989 if ( bNewFormula )
1990 maNewCell.mpFormula->aPos = aBigRange.aStart.MakeAddress();
1991 if ( nDx )
1993 aTmpRange.aStart.IncCol( nDx );
1994 aTmpRange.aEnd.IncCol( nDx );
1996 if ( nDy )
1998 aTmpRange.aStart.IncRow( nDy );
1999 aTmpRange.aEnd.IncRow( nDy );
2001 if ( nDz )
2003 aTmpRange.aStart.IncTab( nDz );
2004 aTmpRange.aEnd.IncTab( nDz );
2006 break;
2007 default:
2009 // added to avoid warnings
2012 ScRange aRange( aTmpRange.MakeRange() );
2014 sc::RefUpdateContext aRefCxt(*pTrack->GetDocument());
2015 aRefCxt.meMode = eMode;
2016 aRefCxt.maRange = aRange;
2017 aRefCxt.mnColDelta = nDx;
2018 aRefCxt.mnRowDelta = nDy;
2019 aRefCxt.mnTabDelta = nDz;
2021 if ( bOldFormula )
2022 maOldCell.mpFormula->UpdateReference(aRefCxt, NULL);
2023 if ( bNewFormula )
2024 maNewCell.mpFormula->UpdateReference(aRefCxt, NULL);
2026 if ( !aBigRange.aStart.IsValid( pTrack->GetDocument() ) )
2027 { //! HACK!
2028 //! UpdateReference cannot handle positions outside of the Document.
2029 //! Therefore set everything to #REF!
2030 //TODO: Remove the need for this hack! This means big changes to ScAddress etc.!
2031 const ScBigAddress& rPos = aBigRange.aStart;
2032 if ( bOldFormula )
2034 ScToken* t;
2035 ScTokenArray* pArr = maOldCell.mpFormula->GetCode();
2036 pArr->Reset();
2037 while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL )
2038 lcl_InvalidateReference( *t, rPos );
2039 pArr->Reset();
2040 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
2041 lcl_InvalidateReference( *t, rPos );
2043 if ( bNewFormula )
2045 ScToken* t;
2046 ScTokenArray* pArr = maNewCell.mpFormula->GetCode();
2047 pArr->Reset();
2048 while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL )
2049 lcl_InvalidateReference( *t, rPos );
2050 pArr->Reset();
2051 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
2052 lcl_InvalidateReference( *t, rPos );
2058 bool ScChangeActionContent::IsMatrixOrigin() const
2060 return GetContentCellType(GetNewCell()) == SC_CACCT_MATORG;
2063 bool ScChangeActionContent::IsOldMatrixReference() const
2065 return GetContentCellType(GetOldCell()) == SC_CACCT_MATREF;
2068 // ScChangeActionReject
2069 ScChangeActionReject::ScChangeActionReject(
2070 const sal_uLong nActionNumber, const ScChangeActionState eStateP,
2071 const sal_uLong nRejectingNumber,
2072 const ScBigRange& aBigRangeP, const OUString& aUserP,
2073 const DateTime& aDateTimeP, const OUString& sComment) :
2074 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment)
2078 bool ScChangeActionReject::Reject(ScDocument* /*pDoc*/)
2080 return false;
2083 // ScChangeTrack
2084 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeTrackMsgInfo )
2086 const SCROW ScChangeTrack::nContentRowsPerSlot = InitContentRowsPerSlot();
2087 const SCSIZE ScChangeTrack::nContentSlots =
2088 (MAXROWCOUNT) / InitContentRowsPerSlot() + 2;
2090 SCROW ScChangeTrack::InitContentRowsPerSlot()
2092 const SCSIZE nMaxSlots = 0xffe0 / sizeof( ScChangeActionContent* ) - 2;
2093 SCROW nRowsPerSlot = (MAXROWCOUNT) / nMaxSlots;
2094 if ( nRowsPerSlot * nMaxSlots < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
2095 ++nRowsPerSlot;
2096 return nRowsPerSlot;
2099 ScChangeTrack::ScChangeTrack( ScDocument* pDocP ) :
2100 aFixDateTime( DateTime::SYSTEM ),
2101 pDoc( pDocP )
2103 Init();
2104 SC_MOD()->GetUserOptions().AddListener(this);
2106 ppContentSlots = new ScChangeActionContent* [ nContentSlots ];
2107 memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) );
2110 ScChangeTrack::ScChangeTrack( ScDocument* pDocP, const std::set<OUString>& aTempUserCollection) :
2111 maUserCollection(aTempUserCollection),
2112 aFixDateTime( DateTime::SYSTEM ),
2113 pDoc( pDocP )
2115 Init();
2116 SC_MOD()->GetUserOptions().AddListener(this);
2117 ppContentSlots = new ScChangeActionContent* [ nContentSlots ];
2118 memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) );
2121 ScChangeTrack::~ScChangeTrack()
2123 SC_MOD()->GetUserOptions().RemoveListener(this);
2124 DtorClear();
2125 delete [] ppContentSlots;
2128 void ScChangeTrack::Init()
2130 pFirst = NULL;
2131 pLast = NULL;
2132 pFirstGeneratedDelContent = NULL;
2133 pLastCutMove = NULL;
2134 pLinkInsertCol = NULL;
2135 pLinkInsertRow = NULL;
2136 pLinkInsertTab = NULL;
2137 pLinkMove = NULL;
2138 pBlockModifyMsg = NULL;
2139 nActionMax = 0;
2140 nGeneratedMin = SC_CHGTRACK_GENERATED_START;
2141 nMarkLastSaved = 0;
2142 nStartLastCut = 0;
2143 nEndLastCut = 0;
2144 nLastMerge = 0;
2145 eMergeState = SC_CTMS_NONE;
2146 bLoadSave = false;
2147 bInDelete = false;
2148 bInDeleteTop = false;
2149 bInDeleteUndo = false;
2150 bInPasteCut = false;
2151 bUseFixDateTime = false;
2152 bTimeNanoSeconds = true;
2154 const SvtUserOptions& rUserOpt = SC_MOD()->GetUserOptions();
2155 OUStringBuffer aBuf;
2156 aBuf.append(rUserOpt.GetFirstName());
2157 aBuf.append(' ');
2158 aBuf.append(rUserOpt.GetLastName());
2159 maUser = aBuf.makeStringAndClear();
2160 maUserCollection.insert(maUser);
2163 void ScChangeTrack::DtorClear()
2165 ScChangeAction* p;
2166 ScChangeAction* pNext;
2167 ScChangeActionMap::iterator itChangeAction;
2168 for ( p = GetFirst(); p; p = pNext )
2170 pNext = p->GetNext();
2171 delete p;
2173 for ( p = pFirstGeneratedDelContent; p; p = pNext )
2175 pNext = p->GetNext();
2176 delete p;
2178 for( itChangeAction = aPasteCutMap.begin(); itChangeAction != aPasteCutMap.end(); ++itChangeAction )
2180 delete itChangeAction->second;
2182 delete pLastCutMove;
2183 ClearMsgQueue();
2186 void ScChangeTrack::ClearMsgQueue()
2188 if ( pBlockModifyMsg )
2190 delete pBlockModifyMsg;
2191 pBlockModifyMsg = NULL;
2193 while ( !aMsgStackTmp.empty() )
2195 delete aMsgStackTmp.top();
2196 aMsgStackTmp.pop();
2198 while ( !aMsgStackFinal.empty() )
2200 delete aMsgStackFinal.top();
2201 aMsgStackFinal.pop();
2204 ScChangeTrackMsgQueue::iterator itQueue;
2205 for ( itQueue = aMsgQueue.begin(); itQueue != aMsgQueue.end(); ++itQueue)
2206 delete *itQueue;
2208 aMsgQueue.clear();
2211 void ScChangeTrack::Clear()
2213 DtorClear();
2214 aMap.clear();
2215 aGeneratedMap.clear();
2216 aPasteCutMap.clear();
2217 maUserCollection.clear();
2218 maUser = OUString();
2219 Init();
2222 const std::set<OUString>& ScChangeTrack::GetUserCollection() const
2224 return maUserCollection;
2227 void ScChangeTrack::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 )
2229 if ( !pDoc->IsInDtorClear() )
2231 const SvtUserOptions& rUserOptions = SC_MOD()->GetUserOptions();
2232 size_t nOldCount = maUserCollection.size();
2234 OUStringBuffer aBuf;
2235 aBuf.append(rUserOptions.GetFirstName());
2236 aBuf.append(' ');
2237 aBuf.append(rUserOptions.GetLastName());
2238 SetUser(aBuf.makeStringAndClear());
2240 if ( maUserCollection.size() != nOldCount )
2242 // New user in collection -> have to repaint because
2243 // colors may be different now (#106697#).
2244 // (Has to be done in the Notify handler, to be sure
2245 // the user collection has already been updated)
2247 SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
2248 if (pDocSh)
2249 pDocSh->Broadcast( ScPaintHint( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB), PAINT_GRID ) );
2254 void ScChangeTrack::SetUser( const OUString& rUser )
2256 if ( IsLoadSave() )
2257 return ; // Do not destroy the Collection
2259 maUser = rUser;
2260 maUserCollection.insert(maUser);
2263 const OUString& ScChangeTrack::GetUser() const
2265 return maUser;
2268 void ScChangeTrack::StartBlockModify( ScChangeTrackMsgType eMsgType,
2269 sal_uLong nStartAction )
2271 if ( aModifiedLink.IsSet() )
2273 if ( pBlockModifyMsg )
2274 aMsgStackTmp.push( pBlockModifyMsg ); // Block in Block
2275 pBlockModifyMsg = new ScChangeTrackMsgInfo;
2276 pBlockModifyMsg->eMsgType = eMsgType;
2277 pBlockModifyMsg->nStartAction = nStartAction;
2281 void ScChangeTrack::EndBlockModify( sal_uLong nEndAction )
2283 if ( aModifiedLink.IsSet() )
2285 if ( pBlockModifyMsg )
2287 if ( pBlockModifyMsg->nStartAction <= nEndAction )
2289 pBlockModifyMsg->nEndAction = nEndAction;
2290 // Blocks dissolved in Blocks
2291 aMsgStackFinal.push( pBlockModifyMsg );
2293 else
2294 delete pBlockModifyMsg;
2295 if (aMsgStackTmp.empty())
2296 pBlockModifyMsg = NULL;
2297 else
2299 pBlockModifyMsg = aMsgStackTmp.top(); // Maybe Block in Block
2300 aMsgStackTmp.pop();
2303 if ( !pBlockModifyMsg )
2305 bool bNew = false;
2306 while ( !aMsgStackFinal.empty() )
2308 aMsgQueue.push_back( aMsgStackFinal.top() );
2309 aMsgStackFinal.pop();
2310 bNew = true;
2312 if ( bNew )
2313 aModifiedLink.Call( this );
2318 void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType,
2319 sal_uLong nStartAction, sal_uLong nEndAction )
2321 if ( aModifiedLink.IsSet() )
2323 if ( !pBlockModifyMsg || pBlockModifyMsg->eMsgType != eMsgType ||
2324 (IsGenerated( nStartAction ) &&
2325 (eMsgType == SC_CTM_APPEND || eMsgType == SC_CTM_REMOVE)) )
2326 { // Append within Append e.g. not
2327 StartBlockModify( eMsgType, nStartAction );
2328 EndBlockModify( nEndAction );
2333 void ScChangeTrack::MasterLinks( ScChangeAction* pAppend )
2335 ScChangeActionType eType = pAppend->GetType();
2337 if ( eType == SC_CAT_CONTENT )
2339 if ( !IsGenerated( pAppend->GetActionNumber() ) )
2341 SCSIZE nSlot = ComputeContentSlot(
2342 pAppend->GetBigRange().aStart.Row() );
2343 ((ScChangeActionContent*)pAppend)->InsertInSlot(
2344 &ppContentSlots[nSlot] );
2346 return ;
2349 if ( pAppend->IsRejecting() )
2350 return ; // Rejects do not have dependencies
2352 switch ( eType )
2354 case SC_CAT_INSERT_COLS :
2356 ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
2357 &pLinkInsertCol, pAppend );
2358 pAppend->AddLink( NULL, pLink );
2360 break;
2361 case SC_CAT_INSERT_ROWS :
2363 ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
2364 &pLinkInsertRow, pAppend );
2365 pAppend->AddLink( NULL, pLink );
2367 break;
2368 case SC_CAT_INSERT_TABS :
2370 ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
2371 &pLinkInsertTab, pAppend );
2372 pAppend->AddLink( NULL, pLink );
2374 break;
2375 case SC_CAT_MOVE :
2377 ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
2378 &pLinkMove, pAppend );
2379 pAppend->AddLink( NULL, pLink );
2381 break;
2382 default:
2384 // added to avoid warnings
2389 void ScChangeTrack::AppendLoaded( ScChangeAction* pAppend )
2391 aMap.insert( ::std::make_pair( pAppend->GetActionNumber(), pAppend ) );
2392 if ( !pLast )
2393 pFirst = pLast = pAppend;
2394 else
2396 pLast->pNext = pAppend;
2397 pAppend->pPrev = pLast;
2398 pLast = pAppend;
2400 MasterLinks( pAppend );
2403 void ScChangeTrack::Append( ScChangeAction* pAppend, sal_uLong nAction )
2405 if ( nActionMax < nAction )
2406 nActionMax = nAction;
2407 pAppend->SetUser( maUser );
2408 if ( bUseFixDateTime )
2409 pAppend->SetDateTimeUTC( aFixDateTime );
2410 pAppend->SetActionNumber( nAction );
2411 aMap.insert( ::std::make_pair( nAction, pAppend ) );
2412 // UpdateReference Inserts before Dependencies.
2413 // Delete rejecting Insert which had UpdateReference with Delete Undo.
2414 // UpdateReference also with pLast==NULL, as pAppend can be a Delete,
2415 // which could have generated DelContents.
2416 if ( pAppend->IsInsertType() && !pAppend->IsRejecting() )
2417 UpdateReference( pAppend, false );
2418 if ( !pLast )
2419 pFirst = pLast = pAppend;
2420 else
2422 pLast->pNext = pAppend;
2423 pAppend->pPrev = pLast;
2424 pLast = pAppend;
2425 Dependencies( pAppend );
2427 // UpdateReference does not Insert() after Dependencies.
2428 // Move rejecting Move, which had UpdateReference with Move Undo.
2429 // Do not delete content in ToRange.
2430 if ( !pAppend->IsInsertType() &&
2431 !(pAppend->GetType() == SC_CAT_MOVE && pAppend->IsRejecting()) )
2432 UpdateReference( pAppend, false );
2433 MasterLinks( pAppend );
2435 if ( aModifiedLink.IsSet() )
2437 NotifyModified( SC_CTM_APPEND, nAction, nAction );
2438 if ( pAppend->GetType() == SC_CAT_CONTENT )
2440 ScChangeActionContent* pContent = (ScChangeActionContent*) pAppend;
2441 if ( ( pContent = pContent->GetPrevContent() ) != NULL )
2443 sal_uLong nMod = pContent->GetActionNumber();
2444 NotifyModified( SC_CTM_CHANGE, nMod, nMod );
2447 else
2448 NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(),
2449 pLast->GetActionNumber() );
2453 void ScChangeTrack::Append( ScChangeAction* pAppend )
2455 Append( pAppend, ++nActionMax );
2458 void ScChangeTrack::AppendDeleteRange( const ScRange& rRange,
2459 ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, SCsTAB nDz )
2461 nStartAction = GetActionMax() + 1;
2462 AppendDeleteRange( rRange, pRefDoc, nDz, 0 );
2463 nEndAction = GetActionMax();
2466 void ScChangeTrack::AppendDeleteRange( const ScRange& rRange,
2467 ScDocument* pRefDoc, SCsTAB nDz, sal_uLong nRejectingInsert )
2469 SetInDeleteRange( rRange );
2470 StartBlockModify( SC_CTM_APPEND, GetActionMax() + 1 );
2471 SCCOL nCol1;
2472 SCROW nRow1;
2473 SCTAB nTab1;
2474 SCCOL nCol2;
2475 SCROW nRow2;
2476 SCTAB nTab2;
2477 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
2478 for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
2480 if ( !pRefDoc || nTab < pRefDoc->GetTableCount() )
2482 if ( nCol1 == 0 && nCol2 == MAXCOL )
2483 { // Whole Row and/or Tables
2484 if ( nRow1 == 0 && nRow2 == MAXROW )
2485 { // Whole Table
2486 // TODO: Can't we do the whole Table as a whole?
2487 ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab );
2488 for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
2489 { // Column by column is less than row by row
2490 aRange.aStart.SetCol( nCol );
2491 aRange.aEnd.SetCol( nCol );
2492 if ( nCol == nCol2 )
2493 SetInDeleteTop( true );
2494 AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
2495 nTab-nTab1 + nDz, nRejectingInsert );
2497 //! Still InDeleteTop
2498 AppendOneDeleteRange( rRange, pRefDoc, 0, 0,
2499 nTab-nTab1 + nDz, nRejectingInsert );
2501 else
2502 { // Whole rows
2503 ScRange aRange( 0, 0, nTab, MAXCOL, 0, nTab );
2504 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
2506 aRange.aStart.SetRow( nRow );
2507 aRange.aEnd.SetRow( nRow );
2508 if ( nRow == nRow2 )
2509 SetInDeleteTop( true );
2510 AppendOneDeleteRange( aRange, pRefDoc, 0, nRow-nRow1,
2511 0, nRejectingInsert );
2515 else if ( nRow1 == 0 && nRow2 == MAXROW )
2516 { // Whole columns
2517 ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab );
2518 for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
2520 aRange.aStart.SetCol( nCol );
2521 aRange.aEnd.SetCol( nCol );
2522 if ( nCol == nCol2 )
2523 SetInDeleteTop( true );
2524 AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
2525 0, nRejectingInsert );
2528 else
2530 OSL_FAIL( "ScChangeTrack::AppendDeleteRange: Block not supported!" );
2532 SetInDeleteTop( false );
2535 EndBlockModify( GetActionMax() );
2538 void ScChangeTrack::AppendOneDeleteRange( const ScRange& rOrgRange,
2539 ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
2540 sal_uLong nRejectingInsert )
2542 ScRange aTrackRange( rOrgRange );
2543 if ( nDx )
2545 aTrackRange.aStart.IncCol( -nDx );
2546 aTrackRange.aEnd.IncCol( -nDx );
2548 if ( nDy )
2550 aTrackRange.aStart.IncRow( -nDy );
2551 aTrackRange.aEnd.IncRow( -nDy );
2553 if ( nDz )
2555 aTrackRange.aStart.IncTab( -nDz );
2556 aTrackRange.aEnd.IncTab( -nDz );
2558 ScChangeActionDel* pAct = new ScChangeActionDel( aTrackRange, nDx, nDy,
2559 this );
2560 // TabDelete not Contents; they are in separate columns
2561 if ( !(rOrgRange.aStart.Col() == 0 && rOrgRange.aStart.Row() == 0 &&
2562 rOrgRange.aEnd.Col() == MAXCOL && rOrgRange.aEnd.Row() == MAXROW) )
2563 LookUpContents( rOrgRange, pRefDoc, -nDx, -nDy, -nDz );
2564 if ( nRejectingInsert )
2566 pAct->SetRejectAction( nRejectingInsert );
2567 pAct->SetState( SC_CAS_ACCEPTED );
2569 Append( pAct );
2572 void ScChangeTrack::LookUpContents( const ScRange& rOrgRange,
2573 ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
2575 if (!pRefDoc)
2576 return;
2578 ScAddress aPos;
2579 ScBigAddress aBigPos;
2580 ScCellIterator aIter( pRefDoc, rOrgRange );
2581 for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
2583 if (!ScChangeActionContent::GetContentCellType(aIter.getRefCellValue()))
2584 continue;
2586 aBigPos.Set( aIter.GetPos().Col() + nDx, aIter.GetPos().Row() + nDy,
2587 aIter.GetPos().Tab() + nDz );
2588 ScChangeActionContent* pContent = SearchContentAt( aBigPos, NULL );
2589 if (pContent)
2590 continue;
2592 // Untracked Contents
2593 aPos.Set( aIter.GetPos().Col() + nDx, aIter.GetPos().Row() + nDy,
2594 aIter.GetPos().Tab() + nDz );
2596 GenerateDelContent(aPos, aIter.getCellValue(), pRefDoc);
2597 //! The Content is _not_ added with AddContent here, but in UpdateReference.
2598 //! We do this in order to e.g. handle intersecting Deletes correctly
2602 void ScChangeTrack::AppendMove( const ScRange& rFromRange,
2603 const ScRange& rToRange, ScDocument* pRefDoc )
2605 ScChangeActionMove* pAct = new ScChangeActionMove( rFromRange, rToRange, this );
2606 LookUpContents( rToRange, pRefDoc, 0, 0, 0 ); // Overwritten Contents
2607 Append( pAct );
2610 bool ScChangeTrack::IsMatrixFormulaRangeDifferent(
2611 const ScCellValue& rOldCell, const ScCellValue& rNewCell )
2613 SCCOL nC1, nC2;
2614 SCROW nR1, nR2;
2615 nC1 = nC2 = 0;
2616 nR1 = nR2 = 0;
2618 if (rOldCell.meType == CELLTYPE_FORMULA && rOldCell.mpFormula->GetMatrixFlag() == MM_FORMULA)
2619 rOldCell.mpFormula->GetMatColsRows(nC1, nR1);
2621 if (rNewCell.meType == CELLTYPE_FORMULA && rNewCell.mpFormula->GetMatrixFlag() == MM_FORMULA)
2622 rNewCell.mpFormula->GetMatColsRows(nC1, nR1);
2624 return nC1 != nC2 || nR1 != nR2;
2627 void ScChangeTrack::AppendContent(
2628 const ScAddress& rPos, const ScCellValue& rOldCell, sal_uLong nOldFormat, ScDocument* pRefDoc )
2630 if ( !pRefDoc )
2631 pRefDoc = pDoc;
2633 OUString aOldValue;
2634 ScChangeActionContent::GetStringOfCell(aOldValue, rOldCell, pRefDoc, nOldFormat);
2636 OUString aNewValue;
2637 ScCellValue aNewCell;
2638 aNewCell.assign(*pDoc, rPos);
2639 ScChangeActionContent::GetStringOfCell(aNewValue, aNewCell, pDoc, rPos);
2641 if (!aOldValue.equals(aNewValue) || IsMatrixFormulaRangeDifferent(rOldCell, aNewCell))
2642 { // Only track real changes
2643 ScRange aRange( rPos );
2644 ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2645 pAct->SetOldValue(rOldCell, pRefDoc, pDoc, nOldFormat);
2646 pAct->SetNewValue(aNewCell, pDoc);
2647 Append( pAct );
2651 void ScChangeTrack::AppendContent( const ScAddress& rPos,
2652 ScDocument* pRefDoc )
2654 OUString aOldValue;
2655 ScCellValue aOldCell;
2656 aOldCell.assign(*pRefDoc, rPos);
2657 ScChangeActionContent::GetStringOfCell(aOldValue, aOldCell, pRefDoc, rPos);
2659 OUString aNewValue;
2660 ScCellValue aNewCell;
2661 aNewCell.assign(*pDoc, rPos);
2662 ScChangeActionContent::GetStringOfCell(aNewValue, aNewCell, pDoc, rPos);
2664 if (!aOldValue.equals(aNewValue) || IsMatrixFormulaRangeDifferent(aOldCell, aNewCell))
2665 { // Only track real changes
2666 ScRange aRange( rPos );
2667 ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2668 pAct->SetOldValue(aOldCell, pRefDoc, pDoc);
2669 pAct->SetNewValue(aNewCell, pDoc);
2670 Append( pAct );
2674 void ScChangeTrack::AppendContent( const ScAddress& rPos, const ScCellValue& rOldCell )
2676 if (ScChangeActionContent::NeedsNumberFormat(rOldCell))
2677 AppendContent(rPos, rOldCell, pDoc->GetNumberFormat(rPos), pDoc);
2678 else
2679 AppendContent(rPos, rOldCell, 0, pDoc);
2682 void ScChangeTrack::SetLastCutMoveRange( const ScRange& rRange,
2683 ScDocument* pRefDoc )
2685 if ( pLastCutMove )
2687 // Do not link ToRange with Deletes and don't change its size
2688 // This is actually unnecessary, as a delete triggers a ResetLastCut
2689 // in ScViewFunc::PasteFromClip before that
2690 ScBigRange& r = pLastCutMove->GetBigRange();
2691 r.aEnd.SetCol( -1 );
2692 r.aEnd.SetRow( -1 );
2693 r.aEnd.SetTab( -1 );
2694 r.aStart.SetCol( -1 - (rRange.aEnd.Col() - rRange.aStart.Col()) );
2695 r.aStart.SetRow( -1 - (rRange.aEnd.Row() - rRange.aStart.Row()) );
2696 r.aStart.SetTab( -1 - (rRange.aEnd.Tab() - rRange.aStart.Tab()) );
2697 // Contents in FromRange we should overwrite
2698 LookUpContents( rRange, pRefDoc, 0, 0, 0 );
2702 void ScChangeTrack::AppendContentRange( const ScRange& rRange,
2703 ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction,
2704 ScChangeActionClipMode eClipMode )
2706 if ( eClipMode == SC_CACM_CUT )
2708 ResetLastCut();
2709 pLastCutMove = new ScChangeActionMove( rRange, rRange, this );
2710 SetLastCutMoveRange( rRange, pRefDoc );
2712 SCCOL nCol1;
2713 SCROW nRow1;
2714 SCTAB nTab1;
2715 SCCOL nCol2;
2716 SCROW nRow2;
2717 SCTAB nTab2;
2718 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
2719 bool bDoContents;
2720 if ( eClipMode == SC_CACM_PASTE && HasLastCut() )
2722 bDoContents = false;
2723 SetInPasteCut( true );
2724 // Adjust Paste and Cut; Paste can be larger a Range
2725 ScRange aRange( rRange );
2726 ScBigRange& r = pLastCutMove->GetBigRange();
2727 SCCOL nTmpCol;
2728 if ( (nTmpCol = (SCCOL) (r.aEnd.Col() - r.aStart.Col())) != (nCol2 - nCol1) )
2730 aRange.aEnd.SetCol( aRange.aStart.Col() + nTmpCol );
2731 nCol1 += nTmpCol + 1;
2732 bDoContents = true;
2734 SCROW nTmpRow;
2735 if ( (nTmpRow = (SCROW) (r.aEnd.Row() - r.aStart.Row())) != (nRow2 - nRow1) )
2737 aRange.aEnd.SetRow( aRange.aStart.Row() + nTmpRow );
2738 nRow1 += nTmpRow + 1;
2739 bDoContents = true;
2741 SCTAB nTmpTab;
2742 if ( (nTmpTab = (SCTAB) (r.aEnd.Tab() - r.aStart.Tab())) != (nTab2 - nTab1) )
2744 aRange.aEnd.SetTab( aRange.aStart.Tab() + nTmpTab );
2745 nTab1 += nTmpTab + 1;
2746 bDoContents = true;
2748 r = aRange;
2749 Undo( nStartLastCut, nEndLastCut ); // Remember Cuts here
2750 //! StartAction only after Undo
2751 nStartAction = GetActionMax() + 1;
2752 StartBlockModify( SC_CTM_APPEND, nStartAction );
2753 // Contents to overwrite in ToRange
2754 LookUpContents( aRange, pRefDoc, 0, 0, 0 );
2755 pLastCutMove->SetStartLastCut( nStartLastCut );
2756 pLastCutMove->SetEndLastCut( nEndLastCut );
2757 Append( pLastCutMove );
2758 pLastCutMove = NULL;
2759 ResetLastCut();
2760 SetInPasteCut( false );
2762 else
2764 bDoContents = true;
2765 nStartAction = GetActionMax() + 1;
2766 StartBlockModify( SC_CTM_APPEND, nStartAction );
2768 if ( bDoContents )
2770 ScAddress aPos;
2771 for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
2773 aPos.SetTab( nTab );
2774 for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
2776 aPos.SetCol( nCol );
2777 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
2779 aPos.SetRow( nRow );
2780 AppendContent( aPos, pRefDoc );
2785 nEndAction = GetActionMax();
2786 EndBlockModify( nEndAction );
2787 if ( eClipMode == SC_CACM_CUT )
2789 nStartLastCut = nStartAction;
2790 nEndLastCut = nEndAction;
2794 void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument* pRefDoc,
2795 sal_uLong& nStartAction, sal_uLong& nEndAction )
2797 ScCellIterator aIter(pRefDoc, ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB));
2798 if (aIter.first())
2800 nStartAction = GetActionMax() + 1;
2801 StartBlockModify( SC_CTM_APPEND, nStartAction );
2802 SvNumberFormatter* pFormatter = pRefDoc->GetFormatTable();
2805 const ScAddress& rPos = aIter.GetPos();
2806 const ScPatternAttr* pPat = pRefDoc->GetPattern(rPos);
2807 AppendContent(
2808 rPos, aIter.getCellValue(), pPat->GetNumberFormat(pFormatter), pRefDoc);
2810 while (aIter.next());
2812 nEndAction = GetActionMax();
2813 EndBlockModify( nEndAction );
2815 else
2816 nStartAction = nEndAction = 0;
2819 ScChangeActionContent* ScChangeTrack::AppendContentOnTheFly(
2820 const ScAddress& rPos, const ScCellValue& rOldCell, const ScCellValue& rNewCell,
2821 sal_uLong nOldFormat, sal_uLong nNewFormat )
2823 ScRange aRange( rPos );
2824 ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2825 pAct->SetOldNewCells(rOldCell, nOldFormat, rNewCell, nNewFormat, pDoc);
2826 Append( pAct );
2827 return pAct;
2830 void ScChangeTrack::AppendInsert( const ScRange& rRange )
2832 ScChangeActionIns* pAct = new ScChangeActionIns( rRange );
2833 Append( pAct );
2836 void ScChangeTrack::DeleteCellEntries( ScChangeActionCellListEntry*& pCellList,
2837 ScChangeAction* pDeletor )
2839 ScChangeActionCellListEntry* pE = pCellList;
2840 while ( pE )
2842 ScChangeActionCellListEntry* pNext = pE->pNext;
2843 pE->pContent->RemoveDeletedIn( pDeletor );
2844 if ( IsGenerated( pE->pContent->GetActionNumber() ) &&
2845 !pE->pContent->IsDeletedIn() )
2846 DeleteGeneratedDelContent( pE->pContent );
2847 delete pE;
2848 pE = pNext;
2850 pCellList = NULL;
2853 ScChangeActionContent* ScChangeTrack::GenerateDelContent(
2854 const ScAddress& rPos, const ScCellValue& rCell, const ScDocument* pFromDoc )
2856 ScChangeActionContent* pContent = new ScChangeActionContent(
2857 ScRange( rPos ) );
2858 pContent->SetActionNumber( --nGeneratedMin );
2859 // Only NewValue
2860 ScChangeActionContent::SetValue( pContent->maNewValue, pContent->maNewCell,
2861 rPos, rCell, pFromDoc, pDoc );
2862 // pNextContent and pPrevContent are not set
2863 if ( pFirstGeneratedDelContent )
2864 { // Insert at front
2865 pFirstGeneratedDelContent->pPrev = pContent;
2866 pContent->pNext = pFirstGeneratedDelContent;
2868 pFirstGeneratedDelContent = pContent;
2869 aGeneratedMap.insert( std::make_pair( nGeneratedMin, pContent ) );
2870 NotifyModified( SC_CTM_APPEND, nGeneratedMin, nGeneratedMin );
2871 return pContent;
2874 void ScChangeTrack::DeleteGeneratedDelContent( ScChangeActionContent* pContent )
2876 sal_uLong nAct = pContent->GetActionNumber();
2877 aGeneratedMap.erase( nAct );
2878 if ( pFirstGeneratedDelContent == pContent )
2879 pFirstGeneratedDelContent = (ScChangeActionContent*) pContent->pNext;
2880 if ( pContent->pNext )
2881 pContent->pNext->pPrev = pContent->pPrev;
2882 if ( pContent->pPrev )
2883 pContent->pPrev->pNext = pContent->pNext;
2884 delete pContent;
2885 NotifyModified( SC_CTM_REMOVE, nAct, nAct );
2886 if ( nAct == nGeneratedMin )
2887 ++nGeneratedMin; //! Only after NotifyModified due to IsGenerated
2890 ScChangeActionContent* ScChangeTrack::SearchContentAt(
2891 const ScBigAddress& rPos, ScChangeAction* pButNotThis ) const
2893 SCSIZE nSlot = ComputeContentSlot( rPos.Row() );
2894 for ( ScChangeActionContent* p = ppContentSlots[nSlot]; p;
2895 p = p->GetNextInSlot() )
2897 if ( p != pButNotThis && !p->IsDeletedIn() &&
2898 p->GetBigRange().aStart == rPos )
2900 ScChangeActionContent* pContent = p->GetTopContent();
2901 if ( !pContent->IsDeletedIn() )
2902 return pContent;
2905 return NULL;
2908 void ScChangeTrack::AddDependentWithNotify( ScChangeAction* pParent,
2909 ScChangeAction* pDependent )
2911 ScChangeActionLinkEntry* pLink = pParent->AddDependent( pDependent );
2912 pDependent->AddLink( pParent, pLink );
2913 if ( aModifiedLink.IsSet() )
2915 sal_uLong nMod = pParent->GetActionNumber();
2916 NotifyModified( SC_CTM_PARENT, nMod, nMod );
2920 void ScChangeTrack::Dependencies( ScChangeAction* pAct )
2922 // Find the last dependency for Col/Row/Tab each
2923 // Concatenate Content at the same position
2924 // Move dependencies
2925 ScChangeActionType eActType = pAct->GetType();
2926 if ( eActType == SC_CAT_REJECT ||
2927 (eActType == SC_CAT_MOVE && pAct->IsRejecting()) )
2928 return ; // These Rejects are not dependant
2930 if ( eActType == SC_CAT_CONTENT )
2932 if ( !(((ScChangeActionContent*)pAct)->GetNextContent() ||
2933 ((ScChangeActionContent*)pAct)->GetPrevContent()) )
2934 { // Concatenate Contents at same position
2935 ScChangeActionContent* pContent = SearchContentAt(
2936 pAct->GetBigRange().aStart, pAct );
2937 if ( pContent )
2939 pContent->SetNextContent( (ScChangeActionContent*) pAct );
2940 ((ScChangeActionContent*)pAct)->SetPrevContent( pContent );
2943 const ScCellValue& rCell = static_cast<ScChangeActionContent*>(pAct)->GetNewCell();
2944 if ( ScChangeActionContent::GetContentCellType(rCell) == SC_CACCT_MATREF )
2946 ScAddress aOrg;
2947 rCell.mpFormula->GetMatrixOrigin(aOrg);
2948 ScChangeActionContent* pContent = SearchContentAt( aOrg, pAct );
2949 if ( pContent && pContent->IsMatrixOrigin() )
2951 AddDependentWithNotify( pContent, pAct );
2953 else
2955 OSL_FAIL( "ScChangeTrack::Dependencies: MatOrg not found" );
2960 if ( !(pLinkInsertCol || pLinkInsertRow || pLinkInsertTab || pLinkMove) )
2961 return ; // No Dependencies
2962 if ( pAct->IsRejecting() )
2963 return ; // Except for Content no Dependencies
2965 // Insert in a corresponding Insert depends on it or else we would need
2966 // to split the preceding one.
2967 // Intersecting Inserts and Deletes are not dependant, everything else
2968 // is dependant.
2969 // The Insert last linked in is at the beginning of a chain, just the way we need it
2971 const ScBigRange& rRange = pAct->GetBigRange();
2972 bool bActNoInsert = !pAct->IsInsertType();
2973 bool bActColDel = ( eActType == SC_CAT_DELETE_COLS );
2974 bool bActRowDel = ( eActType == SC_CAT_DELETE_ROWS );
2975 bool bActTabDel = ( eActType == SC_CAT_DELETE_TABS );
2977 if ( pLinkInsertCol && (eActType == SC_CAT_INSERT_COLS ||
2978 (bActNoInsert && !bActRowDel && !bActTabDel)) )
2980 for ( ScChangeActionLinkEntry* pL = pLinkInsertCol; pL; pL = pL->GetNext() )
2982 ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
2983 if ( !pTest->IsRejected() &&
2984 pTest->GetBigRange().Intersects( rRange ) )
2986 AddDependentWithNotify( pTest, pAct );
2987 break; // for
2991 if ( pLinkInsertRow && (eActType == SC_CAT_INSERT_ROWS ||
2992 (bActNoInsert && !bActColDel && !bActTabDel)) )
2994 for ( ScChangeActionLinkEntry* pL = pLinkInsertRow; pL; pL = pL->GetNext() )
2996 ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
2997 if ( !pTest->IsRejected() &&
2998 pTest->GetBigRange().Intersects( rRange ) )
3000 AddDependentWithNotify( pTest, pAct );
3001 break; // for
3005 if ( pLinkInsertTab && (eActType == SC_CAT_INSERT_TABS ||
3006 (bActNoInsert && !bActColDel && !bActRowDel)) )
3008 for ( ScChangeActionLinkEntry* pL = pLinkInsertTab; pL; pL = pL->GetNext() )
3010 ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
3011 if ( !pTest->IsRejected() &&
3012 pTest->GetBigRange().Intersects( rRange ) )
3014 AddDependentWithNotify( pTest, pAct );
3015 break; // for
3020 if ( pLinkMove )
3022 if ( eActType == SC_CAT_CONTENT )
3023 { // Content is depending on FromRange
3024 const ScBigAddress& rPos = rRange.aStart;
3025 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
3027 ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
3028 if ( !pTest->IsRejected() &&
3029 pTest->GetFromRange().In( rPos ) )
3031 AddDependentWithNotify( pTest, pAct );
3035 else if ( eActType == SC_CAT_MOVE )
3036 { // Move FromRange is depending on ToRange
3037 const ScBigRange& rFromRange = ((ScChangeActionMove*)pAct)->GetFromRange();
3038 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
3040 ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
3041 if ( !pTest->IsRejected() &&
3042 pTest->GetBigRange().Intersects( rFromRange ) )
3044 AddDependentWithNotify( pTest, pAct );
3048 else
3049 { // Inserts and Deletes are depending as soon as they cross FromRange or
3050 // ToRange
3051 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
3053 ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
3054 if ( !pTest->IsRejected() &&
3055 (pTest->GetFromRange().Intersects( rRange ) ||
3056 pTest->GetBigRange().Intersects( rRange )) )
3058 AddDependentWithNotify( pTest, pAct );
3065 void ScChangeTrack::Remove( ScChangeAction* pRemove )
3067 // Remove from Track
3068 sal_uLong nAct = pRemove->GetActionNumber();
3069 aMap.erase( nAct );
3070 if ( nAct == nActionMax )
3071 --nActionMax;
3072 if ( pRemove == pLast )
3073 pLast = pRemove->pPrev;
3074 if ( pRemove == pFirst )
3075 pFirst = pRemove->pNext;
3076 if ( nAct == nMarkLastSaved )
3077 nMarkLastSaved =
3078 ( pRemove->pPrev ? pRemove->pPrev->GetActionNumber() : 0 );
3080 // Remove from global chain
3081 if ( pRemove->pNext )
3082 pRemove->pNext->pPrev = pRemove->pPrev;
3083 if ( pRemove->pPrev )
3084 pRemove->pPrev->pNext = pRemove->pNext;
3086 // Don't delete Dependencies
3087 // That happens automatically on delete by LinkEntry without traversing lists
3088 if ( aModifiedLink.IsSet() )
3090 NotifyModified( SC_CTM_REMOVE, nAct, nAct );
3091 if ( pRemove->GetType() == SC_CAT_CONTENT )
3093 ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove;
3094 if ( ( pContent = pContent->GetPrevContent() ) != NULL )
3096 sal_uLong nMod = pContent->GetActionNumber();
3097 NotifyModified( SC_CTM_CHANGE, nMod, nMod );
3100 else if ( pLast )
3101 NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(),
3102 pLast->GetActionNumber() );
3105 if ( IsInPasteCut() && pRemove->GetType() == SC_CAT_CONTENT )
3106 { //! Content is reused
3107 ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove;
3108 pContent->RemoveAllLinks();
3109 pContent->ClearTrack();
3110 pContent->pNext = pContent->pPrev = NULL;
3111 pContent->pNextContent = pContent->pPrevContent = NULL;
3115 void ScChangeTrack::Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge )
3117 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3118 if ( bMerge )
3120 SetMergeState( SC_CTMS_UNDO );
3123 if ( nStartAction == 0 )
3124 ++nStartAction;
3125 if ( nEndAction > nActionMax )
3126 nEndAction = nActionMax;
3127 if ( nEndAction && nStartAction <= nEndAction )
3129 if ( nStartAction == nStartLastCut && nEndAction == nEndLastCut &&
3130 !IsInPasteCut() )
3131 ResetLastCut();
3132 StartBlockModify( SC_CTM_REMOVE, nStartAction );
3133 for ( sal_uLong j = nEndAction; j >= nStartAction; --j )
3134 { // Traverse backwards to recycle nActionMax and for faster access via pLast
3135 // Deletes are in right order
3136 ScChangeAction* pAct = ( (j == nActionMax && pLast &&
3137 pLast->GetActionNumber() == j) ? pLast : GetAction( j ) );
3138 if ( pAct )
3140 if ( pAct->IsDeleteType() )
3142 if ( j == nEndAction || (pAct != pLast &&
3143 ((ScChangeActionDel*)pAct)->IsTopDelete()) )
3145 SetInDeleteTop( true );
3146 SetInDeleteRange( ((ScChangeActionDel*)pAct)->
3147 GetOverAllRange().MakeRange() );
3150 UpdateReference( pAct, true );
3151 SetInDeleteTop( false );
3152 Remove( pAct );
3153 if ( IsInPasteCut() )
3154 aPasteCutMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) );
3155 else
3157 if ( j == nStartAction && pAct->GetType() == SC_CAT_MOVE )
3159 ScChangeActionMove* pMove = (ScChangeActionMove*) pAct;
3160 sal_uLong nStart = pMove->GetStartLastCut();
3161 sal_uLong nEnd = pMove->GetEndLastCut();
3162 if ( nStart && nStart <= nEnd )
3163 { // Recover LastCut
3164 //! Break Links before Cut Append
3165 pMove->RemoveAllLinks();
3166 StartBlockModify( SC_CTM_APPEND, nStart );
3167 for ( sal_uLong nCut = nStart; nCut <= nEnd; nCut++ )
3169 ScChangeActionMap::iterator itCut = aPasteCutMap.find( nCut );
3171 if ( itCut != aPasteCutMap.end() )
3173 OSL_ENSURE( aMap.find( nCut ) == aMap.end(), "ScChangeTrack::Undo: nCut dup" );
3174 Append( itCut->second, nCut );
3175 aPasteCutMap.erase( itCut );
3177 else
3179 OSL_FAIL( "ScChangeTrack::Undo: nCut not found" );
3182 EndBlockModify( nEnd );
3183 ResetLastCut();
3184 nStartLastCut = nStart;
3185 nEndLastCut = nEnd;
3186 pLastCutMove = pMove;
3187 SetLastCutMoveRange(
3188 pMove->GetFromRange().MakeRange(), pDoc );
3190 else
3191 delete pMove;
3193 else
3194 delete pAct;
3198 EndBlockModify( nEndAction );
3201 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3202 if ( bMerge )
3204 SetMergeState( SC_CTMS_OTHER );
3208 bool ScChangeTrack::MergeIgnore( const ScChangeAction& rAction, sal_uLong nFirstMerge )
3210 if ( rAction.IsRejected() )
3211 return true; // There's still a suitable Reject Action coming
3213 if ( rAction.IsRejecting() && rAction.GetRejectAction() >= nFirstMerge )
3214 return true; // There it is
3216 return false; // Everything else
3219 void ScChangeTrack::MergePrepare( ScChangeAction* pFirstMerge, bool bShared )
3221 SetMergeState( SC_CTMS_PREPARE );
3222 sal_uLong nFirstMerge = pFirstMerge->GetActionNumber();
3223 ScChangeAction* pAct = GetLast();
3224 if ( pAct )
3226 SetLastMerge( pAct->GetActionNumber() );
3227 while ( pAct )
3228 { // Traverse backwards; Deletes in right order
3229 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3230 if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) )
3232 if ( pAct->IsDeleteType() )
3234 if ( ((ScChangeActionDel*)pAct)->IsTopDelete() )
3236 SetInDeleteTop( true );
3237 SetInDeleteRange( ((ScChangeActionDel*)pAct)->
3238 GetOverAllRange().MakeRange() );
3241 UpdateReference( pAct, true );
3242 SetInDeleteTop( false );
3243 pAct->DeleteCellEntries(); // Else segfault in Track Clear()
3245 pAct = ( pAct == pFirstMerge ? NULL : pAct->GetPrev() );
3248 SetMergeState( SC_CTMS_OTHER ); //! Preceding by default MergeOther
3251 void ScChangeTrack::MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared )
3253 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3254 if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) )
3256 SetMergeState( SC_CTMS_OWN );
3257 if ( pAct->IsDeleteType() )
3259 if ( ((ScChangeActionDel*)pAct)->IsTopDelete() )
3261 SetInDeleteTop( true );
3262 SetInDeleteRange( ((ScChangeActionDel*)pAct)->
3263 GetOverAllRange().MakeRange() );
3266 UpdateReference( pAct, false );
3267 SetInDeleteTop( false );
3268 SetMergeState( SC_CTMS_OTHER ); //! Preceding by default MergeOther
3272 void ScChangeTrack::UpdateReference( ScChangeAction* pAct, bool bUndo )
3274 ScChangeActionType eActType = pAct->GetType();
3275 if ( eActType == SC_CAT_CONTENT || eActType == SC_CAT_REJECT )
3276 return ;
3278 //! Formula cells are not in the Document
3279 bool bOldAutoCalc = pDoc->GetAutoCalc();
3280 pDoc->SetAutoCalc( false );
3281 bool bOldNoListening = pDoc->GetNoListening();
3282 pDoc->SetNoListening( true );
3284 //! Formula cells ExpandRefs synchronized to the ones in the Document
3285 bool bOldExpandRefs = pDoc->IsExpandRefs();
3286 if ( (!bUndo && pAct->IsInsertType()) || (bUndo && pAct->IsDeleteType()) )
3287 pDoc->SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
3289 if ( pAct->IsDeleteType() )
3291 SetInDeleteUndo( bUndo );
3292 SetInDelete( true );
3294 else if ( GetMergeState() == SC_CTMS_OWN )
3296 // Recover references of formula cells
3297 // Previous MergePrepare behaved like a Delete when Inserting
3298 if ( pAct->IsInsertType() )
3299 SetInDeleteUndo( true );
3302 //! First the generated ones, as if they were tracked previously
3303 if ( pFirstGeneratedDelContent )
3304 UpdateReference( (ScChangeAction**)&pFirstGeneratedDelContent, pAct,
3305 bUndo );
3306 UpdateReference( &pFirst, pAct, bUndo );
3308 SetInDelete( false );
3309 SetInDeleteUndo( false );
3311 pDoc->SetExpandRefs( bOldExpandRefs );
3312 pDoc->SetNoListening( bOldNoListening );
3313 pDoc->SetAutoCalc( bOldAutoCalc );
3316 void ScChangeTrack::UpdateReference( ScChangeAction** ppFirstAction,
3317 ScChangeAction* pAct, bool bUndo )
3319 ScChangeActionType eActType = pAct->GetType();
3320 bool bGeneratedDelContents =
3321 ( ppFirstAction == (ScChangeAction**)&pFirstGeneratedDelContent );
3322 const ScBigRange& rOrgRange = pAct->GetBigRange();
3323 ScBigRange aRange( rOrgRange );
3324 ScBigRange aDelRange( rOrgRange );
3325 sal_Int32 nDx, nDy, nDz;
3326 nDx = nDy = nDz = 0;
3327 UpdateRefMode eMode = URM_INSDEL;
3328 bool bDel = false;
3329 switch ( eActType )
3331 case SC_CAT_INSERT_COLS :
3332 aRange.aEnd.SetCol( nInt32Max );
3333 nDx = rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1;
3334 break;
3335 case SC_CAT_INSERT_ROWS :
3336 aRange.aEnd.SetRow( nInt32Max );
3337 nDy = rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1;
3338 break;
3339 case SC_CAT_INSERT_TABS :
3340 aRange.aEnd.SetTab( nInt32Max );
3341 nDz = rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1;
3342 break;
3343 case SC_CAT_DELETE_COLS :
3344 aRange.aEnd.SetCol( nInt32Max );
3345 nDx = -(rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1);
3346 aDelRange.aEnd.SetCol( aDelRange.aStart.Col() - nDx - 1 );
3347 bDel = true;
3348 break;
3349 case SC_CAT_DELETE_ROWS :
3350 aRange.aEnd.SetRow( nInt32Max );
3351 nDy = -(rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1);
3352 aDelRange.aEnd.SetRow( aDelRange.aStart.Row() - nDy - 1 );
3353 bDel = true;
3354 break;
3355 case SC_CAT_DELETE_TABS :
3356 aRange.aEnd.SetTab( nInt32Max );
3357 nDz = -(rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1);
3358 aDelRange.aEnd.SetTab( aDelRange.aStart.Tab() - nDz - 1 );
3359 bDel = true;
3360 break;
3361 case SC_CAT_MOVE :
3362 eMode = URM_MOVE;
3363 ((ScChangeActionMove*)pAct)->GetDelta( nDx, nDy, nDz );
3364 break;
3365 default:
3366 OSL_FAIL( "ScChangeTrack::UpdateReference: unknown Type" );
3368 if ( bUndo )
3370 nDx = -nDx;
3371 nDy = -nDy;
3372 nDz = -nDz;
3374 if ( bDel )
3375 { //! For this mechanism we assume:
3376 //! There's only a whole, simple deleted row/column
3377 ScChangeActionDel* pActDel = (ScChangeActionDel*) pAct;
3378 if ( !bUndo )
3379 { // Delete
3380 ScChangeActionType eInsType = SC_CAT_NONE; // for Insert Undo "Deletes"
3381 switch ( eActType )
3383 case SC_CAT_DELETE_COLS :
3384 eInsType = SC_CAT_INSERT_COLS;
3385 break;
3386 case SC_CAT_DELETE_ROWS :
3387 eInsType = SC_CAT_INSERT_ROWS;
3388 break;
3389 case SC_CAT_DELETE_TABS :
3390 eInsType = SC_CAT_INSERT_TABS;
3391 break;
3392 default:
3394 // added to avoid warnings
3397 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3399 if ( p == pAct )
3400 continue; // for
3401 bool bUpdate = true;
3402 if ( GetMergeState() == SC_CTMS_OTHER &&
3403 p->GetActionNumber() <= GetLastMerge() )
3404 { // Delete in merged Document, Action in the one to be merged
3405 if ( p->IsInsertType() )
3407 // On Insert only adjust references if the Delete does
3408 // not intersect the Insert
3409 if ( !aDelRange.Intersects( p->GetBigRange() ) )
3410 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3411 bUpdate = false;
3413 else if ( p->GetType() == SC_CAT_CONTENT &&
3414 p->IsDeletedInDelType( eInsType ) )
3415 { // Content in Insert Undo "Delete"
3416 // Do not adjust if this Delete would be in the Insert "Delete" (was just moved)
3417 if ( aDelRange.In( p->GetBigRange().aStart ) )
3418 bUpdate = false;
3419 else
3421 const ScChangeActionLinkEntry* pLink = p->GetDeletedIn();
3422 while ( pLink && bUpdate )
3424 const ScChangeAction* pDel = pLink->GetAction();
3425 if ( pDel && pDel->GetType() == eInsType &&
3426 pDel->GetBigRange().In( aDelRange ) )
3427 bUpdate = false;
3428 pLink = pLink->GetNext();
3432 if ( !bUpdate )
3433 continue; // for
3435 if ( aDelRange.In( p->GetBigRange() ) )
3437 // Do not adjust within a just deleted range,
3438 // instead assign the range.
3439 // Stack up ranges that have been deleted multiple times.
3440 // Intersecting Deletes cause "multiple delete" to be set.
3441 if ( !p->IsDeletedInDelType( eActType ) )
3443 p->SetDeletedIn( pActDel );
3444 // Add GeneratedDelContent to the to-be-deleted list
3445 if ( bGeneratedDelContents )
3446 pActDel->AddContent( (ScChangeActionContent*) p );
3448 bUpdate = false;
3450 else
3452 // Cut off inserted ranges, if Start/End is within the Delete,
3453 // but the Insert is not completely within the Delete or
3454 // the Delete is not completelty within the Insert.
3455 // The Delete remembers which Insert it has cut off from;
3456 // it can also just be a single Insert (because Delete has
3457 // a single column/is a single row).
3458 // There can be a lot of cut-off Moves.
3460 // ! A Delete is always a single column/a single row, therefore
3461 // ! 1 without calculating the intersection.
3462 switch ( p->GetType() )
3464 case SC_CAT_INSERT_COLS :
3465 if ( eActType == SC_CAT_DELETE_COLS )
3467 if ( aDelRange.In( p->GetBigRange().aStart ) )
3469 pActDel->SetCutOffInsert(
3470 (ScChangeActionIns*) p, 1 );
3471 p->GetBigRange().aStart.IncCol( 1 );
3473 else if ( aDelRange.In( p->GetBigRange().aEnd ) )
3475 pActDel->SetCutOffInsert(
3476 (ScChangeActionIns*) p, -1 );
3477 p->GetBigRange().aEnd.IncCol( -1 );
3480 break;
3481 case SC_CAT_INSERT_ROWS :
3482 if ( eActType == SC_CAT_DELETE_ROWS )
3484 if ( aDelRange.In( p->GetBigRange().aStart ) )
3486 pActDel->SetCutOffInsert(
3487 (ScChangeActionIns*) p, 1 );
3488 p->GetBigRange().aStart.IncRow( 1 );
3490 else if ( aDelRange.In( p->GetBigRange().aEnd ) )
3492 pActDel->SetCutOffInsert(
3493 (ScChangeActionIns*) p, -1 );
3494 p->GetBigRange().aEnd.IncRow( -1 );
3497 break;
3498 case SC_CAT_INSERT_TABS :
3499 if ( eActType == SC_CAT_DELETE_TABS )
3501 if ( aDelRange.In( p->GetBigRange().aStart ) )
3503 pActDel->SetCutOffInsert(
3504 (ScChangeActionIns*) p, 1 );
3505 p->GetBigRange().aStart.IncTab( 1 );
3507 else if ( aDelRange.In( p->GetBigRange().aEnd ) )
3509 pActDel->SetCutOffInsert(
3510 (ScChangeActionIns*) p, -1 );
3511 p->GetBigRange().aEnd.IncTab( -1 );
3514 break;
3515 case SC_CAT_MOVE :
3517 ScChangeActionMove* pMove = (ScChangeActionMove*) p;
3518 short nFrom = 0;
3519 short nTo = 0;
3520 if ( aDelRange.In( pMove->GetBigRange().aStart ) )
3521 nTo = 1;
3522 else if ( aDelRange.In( pMove->GetBigRange().aEnd ) )
3523 nTo = -1;
3524 if ( aDelRange.In( pMove->GetFromRange().aStart ) )
3525 nFrom = 1;
3526 else if ( aDelRange.In( pMove->GetFromRange().aEnd ) )
3527 nFrom = -1;
3528 if ( nFrom )
3530 switch ( eActType )
3532 case SC_CAT_DELETE_COLS :
3533 if ( nFrom > 0 )
3534 pMove->GetFromRange().aStart.IncCol( nFrom );
3535 else
3536 pMove->GetFromRange().aEnd.IncCol( nFrom );
3537 break;
3538 case SC_CAT_DELETE_ROWS :
3539 if ( nFrom > 0 )
3540 pMove->GetFromRange().aStart.IncRow( nFrom );
3541 else
3542 pMove->GetFromRange().aEnd.IncRow( nFrom );
3543 break;
3544 case SC_CAT_DELETE_TABS :
3545 if ( nFrom > 0 )
3546 pMove->GetFromRange().aStart.IncTab( nFrom );
3547 else
3548 pMove->GetFromRange().aEnd.IncTab( nFrom );
3549 break;
3550 default:
3552 // added to avoid warnings
3556 if ( nTo )
3558 switch ( eActType )
3560 case SC_CAT_DELETE_COLS :
3561 if ( nTo > 0 )
3562 pMove->GetBigRange().aStart.IncCol( nTo );
3563 else
3564 pMove->GetBigRange().aEnd.IncCol( nTo );
3565 break;
3566 case SC_CAT_DELETE_ROWS :
3567 if ( nTo > 0 )
3568 pMove->GetBigRange().aStart.IncRow( nTo );
3569 else
3570 pMove->GetBigRange().aEnd.IncRow( nTo );
3571 break;
3572 case SC_CAT_DELETE_TABS :
3573 if ( nTo > 0 )
3574 pMove->GetBigRange().aStart.IncTab( nTo );
3575 else
3576 pMove->GetBigRange().aEnd.IncTab( nTo );
3577 break;
3578 default:
3580 // added to avoid warnings
3584 if ( nFrom || nTo )
3586 ScChangeActionDelMoveEntry* pLink =
3587 pActDel->AddCutOffMove( pMove, nFrom, nTo );
3588 pMove->AddLink( pActDel, pLink );
3591 break;
3592 default:
3594 // added to avoid warnings
3598 if ( bUpdate )
3600 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3601 if ( p->GetType() == eActType && !p->IsRejected() &&
3602 !pActDel->IsDeletedIn() &&
3603 p->GetBigRange().In( aDelRange ) )
3604 pActDel->SetDeletedIn( p ); // Slipped underneath it
3608 else
3609 { // Undo Delete
3610 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3612 if ( p == pAct )
3613 continue; // for
3614 bool bUpdate = true;
3615 if ( aDelRange.In( p->GetBigRange() ) )
3617 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3618 if ( GetMergeState() == SC_CTMS_UNDO && !p->IsDeletedIn( pAct ) && pAct->IsDeleteType() &&
3619 ( p->GetType() == SC_CAT_CONTENT ||
3620 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3621 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) )
3623 p->SetDeletedIn( pAct );
3626 if ( p->IsDeletedInDelType( eActType ) )
3628 if ( p->IsDeletedIn( pActDel ) )
3630 if ( p->GetType() != SC_CAT_CONTENT ||
3631 ((ScChangeActionContent*)p)->IsTopContent() )
3632 { // First really remove the TopContent
3633 p->RemoveDeletedIn( pActDel );
3634 // Do NOT delete GeneratedDelContent from the list, we might need
3635 // it later on for Reject; we delete in DeleteCellEntries
3638 bUpdate = false;
3640 else if ( eActType != SC_CAT_DELETE_TABS &&
3641 p->IsDeletedInDelType( SC_CAT_DELETE_TABS ) )
3642 { // Do not update in deleted Tables except for when moving Tables
3643 bUpdate = false;
3645 if ( p->GetType() == eActType && pActDel->IsDeletedIn( p ) )
3647 pActDel->RemoveDeletedIn( p );// Slipped underneath
3648 bUpdate = true;
3651 if ( bUpdate )
3652 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3654 if ( !bGeneratedDelContents )
3655 { // These are else also needed for the real Undo
3656 pActDel->UndoCutOffInsert();
3657 pActDel->UndoCutOffMoves();
3661 else if ( eActType == SC_CAT_MOVE )
3663 ScChangeActionMove* pActMove = (ScChangeActionMove*) pAct;
3664 bool bLastCutMove = ( pActMove == pLastCutMove );
3665 const ScBigRange& rTo = pActMove->GetBigRange();
3666 const ScBigRange& rFrom = pActMove->GetFromRange();
3667 if ( !bUndo )
3668 { // Move
3669 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3671 if ( p == pAct )
3672 continue; // for
3673 if ( p->GetType() == SC_CAT_CONTENT )
3675 // Delete content in Target (Move Content to Source)
3676 if ( rTo.In( p->GetBigRange() ) )
3678 if ( !p->IsDeletedIn( pActMove ) )
3680 p->SetDeletedIn( pActMove );
3681 // Add GeneratedDelContent to the to-be-deleted list
3682 if ( bGeneratedDelContents )
3683 pActMove->AddContent( (ScChangeActionContent*) p );
3686 else if ( bLastCutMove &&
3687 p->GetActionNumber() > nEndLastCut &&
3688 rFrom.In( p->GetBigRange() ) )
3689 { // Paste Cut: insert new Content inserted after stays
3690 // Split up the ContentChain
3691 ScChangeActionContent *pHere, *pTmp;
3692 pHere = (ScChangeActionContent*) p;
3693 while ( (pTmp = pHere->GetPrevContent()) != NULL &&
3694 pTmp->GetActionNumber() > nEndLastCut )
3695 pHere = pTmp;
3696 if ( pTmp )
3697 { // Becomes TopContent of the Move
3698 pTmp->SetNextContent( NULL );
3699 pHere->SetPrevContent( NULL );
3702 { // Recover dependency from FromRange
3703 AddDependentWithNotify( pActMove, pHere );
3704 } while ( ( pHere = pHere->GetNextContent() ) != NULL );
3706 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3707 else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() )
3708 p->UpdateReference( this, eMode, rFrom, nDx, nDy, nDz );
3712 else
3713 { // Undo Move
3714 bool bActRejected = pActMove->IsRejected();
3715 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3717 if ( p == pAct )
3718 continue; // for
3719 if ( p->GetType() == SC_CAT_CONTENT )
3721 // Move Content into Target if not deleted else to delete (FIXME: What?)
3722 if ( p->IsDeletedIn( pActMove ) )
3724 if ( ((ScChangeActionContent*)p)->IsTopContent() )
3725 { // First really remove the TopContent
3726 p->RemoveDeletedIn( pActMove );
3727 // Do NOT delete GeneratedDelContent from the list, we might need
3728 // it later on for Reject; we delete in DeleteCellEntries
3731 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3732 else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() )
3733 p->UpdateReference( this, eMode, rTo, nDx, nDy, nDz );
3734 if ( bActRejected &&
3735 ((ScChangeActionContent*)p)->IsTopContent() &&
3736 rFrom.In( p->GetBigRange() ) )
3737 { // Recover dependency to write Content
3738 ScChangeActionLinkEntry* pLink =
3739 pActMove->AddDependent( p );
3740 p->AddLink( pActMove, pLink );
3746 else
3747 { // Insert/Undo Insert
3748 switch ( GetMergeState() )
3750 case SC_CTMS_NONE :
3751 case SC_CTMS_OTHER :
3753 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3755 if ( p == pAct )
3756 continue; // for
3757 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3760 break;
3761 case SC_CTMS_PREPARE :
3763 // "Delete" in Insert-Undo
3764 const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry();
3765 while ( pLink )
3767 ScChangeAction* p = (ScChangeAction*) pLink->GetAction();
3768 if ( p )
3769 p->SetDeletedIn( pAct );
3770 pLink = pLink->GetNext();
3773 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3774 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3776 if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
3777 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3778 ( p->GetType() == SC_CAT_CONTENT ||
3779 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3780 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
3781 pAct->GetBigRange().Intersects( p->GetBigRange() ) )
3783 p->SetDeletedIn( pAct );
3787 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3789 if ( p == pAct )
3790 continue; // for
3791 if ( !p->IsDeletedIn( pAct )
3792 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3793 && p->GetActionNumber() <= pAct->GetActionNumber() )
3795 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3799 break;
3800 case SC_CTMS_OWN :
3802 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3804 if ( p == pAct )
3805 continue; // for
3806 if ( !p->IsDeletedIn( pAct )
3807 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3808 && p->GetActionNumber() <= pAct->GetActionNumber() )
3810 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3813 // Undo "Delete" in Insert-Undo
3814 const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry();
3815 while ( pLink )
3817 ScChangeAction* p = (ScChangeAction*) pLink->GetAction();
3818 if ( p )
3819 p->RemoveDeletedIn( pAct );
3820 pLink = pLink->GetNext();
3823 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3824 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3826 if ( p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
3827 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3828 ( p->GetType() == SC_CAT_CONTENT ||
3829 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3830 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
3831 pAct->GetBigRange().Intersects( p->GetBigRange() ) )
3833 p->RemoveDeletedIn( pAct );
3837 break;
3838 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3839 case SC_CTMS_UNDO :
3841 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3843 if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
3844 ( p->GetType() == SC_CAT_CONTENT ||
3845 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3846 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
3847 pAct->GetBigRange().Intersects( p->GetBigRange() ) )
3849 p->SetDeletedIn( pAct );
3853 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3855 if ( p == pAct )
3857 continue;
3859 if ( !p->IsDeletedIn( pAct ) && p->GetActionNumber() <= pAct->GetActionNumber() )
3861 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3865 break;
3870 void ScChangeTrack::GetDependents( ScChangeAction* pAct,
3871 ScChangeActionMap& rMap, bool bListMasterDelete, bool bAllFlat ) const
3873 //! bAllFlat==TRUE: called internally from Accept or Reject
3874 //! => Generated will not be added
3875 bool bIsDelete = pAct->IsDeleteType();
3876 bool bIsMasterDelete = ( bListMasterDelete && pAct->IsMasterDelete() );
3878 const ScChangeAction* pCur = NULL;
3879 ::std::stack<ScChangeAction*> cStack;
3880 cStack.push(pAct);
3882 while ( !cStack.empty() )
3884 pCur = cStack.top();
3885 cStack.pop();
3887 if ( pCur->IsInsertType() )
3889 const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry();
3890 while ( pL )
3892 ScChangeAction* p = (ScChangeAction*) pL->GetAction();
3893 if ( p != pAct )
3895 if ( bAllFlat )
3897 sal_uLong n = p->GetActionNumber();
3898 if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second )
3899 if ( p->HasDependent() )
3900 cStack.push( p );
3902 else
3904 if ( p->GetType() == SC_CAT_CONTENT )
3906 if ( ((ScChangeActionContent*)p)->IsTopContent() )
3907 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3909 else
3910 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3913 pL = pL->GetNext();
3916 else if ( pCur->IsDeleteType() )
3918 if ( bIsDelete )
3919 { // Contents of deleted Ranges are only of interest on Delete
3920 ScChangeActionDel* pDel = (ScChangeActionDel*) pCur;
3921 if ( !bAllFlat && bIsMasterDelete && pCur == pAct )
3923 // Corresponding Deletes to this Delete to the same level,
3924 // if this Delete is at the top of a Row
3925 ScChangeActionType eType = pDel->GetType();
3926 ScChangeAction* p = pDel;
3927 while ( (p = p->GetPrev()) != NULL && p->GetType() == eType &&
3928 !((ScChangeActionDel*)p)->IsTopDelete() )
3929 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3930 // delete this in the map too
3931 rMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) );
3933 else
3935 const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry();
3936 while ( pL )
3938 ScChangeAction* p = (ScChangeAction*) pL->GetAction();
3939 if ( p != pAct )
3941 if ( bAllFlat )
3943 // Only a TopContent of a chain is in LinkDeleted
3944 sal_uLong n = p->GetActionNumber();
3945 if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second )
3946 if ( p->HasDeleted() ||
3947 p->GetType() == SC_CAT_CONTENT )
3948 cStack.push( p );
3950 else
3952 if ( p->IsDeleteType() )
3953 { // Further TopDeletes to same level: it's not rejectable
3954 if ( ((ScChangeActionDel*)p)->IsTopDelete() )
3955 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3957 else
3958 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3961 pL = pL->GetNext();
3966 else if ( pCur->GetType() == SC_CAT_MOVE )
3968 // Deleted Contents in ToRange
3969 const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry();
3970 while ( pL )
3972 ScChangeAction* p = (ScChangeAction*) pL->GetAction();
3973 if ( p != pAct && rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ).second )
3975 // Only one TopContent of a chain is in LinkDeleted
3976 if ( bAllFlat && (p->HasDeleted() ||
3977 p->GetType() == SC_CAT_CONTENT) )
3978 cStack.push( p );
3980 pL = pL->GetNext();
3982 // New Contents in FromRange or new FromRange in ToRange
3983 // or Inserts/Deletes in FromRange/ToRange
3984 pL = pCur->GetFirstDependentEntry();
3985 while ( pL )
3987 ScChangeAction* p = (ScChangeAction*) pL->GetAction();
3988 if ( p != pAct )
3990 if ( bAllFlat )
3992 sal_uLong n = p->GetActionNumber();
3993 if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second )
3994 if ( p->HasDependent() || p->HasDeleted() )
3995 cStack.push( p );
3997 else
3999 if ( p->GetType() == SC_CAT_CONTENT )
4001 if ( ((ScChangeActionContent*)p)->IsTopContent() )
4002 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
4004 else
4005 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
4008 pL = pL->GetNext();
4011 else if ( pCur->GetType() == SC_CAT_CONTENT )
4012 { // All changes at same position
4013 ScChangeActionContent* pContent = (ScChangeActionContent*) pCur;
4014 // All preceding ones
4015 while ( ( pContent = pContent->GetPrevContent() ) != NULL )
4017 if ( !pContent->IsRejected() )
4018 rMap.insert( ::std::make_pair( pContent->GetActionNumber(), pContent ) );
4020 pContent = (ScChangeActionContent*) pCur;
4021 // All succeeding ones
4022 while ( ( pContent = pContent->GetNextContent() ) != NULL )
4024 if ( !pContent->IsRejected() )
4025 rMap.insert( ::std::make_pair( pContent->GetActionNumber(), pContent ) );
4027 // all MatrixReferences of a MatrixOrigin
4028 const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry();
4029 while ( pL )
4031 ScChangeAction* p = (ScChangeAction*) pL->GetAction();
4032 if ( p != pAct )
4034 if ( bAllFlat )
4036 sal_uLong n = p->GetActionNumber();
4037 if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second )
4038 if ( p->HasDependent() )
4039 cStack.push( p );
4041 else
4042 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
4044 pL = pL->GetNext();
4047 else if ( pCur->GetType() == SC_CAT_REJECT )
4049 if ( bAllFlat )
4051 ScChangeAction* p = GetAction(
4052 ((ScChangeActionReject*)pCur)->GetRejectAction() );
4053 if (p != pAct && rMap.find( p->GetActionNumber() ) == rMap.end())
4054 cStack.push( p );
4060 bool ScChangeTrack::SelectContent( ScChangeAction* pAct, bool bOldest )
4062 if ( pAct->GetType() != SC_CAT_CONTENT )
4063 return false;
4065 ScChangeActionContent* pContent = (ScChangeActionContent*) pAct;
4066 if ( bOldest )
4068 pContent = pContent->GetTopContent();
4069 ScChangeActionContent* pPrevContent;
4070 while ( (pPrevContent = pContent->GetPrevContent()) != NULL &&
4071 pPrevContent->IsVirgin() )
4072 pContent = pPrevContent;
4075 if ( !pContent->IsClickable() )
4076 return false;
4078 ScBigRange aBigRange( pContent->GetBigRange() );
4079 const ScCellValue& rCell = (bOldest ? pContent->GetOldCell() : pContent->GetNewCell());
4080 if ( ScChangeActionContent::GetContentCellType(rCell) == SC_CACCT_MATORG )
4082 SCCOL nC;
4083 SCROW nR;
4084 rCell.mpFormula->GetMatColsRows(nC, nR);
4085 aBigRange.aEnd.IncCol( nC-1 );
4086 aBigRange.aEnd.IncRow( nR-1 );
4089 if ( !aBigRange.IsValid( pDoc ) )
4090 return false;
4092 ScRange aRange( aBigRange.MakeRange() );
4093 if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
4094 aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
4095 return false;
4097 if ( pContent->HasDependent() )
4099 bool bOk = true;
4100 ::std::stack<ScChangeActionContent*> aRejectActions;
4101 const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry();
4102 while ( pL )
4104 ScChangeAction* p = (ScChangeAction*) pL->GetAction();
4105 if ( p != pContent )
4107 if ( p->GetType() == SC_CAT_CONTENT )
4109 // we don't need no recursion here, do we?
4110 bOk &= ((ScChangeActionContent*)p)->Select( pDoc, this,
4111 bOldest, &aRejectActions );
4113 else
4115 OSL_FAIL( "ScChangeTrack::SelectContent: content dependent no content" );
4118 pL = pL->GetNext();
4121 bOk &= pContent->Select( pDoc, this, bOldest, NULL );
4122 // now the matrix is inserted and new content values are ready
4124 ScChangeActionContent* pNew;
4125 while ( !aRejectActions.empty() )
4127 pNew = aRejectActions.top();
4128 aRejectActions.pop();
4129 ScAddress aPos( pNew->GetBigRange().aStart.MakeAddress() );
4130 ScCellValue aCell;
4131 aCell.assign(*pDoc, aPos);
4132 pNew->SetNewValue(aCell, pDoc);
4133 Append( pNew );
4135 return bOk;
4137 else
4138 return pContent->Select( pDoc, this, bOldest, NULL );
4141 void ScChangeTrack::AcceptAll()
4143 for ( ScChangeAction* p = GetFirst(); p; p = p->GetNext() )
4145 p->Accept();
4149 bool ScChangeTrack::Accept( ScChangeAction* pAct )
4151 if ( !pAct->IsClickable() )
4152 return false;
4154 if ( pAct->IsDeleteType() || pAct->GetType() == SC_CAT_CONTENT )
4156 ScChangeActionMap aActionMap;
4157 ScChangeActionMap::iterator itChangeAction;
4159 GetDependents( pAct, aActionMap, false, true );
4161 for( itChangeAction = aActionMap.begin(); itChangeAction != aActionMap.end(); ++itChangeAction )
4163 itChangeAction->second->Accept();
4166 pAct->Accept();
4167 return true;
4170 bool ScChangeTrack::RejectAll()
4172 bool bOk = true;
4173 for ( ScChangeAction* p = GetLast(); p && bOk; p = p->GetPrev() )
4174 { //! Traverse backwards as dependencies attached to RejectActions
4175 if ( p->IsInternalRejectable() )
4176 bOk = Reject( p );
4178 return bOk;
4181 bool ScChangeTrack::Reject( ScChangeAction* pAct, bool bShared )
4183 // #i100895# When collaboration changes are reversed, it must be possible
4184 // to reject a deleted row above another deleted row.
4185 if ( bShared && pAct->IsDeletedIn() )
4186 pAct->RemoveAllDeletedIn();
4188 if ( !pAct->IsRejectable() )
4189 return false;
4191 ScChangeActionMap* pMap = NULL;
4192 if ( pAct->HasDependent() )
4194 pMap = new ScChangeActionMap;
4195 GetDependents( pAct, *pMap, false, true );
4197 bool bRejected = Reject( pAct, pMap, false );
4198 if ( pMap )
4199 delete pMap;
4200 return bRejected;
4203 bool ScChangeTrack::Reject(
4204 ScChangeAction* pAct, ScChangeActionMap* pMap, bool bRecursion )
4206 if ( !pAct->IsInternalRejectable() )
4207 return false;
4209 bool bOk = true;
4210 bool bRejected = false;
4211 if ( pAct->IsInsertType() )
4213 if ( pAct->HasDependent() && !bRecursion )
4215 OSL_ENSURE( pMap, "ScChangeTrack::Reject: Insert without map" );
4216 ScChangeActionMap::reverse_iterator itChangeAction;
4217 for (itChangeAction = pMap->rbegin();
4218 itChangeAction != pMap->rend() && bOk; ++itChangeAction)
4220 // Do not restore Contents which would end up being deleted anyways
4221 if ( itChangeAction->second->GetType() == SC_CAT_CONTENT )
4222 itChangeAction->second->SetRejected();
4223 else if ( itChangeAction->second->IsDeleteType() )
4224 itChangeAction->second->Accept(); // Deleted to Nirvana
4225 else
4226 bOk = Reject( itChangeAction->second, NULL, true ); //! Recursion
4229 if ( bOk && (bRejected = pAct->Reject( pDoc )) != false )
4231 // pRefDoc NULL := Do not save deleted Cells
4232 AppendDeleteRange( pAct->GetBigRange().MakeRange(), NULL, (short) 0,
4233 pAct->GetActionNumber() );
4236 else if ( pAct->IsDeleteType() )
4238 OSL_ENSURE( !pMap, "ScChangeTrack::Reject: Delete with map" );
4239 ScBigRange aDelRange;
4240 sal_uLong nRejectAction = pAct->GetActionNumber();
4241 bool bTabDel, bTabDelOk;
4242 if ( pAct->GetType() == SC_CAT_DELETE_TABS )
4244 bTabDel = true;
4245 aDelRange = pAct->GetBigRange();
4246 bTabDelOk = pAct->Reject( pDoc );
4247 bOk = bTabDelOk;
4248 if ( bOk )
4250 pAct = pAct->GetPrev();
4251 bOk = ( pAct && pAct->GetType() == SC_CAT_DELETE_COLS );
4254 else
4255 bTabDel = bTabDelOk = false;
4256 ScChangeActionDel* pDel = (ScChangeActionDel*) pAct;
4257 if ( bOk )
4259 aDelRange = pDel->GetOverAllRange();
4260 bOk = aDelRange.IsValid( pDoc );
4262 bool bOneOk = false;
4263 if ( bOk )
4265 ScChangeActionType eActType = pAct->GetType();
4266 switch ( eActType )
4268 case SC_CAT_DELETE_COLS :
4269 aDelRange.aStart.SetCol( aDelRange.aEnd.Col() );
4270 break;
4271 case SC_CAT_DELETE_ROWS :
4272 aDelRange.aStart.SetRow( aDelRange.aEnd.Row() );
4273 break;
4274 case SC_CAT_DELETE_TABS :
4275 aDelRange.aStart.SetTab( aDelRange.aEnd.Tab() );
4276 break;
4277 default:
4279 // added to avoid warnings
4282 ScChangeAction* p = pAct;
4283 bool bLoop = true;
4286 pDel = (ScChangeActionDel*) p;
4287 bOk = pDel->Reject( pDoc );
4288 if ( bOk )
4290 if ( bOneOk )
4292 switch ( pDel->GetType() )
4294 case SC_CAT_DELETE_COLS :
4295 aDelRange.aStart.IncCol( -1 );
4296 break;
4297 case SC_CAT_DELETE_ROWS :
4298 aDelRange.aStart.IncRow( -1 );
4299 break;
4300 case SC_CAT_DELETE_TABS :
4301 aDelRange.aStart.IncTab( -1 );
4302 break;
4303 default:
4305 // added to avoid warnings
4309 else
4310 bOneOk = true;
4312 if ( pDel->IsBaseDelete() )
4313 bLoop = false;
4314 else
4315 p = p->GetPrev();
4316 } while ( bOk && bLoop && p && p->GetType() == eActType &&
4317 !((ScChangeActionDel*)p)->IsTopDelete() );
4319 bRejected = bOk;
4320 if ( bOneOk || (bTabDel && bTabDelOk) )
4322 // Delete Reject made UpdateReference Undo
4323 ScChangeActionIns* pReject = new ScChangeActionIns(
4324 aDelRange.MakeRange() );
4325 pReject->SetRejectAction( nRejectAction );
4326 pReject->SetState( SC_CAS_ACCEPTED );
4327 Append( pReject );
4330 else if ( pAct->GetType() == SC_CAT_MOVE )
4332 if ( pAct->HasDependent() && !bRecursion )
4334 OSL_ENSURE( pMap, "ScChangeTrack::Reject: Move without Map" );
4335 ScChangeActionMap::reverse_iterator itChangeAction;
4337 for( itChangeAction = pMap->rbegin(); itChangeAction != pMap->rend() && bOk; ++itChangeAction )
4339 bOk = Reject( itChangeAction->second, NULL, true );//! Recursion
4342 if ( bOk && (bRejected = pAct->Reject( pDoc )) != false )
4344 ScChangeActionMove* pReject = new ScChangeActionMove(
4345 pAct->GetBigRange().MakeRange(),
4346 ((ScChangeActionMove*)pAct)->GetFromRange().MakeRange(), this );
4347 pReject->SetRejectAction( pAct->GetActionNumber() );
4348 pReject->SetState( SC_CAS_ACCEPTED );
4349 Append( pReject );
4352 else if ( pAct->GetType() == SC_CAT_CONTENT )
4354 ScRange aRange;
4355 ScChangeActionContent* pReject;
4356 if ( bRecursion )
4357 pReject = NULL;
4358 else
4360 aRange = pAct->GetBigRange().aStart.MakeAddress();
4361 pReject = new ScChangeActionContent( aRange );
4362 ScCellValue aCell;
4363 aCell.assign(*pDoc, aRange.aStart);
4364 pReject->SetOldValue(aCell, pDoc, pDoc);
4366 if ( (bRejected = pAct->Reject( pDoc )) != false && !bRecursion )
4368 ScCellValue aCell;
4369 aCell.assign(*pDoc, aRange.aStart);
4370 pReject->SetNewValue(aCell, pDoc);
4371 pReject->SetRejectAction( pAct->GetActionNumber() );
4372 pReject->SetState( SC_CAS_ACCEPTED );
4373 Append( pReject );
4375 else if ( pReject )
4376 delete pReject;
4378 else
4380 OSL_FAIL( "ScChangeTrack::Reject: say what?" );
4383 return bRejected;
4386 sal_uLong ScChangeTrack::AddLoadedGenerated(
4387 const ScCellValue& rNewCell, const ScBigRange& aBigRange, const OUString& sNewValue )
4389 ScChangeActionContent* pAct = new ScChangeActionContent( --nGeneratedMin, rNewCell, aBigRange, pDoc, sNewValue );
4390 if ( pAct )
4392 if ( pFirstGeneratedDelContent )
4393 pFirstGeneratedDelContent->pPrev = pAct;
4394 pAct->pNext = pFirstGeneratedDelContent;
4395 pFirstGeneratedDelContent = pAct;
4396 aGeneratedMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) );
4397 return pAct->GetActionNumber();
4399 return 0;
4402 void ScChangeTrack::AppendCloned( ScChangeAction* pAppend )
4404 aMap.insert( ::std::make_pair( pAppend->GetActionNumber(), pAppend ) );
4405 if ( !pLast )
4406 pFirst = pLast = pAppend;
4407 else
4409 pLast->pNext = pAppend;
4410 pAppend->pPrev = pLast;
4411 pLast = pAppend;
4415 ScChangeTrack* ScChangeTrack::Clone( ScDocument* pDocument ) const
4417 if ( !pDocument )
4419 return NULL;
4422 ScChangeTrack* pClonedTrack = new ScChangeTrack( pDocument );
4423 pClonedTrack->SetTimeNanoSeconds( IsTimeNanoSeconds() );
4425 // clone generated actions
4426 ::std::stack< const ScChangeAction* > aGeneratedStack;
4427 const ScChangeAction* pGenerated = GetFirstGenerated();
4428 while ( pGenerated )
4430 aGeneratedStack.push( pGenerated );
4431 pGenerated = pGenerated->GetNext();
4433 while ( !aGeneratedStack.empty() )
4435 pGenerated = aGeneratedStack.top();
4436 aGeneratedStack.pop();
4437 const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pGenerated );
4438 OSL_ENSURE( pContent, "ScChangeTrack::Clone: pContent is null!" );
4439 const ScCellValue& rNewCell = pContent->GetNewCell();
4440 if (!rNewCell.isEmpty())
4442 ScCellValue aClonedNewCell;
4443 aClonedNewCell.assign(rNewCell, *pDocument);
4444 OUString aNewValue;
4445 pContent->GetNewString( aNewValue, pDocument );
4446 pClonedTrack->nGeneratedMin = pGenerated->GetActionNumber() + 1;
4447 pClonedTrack->AddLoadedGenerated(aClonedNewCell, pGenerated->GetBigRange(), aNewValue);
4451 // clone actions
4452 const ScChangeAction* pAction = GetFirst();
4453 while ( pAction )
4455 ScChangeAction* pClonedAction = NULL;
4457 switch ( pAction->GetType() )
4459 case SC_CAT_INSERT_COLS:
4460 case SC_CAT_INSERT_ROWS:
4461 case SC_CAT_INSERT_TABS:
4463 pClonedAction = new ScChangeActionIns(
4464 pAction->GetActionNumber(),
4465 pAction->GetState(),
4466 pAction->GetRejectAction(),
4467 pAction->GetBigRange(),
4468 pAction->GetUser(),
4469 pAction->GetDateTimeUTC(),
4470 pAction->GetComment(),
4471 pAction->GetType() );
4473 break;
4474 case SC_CAT_DELETE_COLS:
4475 case SC_CAT_DELETE_ROWS:
4476 case SC_CAT_DELETE_TABS:
4478 const ScChangeActionDel* pDelete = dynamic_cast< const ScChangeActionDel* >( pAction );
4479 OSL_ENSURE( pDelete, "ScChangeTrack::Clone: pDelete is null!" );
4481 SCsCOLROW nD = 0;
4482 ScChangeActionType eType = pAction->GetType();
4483 if ( eType == SC_CAT_DELETE_COLS )
4485 nD = static_cast< SCsCOLROW >( pDelete->GetDx() );
4487 else if ( eType == SC_CAT_DELETE_ROWS )
4489 nD = static_cast< SCsCOLROW >( pDelete->GetDy() );
4492 pClonedAction = new ScChangeActionDel(
4493 pAction->GetActionNumber(),
4494 pAction->GetState(),
4495 pAction->GetRejectAction(),
4496 pAction->GetBigRange(),
4497 pAction->GetUser(),
4498 pAction->GetDateTimeUTC(),
4499 pAction->GetComment(),
4500 eType,
4502 pClonedTrack );
4504 break;
4505 case SC_CAT_MOVE:
4507 const ScChangeActionMove* pMove = dynamic_cast< const ScChangeActionMove* >( pAction );
4508 OSL_ENSURE( pMove, "ScChangeTrack::Clone: pMove is null!" );
4510 pClonedAction = new ScChangeActionMove(
4511 pAction->GetActionNumber(),
4512 pAction->GetState(),
4513 pAction->GetRejectAction(),
4514 pAction->GetBigRange(),
4515 pAction->GetUser(),
4516 pAction->GetDateTimeUTC(),
4517 pAction->GetComment(),
4518 pMove->GetFromRange(),
4519 pClonedTrack );
4521 break;
4522 case SC_CAT_CONTENT:
4524 const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pAction );
4525 OSL_ENSURE( pContent, "ScChangeTrack::Clone: pContent is null!" );
4526 const ScCellValue& rOldCell = pContent->GetOldCell();
4527 ScCellValue aClonedOldCell;
4528 aClonedOldCell.assign(rOldCell, *pDocument);
4529 OUString aOldValue;
4530 pContent->GetOldString( aOldValue, pDocument );
4532 ScChangeActionContent* pClonedContent = new ScChangeActionContent(
4533 pAction->GetActionNumber(),
4534 pAction->GetState(),
4535 pAction->GetRejectAction(),
4536 pAction->GetBigRange(),
4537 pAction->GetUser(),
4538 pAction->GetDateTimeUTC(),
4539 pAction->GetComment(),
4540 aClonedOldCell,
4541 pDocument,
4542 aOldValue );
4544 const ScCellValue& rNewCell = pContent->GetNewCell();
4545 if (!rNewCell.isEmpty())
4547 ScCellValue aClonedNewCell;
4548 aClonedNewCell.assign(rNewCell, *pDocument);
4549 pClonedContent->SetNewValue(aClonedNewCell, pDocument);
4552 pClonedAction = pClonedContent;
4554 break;
4555 case SC_CAT_REJECT:
4557 pClonedAction = new ScChangeActionReject(
4558 pAction->GetActionNumber(),
4559 pAction->GetState(),
4560 pAction->GetRejectAction(),
4561 pAction->GetBigRange(),
4562 pAction->GetUser(),
4563 pAction->GetDateTimeUTC(),
4564 pAction->GetComment() );
4566 break;
4567 default:
4570 break;
4573 if ( pClonedAction )
4575 pClonedTrack->AppendCloned( pClonedAction );
4578 pAction = pAction->GetNext();
4581 if ( pClonedTrack->GetLast() )
4583 pClonedTrack->SetActionMax( pClonedTrack->GetLast()->GetActionNumber() );
4586 // set dependencies for Deleted/DeletedIn
4587 pAction = GetFirst();
4588 while ( pAction )
4590 if ( pAction->HasDeleted() )
4592 ::std::stack< sal_uLong > aStack;
4593 const ScChangeActionLinkEntry* pL = pAction->GetFirstDeletedEntry();
4594 while ( pL )
4596 const ScChangeAction* pDeleted = pL->GetAction();
4597 if ( pDeleted )
4599 aStack.push( pDeleted->GetActionNumber() );
4601 pL = pL->GetNext();
4603 ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() );
4604 if ( pClonedAction )
4606 while ( !aStack.empty() )
4608 ScChangeAction* pClonedDeleted = pClonedTrack->GetActionOrGenerated( aStack.top() );
4609 aStack.pop();
4610 if ( pClonedDeleted )
4612 pClonedDeleted->SetDeletedIn( pClonedAction );
4617 pAction = pAction->GetNext();
4620 // set dependencies for Dependent/Any
4621 pAction = GetLast();
4622 while ( pAction )
4624 if ( pAction->HasDependent() )
4626 ::std::stack< sal_uLong > aStack;
4627 const ScChangeActionLinkEntry* pL = pAction->GetFirstDependentEntry();
4628 while ( pL )
4630 const ScChangeAction* pDependent = pL->GetAction();
4631 if ( pDependent )
4633 aStack.push( pDependent->GetActionNumber() );
4635 pL = pL->GetNext();
4637 ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() );
4638 if ( pClonedAction )
4640 while ( !aStack.empty() )
4642 ScChangeAction* pClonedDependent = pClonedTrack->GetActionOrGenerated( aStack.top() );
4643 aStack.pop();
4644 if ( pClonedDependent )
4646 ScChangeActionLinkEntry* pLink = pClonedAction->AddDependent( pClonedDependent );
4647 pClonedDependent->AddLink( pClonedAction, pLink );
4652 pAction = pAction->GetPrev();
4655 // masterlinks
4656 ScChangeAction* pClonedAction = pClonedTrack->GetFirst();
4657 while ( pClonedAction )
4659 pClonedTrack->MasterLinks( pClonedAction );
4660 pClonedAction = pClonedAction->GetNext();
4663 if ( IsProtected() )
4665 pClonedTrack->SetProtection( GetProtection() );
4668 if ( pClonedTrack->GetLast() )
4670 pClonedTrack->SetLastSavedActionNumber( pClonedTrack->GetLast()->GetActionNumber() );
4673 pDocument->SetChangeTrack( pClonedTrack );
4675 return pClonedTrack;
4678 void ScChangeTrack::MergeActionState( ScChangeAction* pAct, const ScChangeAction* pOtherAct )
4680 if ( pAct->IsVirgin() )
4682 if ( pOtherAct->IsAccepted() )
4684 pAct->Accept();
4685 if ( pOtherAct->IsRejecting() )
4687 pAct->SetRejectAction( pOtherAct->GetRejectAction() );
4690 else if ( pOtherAct->IsRejected() )
4692 pAct->SetRejected();
4697 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */