1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
25 #include "rechead.hxx"
26 #include "scerrors.hxx"
28 #include "inputopt.hxx"
29 #include "patattr.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
)
53 aDateTime( DateTime::SYSTEM
),
57 pLinkDeletedIn( NULL
),
59 pLinkDependent( NULL
),
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
) :
74 aDateTime( aTempDateTime
),
76 aComment( aTempComment
),
80 pLinkDeletedIn( NULL
),
82 pLinkDependent( NULL
),
83 nAction( nTempAction
),
84 nRejectAction( nTempRejectAction
),
90 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP
, const ScBigRange
& rRange
,
91 const sal_uLong nTempAction
)
94 aDateTime( DateTime::SYSTEM
),
98 pLinkDeletedIn( NULL
),
100 pLinkDependent( NULL
),
101 nAction( nTempAction
),
104 eState( SC_CAS_VIRGIN
)
106 aDateTime
.ConvertToUTC();
109 ScChangeAction::~ScChangeAction()
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() )
149 if ( GetType() == SC_CAT_CONTENT
)
150 return ((ScChangeActionContent
*)this)->IsTopContent();
154 bool ScChangeAction::IsTouchable() const
156 //! sequence order of execution is significant
157 if ( IsRejected() || GetType() == SC_CAT_REJECT
|| IsDeletedIn() )
159 // content may reject and be touchable if on top
160 if ( GetType() == SC_CAT_CONTENT
)
161 return ((ScChangeActionContent
*)this)->IsTopContent();
167 bool ScChangeAction::IsClickable() const
169 //! sequence order of execution is significant
174 if ( GetType() == SC_CAT_CONTENT
)
176 ScChangeActionContentCellType eCCT
=
177 ScChangeActionContent::GetContentCellType(
178 ((ScChangeActionContent
*)this)->GetNewCell() );
179 if ( eCCT
== SC_CACCT_MATREF
)
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();
187 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
188 if ( p
&& p
->IsDeletedIn() )
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() )
203 if ( GetType() == SC_CAT_CONTENT
)
205 if ( ((ScChangeActionContent
*)this)->IsOldMatrixReference() )
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
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() )
246 if ( ((ScChangeActionContent
*)this)->IsMatrixOrigin() && HasDependent() )
248 ScChangeActionContent
* pPrevContent
=
249 ((ScChangeActionContent
*)this)->GetPrevContent();
250 return pPrevContent
&& pPrevContent
->IsVirgin();
252 if ( HasDependent() )
253 return IsDeleteType() ? true : !IsDeletedIn();
256 if ( IsDeleteType() )
258 if ( IsDialogRoot() )
260 ScChangeActionLinkEntry
* pL
= pLinkDeleted
;
263 ScChangeAction
* p
= pL
->GetAction();
264 if ( p
&& p
->GetType() != eType
)
275 bool ScChangeAction::IsMasterDelete() const
277 if ( !IsDeleteType() )
279 ScChangeActionDel
* pDel
= (ScChangeActionDel
*) this;
280 return pDel
->IsMultiDelete() && (pDel
->IsTopDelete() || pDel
->IsRejectable());
283 void ScChangeAction::RemoveAllLinks()
286 RemoveAllDeletedIn();
288 RemoveAllDependent();
291 void ScChangeAction::RemoveAllAnyLinks()
294 delete pLinkAny
; // Moves up by itself
297 bool ScChangeAction::RemoveDeletedIn( const ScChangeAction
* p
)
299 bool bRemoved
= false;
300 ScChangeActionLinkEntry
* pL
= GetDeletedIn();
303 ScChangeActionLinkEntry
* pNextLink
= pL
->GetNext();
304 if ( pL
->GetAction() == p
)
314 bool ScChangeAction::IsDeletedIn() const
316 return GetDeletedIn() != NULL
;
319 bool ScChangeAction::IsDeletedIn( const ScChangeAction
* p
) const
321 ScChangeActionLinkEntry
* pL
= GetDeletedIn();
324 if ( pL
->GetAction() == p
)
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();
343 // InsertType for MergePrepare/MergeOwn
344 ScChangeActionType eInsType
;
347 case SC_CAT_DELETE_COLS
:
348 eInsType
= SC_CAT_INSERT_COLS
;
350 case SC_CAT_DELETE_ROWS
:
351 eInsType
= SC_CAT_INSERT_ROWS
;
353 case SC_CAT_DELETE_TABS
:
354 eInsType
= SC_CAT_INSERT_TABS
;
357 eInsType
= SC_CAT_NONE
;
362 if ( (p
= pL
->GetAction()) != NULL
&&
363 (p
->GetType() == eDelType
|| p
->GetType() == eInsType
) )
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() );
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();
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
)
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
)
432 ScGlobal::GetRscString(STR_CHANGED_MOVE_REJECTION_WARNING
) + " ");
433 rStr
= aBuf
.makeStringAndClear();
440 ScGlobal::GetRscString(STR_CHANGED_DELETE_REJECTION_WARNING
) + " ");
441 rStr
= aBuf
.makeStringAndClear();
445 const ScChangeTrack
* pCT
= GetChangeTrack();
449 ScChangeAction
* pReject
= pCT
->GetActionOrGenerated(GetRejectAction());
454 if (pReject
->GetType() == SC_CAT_MOVE
)
457 ScGlobal::GetRscString(STR_CHANGED_MOVE_REJECTION_WARNING
));
459 rStr
= aBuf
.makeStringAndClear();
463 if (pReject
->IsDeleteType())
466 ScGlobal::GetRscString(STR_CHANGED_DELETE_REJECTION_WARNING
));
468 rStr
= aBuf
.makeStringAndClear();
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
)
482 ScGlobal::GetRscString(STR_CHANGED_MOVE_REJECTION_WARNING
));
484 rStr
= aBuf
.makeStringAndClear();
488 if (pReject
->IsDeleteType())
491 ScGlobal::GetRscString(STR_CHANGED_DELETE_REJECTION_WARNING
));
493 rStr
= aBuf
.makeStringAndClear();
500 OUString
ScChangeAction::GetRefString(
501 const ScBigRange
& rRange
, ScDocument
* pDoc
, bool bFlag3D
) const
504 sal_uInt16 nFlags
= ( rRange
.IsValid( pDoc
) ? SCA_VALID
: 0 );
506 aBuf
.append(ScGlobal::GetRscString(STR_NOREF_STR
));
509 ScRange
aTmpRange( rRange
.MakeRange() );
512 case SC_CAT_INSERT_COLS
:
513 case SC_CAT_DELETE_COLS
:
517 pDoc
->GetName( aTmpRange
.aStart
.Tab(), aTmp
);
521 aBuf
.append(ScColToAlpha(aTmpRange
.aStart
.Col()));
523 aBuf
.append(ScColToAlpha(aTmpRange
.aEnd
.Col()));
525 case SC_CAT_INSERT_ROWS
:
526 case SC_CAT_DELETE_ROWS
:
530 pDoc
->GetName( aTmpRange
.aStart
.Tab(), aTmp
);
534 aBuf
.append(static_cast<sal_Int32
>(aTmpRange
.aStart
.Row()+1));
536 aBuf
.append(static_cast<sal_Int32
>(aTmpRange
.aEnd
.Row()+1));
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() )
552 return aBuf
.makeStringAndClear();
555 const OUString
& ScChangeAction::GetUser() const
560 void ScChangeAction::SetUser( const OUString
& r
)
565 const OUString
& ScChangeAction::GetComment() const
570 void ScChangeAction::SetComment( const OUString
& rStr
)
575 void ScChangeAction::GetRefString(
576 OUString
& rStr
, ScDocument
* pDoc
, bool bFlag3D
) const
578 rStr
= GetRefString( GetBigRange(), pDoc
, bFlag3D
);
581 void ScChangeAction::Accept()
585 SetState( SC_CAS_ACCEPTED
);
590 void ScChangeAction::SetRejected()
594 SetState( SC_CAS_REJECTED
);
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
);
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
;
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
;
632 DeleteCellEntries(); // Remove generated ones
635 void ScChangeAction::SetDeletedInThis( sal_uLong nActionNumber
,
636 const ScChangeTrack
* pTrack
)
640 ScChangeAction
* pAct
= pTrack
->GetActionOrGenerated( nActionNumber
);
641 OSL_ENSURE( pAct
, "ScChangeAction::SetDeletedInThis: missing Action" );
643 pAct
->SetDeletedIn( this );
647 void ScChangeAction::AddDependent( sal_uLong nActionNumber
,
648 const ScChangeTrack
* pTrack
)
652 ScChangeAction
* pAct
= pTrack
->GetActionOrGenerated( nActionNumber
);
653 OSL_ENSURE( pAct
, "ScChangeAction::AddDependent: missing Action" );
656 ScChangeActionLinkEntry
* pLink
= AddDependent( pAct
);
657 pAct
->AddLink( this, pLink
);
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
);
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
);
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
);
712 case SC_CAT_INSERT_COLS
:
713 nWhatId
= STR_COLUMN
;
715 case SC_CAT_INSERT_ROWS
:
722 OUString aRsc
= ScGlobal::GetRscString(STR_CHANGED_INSERT
);
723 sal_Int32 nPos
= aRsc
.indexOfAsciiL("#1", 2);
726 // Construct a range string to replace '#1' first.
727 OUStringBuffer
aBuf(ScGlobal::GetRscString(nWhatId
));
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
) )
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() ) )
751 case SC_CAT_INSERT_COLS
:
752 pDoc
->DeleteCol( aRange
);
754 case SC_CAT_INSERT_ROWS
:
755 pDoc
->DeleteRow( aRange
);
757 case SC_CAT_INSERT_TABS
:
758 pDoc
->DeleteTab( aRange
.aStart
.Tab() );
762 // added to avoid warnings
765 SetState( SC_CAS_REJECTED
);
771 ScChangeActionDel::ScChangeActionDel( const ScRange
& rRange
,
772 SCsCOL nDxP
, SCsROW nDyP
, ScChangeTrack
* pTrackP
)
774 ScChangeAction( SC_CAT_NONE
, rRange
),
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
);
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
);
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
),
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()
835 void ScChangeActionDel::AddContent( ScChangeActionContent
* pContent
)
837 ScChangeActionCellListEntry
* pE
= new ScChangeActionCellListEntry(
838 pContent
, pFirstCell
);
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() )
857 return ((ScChangeActionDel
*)p
)->IsBaseDelete();
860 bool ScChangeActionDel::IsMultiDelete() const
862 if ( GetDx() || GetDy() )
864 const ScChangeAction
* p
= GetNext();
865 if ( !p
|| p
->GetType() != GetType() )
867 const ScChangeActionDel
* pDel
= (const ScChangeActionDel
*) p
;
868 if ( (pDel
->GetDx() > GetDx() || pDel
->GetDy() > GetDy()) &&
869 pDel
->GetBigRange() == aBigRange
)
874 bool ScChangeActionDel::IsTabDeleteCol() const
876 if ( GetType() != SC_CAT_DELETE_COLS
)
878 const ScChangeAction
* p
= this;
879 while ( p
&& p
->GetType() == SC_CAT_DELETE_COLS
&&
880 !((const ScChangeActionDel
*)p
)->IsTopDelete() )
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() )
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() ) )
912 case SC_CAT_DELETE_COLS
:
913 p
->GetBigRange().aStart
.SetCol( GetBigRange().aStart
.Col() );
914 p
->GetBigRange().aEnd
.SetCol( GetBigRange().aStart
.Col() );
916 case SC_CAT_DELETE_ROWS
:
917 p
->GetBigRange().aStart
.SetRow( GetBigRange().aStart
.Row() );
918 p
->GetBigRange().aEnd
.SetRow( GetBigRange().aStart
.Row() );
920 case SC_CAT_DELETE_TABS
:
921 p
->GetBigRange().aStart
.SetTab( GetBigRange().aStart
.Tab() );
922 p
->GetBigRange().aEnd
.SetTab( GetBigRange().aStart
.Tab() );
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() );
941 void ScChangeActionDel::GetDescription(
942 OUString
& rStr
, ScDocument
* pDoc
, bool bSplitRange
, bool bWarning
) const
944 ScChangeAction::GetDescription( rStr
, pDoc
, bSplitRange
, bWarning
);
949 case SC_CAT_DELETE_COLS
:
950 nWhatId
= STR_COLUMN
;
952 case SC_CAT_DELETE_ROWS
:
959 ScBigRange
aTmpRange( GetBigRange() );
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);
975 // Build a string to replace with.
977 aBuf
.append(ScGlobal::GetRscString(nWhatId
));
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
)
994 { // Restore whole section in one go
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() )
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
);
1024 case SC_CAT_DELETE_ROWS
:
1025 if ( ( bOk
= pDoc
->CanInsertRow( aRange
) ) != false )
1026 bOk
= pDoc
->InsertRow( aRange
);
1028 case SC_CAT_DELETE_TABS
:
1030 //TODO: Remember table names?
1032 pDoc
->CreateValidTabName( aName
);
1033 if ( ( bOk
= pDoc
->ValidNewTabName( aName
) ) != false )
1034 bOk
= pDoc
->InsertTab( aRange
.aStart
.Tab(), aName
);
1039 // added to avoid warnings
1042 pTrack
->SetInDelete( false );
1043 pTrack
->SetInDeleteUndo( false );
1047 pTrack
->SetInDeleteTop( 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 );
1061 void ScChangeActionDel::UndoCutOffMoves()
1062 { // Restore cut off Moves; delete Entries/Links
1065 ScChangeActionMove
* pMove
= pLinkMove
->GetMove();
1066 short nFrom
= pLinkMove
->GetCutOffFrom();
1067 short nTo
= pLinkMove
->GetCutOffTo();
1068 switch ( GetType() )
1070 case SC_CAT_DELETE_COLS
:
1072 pMove
->GetFromRange().aStart
.IncCol( -nFrom
);
1073 else if ( nFrom
< 0 )
1074 pMove
->GetFromRange().aEnd
.IncCol( -nFrom
);
1076 pMove
->GetBigRange().aStart
.IncCol( -nTo
);
1078 pMove
->GetBigRange().aEnd
.IncCol( -nTo
);
1080 case SC_CAT_DELETE_ROWS
:
1082 pMove
->GetFromRange().aStart
.IncRow( -nFrom
);
1083 else if ( nFrom
< 0 )
1084 pMove
->GetFromRange().aEnd
.IncRow( -nFrom
);
1086 pMove
->GetBigRange().aStart
.IncRow( -nTo
);
1088 pMove
->GetBigRange().aEnd
.IncRow( -nTo
);
1090 case SC_CAT_DELETE_TABS
:
1092 pMove
->GetFromRange().aStart
.IncTab( -nFrom
);
1093 else if ( nFrom
< 0 )
1094 pMove
->GetFromRange().aEnd
.IncTab( -nFrom
);
1096 pMove
->GetBigRange().aStart
.IncTab( -nTo
);
1098 pMove
->GetBigRange().aEnd
.IncTab( -nTo
);
1102 // added to avoid warnings
1105 delete pLinkMove
; // Moves up by itself
1109 void ScChangeActionDel::UndoCutOffInsert()
1110 { //Restore cut off Insert
1113 switch ( pCutOff
->GetType() )
1115 case SC_CAT_INSERT_COLS
:
1117 pCutOff
->GetBigRange().aEnd
.IncCol( -nCutOff
);
1119 pCutOff
->GetBigRange().aStart
.IncCol( -nCutOff
);
1121 case SC_CAT_INSERT_ROWS
:
1123 pCutOff
->GetBigRange().aEnd
.IncRow( -nCutOff
);
1125 pCutOff
->GetBigRange().aStart
.IncRow( -nCutOff
);
1127 case SC_CAT_INSERT_TABS
:
1129 pCutOff
->GetBigRange().aEnd
.IncTab( -nCutOff
);
1131 pCutOff
->GetBigRange().aStart
.IncTab( -nCutOff
);
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
),
1158 ScChangeActionMove::~ScChangeActionMove()
1160 DeleteCellEntries();
1163 void ScChangeActionMove::AddContent( ScChangeActionContent
* pContent
)
1165 ScChangeActionCellListEntry
* pE
= new ScChangeActionCellListEntry(
1166 pContent
, pFirstCell
);
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);
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
);
1213 aRsc
= aRsc
.replaceAt(nPos
, 2, aTmpStr
);
1214 nPos
+= aTmpStr
.getLength();
1217 OUStringBuffer
aBuf(rStr
); // append to the original string.
1219 rStr
= aBuf
.makeStringAndClear();
1222 void ScChangeActionMove::GetRefString(
1223 OUString
& rStr
, ScDocument
* pDoc
, bool bFlag3D
) const
1226 bFlag3D
= ( GetFromRange().aStart
.Tab() != GetBigRange().aStart
.Tab() );
1228 // overwrite existing string value.
1229 rStr
= ScChangeAction::GetRefString(GetFromRange(), pDoc
, bFlag3D
)
1231 + ScChangeAction::GetRefString(GetBigRange(), pDoc
, bFlag3D
);
1234 bool ScChangeActionMove::Reject( ScDocument
* pDoc
)
1236 if ( !(aBigRange
.IsValid( pDoc
) && aFromRange
.IsValid( pDoc
)) )
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() );
1246 bOk
= pDoc
->IsBlockEditable( aFrmRange
.aStart
.Tab(),
1247 aFrmRange
.aStart
.Col(), aFrmRange
.aStart
.Row(),
1248 aFrmRange
.aEnd
.Col(), aFrmRange
.aEnd
.Row() );
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
;
1296 // ScChangeActionContent
1297 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent
)
1299 ScChangeActionContent::ScChangeActionContent( const ScRange
& rRange
) :
1300 ScChangeAction(SC_CAT_CONTENT
, rRange
),
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
),
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
),
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()
1350 void ScChangeActionContent::ClearTrack()
1354 pPrevContent
->pNextContent
= pNextContent
;
1356 pNextContent
->pPrevContent
= pPrevContent
;
1359 ScChangeActionContent
* ScChangeActionContent::GetTopContent() const
1363 ScChangeActionContent
* pContent
= pNextContent
;
1364 while ( pContent
->pNextContent
&& pContent
!= pContent
->pNextContent
)
1365 pContent
= pContent
->pNextContent
;
1368 return (ScChangeActionContent
*) this;
1371 ScChangeActionLinkEntry
* ScChangeActionContent::GetDeletedIn() const
1374 return GetTopContent()->pLinkDeletedIn
;
1375 return pLinkDeletedIn
;
1378 ScChangeActionLinkEntry
** ScChangeActionContent::GetDeletedInAddress()
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
)
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
)
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);
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
1460 const ScCellValue
& ScChangeActionContent::GetNewCell() const
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
);
1473 GetRefString(aTmpStr
, pDoc
);
1476 nPos
= aRsc
.indexOfAsciiL("#1", 2, nPos
);
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
);
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
);
1501 aRsc
= aRsc
.replaceAt(nPos
, 2, aTmpStr
);
1502 nPos
+= aTmpStr
.getLength();
1505 OUStringBuffer
aBuf(rStr
); // append to the original string.
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 );
1516 const ScCellValue
& rCell
= GetNewCell();
1517 if ( GetContentCellType(rCell
) == SC_CACCT_MATORG
)
1519 ScBigRange
aLocalBigRange( GetBigRange() );
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
);
1530 ScAddress
aTmpAddress( GetBigRange().aStart
.MakeAddress() );
1532 nFlags
|= SCA_TAB_3D
;
1533 rStr
= aTmpAddress
.Format(nFlags
, pDoc
, pDoc
->GetAddressConvention());
1534 if ( IsDeletedIn() )
1536 // Insert the parentheses.
1537 OUStringBuffer aBuf
;
1541 rStr
= aBuf
.makeStringAndClear();
1545 rStr
= ScGlobal::GetRscString( STR_NOREF_STR
);
1548 bool ScChangeActionContent::Reject( ScDocument
* pDoc
)
1550 if ( !aBigRange
.IsValid( pDoc
) )
1553 PutOldValueToDoc( pDoc
, 0, 0 );
1555 SetState( SC_CAS_REJECTED
);
1561 bool ScChangeActionContent::Select( ScDocument
* pDoc
, ScChangeTrack
* pTrack
,
1562 bool bOldest
, ::std::stack
<ScChangeActionContent
*>* pRejectActions
)
1564 if ( !aBigRange
.IsValid( pDoc
) )
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();
1582 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
1587 pContent
->SetRejected();
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
);
1598 aCell
.assign(*pDoc
, rPos
);
1599 pNew
->SetOldValue(aCell
, pDoc
, pDoc
);
1602 PutOldValueToDoc( pDoc
, 0, 0 );
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
);
1612 aCell
.assign(*pDoc
, rPos
);
1613 pNew
->SetNewValue(aCell
, pDoc
);
1614 pTrack
->Append( pNew
);
1621 SetState( SC_CAS_ACCEPTED
);
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
));
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
))
1643 switch (rCell
.meType
)
1645 case CELLTYPE_VALUE
:
1646 pDoc
->GetFormatTable()->GetInputLineString(rCell
.mfValue
, nFormat
, rStr
);
1648 case CELLTYPE_STRING
:
1649 rStr
= rCell
.mpString
->getString();
1652 if (rCell
.mpEditText
)
1653 rStr
= ScEditUtil::GetString(*rCell
.mpEditText
, pDoc
);
1655 case CELLTYPE_FORMULA
:
1656 rCell
.mpFormula
->GetFormula(rStr
);
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())
1675 return SC_CACCT_NORMAL
;
1678 return SC_CACCT_MATORG
;
1680 return SC_CACCT_MATREF
;
1682 return SC_CACCT_NORMAL
;
1684 return SC_CACCT_NONE
;
1688 ScChangeActionContentCellType
ScChangeActionContent::GetContentCellType( const ScRefCellValue
& rCell
)
1690 switch (rCell
.meType
)
1692 case CELLTYPE_VALUE
:
1693 case CELLTYPE_STRING
:
1695 return SC_CACCT_NORMAL
;
1696 case CELLTYPE_FORMULA
:
1698 const ScFormulaCell
* pCell
= rCell
.mpFormula
;
1699 switch (pCell
->GetMatrixFlag())
1702 return SC_CACCT_NORMAL
;
1705 return SC_CACCT_MATORG
;
1707 return SC_CACCT_MATREF
;
1711 return SC_CACCT_NORMAL
;
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
)
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
);
1750 case CELLTYPE_FORMULA
:
1751 rCell
.mpFormula
->SetInChangeTrack(true);
1755 // added to avoid warnings
1763 void ScChangeActionContent::SetCell( OUString
& rStr
, ScCellValue
& rCell
, sal_uLong nFormat
, const ScDocument
* pDoc
)
1766 if (rCell
.isEmpty())
1769 switch (rCell
.meType
)
1771 case CELLTYPE_VALUE
:
1772 // e.g. remember date as date string
1773 pDoc
->GetFormatTable()->GetInputLineString(rCell
.mfValue
, nFormat
, rStr
);
1775 case CELLTYPE_FORMULA
:
1776 rCell
.mpFormula
->SetInChangeTrack(true);
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())
1794 switch (rCell
.meType
)
1796 case CELLTYPE_STRING
:
1797 rStr
= rCell
.mpString
->getString();
1799 case CELLTYPE_EDIT
:
1800 if (rCell
.mpEditText
)
1801 rStr
= ScEditUtil::GetString(*rCell
.mpEditText
, pDoc
);
1803 case CELLTYPE_VALUE
: // Is always in rValue
1806 case CELLTYPE_FORMULA
:
1807 GetFormulaString(rStr
, rCell
.mpFormula
);
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
);
1824 OSL_FAIL( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" );
1825 ScFormulaCell
* pNew
= new ScFormulaCell( *pCell
, *pCell
->GetDocument(), aPos
);
1826 pNew
->GetFormula( rStr
);
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() );
1853 if (!rValue
.isEmpty())
1855 pDoc
->SetString(aPos
, rValue
);
1859 if (rCell
.isEmpty())
1861 pDoc
->SetEmptyCell(aPos
);
1865 if (rCell
.meType
== CELLTYPE_VALUE
)
1867 pDoc
->SetString( aPos
.Col(), aPos
.Row(), aPos
.Tab(), rValue
);
1871 switch (GetContentCellType(rCell
))
1873 case SC_CACCT_MATORG
:
1877 rCell
.mpFormula
->GetMatColsRows(nC
, nR
);
1878 OSL_ENSURE( nC
>0 && nR
>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" );
1879 ScRange
aRange( aPos
);
1881 aRange
.aEnd
.IncCol( nC
-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());
1892 case SC_CACCT_MATREF
:
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
)
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();
1957 nDx
= rDelRange
.aEnd
.Col() - rDelRange
.aStart
.Col() + 1;
1959 nDx
= -(rDelRange
.aEnd
.Col() - rDelRange
.aStart
.Col() + 1);
1961 nDy
= rDelRange
.aEnd
.Row() - rDelRange
.aStart
.Row() + 1;
1963 nDy
= -(rDelRange
.aEnd
.Row() - rDelRange
.aStart
.Row() + 1);
1965 nDz
= rDelRange
.aEnd
.Tab() - rDelRange
.aStart
.Tab() + 1;
1967 nDz
= -(rDelRange
.aEnd
.Tab() - rDelRange
.aStart
.Tab() + 1);
1969 ScBigRange
aTmpRange( rRange
);
1973 if ( nDx
< 0 || nDy
< 0 || nDz
< 0 )
1974 { // Delete starts there after removed range
1975 // Position is changed there
1977 aTmpRange
.aStart
.IncCol( -nDx
);
1979 aTmpRange
.aStart
.IncRow( -nDy
);
1981 aTmpRange
.aStart
.IncTab( -nDz
);
1985 // Move is Source here and Target there
1986 // Position needs to be adjusted before that
1988 maOldCell
.mpFormula
->aPos
= aBigRange
.aStart
.MakeAddress();
1990 maNewCell
.mpFormula
->aPos
= aBigRange
.aStart
.MakeAddress();
1993 aTmpRange
.aStart
.IncCol( nDx
);
1994 aTmpRange
.aEnd
.IncCol( nDx
);
1998 aTmpRange
.aStart
.IncRow( nDy
);
1999 aTmpRange
.aEnd
.IncRow( nDy
);
2003 aTmpRange
.aStart
.IncTab( nDz
);
2004 aTmpRange
.aEnd
.IncTab( nDz
);
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
;
2022 maOldCell
.mpFormula
->UpdateReference(aRefCxt
, NULL
);
2024 maNewCell
.mpFormula
->UpdateReference(aRefCxt
, NULL
);
2026 if ( !aBigRange
.aStart
.IsValid( pTrack
->GetDocument() ) )
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
;
2035 ScTokenArray
* pArr
= maOldCell
.mpFormula
->GetCode();
2037 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReference()) ) != NULL
)
2038 lcl_InvalidateReference( *t
, rPos
);
2040 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()) ) != NULL
)
2041 lcl_InvalidateReference( *t
, rPos
);
2046 ScTokenArray
* pArr
= maNewCell
.mpFormula
->GetCode();
2048 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReference()) ) != NULL
)
2049 lcl_InvalidateReference( *t
, rPos
);
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*/)
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
) )
2096 return nRowsPerSlot
;
2099 ScChangeTrack::ScChangeTrack( ScDocument
* pDocP
) :
2100 aFixDateTime( DateTime::SYSTEM
),
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
),
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);
2125 delete [] ppContentSlots
;
2128 void ScChangeTrack::Init()
2132 pFirstGeneratedDelContent
= NULL
;
2133 pLastCutMove
= NULL
;
2134 pLinkInsertCol
= NULL
;
2135 pLinkInsertRow
= NULL
;
2136 pLinkInsertTab
= NULL
;
2138 pBlockModifyMsg
= NULL
;
2140 nGeneratedMin
= SC_CHGTRACK_GENERATED_START
;
2145 eMergeState
= SC_CTMS_NONE
;
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());
2158 aBuf
.append(rUserOpt
.GetLastName());
2159 maUser
= aBuf
.makeStringAndClear();
2160 maUserCollection
.insert(maUser
);
2163 void ScChangeTrack::DtorClear()
2166 ScChangeAction
* pNext
;
2167 ScChangeActionMap::iterator itChangeAction
;
2168 for ( p
= GetFirst(); p
; p
= pNext
)
2170 pNext
= p
->GetNext();
2173 for ( p
= pFirstGeneratedDelContent
; p
; p
= pNext
)
2175 pNext
= p
->GetNext();
2178 for( itChangeAction
= aPasteCutMap
.begin(); itChangeAction
!= aPasteCutMap
.end(); ++itChangeAction
)
2180 delete itChangeAction
->second
;
2182 delete pLastCutMove
;
2186 void ScChangeTrack::ClearMsgQueue()
2188 if ( pBlockModifyMsg
)
2190 delete pBlockModifyMsg
;
2191 pBlockModifyMsg
= NULL
;
2193 while ( !aMsgStackTmp
.empty() )
2195 delete aMsgStackTmp
.top();
2198 while ( !aMsgStackFinal
.empty() )
2200 delete aMsgStackFinal
.top();
2201 aMsgStackFinal
.pop();
2204 ScChangeTrackMsgQueue::iterator itQueue
;
2205 for ( itQueue
= aMsgQueue
.begin(); itQueue
!= aMsgQueue
.end(); ++itQueue
)
2211 void ScChangeTrack::Clear()
2215 aGeneratedMap
.clear();
2216 aPasteCutMap
.clear();
2217 maUserCollection
.clear();
2218 maUser
= OUString();
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());
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();
2249 pDocSh
->Broadcast( ScPaintHint( ScRange(0,0,0,MAXCOL
,MAXROW
,MAXTAB
), PAINT_GRID
) );
2254 void ScChangeTrack::SetUser( const OUString
& rUser
)
2257 return ; // Do not destroy the Collection
2260 maUserCollection
.insert(maUser
);
2263 const OUString
& ScChangeTrack::GetUser() const
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
);
2294 delete pBlockModifyMsg
;
2295 if (aMsgStackTmp
.empty())
2296 pBlockModifyMsg
= NULL
;
2299 pBlockModifyMsg
= aMsgStackTmp
.top(); // Maybe Block in Block
2303 if ( !pBlockModifyMsg
)
2306 while ( !aMsgStackFinal
.empty() )
2308 aMsgQueue
.push_back( aMsgStackFinal
.top() );
2309 aMsgStackFinal
.pop();
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
] );
2349 if ( pAppend
->IsRejecting() )
2350 return ; // Rejects do not have dependencies
2354 case SC_CAT_INSERT_COLS
:
2356 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2357 &pLinkInsertCol
, pAppend
);
2358 pAppend
->AddLink( NULL
, pLink
);
2361 case SC_CAT_INSERT_ROWS
:
2363 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2364 &pLinkInsertRow
, pAppend
);
2365 pAppend
->AddLink( NULL
, pLink
);
2368 case SC_CAT_INSERT_TABS
:
2370 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2371 &pLinkInsertTab
, pAppend
);
2372 pAppend
->AddLink( NULL
, pLink
);
2377 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2378 &pLinkMove
, pAppend
);
2379 pAppend
->AddLink( NULL
, pLink
);
2384 // added to avoid warnings
2389 void ScChangeTrack::AppendLoaded( ScChangeAction
* pAppend
)
2391 aMap
.insert( ::std::make_pair( pAppend
->GetActionNumber(), pAppend
) );
2393 pFirst
= pLast
= pAppend
;
2396 pLast
->pNext
= pAppend
;
2397 pAppend
->pPrev
= pLast
;
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 );
2419 pFirst
= pLast
= pAppend
;
2422 pLast
->pNext
= pAppend
;
2423 pAppend
->pPrev
= pLast
;
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
);
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 );
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
)
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
);
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
)
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
);
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
);
2545 aTrackRange
.aStart
.IncCol( -nDx
);
2546 aTrackRange
.aEnd
.IncCol( -nDx
);
2550 aTrackRange
.aStart
.IncRow( -nDy
);
2551 aTrackRange
.aEnd
.IncRow( -nDy
);
2555 aTrackRange
.aStart
.IncTab( -nDz
);
2556 aTrackRange
.aEnd
.IncTab( -nDz
);
2558 ScChangeActionDel
* pAct
= new ScChangeActionDel( aTrackRange
, nDx
, nDy
,
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
);
2572 void ScChangeTrack::LookUpContents( const ScRange
& rOrgRange
,
2573 ScDocument
* pRefDoc
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
2579 ScBigAddress aBigPos
;
2580 ScCellIterator
aIter( pRefDoc
, rOrgRange
);
2581 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
2583 if (!ScChangeActionContent::GetContentCellType(aIter
.getRefCellValue()))
2586 aBigPos
.Set( aIter
.GetPos().Col() + nDx
, aIter
.GetPos().Row() + nDy
,
2587 aIter
.GetPos().Tab() + nDz
);
2588 ScChangeActionContent
* pContent
= SearchContentAt( aBigPos
, NULL
);
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
2610 bool ScChangeTrack::IsMatrixFormulaRangeDifferent(
2611 const ScCellValue
& rOldCell
, const ScCellValue
& rNewCell
)
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
)
2634 ScChangeActionContent::GetStringOfCell(aOldValue
, rOldCell
, pRefDoc
, nOldFormat
);
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
);
2651 void ScChangeTrack::AppendContent( const ScAddress
& rPos
,
2652 ScDocument
* pRefDoc
)
2655 ScCellValue aOldCell
;
2656 aOldCell
.assign(*pRefDoc
, rPos
);
2657 ScChangeActionContent::GetStringOfCell(aOldValue
, aOldCell
, pRefDoc
, rPos
);
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
);
2674 void ScChangeTrack::AppendContent( const ScAddress
& rPos
, const ScCellValue
& rOldCell
)
2676 if (ScChangeActionContent::NeedsNumberFormat(rOldCell
))
2677 AppendContent(rPos
, rOldCell
, pDoc
->GetNumberFormat(rPos
), pDoc
);
2679 AppendContent(rPos
, rOldCell
, 0, pDoc
);
2682 void ScChangeTrack::SetLastCutMoveRange( const ScRange
& rRange
,
2683 ScDocument
* pRefDoc
)
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
)
2709 pLastCutMove
= new ScChangeActionMove( rRange
, rRange
, this );
2710 SetLastCutMoveRange( rRange
, pRefDoc
);
2718 rRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
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();
2728 if ( (nTmpCol
= (SCCOL
) (r
.aEnd
.Col() - r
.aStart
.Col())) != (nCol2
- nCol1
) )
2730 aRange
.aEnd
.SetCol( aRange
.aStart
.Col() + nTmpCol
);
2731 nCol1
+= nTmpCol
+ 1;
2735 if ( (nTmpRow
= (SCROW
) (r
.aEnd
.Row() - r
.aStart
.Row())) != (nRow2
- nRow1
) )
2737 aRange
.aEnd
.SetRow( aRange
.aStart
.Row() + nTmpRow
);
2738 nRow1
+= nTmpRow
+ 1;
2742 if ( (nTmpTab
= (SCTAB
) (r
.aEnd
.Tab() - r
.aStart
.Tab())) != (nTab2
- nTab1
) )
2744 aRange
.aEnd
.SetTab( aRange
.aStart
.Tab() + nTmpTab
);
2745 nTab1
+= nTmpTab
+ 1;
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
;
2760 SetInPasteCut( false );
2765 nStartAction
= GetActionMax() + 1;
2766 StartBlockModify( SC_CTM_APPEND
, nStartAction
);
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
));
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
);
2808 rPos
, aIter
.getCellValue(), pPat
->GetNumberFormat(pFormatter
), pRefDoc
);
2810 while (aIter
.next());
2812 nEndAction
= GetActionMax();
2813 EndBlockModify( nEndAction
);
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
);
2830 void ScChangeTrack::AppendInsert( const ScRange
& rRange
)
2832 ScChangeActionIns
* pAct
= new ScChangeActionIns( rRange
);
2836 void ScChangeTrack::DeleteCellEntries( ScChangeActionCellListEntry
*& pCellList
,
2837 ScChangeAction
* pDeletor
)
2839 ScChangeActionCellListEntry
* pE
= pCellList
;
2842 ScChangeActionCellListEntry
* pNext
= pE
->pNext
;
2843 pE
->pContent
->RemoveDeletedIn( pDeletor
);
2844 if ( IsGenerated( pE
->pContent
->GetActionNumber() ) &&
2845 !pE
->pContent
->IsDeletedIn() )
2846 DeleteGeneratedDelContent( pE
->pContent
);
2853 ScChangeActionContent
* ScChangeTrack::GenerateDelContent(
2854 const ScAddress
& rPos
, const ScCellValue
& rCell
, const ScDocument
* pFromDoc
)
2856 ScChangeActionContent
* pContent
= new ScChangeActionContent(
2858 pContent
->SetActionNumber( --nGeneratedMin
);
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
);
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
;
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() )
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
);
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
)
2947 rCell
.mpFormula
->GetMatrixOrigin(aOrg
);
2948 ScChangeActionContent
* pContent
= SearchContentAt( aOrg
, pAct
);
2949 if ( pContent
&& pContent
->IsMatrixOrigin() )
2951 AddDependentWithNotify( pContent
, pAct
);
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
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
);
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
);
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
);
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
);
3049 { // Inserts and Deletes are depending as soon as they cross FromRange or
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();
3070 if ( nAct
== nActionMax
)
3072 if ( pRemove
== pLast
)
3073 pLast
= pRemove
->pPrev
;
3074 if ( pRemove
== pFirst
)
3075 pFirst
= pRemove
->pNext
;
3076 if ( nAct
== 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
);
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
3120 SetMergeState( SC_CTMS_UNDO
);
3123 if ( nStartAction
== 0 )
3125 if ( nEndAction
> nActionMax
)
3126 nEndAction
= nActionMax
;
3127 if ( nEndAction
&& nStartAction
<= nEndAction
)
3129 if ( nStartAction
== nStartLastCut
&& nEndAction
== nEndLastCut
&&
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
) );
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 );
3153 if ( IsInPasteCut() )
3154 aPasteCutMap
.insert( ::std::make_pair( pAct
->GetActionNumber(), pAct
) );
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
);
3179 OSL_FAIL( "ScChangeTrack::Undo: nCut not found" );
3182 EndBlockModify( nEnd
);
3184 nStartLastCut
= nStart
;
3186 pLastCutMove
= pMove
;
3187 SetLastCutMoveRange(
3188 pMove
->GetFromRange().MakeRange(), pDoc
);
3198 EndBlockModify( nEndAction
);
3201 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
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();
3226 SetLastMerge( pAct
->GetActionNumber() );
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
)
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
,
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
;
3331 case SC_CAT_INSERT_COLS
:
3332 aRange
.aEnd
.SetCol( nInt32Max
);
3333 nDx
= rOrgRange
.aEnd
.Col() - rOrgRange
.aStart
.Col() + 1;
3335 case SC_CAT_INSERT_ROWS
:
3336 aRange
.aEnd
.SetRow( nInt32Max
);
3337 nDy
= rOrgRange
.aEnd
.Row() - rOrgRange
.aStart
.Row() + 1;
3339 case SC_CAT_INSERT_TABS
:
3340 aRange
.aEnd
.SetTab( nInt32Max
);
3341 nDz
= rOrgRange
.aEnd
.Tab() - rOrgRange
.aStart
.Tab() + 1;
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 );
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 );
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 );
3363 ((ScChangeActionMove
*)pAct
)->GetDelta( nDx
, nDy
, nDz
);
3366 OSL_FAIL( "ScChangeTrack::UpdateReference: unknown Type" );
3375 { //! For this mechanism we assume:
3376 //! There's only a whole, simple deleted row/column
3377 ScChangeActionDel
* pActDel
= (ScChangeActionDel
*) pAct
;
3380 ScChangeActionType eInsType
= SC_CAT_NONE
; // for Insert Undo "Deletes"
3383 case SC_CAT_DELETE_COLS
:
3384 eInsType
= SC_CAT_INSERT_COLS
;
3386 case SC_CAT_DELETE_ROWS
:
3387 eInsType
= SC_CAT_INSERT_ROWS
;
3389 case SC_CAT_DELETE_TABS
:
3390 eInsType
= SC_CAT_INSERT_TABS
;
3394 // added to avoid warnings
3397 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
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
);
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
) )
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
) )
3428 pLink
= pLink
->GetNext();
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
);
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 );
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 );
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 );
3517 ScChangeActionMove
* pMove
= (ScChangeActionMove
*) p
;
3520 if ( aDelRange
.In( pMove
->GetBigRange().aStart
) )
3522 else if ( aDelRange
.In( pMove
->GetBigRange().aEnd
) )
3524 if ( aDelRange
.In( pMove
->GetFromRange().aStart
) )
3526 else if ( aDelRange
.In( pMove
->GetFromRange().aEnd
) )
3532 case SC_CAT_DELETE_COLS
:
3534 pMove
->GetFromRange().aStart
.IncCol( nFrom
);
3536 pMove
->GetFromRange().aEnd
.IncCol( nFrom
);
3538 case SC_CAT_DELETE_ROWS
:
3540 pMove
->GetFromRange().aStart
.IncRow( nFrom
);
3542 pMove
->GetFromRange().aEnd
.IncRow( nFrom
);
3544 case SC_CAT_DELETE_TABS
:
3546 pMove
->GetFromRange().aStart
.IncTab( nFrom
);
3548 pMove
->GetFromRange().aEnd
.IncTab( nFrom
);
3552 // added to avoid warnings
3560 case SC_CAT_DELETE_COLS
:
3562 pMove
->GetBigRange().aStart
.IncCol( nTo
);
3564 pMove
->GetBigRange().aEnd
.IncCol( nTo
);
3566 case SC_CAT_DELETE_ROWS
:
3568 pMove
->GetBigRange().aStart
.IncRow( nTo
);
3570 pMove
->GetBigRange().aEnd
.IncRow( nTo
);
3572 case SC_CAT_DELETE_TABS
:
3574 pMove
->GetBigRange().aStart
.IncTab( nTo
);
3576 pMove
->GetBigRange().aEnd
.IncTab( nTo
);
3580 // added to avoid warnings
3586 ScChangeActionDelMoveEntry
* pLink
=
3587 pActDel
->AddCutOffMove( pMove
, nFrom
, nTo
);
3588 pMove
->AddLink( pActDel
, pLink
);
3594 // added to avoid warnings
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
3610 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
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
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
3645 if ( p
->GetType() == eActType
&& pActDel
->IsDeletedIn( p
) )
3647 pActDel
->RemoveDeletedIn( p
);// Slipped underneath
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();
3669 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
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
)
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
);
3714 bool bActRejected
= pActMove
->IsRejected();
3715 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
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
);
3747 { // Insert/Undo Insert
3748 switch ( GetMergeState() )
3751 case SC_CTMS_OTHER
:
3753 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3757 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3761 case SC_CTMS_PREPARE
:
3763 // "Delete" in Insert-Undo
3764 const ScChangeActionLinkEntry
* pLink
= pAct
->GetFirstDependentEntry();
3767 ScChangeAction
* p
= (ScChangeAction
*) pLink
->GetAction();
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() )
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
);
3802 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
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();
3817 ScChangeAction
* p
= (ScChangeAction
*) pLink
->GetAction();
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
);
3838 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
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() )
3859 if ( !p
->IsDeletedIn( pAct
) && p
->GetActionNumber() <= pAct
->GetActionNumber() )
3861 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
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
;
3882 while ( !cStack
.empty() )
3884 pCur
= cStack
.top();
3887 if ( pCur
->IsInsertType() )
3889 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDependentEntry();
3892 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
3897 sal_uLong n
= p
->GetActionNumber();
3898 if ( !IsGenerated( n
) && rMap
.insert( ::std::make_pair( n
, p
) ).second
)
3899 if ( p
->HasDependent() )
3904 if ( p
->GetType() == SC_CAT_CONTENT
)
3906 if ( ((ScChangeActionContent
*)p
)->IsTopContent() )
3907 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3910 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3916 else if ( pCur
->IsDeleteType() )
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
) );
3935 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDeletedEntry();
3938 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
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
)
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
) );
3958 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3966 else if ( pCur
->GetType() == SC_CAT_MOVE
)
3968 // Deleted Contents in ToRange
3969 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDeletedEntry();
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
) )
3982 // New Contents in FromRange or new FromRange in ToRange
3983 // or Inserts/Deletes in FromRange/ToRange
3984 pL
= pCur
->GetFirstDependentEntry();
3987 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
3992 sal_uLong n
= p
->GetActionNumber();
3993 if ( !IsGenerated( n
) && rMap
.insert( ::std::make_pair( n
, p
) ).second
)
3994 if ( p
->HasDependent() || p
->HasDeleted() )
3999 if ( p
->GetType() == SC_CAT_CONTENT
)
4001 if ( ((ScChangeActionContent
*)p
)->IsTopContent() )
4002 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
4005 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
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();
4031 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
4036 sal_uLong n
= p
->GetActionNumber();
4037 if ( !IsGenerated( n
) && rMap
.insert( ::std::make_pair( n
, p
) ).second
)
4038 if ( p
->HasDependent() )
4042 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
4047 else if ( pCur
->GetType() == SC_CAT_REJECT
)
4051 ScChangeAction
* p
= GetAction(
4052 ((ScChangeActionReject
*)pCur
)->GetRejectAction() );
4053 if (p
!= pAct
&& rMap
.find( p
->GetActionNumber() ) == rMap
.end())
4060 bool ScChangeTrack::SelectContent( ScChangeAction
* pAct
, bool bOldest
)
4062 if ( pAct
->GetType() != SC_CAT_CONTENT
)
4065 ScChangeActionContent
* pContent
= (ScChangeActionContent
*) pAct
;
4068 pContent
= pContent
->GetTopContent();
4069 ScChangeActionContent
* pPrevContent
;
4070 while ( (pPrevContent
= pContent
->GetPrevContent()) != NULL
&&
4071 pPrevContent
->IsVirgin() )
4072 pContent
= pPrevContent
;
4075 if ( !pContent
->IsClickable() )
4078 ScBigRange
aBigRange( pContent
->GetBigRange() );
4079 const ScCellValue
& rCell
= (bOldest
? pContent
->GetOldCell() : pContent
->GetNewCell());
4080 if ( ScChangeActionContent::GetContentCellType(rCell
) == SC_CACCT_MATORG
)
4084 rCell
.mpFormula
->GetMatColsRows(nC
, nR
);
4085 aBigRange
.aEnd
.IncCol( nC
-1 );
4086 aBigRange
.aEnd
.IncRow( nR
-1 );
4089 if ( !aBigRange
.IsValid( pDoc
) )
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() ) )
4097 if ( pContent
->HasDependent() )
4100 ::std::stack
<ScChangeActionContent
*> aRejectActions
;
4101 const ScChangeActionLinkEntry
* pL
= pContent
->GetFirstDependentEntry();
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
);
4115 OSL_FAIL( "ScChangeTrack::SelectContent: content dependent no content" );
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() );
4131 aCell
.assign(*pDoc
, aPos
);
4132 pNew
->SetNewValue(aCell
, pDoc
);
4138 return pContent
->Select( pDoc
, this, bOldest
, NULL
);
4141 void ScChangeTrack::AcceptAll()
4143 for ( ScChangeAction
* p
= GetFirst(); p
; p
= p
->GetNext() )
4149 bool ScChangeTrack::Accept( ScChangeAction
* pAct
)
4151 if ( !pAct
->IsClickable() )
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();
4170 bool ScChangeTrack::RejectAll()
4173 for ( ScChangeAction
* p
= GetLast(); p
&& bOk
; p
= p
->GetPrev() )
4174 { //! Traverse backwards as dependencies attached to RejectActions
4175 if ( p
->IsInternalRejectable() )
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() )
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 );
4203 bool ScChangeTrack::Reject(
4204 ScChangeAction
* pAct
, ScChangeActionMap
* pMap
, bool bRecursion
)
4206 if ( !pAct
->IsInternalRejectable() )
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
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
)
4245 aDelRange
= pAct
->GetBigRange();
4246 bTabDelOk
= pAct
->Reject( pDoc
);
4250 pAct
= pAct
->GetPrev();
4251 bOk
= ( pAct
&& pAct
->GetType() == SC_CAT_DELETE_COLS
);
4255 bTabDel
= bTabDelOk
= false;
4256 ScChangeActionDel
* pDel
= (ScChangeActionDel
*) pAct
;
4259 aDelRange
= pDel
->GetOverAllRange();
4260 bOk
= aDelRange
.IsValid( pDoc
);
4262 bool bOneOk
= false;
4265 ScChangeActionType eActType
= pAct
->GetType();
4268 case SC_CAT_DELETE_COLS
:
4269 aDelRange
.aStart
.SetCol( aDelRange
.aEnd
.Col() );
4271 case SC_CAT_DELETE_ROWS
:
4272 aDelRange
.aStart
.SetRow( aDelRange
.aEnd
.Row() );
4274 case SC_CAT_DELETE_TABS
:
4275 aDelRange
.aStart
.SetTab( aDelRange
.aEnd
.Tab() );
4279 // added to avoid warnings
4282 ScChangeAction
* p
= pAct
;
4286 pDel
= (ScChangeActionDel
*) p
;
4287 bOk
= pDel
->Reject( pDoc
);
4292 switch ( pDel
->GetType() )
4294 case SC_CAT_DELETE_COLS
:
4295 aDelRange
.aStart
.IncCol( -1 );
4297 case SC_CAT_DELETE_ROWS
:
4298 aDelRange
.aStart
.IncRow( -1 );
4300 case SC_CAT_DELETE_TABS
:
4301 aDelRange
.aStart
.IncTab( -1 );
4305 // added to avoid warnings
4312 if ( pDel
->IsBaseDelete() )
4316 } while ( bOk
&& bLoop
&& p
&& p
->GetType() == eActType
&&
4317 !((ScChangeActionDel
*)p
)->IsTopDelete() );
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
);
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
);
4352 else if ( pAct
->GetType() == SC_CAT_CONTENT
)
4355 ScChangeActionContent
* pReject
;
4360 aRange
= pAct
->GetBigRange().aStart
.MakeAddress();
4361 pReject
= new ScChangeActionContent( aRange
);
4363 aCell
.assign(*pDoc
, aRange
.aStart
);
4364 pReject
->SetOldValue(aCell
, pDoc
, pDoc
);
4366 if ( (bRejected
= pAct
->Reject( pDoc
)) != false && !bRecursion
)
4369 aCell
.assign(*pDoc
, aRange
.aStart
);
4370 pReject
->SetNewValue(aCell
, pDoc
);
4371 pReject
->SetRejectAction( pAct
->GetActionNumber() );
4372 pReject
->SetState( SC_CAS_ACCEPTED
);
4380 OSL_FAIL( "ScChangeTrack::Reject: say what?" );
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
);
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();
4402 void ScChangeTrack::AppendCloned( ScChangeAction
* pAppend
)
4404 aMap
.insert( ::std::make_pair( pAppend
->GetActionNumber(), pAppend
) );
4406 pFirst
= pLast
= pAppend
;
4409 pLast
->pNext
= pAppend
;
4410 pAppend
->pPrev
= pLast
;
4415 ScChangeTrack
* ScChangeTrack::Clone( ScDocument
* pDocument
) const
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
);
4445 pContent
->GetNewString( aNewValue
, pDocument
);
4446 pClonedTrack
->nGeneratedMin
= pGenerated
->GetActionNumber() + 1;
4447 pClonedTrack
->AddLoadedGenerated(aClonedNewCell
, pGenerated
->GetBigRange(), aNewValue
);
4452 const ScChangeAction
* pAction
= GetFirst();
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(),
4469 pAction
->GetDateTimeUTC(),
4470 pAction
->GetComment(),
4471 pAction
->GetType() );
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!" );
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(),
4498 pAction
->GetDateTimeUTC(),
4499 pAction
->GetComment(),
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(),
4516 pAction
->GetDateTimeUTC(),
4517 pAction
->GetComment(),
4518 pMove
->GetFromRange(),
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
);
4530 pContent
->GetOldString( aOldValue
, pDocument
);
4532 ScChangeActionContent
* pClonedContent
= new ScChangeActionContent(
4533 pAction
->GetActionNumber(),
4534 pAction
->GetState(),
4535 pAction
->GetRejectAction(),
4536 pAction
->GetBigRange(),
4538 pAction
->GetDateTimeUTC(),
4539 pAction
->GetComment(),
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
;
4557 pClonedAction
= new ScChangeActionReject(
4558 pAction
->GetActionNumber(),
4559 pAction
->GetState(),
4560 pAction
->GetRejectAction(),
4561 pAction
->GetBigRange(),
4563 pAction
->GetDateTimeUTC(),
4564 pAction
->GetComment() );
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();
4590 if ( pAction
->HasDeleted() )
4592 ::std::stack
< sal_uLong
> aStack
;
4593 const ScChangeActionLinkEntry
* pL
= pAction
->GetFirstDeletedEntry();
4596 const ScChangeAction
* pDeleted
= pL
->GetAction();
4599 aStack
.push( pDeleted
->GetActionNumber() );
4603 ScChangeAction
* pClonedAction
= pClonedTrack
->GetAction( pAction
->GetActionNumber() );
4604 if ( pClonedAction
)
4606 while ( !aStack
.empty() )
4608 ScChangeAction
* pClonedDeleted
= pClonedTrack
->GetActionOrGenerated( aStack
.top() );
4610 if ( pClonedDeleted
)
4612 pClonedDeleted
->SetDeletedIn( pClonedAction
);
4617 pAction
= pAction
->GetNext();
4620 // set dependencies for Dependent/Any
4621 pAction
= GetLast();
4624 if ( pAction
->HasDependent() )
4626 ::std::stack
< sal_uLong
> aStack
;
4627 const ScChangeActionLinkEntry
* pL
= pAction
->GetFirstDependentEntry();
4630 const ScChangeAction
* pDependent
= pL
->GetAction();
4633 aStack
.push( pDependent
->GetActionNumber() );
4637 ScChangeAction
* pClonedAction
= pClonedTrack
->GetAction( pAction
->GetActionNumber() );
4638 if ( pClonedAction
)
4640 while ( !aStack
.empty() )
4642 ScChangeAction
* pClonedDependent
= pClonedTrack
->GetActionOrGenerated( aStack
.top() );
4644 if ( pClonedDependent
)
4646 ScChangeActionLinkEntry
* pLink
= pClonedAction
->AddDependent( pClonedDependent
);
4647 pClonedDependent
->AddLink( pClonedAction
, pLink
);
4652 pAction
= pAction
->GetPrev();
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() )
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: */