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 <compiler.hxx>
22 #include <formulacell.hxx>
23 #include <document.hxx>
25 #include <dociter.hxx>
28 #include <inputopt.hxx>
29 #include <patattr.hxx>
31 #include <markdata.hxx>
32 #include <globstr.hrc>
33 #include <scresid.hxx>
34 #include <editutil.hxx>
35 #include <tokenarray.hxx>
36 #include <refupdatecontext.hxx>
37 #include <refupdat.hxx>
39 #include <osl/diagnose.h>
40 #include <svl/numformat.hxx>
41 #include <sfx2/objsh.hxx>
42 #include <unotools/useroptions.hxx>
43 #include <unotools/datetime.hxx>
44 #include <tools/json_writer.hxx>
47 #include <strings.hrc>
50 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP
, const ScRange
& rRange
)
53 aDateTime( DateTime::SYSTEM
),
57 pLinkDeletedIn( nullptr ),
58 pLinkDeleted( nullptr ),
59 pLinkDependent( nullptr ),
63 eState( SC_CAS_VIRGIN
)
65 aDateTime
.ConvertToUTC();
68 ScChangeAction::ScChangeAction(
69 ScChangeActionType eTypeP
, ScBigRange aRange
,
70 const sal_uLong nTempAction
, const sal_uLong nTempRejectAction
,
71 const ScChangeActionState eTempState
, const DateTime
& aTempDateTime
,
72 OUString aTempUser
, OUString aTempComment
) :
73 aBigRange(std::move( aRange
)),
74 aDateTime( aTempDateTime
),
75 aUser(std::move( aTempUser
)),
76 aComment(std::move( aTempComment
)),
80 pLinkDeletedIn( nullptr ),
81 pLinkDeleted( nullptr ),
82 pLinkDependent( nullptr ),
83 nAction( nTempAction
),
84 nRejectAction( nTempRejectAction
),
90 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP
, ScBigRange aRange
,
91 const sal_uLong nTempAction
)
93 aBigRange(std::move( aRange
)),
94 aDateTime( DateTime::SYSTEM
),
98 pLinkDeletedIn( nullptr ),
99 pLinkDeleted( nullptr ),
100 pLinkDependent( nullptr ),
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 static_cast<const 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 static_cast<const 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 static_cast<const 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 static_cast<const ScChangeActionContent
*>(this)->GetFirstDependentEntry();
187 ScChangeAction
* p
= const_cast<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 ( static_cast<const ScChangeActionContent
*>(this)->IsOldMatrixReference() )
207 ScChangeActionContent
* pNextContent
=
208 static_cast<const ScChangeActionContent
*>(this)->GetNextContent();
209 if ( pNextContent
== nullptr )
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 static_cast<const ScChangeActionContent
*>(this)->GetNextContent();
227 if ( pNextContent
== nullptr )
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 ( static_cast<const ScChangeActionContent
*>(this)->IsMatrixOrigin() && HasDependent() )
248 ScChangeActionContent
* pPrevContent
=
249 static_cast<const ScChangeActionContent
*>(this)->GetPrevContent();
250 return pPrevContent
&& pPrevContent
->IsVirgin();
252 if ( HasDependent() )
253 return IsDeleteType() || !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 const ScChangeActionDel
* pDel
= static_cast<const ScChangeActionDel
*>(this);
280 return pDel
->IsMultiDelete() && (pDel
->IsTopDelete() || pDel
->IsRejectable());
283 void ScChangeAction::RemoveAllLinks()
287 // coverity[use_after_free] - Moves up by itself
291 RemoveAllDeletedIn();
295 // coverity[use_after_free] - Moves up by itself
299 RemoveAllDependent();
302 bool ScChangeAction::RemoveDeletedIn( const ScChangeAction
* p
)
304 bool bRemoved
= false;
305 ScChangeActionLinkEntry
* pL
= GetDeletedIn();
308 ScChangeActionLinkEntry
* pNextLink
= pL
->GetNext();
309 if ( pL
->GetAction() == p
)
319 bool ScChangeAction::IsDeletedIn() const
321 return GetDeletedIn() != nullptr;
324 bool ScChangeAction::IsDeletedIn( const ScChangeAction
* p
) const
326 ScChangeActionLinkEntry
* pL
= GetDeletedIn();
329 if ( pL
->GetAction() == p
)
336 void ScChangeAction::RemoveAllDeletedIn()
338 //TODO: Not from TopContent, but really this one
339 while (pLinkDeletedIn
)
341 // coverity[use_after_free] - Moves up by itself
342 delete pLinkDeletedIn
;
346 bool ScChangeAction::IsDeletedInDelType( ScChangeActionType eDelType
) const
348 ScChangeActionLinkEntry
* pL
= GetDeletedIn();
351 // InsertType for MergePrepare/MergeOwn
352 ScChangeActionType eInsType
;
355 case SC_CAT_DELETE_COLS
:
356 eInsType
= SC_CAT_INSERT_COLS
;
358 case SC_CAT_DELETE_ROWS
:
359 eInsType
= SC_CAT_INSERT_ROWS
;
361 case SC_CAT_DELETE_TABS
:
362 eInsType
= SC_CAT_INSERT_TABS
;
365 eInsType
= SC_CAT_NONE
;
369 ScChangeAction
* p
= pL
->GetAction();
370 if ( p
!= nullptr && (p
->GetType() == eDelType
|| p
->GetType() == eInsType
) )
378 bool ScChangeAction::HasDependent() const
380 return pLinkDependent
!= nullptr;
383 bool ScChangeAction::HasDeleted() const
385 return pLinkDeleted
!= nullptr;
388 void ScChangeAction::SetDeletedIn( ScChangeAction
* p
)
390 ScChangeActionLinkEntry
* pLink1
= new ScChangeActionLinkEntry( GetDeletedInAddress(), p
);
391 ScChangeActionLinkEntry
* pLink2
;
392 if ( GetType() == SC_CAT_CONTENT
)
393 pLink2
= p
->AddDeleted( static_cast<ScChangeActionContent
*>(this)->GetTopContent() );
395 pLink2
= p
->AddDeleted( this );
396 pLink1
->SetLink( pLink2
);
399 void ScChangeAction::RemoveAllDependent()
401 while (pLinkDependent
)
403 // coverity[use_after_free] - Moves up by itself
404 delete pLinkDependent
;
408 DateTime
ScChangeAction::GetDateTime() const
410 DateTime
aDT( aDateTime
);
411 aDT
.ConvertToLocalTime();
415 void ScChangeAction::UpdateReference( const ScChangeTrack
* /* pTrack */,
416 UpdateRefMode eMode
, const ScBigRange
& rRange
,
417 sal_Int32 nDx
, sal_Int32 nDy
, sal_Int32 nDz
)
419 ScRefUpdate::Update( eMode
, rRange
, nDx
, nDy
, nDz
, GetBigRange() );
422 OUString
ScChangeAction::GetDescription(
423 ScDocument
& /* rDoc */, bool /* bSplitRange */, bool bWarning
) const
425 if (!IsRejecting() || !bWarning
)
428 // Add comment if rejection may have resulted in references
429 // not properly restored in formulas. See specification at
430 // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw
432 if (GetType() == SC_CAT_MOVE
)
434 return ScResId(STR_CHANGED_MOVE_REJECTION_WARNING
) + " ";
439 return ScResId(STR_CHANGED_DELETE_REJECTION_WARNING
) + " ";
442 const ScChangeTrack
* pCT
= GetChangeTrack();
446 ScChangeAction
* pReject
= pCT
->GetActionOrGenerated(GetRejectAction());
451 if (pReject
->GetType() == SC_CAT_MOVE
)
453 return ScResId(STR_CHANGED_MOVE_REJECTION_WARNING
) + " ";
456 if (pReject
->IsDeleteType())
458 return ScResId(STR_CHANGED_DELETE_REJECTION_WARNING
) + " ";
461 if (!pReject
->HasDependent())
464 ScChangeActionMap aMap
;
465 pCT
->GetDependents( pReject
, aMap
, false, true );
466 ScChangeActionMap::iterator itChangeAction
= std::find_if(aMap
.begin(), aMap
.end(),
467 [&pReject
](const ScChangeActionMap::value_type
& rEntry
) {
468 return rEntry
.second
->GetType() == SC_CAT_MOVE
|| pReject
->IsDeleteType(); });
469 if (itChangeAction
== aMap
.end())
472 if( itChangeAction
->second
->GetType() == SC_CAT_MOVE
)
473 return ScResId(STR_CHANGED_MOVE_REJECTION_WARNING
) + " ";
475 return ScResId(STR_CHANGED_DELETE_REJECTION_WARNING
) + " ";
478 OUString
ScChangeAction::GetRefString(
479 const ScBigRange
& rRange
, const ScDocument
& rDoc
, bool bFlag3D
) const
482 ScRefFlags nFlags
= ( rRange
.IsValid( rDoc
) ? ScRefFlags::VALID
: ScRefFlags::ZERO
);
483 if ( nFlags
== ScRefFlags::ZERO
)
484 aBuf
.append(ScCompiler::GetNativeSymbol(ocErrRef
));
487 ScRange
aTmpRange( rRange
.MakeRange( rDoc
) );
490 case SC_CAT_INSERT_COLS
:
491 case SC_CAT_DELETE_COLS
:
495 rDoc
.GetName( aTmpRange
.aStart
.Tab(), aTmp
);
496 aBuf
.append(aTmp
+ ".");
498 aBuf
.append(ScColToAlpha(aTmpRange
.aStart
.Col())
499 + ":" + ScColToAlpha(aTmpRange
.aEnd
.Col()));
501 case SC_CAT_INSERT_ROWS
:
502 case SC_CAT_DELETE_ROWS
:
506 rDoc
.GetName( aTmpRange
.aStart
.Tab(), aTmp
);
507 aBuf
.append(aTmp
+ ".");
509 aBuf
.append(OUString::number(static_cast<sal_Int64
>(aTmpRange
.aStart
.Row()+1))
510 + ":" + OUString::number(static_cast<sal_Int64
>(aTmpRange
.aEnd
.Row()+1)));
514 if ( bFlag3D
|| GetType() == SC_CAT_INSERT_TABS
)
515 nFlags
|= ScRefFlags::TAB_3D
;
517 aBuf
.append(aTmpRange
.Format(rDoc
, nFlags
, rDoc
.GetAddressConvention()));
520 if ( (bFlag3D
&& IsDeleteType()) || IsDeletedIn() )
526 return aBuf
.makeStringAndClear();
529 void ScChangeAction::SetUser( const OUString
& r
)
534 void ScChangeAction::SetComment( const OUString
& rStr
)
539 OUString
ScChangeAction::GetRefString( ScDocument
& rDoc
, bool bFlag3D
) const
541 return GetRefString( GetBigRange(), rDoc
, bFlag3D
);
544 void ScChangeAction::Accept()
548 SetState( SC_CAS_ACCEPTED
);
553 void ScChangeAction::SetRejected()
557 SetState( SC_CAS_REJECTED
);
563 void ScChangeAction::RejectRestoreContents( ScChangeTrack
* pTrack
,
564 SCCOL nDx
, SCROW nDy
)
566 // Construct list of Contents
567 std::vector
<ScChangeActionContent
*> aContentsList
;
568 for ( ScChangeActionLinkEntry
* pL
= pLinkDeleted
; pL
; pL
= pL
->GetNext() )
570 ScChangeAction
* p
= pL
->GetAction();
571 if ( p
&& p
->GetType() == SC_CAT_CONTENT
)
573 aContentsList
.push_back(static_cast<ScChangeActionContent
*>(p
) );
576 SetState( SC_CAS_REJECTED
); // Before UpdateReference for Move
577 pTrack
->UpdateReference( this, true ); // Free LinkDeleted
578 OSL_ENSURE( !pLinkDeleted
, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" );
580 // Work through list of Contents and delete
581 ScDocument
& rDoc
= pTrack
->GetDocument();
582 for (ScChangeActionContent
* pContent
: aContentsList
)
584 if ( !pContent
->IsDeletedIn() &&
585 pContent
->GetBigRange().aStart
.IsValid( rDoc
) )
586 pContent
->PutNewValueToDoc( &rDoc
, nDx
, nDy
);
588 DeleteCellEntries(); // Remove generated ones
591 void ScChangeAction::SetDeletedInThis( sal_uLong nActionNumber
,
592 const ScChangeTrack
* pTrack
)
596 ScChangeAction
* pAct
= pTrack
->GetActionOrGenerated( nActionNumber
);
597 OSL_ENSURE( pAct
, "ScChangeAction::SetDeletedInThis: missing Action" );
599 pAct
->SetDeletedIn( this );
603 void ScChangeAction::AddDependent( sal_uLong nActionNumber
,
604 const ScChangeTrack
* pTrack
)
608 ScChangeAction
* pAct
= pTrack
->GetActionOrGenerated( nActionNumber
);
609 OSL_ENSURE( pAct
, "ScChangeAction::AddDependent: missing Action" );
612 ScChangeActionLinkEntry
* pLink
= AddDependent( pAct
);
613 pAct
->AddLink( this, pLink
);
619 ScChangeActionIns::ScChangeActionIns( const ScDocument
* pDoc
, const ScRange
& rRange
, bool bEndOfList
) :
620 ScChangeAction(SC_CAT_NONE
, rRange
),
621 mbEndOfList(bEndOfList
)
623 if ( rRange
.aStart
.Col() == 0 && rRange
.aEnd
.Col() == pDoc
->MaxCol() )
625 aBigRange
.aStart
.SetCol( ScBigRange::nRangeMin
);
626 aBigRange
.aEnd
.SetCol( ScBigRange::nRangeMax
);
627 if ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == pDoc
->MaxRow() )
629 SetType( SC_CAT_INSERT_TABS
);
630 aBigRange
.aStart
.SetRow( ScBigRange::nRangeMin
);
631 aBigRange
.aEnd
.SetRow( ScBigRange::nRangeMax
);
634 SetType( SC_CAT_INSERT_ROWS
);
636 else if ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == pDoc
->MaxRow() )
638 SetType( SC_CAT_INSERT_COLS
);
639 aBigRange
.aStart
.SetRow( ScBigRange::nRangeMin
);
640 aBigRange
.aEnd
.SetRow( ScBigRange::nRangeMax
);
644 OSL_FAIL( "ScChangeActionIns: Block not supported!" );
648 ScChangeActionIns::ScChangeActionIns(
649 const sal_uLong nActionNumber
, const ScChangeActionState eStateP
,
650 const sal_uLong nRejectingNumber
, const ScBigRange
& aBigRangeP
,
651 const OUString
& aUserP
, const DateTime
& aDateTimeP
,
652 const OUString
& sComment
, const ScChangeActionType eTypeP
,
654 ScChangeAction(eTypeP
, aBigRangeP
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
),
655 mbEndOfList(bEndOfList
)
659 ScChangeActionIns::~ScChangeActionIns()
663 OUString
ScChangeActionIns::GetDescription( ScDocument
& rDoc
, bool bSplitRange
, bool bWarning
) const
665 OUString str
= ScChangeAction::GetDescription( rDoc
, bSplitRange
, bWarning
);
670 case SC_CAT_INSERT_COLS
:
671 pWhatId
= STR_COLUMN
;
673 case SC_CAT_INSERT_ROWS
:
680 OUString aRsc
= ScResId(STR_CHANGED_INSERT
);
681 sal_Int32 nPos
= aRsc
.indexOf("#1");
685 // Construct a range string to replace '#1' first.
686 OUString aRangeStr
= ScResId(pWhatId
) +
688 GetRefString(GetBigRange(), rDoc
);
690 aRsc
= aRsc
.replaceAt(nPos
, 2, aRangeStr
); // replace '#1' with the range string.
695 bool ScChangeActionIns::IsEndOfList() const
700 bool ScChangeActionIns::Reject( ScDocument
& rDoc
)
702 if ( !aBigRange
.IsValid( rDoc
) )
705 ScRange
aRange( aBigRange
.MakeRange( rDoc
) );
706 if ( !rDoc
.IsBlockEditable( aRange
.aStart
.Tab(), aRange
.aStart
.Col(),
707 aRange
.aStart
.Row(), aRange
.aEnd
.Col(), aRange
.aEnd
.Row() ) )
712 case SC_CAT_INSERT_COLS
:
713 rDoc
.DeleteCol( aRange
);
715 case SC_CAT_INSERT_ROWS
:
716 rDoc
.DeleteRow( aRange
);
718 case SC_CAT_INSERT_TABS
:
719 rDoc
.DeleteTab( aRange
.aStart
.Tab() );
723 // added to avoid warnings
726 SetState( SC_CAS_REJECTED
);
732 ScChangeActionDel::ScChangeActionDel( const ScDocument
* pDoc
, const ScRange
& rRange
,
733 SCCOL nDxP
, SCROW nDyP
, ScChangeTrack
* pTrackP
)
735 ScChangeAction( SC_CAT_NONE
, rRange
),
739 pLinkMove( nullptr ),
743 if ( rRange
.aStart
.Col() == 0 && rRange
.aEnd
.Col() == pDoc
->MaxCol() )
745 aBigRange
.aStart
.SetCol( ScBigRange::nRangeMin
);
746 aBigRange
.aEnd
.SetCol( ScBigRange::nRangeMax
);
747 if ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == pDoc
->MaxRow() )
749 SetType( SC_CAT_DELETE_TABS
);
750 aBigRange
.aStart
.SetRow( ScBigRange::nRangeMin
);
751 aBigRange
.aEnd
.SetRow( ScBigRange::nRangeMax
);
754 SetType( SC_CAT_DELETE_ROWS
);
756 else if ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == pDoc
->MaxRow() )
758 SetType( SC_CAT_DELETE_COLS
);
759 aBigRange
.aStart
.SetRow( ScBigRange::nRangeMin
);
760 aBigRange
.aEnd
.SetRow( ScBigRange::nRangeMax
);
764 OSL_FAIL( "ScChangeActionDel: Block not supported!" );
768 ScChangeActionDel::ScChangeActionDel(
769 const sal_uLong nActionNumber
, const ScChangeActionState eStateP
,
770 const sal_uLong nRejectingNumber
, const ScBigRange
& aBigRangeP
,
771 const OUString
& aUserP
, const DateTime
& aDateTimeP
, const OUString
&sComment
,
772 const ScChangeActionType eTypeP
, const SCCOLROW nD
, ScChangeTrack
* pTrackP
) : // which of nDx and nDy is set depends on the type
773 ScChangeAction(eTypeP
, aBigRangeP
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
),
777 pLinkMove( nullptr ),
781 if (eType
== SC_CAT_DELETE_COLS
)
782 nDx
= static_cast<SCCOL
>(nD
);
783 else if (eType
== SC_CAT_DELETE_ROWS
)
784 nDy
= static_cast<SCROW
>(nD
);
787 ScChangeActionDel::~ScChangeActionDel()
792 // coverity[use_after_free] - Moves up by itself
797 void ScChangeActionDel::AddContent( ScChangeActionContent
* pContent
)
799 mvCells
.push_back(pContent
);
802 void ScChangeActionDel::DeleteCellEntries()
804 pTrack
->DeleteCellEntries( mvCells
, this );
807 bool ScChangeActionDel::IsBaseDelete() const
809 return !GetDx() && !GetDy();
812 bool ScChangeActionDel::IsTopDelete() const
814 const ScChangeAction
* p
= GetNext();
815 if ( !p
|| p
->GetType() != GetType() )
817 return static_cast<const ScChangeActionDel
*>(p
)->IsBaseDelete();
820 bool ScChangeActionDel::IsMultiDelete() const
822 if ( GetDx() || GetDy() )
824 const ScChangeAction
* p
= GetNext();
825 if ( !p
|| p
->GetType() != GetType() )
827 const ScChangeActionDel
* pDel
= static_cast<const ScChangeActionDel
*>(p
);
828 return (pDel
->GetDx() > GetDx() || pDel
->GetDy() > GetDy()) &&
829 pDel
->GetBigRange() == aBigRange
;
832 bool ScChangeActionDel::IsTabDeleteCol() const
834 if ( GetType() != SC_CAT_DELETE_COLS
)
836 const ScChangeAction
* p
= this;
837 while ( p
&& p
->GetType() == SC_CAT_DELETE_COLS
&&
838 !static_cast<const ScChangeActionDel
*>(p
)->IsTopDelete() )
840 return p
&& p
->GetType() == SC_CAT_DELETE_TABS
;
843 ScChangeActionDelMoveEntry
* ScChangeActionDel::AddCutOffMove(
844 ScChangeActionMove
* pMove
, short nFrom
, short nTo
)
846 return new ScChangeActionDelMoveEntry(&pLinkMove
, pMove
, nFrom
, nTo
);
849 void ScChangeActionDel::UpdateReference( const ScChangeTrack
* /* pTrack */,
850 UpdateRefMode eMode
, const ScBigRange
& rRange
,
851 sal_Int32 nDxP
, sal_Int32 nDyP
, sal_Int32 nDz
)
853 ScRefUpdate::Update( eMode
, rRange
, nDxP
, nDyP
, nDz
, GetBigRange() );
855 if ( !IsDeletedIn() )
858 // Correct in the ones who slipped through
859 for ( ScChangeActionLinkEntry
* pL
= pLinkDeleted
; pL
; pL
= pL
->GetNext() )
861 ScChangeAction
* p
= pL
->GetAction();
862 if ( p
&& p
->GetType() == SC_CAT_CONTENT
&&
863 !GetBigRange().Contains( p
->GetBigRange() ) )
867 case SC_CAT_DELETE_COLS
:
868 p
->GetBigRange().aStart
.SetCol( GetBigRange().aStart
.Col() );
869 p
->GetBigRange().aEnd
.SetCol( GetBigRange().aStart
.Col() );
871 case SC_CAT_DELETE_ROWS
:
872 p
->GetBigRange().aStart
.SetRow( GetBigRange().aStart
.Row() );
873 p
->GetBigRange().aEnd
.SetRow( GetBigRange().aStart
.Row() );
875 case SC_CAT_DELETE_TABS
:
876 p
->GetBigRange().aStart
.SetTab( GetBigRange().aStart
.Tab() );
877 p
->GetBigRange().aEnd
.SetTab( GetBigRange().aStart
.Tab() );
881 // added to avoid warnings
888 ScBigRange
ScChangeActionDel::GetOverAllRange() const
890 ScBigRange
aTmpRange( GetBigRange() );
891 aTmpRange
.aEnd
.SetCol( aTmpRange
.aEnd
.Col() + GetDx() );
892 aTmpRange
.aEnd
.SetRow( aTmpRange
.aEnd
.Row() + GetDy() );
896 OUString
ScChangeActionDel::GetDescription( ScDocument
& rDoc
, bool bSplitRange
, bool bWarning
) const
898 OUString str
= ScChangeAction::GetDescription( rDoc
, bSplitRange
, bWarning
);
903 case SC_CAT_DELETE_COLS
:
904 pWhatId
= STR_COLUMN
;
906 case SC_CAT_DELETE_ROWS
:
913 ScBigRange
aTmpRange( GetBigRange() );
918 aTmpRange
.aStart
.SetCol( aTmpRange
.aStart
.Col() + GetDx() );
919 aTmpRange
.aStart
.SetRow( aTmpRange
.aStart
.Row() + GetDy() );
921 aTmpRange
.aEnd
.SetCol( aTmpRange
.aEnd
.Col() + GetDx() );
922 aTmpRange
.aEnd
.SetRow( aTmpRange
.aEnd
.Row() + GetDy() );
925 OUString aRsc
= ScResId(STR_CHANGED_DELETE
);
926 sal_Int32 nPos
= aRsc
.indexOf("#1");
930 // Build a string to replace with.
931 OUString aRangeStr
= ScResId(pWhatId
) + " " +
932 GetRefString(aTmpRange
, rDoc
);
933 aRsc
= aRsc
.replaceAt(nPos
, 2, aRangeStr
); // replace '#1' with the string.
935 return str
+ aRsc
; // append to the original.
938 bool ScChangeActionDel::Reject( ScDocument
& rDoc
)
940 if ( !aBigRange
.IsValid( rDoc
) && GetType() != SC_CAT_DELETE_TABS
)
944 { // Restore whole section in one go
946 ScBigRange
aTmpRange( GetOverAllRange() );
947 if ( !aTmpRange
.IsValid( rDoc
) )
949 if ( GetType() == SC_CAT_DELETE_TABS
)
950 { // Do we attach a Tab?
951 if ( aTmpRange
.aStart
.Tab() > rDoc
.GetMaxTableNumber() )
959 ScRange
aRange( aTmpRange
.MakeRange( rDoc
) );
960 // InDelete... for formula UpdateReference in Document
961 pTrack
->SetInDeleteRange( aRange
);
962 pTrack
->SetInDeleteTop( true );
963 pTrack
->SetInDeleteUndo( true );
964 pTrack
->SetInDelete( true );
967 case SC_CAT_DELETE_COLS
:
968 if ( aRange
.aStart
.Col() != 0 || aRange
.aEnd
.Col() != rDoc
.MaxCol() )
969 { // Only if not TabDelete
970 bOk
= rDoc
.CanInsertCol( aRange
) && rDoc
.InsertCol( aRange
);
973 case SC_CAT_DELETE_ROWS
:
974 bOk
= rDoc
.CanInsertRow( aRange
) && rDoc
.InsertRow( aRange
);
976 case SC_CAT_DELETE_TABS
:
978 //TODO: Remember table names?
980 rDoc
.CreateValidTabName( aName
);
981 bOk
= rDoc
.ValidNewTabName( aName
) && rDoc
.InsertTab( aRange
.aStart
.Tab(), aName
);
986 // added to avoid warnings
989 pTrack
->SetInDelete( false );
990 pTrack
->SetInDeleteUndo( false );
994 pTrack
->SetInDeleteTop( false );
997 // Keep InDeleteTop for UpdateReference Undo
1000 // Sets rejected and calls UpdateReference-Undo and DeleteCellEntries
1001 RejectRestoreContents( pTrack
, GetDx(), GetDy() );
1003 pTrack
->SetInDeleteTop( false );
1008 void ScChangeActionDel::UndoCutOffMoves()
1009 { // Restore cut off Moves; delete Entries/Links
1012 // coverity[deref_arg] - the call on delete pLinkMove at the block end Moves a new entry into pLinkMode by itself
1013 ScChangeActionMove
* pMove
= pLinkMove
->GetMove();
1014 short nFrom
= pLinkMove
->GetCutOffFrom();
1015 short nTo
= pLinkMove
->GetCutOffTo();
1016 switch ( GetType() )
1018 case SC_CAT_DELETE_COLS
:
1020 pMove
->GetFromRange().aStart
.IncCol( -nFrom
);
1021 else if ( nFrom
< 0 )
1022 pMove
->GetFromRange().aEnd
.IncCol( -nFrom
);
1024 pMove
->GetBigRange().aStart
.IncCol( -nTo
);
1026 pMove
->GetBigRange().aEnd
.IncCol( -nTo
);
1028 case SC_CAT_DELETE_ROWS
:
1030 pMove
->GetFromRange().aStart
.IncRow( -nFrom
);
1031 else if ( nFrom
< 0 )
1032 pMove
->GetFromRange().aEnd
.IncRow( -nFrom
);
1034 pMove
->GetBigRange().aStart
.IncRow( -nTo
);
1036 pMove
->GetBigRange().aEnd
.IncRow( -nTo
);
1038 case SC_CAT_DELETE_TABS
:
1040 pMove
->GetFromRange().aStart
.IncTab( -nFrom
);
1041 else if ( nFrom
< 0 )
1042 pMove
->GetFromRange().aEnd
.IncTab( -nFrom
);
1044 pMove
->GetBigRange().aStart
.IncTab( -nTo
);
1046 pMove
->GetBigRange().aEnd
.IncTab( -nTo
);
1050 // added to avoid warnings
1053 delete pLinkMove
; // Moves up by itself
1057 void ScChangeActionDel::UndoCutOffInsert()
1058 { //Restore cut off Insert
1062 switch ( pCutOff
->GetType() )
1064 case SC_CAT_INSERT_COLS
:
1066 pCutOff
->GetBigRange().aEnd
.IncCol( -nCutOff
);
1068 pCutOff
->GetBigRange().aStart
.IncCol( -nCutOff
);
1070 case SC_CAT_INSERT_ROWS
:
1072 pCutOff
->GetBigRange().aEnd
.IncRow( -nCutOff
);
1074 pCutOff
->GetBigRange().aStart
.IncRow( -nCutOff
);
1076 case SC_CAT_INSERT_TABS
:
1078 pCutOff
->GetBigRange().aEnd
.IncTab( -nCutOff
);
1080 pCutOff
->GetBigRange().aStart
.IncTab( -nCutOff
);
1084 // added to avoid warnings
1087 SetCutOffInsert( nullptr, 0 );
1090 // ScChangeActionMove
1091 ScChangeActionMove::ScChangeActionMove(
1092 const sal_uLong nActionNumber
, const ScChangeActionState eStateP
,
1093 const sal_uLong nRejectingNumber
, const ScBigRange
& aToBigRange
,
1094 const OUString
& aUserP
, const DateTime
& aDateTimeP
,
1095 const OUString
&sComment
, ScBigRange aFromBigRange
,
1096 ScChangeTrack
* pTrackP
) : // which of nDx and nDy is set depends on the type
1097 ScChangeAction(SC_CAT_MOVE
, aToBigRange
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
),
1098 aFromRange(std::move(aFromBigRange
)),
1105 ScChangeActionMove::~ScChangeActionMove()
1107 DeleteCellEntries();
1110 void ScChangeActionMove::AddContent( ScChangeActionContent
* pContent
)
1112 mvCells
.push_back(pContent
);
1115 void ScChangeActionMove::DeleteCellEntries()
1117 pTrack
->DeleteCellEntries( mvCells
, this );
1120 void ScChangeActionMove::UpdateReference( const ScChangeTrack
* /* pTrack */,
1121 UpdateRefMode eMode
, const ScBigRange
& rRange
,
1122 sal_Int32 nDx
, sal_Int32 nDy
, sal_Int32 nDz
)
1124 ScRefUpdate::Update( eMode
, rRange
, nDx
, nDy
, nDz
, aFromRange
);
1125 ScRefUpdate::Update( eMode
, rRange
, nDx
, nDy
, nDz
, GetBigRange() );
1128 void ScChangeActionMove::GetDelta( sal_Int32
& nDx
, sal_Int32
& nDy
, sal_Int32
& nDz
) const
1130 const ScBigAddress
& rToPos
= GetBigRange().aStart
;
1131 const ScBigAddress
& rFromPos
= GetFromRange().aStart
;
1132 nDx
= rToPos
.Col() - rFromPos
.Col();
1133 nDy
= rToPos
.Row() - rFromPos
.Row();
1134 nDz
= rToPos
.Tab() - rFromPos
.Tab();
1137 OUString
ScChangeActionMove::GetDescription(
1138 ScDocument
& rDoc
, bool bSplitRange
, bool bWarning
) const
1140 OUString str
= ScChangeAction::GetDescription( rDoc
, bSplitRange
, bWarning
);
1142 bool bFlag3D
= GetFromRange().aStart
.Tab() != GetBigRange().aStart
.Tab();
1144 OUString aRsc
= ScResId(STR_CHANGED_MOVE
);
1146 OUString aTmpStr
= ScChangeAction::GetRefString(GetFromRange(), rDoc
, bFlag3D
);
1147 sal_Int32 nPos
= aRsc
.indexOf("#1");
1150 aRsc
= aRsc
.replaceAt(nPos
, 2, aTmpStr
);
1151 nPos
+= aTmpStr
.getLength();
1154 aTmpStr
= ScChangeAction::GetRefString(GetBigRange(), rDoc
, bFlag3D
);
1155 nPos
= nPos
>= 0 ? aRsc
.indexOf("#2", nPos
) : -1;
1158 aRsc
= aRsc
.replaceAt(nPos
, 2, aTmpStr
);
1161 return str
+ aRsc
; // append to the original string.
1164 OUString
ScChangeActionMove::GetRefString( ScDocument
& rDoc
, bool bFlag3D
) const
1167 bFlag3D
= ( GetFromRange().aStart
.Tab() != GetBigRange().aStart
.Tab() );
1169 return ScChangeAction::GetRefString(GetFromRange(), rDoc
, bFlag3D
)
1171 + ScChangeAction::GetRefString(GetBigRange(), rDoc
, bFlag3D
);
1174 bool ScChangeActionMove::Reject( ScDocument
& rDoc
)
1176 if ( !(aBigRange
.IsValid( rDoc
) && aFromRange
.IsValid( rDoc
)) )
1179 ScRange
aToRange( aBigRange
.MakeRange( rDoc
) );
1180 ScRange
aFrmRange( aFromRange
.MakeRange( rDoc
) );
1182 bool bOk
= rDoc
.IsBlockEditable( aToRange
.aStart
.Tab(),
1183 aToRange
.aStart
.Col(), aToRange
.aStart
.Row(),
1184 aToRange
.aEnd
.Col(), aToRange
.aEnd
.Row() );
1186 bOk
= rDoc
.IsBlockEditable( aFrmRange
.aStart
.Tab(),
1187 aFrmRange
.aStart
.Col(), aFrmRange
.aStart
.Row(),
1188 aFrmRange
.aEnd
.Col(), aFrmRange
.aEnd
.Row() );
1192 pTrack
->LookUpContents( aToRange
, &rDoc
, 0, 0, 0 ); // Contents to be moved
1194 rDoc
.DeleteAreaTab( aToRange
, InsertDeleteFlags::ALL
);
1195 rDoc
.DeleteAreaTab( aFrmRange
, InsertDeleteFlags::ALL
);
1196 // Adjust formula in the Document
1197 sc::RefUpdateContext
aCxt(rDoc
);
1198 aCxt
.meMode
= URM_MOVE
;
1199 aCxt
.maRange
= aFrmRange
;
1200 aCxt
.mnColDelta
= aFrmRange
.aStart
.Col() - aToRange
.aStart
.Col();
1201 aCxt
.mnRowDelta
= aFrmRange
.aStart
.Row() - aToRange
.aStart
.Row();
1202 aCxt
.mnTabDelta
= aFrmRange
.aStart
.Tab() - aToRange
.aStart
.Tab();
1203 rDoc
.UpdateReference(aCxt
);
1205 // Free LinkDependent, set succeeding UpdateReference Undo
1206 // ToRange->FromRange Dependents
1207 RemoveAllDependent();
1209 // Sets rejected and calls UpdateReference Undo and DeleteCellEntries
1210 RejectRestoreContents( pTrack
, 0, 0 );
1212 while ( pLinkDependent
)
1214 ScChangeAction
* p
= pLinkDependent
->GetAction();
1215 if ( p
&& p
->GetType() == SC_CAT_CONTENT
)
1217 ScChangeActionContent
* pContent
= static_cast<ScChangeActionContent
*>(p
);
1218 if ( !pContent
->IsDeletedIn() &&
1219 pContent
->GetBigRange().aStart
.IsValid( rDoc
) )
1220 pContent
->PutNewValueToDoc( &rDoc
, 0, 0 );
1221 // Delete the ones created in LookUpContents
1222 if ( pTrack
->IsGenerated( pContent
->GetActionNumber() ) &&
1223 !pContent
->IsDeletedIn() )
1225 pLinkDependent
->UnLink(); // Else this one is also deleted!
1226 pTrack
->DeleteGeneratedDelContent( pContent
);
1229 delete pLinkDependent
;
1236 ScChangeActionContent::ScChangeActionContent( const ScRange
& rRange
) :
1237 ScChangeAction(SC_CAT_CONTENT
, rRange
),
1238 pNextContent(nullptr),
1239 pPrevContent(nullptr),
1240 pNextInSlot(nullptr),
1241 ppPrevInSlot(nullptr)
1244 ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber
,
1245 const ScChangeActionState eStateP
, const sal_uLong nRejectingNumber
,
1246 const ScBigRange
& aBigRangeP
, const OUString
& aUserP
,
1247 const DateTime
& aDateTimeP
, const OUString
& sComment
,
1248 ScCellValue aOldCell
, const ScDocument
* pDoc
, const OUString
& sOldValue
) :
1249 ScChangeAction(SC_CAT_CONTENT
, aBigRangeP
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
),
1250 maOldCell(std::move(aOldCell
)),
1251 maOldValue(sOldValue
),
1252 pNextContent(nullptr),
1253 pPrevContent(nullptr),
1254 pNextInSlot(nullptr),
1255 ppPrevInSlot(nullptr)
1257 if (!maOldCell
.isEmpty())
1258 SetCell(maOldValue
, maOldCell
, 0, pDoc
);
1260 if (!sOldValue
.isEmpty()) // #i40704# don't overwrite SetCell result with empty string
1261 maOldValue
= sOldValue
; // set again, because SetCell removes it
1264 ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber
,
1265 ScCellValue aNewCell
, const ScBigRange
& aBigRangeP
,
1266 const ScDocument
* pDoc
, const OUString
& sNewValue
) :
1267 ScChangeAction(SC_CAT_CONTENT
, aBigRangeP
, nActionNumber
),
1268 maNewCell(std::move(aNewCell
)),
1269 maNewValue(sNewValue
),
1270 pNextContent(nullptr),
1271 pPrevContent(nullptr),
1272 pNextInSlot(nullptr),
1273 ppPrevInSlot(nullptr)
1275 if (!maNewCell
.isEmpty())
1276 SetCell(maNewValue
, maNewCell
, 0, pDoc
);
1278 if (!sNewValue
.isEmpty()) // #i40704# don't overwrite SetCell result with empty string
1279 maNewValue
= sNewValue
; // set again, because SetCell removes it
1282 ScChangeActionContent::~ScChangeActionContent()
1287 void ScChangeActionContent::ClearTrack()
1291 pPrevContent
->pNextContent
= pNextContent
;
1293 pNextContent
->pPrevContent
= pPrevContent
;
1296 ScChangeActionContent
* ScChangeActionContent::GetTopContent() const
1300 ScChangeActionContent
* pContent
= pNextContent
;
1301 while ( pContent
->pNextContent
&& pContent
!= pContent
->pNextContent
)
1302 pContent
= pContent
->pNextContent
;
1305 return const_cast<ScChangeActionContent
*>(this);
1308 ScChangeActionLinkEntry
* ScChangeActionContent::GetDeletedIn() const
1311 return GetTopContent()->pLinkDeletedIn
;
1312 return pLinkDeletedIn
;
1315 ScChangeActionLinkEntry
** ScChangeActionContent::GetDeletedInAddress()
1318 return GetTopContent()->GetDeletedInAddress();
1319 return &pLinkDeletedIn
;
1322 void ScChangeActionContent::SetOldValue(
1323 const ScCellValue
& rCell
, const ScDocument
* pFromDoc
, ScDocument
* pToDoc
, sal_uLong nFormat
)
1325 SetValue(maOldValue
, maOldCell
, nFormat
, rCell
, pFromDoc
, pToDoc
);
1328 void ScChangeActionContent::SetOldValue(
1329 const ScCellValue
& rCell
, const ScDocument
* pFromDoc
, ScDocument
* pToDoc
)
1331 SetValue(maOldValue
, maOldCell
, aBigRange
.aStart
.MakeAddress(*pFromDoc
), rCell
, pFromDoc
, pToDoc
);
1334 void ScChangeActionContent::SetNewValue( const ScCellValue
& rCell
, ScDocument
* pDoc
)
1336 SetValue(maNewValue
, maNewCell
, aBigRange
.aStart
.MakeAddress(*pDoc
), rCell
, pDoc
, pDoc
);
1339 void ScChangeActionContent::SetOldNewCells(
1340 const ScCellValue
& rOldCell
, sal_uLong nOldFormat
, const ScCellValue
& rNewCell
,
1341 sal_uLong nNewFormat
, const ScDocument
* pDoc
)
1343 maOldCell
= rOldCell
;
1344 maNewCell
= rNewCell
;
1345 SetCell(maOldValue
, maOldCell
, nOldFormat
, pDoc
);
1346 SetCell(maNewValue
, maNewCell
, nNewFormat
, pDoc
);
1349 void ScChangeActionContent::SetNewCell(
1350 const ScCellValue
& rCell
, const ScDocument
* pDoc
, const OUString
& rFormatted
)
1353 SetCell(maNewValue
, maNewCell
, 0, pDoc
);
1355 // #i40704# allow to set formatted text here - don't call SetNewValue with string from XML filter
1356 if (!rFormatted
.isEmpty())
1357 maNewValue
= rFormatted
;
1360 void ScChangeActionContent::SetValueString(
1361 OUString
& rValue
, ScCellValue
& rCell
, const OUString
& rStr
, ScDocument
* pDoc
)
1364 if ( rStr
.getLength() > 1 && rStr
[0] == '=' )
1367 rCell
.set(new ScFormulaCell(
1368 *pDoc
, aBigRange
.aStart
.MakeAddress(*pDoc
), rStr
,
1369 pDoc
->GetGrammar() ));
1370 rCell
.getFormula()->SetInChangeTrack(true);
1376 void ScChangeActionContent::SetOldValue( const OUString
& rOld
, ScDocument
* pDoc
)
1378 SetValueString(maOldValue
, maOldCell
, rOld
, pDoc
);
1381 OUString
ScChangeActionContent::GetOldString( const ScDocument
* pDoc
) const
1383 return GetValueString(maOldValue
, maOldCell
, pDoc
);
1386 OUString
ScChangeActionContent::GetNewString( const ScDocument
* pDoc
) const
1388 return GetValueString(maNewValue
, maNewCell
, pDoc
);
1391 OUString
ScChangeActionContent::GetDescription(
1392 ScDocument
& rDoc
, bool bSplitRange
, bool bWarning
) const
1394 OUString str
= ScChangeAction::GetDescription( rDoc
, bSplitRange
, bWarning
);
1396 OUString aRsc
= ScResId(STR_CHANGED_CELL
);
1398 OUString aTmpStr
= GetRefString(rDoc
);
1400 sal_Int32 nPos
= aRsc
.indexOf("#1", 0);
1403 aRsc
= aRsc
.replaceAt(nPos
, 2, aTmpStr
);
1404 nPos
+= aTmpStr
.getLength();
1407 aTmpStr
= GetOldString( &rDoc
);
1408 if (aTmpStr
.isEmpty())
1409 aTmpStr
= ScResId( STR_CHANGED_BLANK
);
1411 nPos
= nPos
>= 0 ? aRsc
.indexOf("#2", nPos
) : -1;
1414 aRsc
= aRsc
.replaceAt(nPos
, 2, aTmpStr
);
1415 nPos
+= aTmpStr
.getLength();
1418 aTmpStr
= GetNewString( &rDoc
);
1419 if (aTmpStr
.isEmpty())
1420 aTmpStr
= ScResId( STR_CHANGED_BLANK
);
1422 nPos
= nPos
>= 0 ? aRsc
.indexOf("#3", nPos
) : -1;
1425 aRsc
= aRsc
.replaceAt(nPos
, 2, aTmpStr
);
1428 return str
+ aRsc
; // append to the original string.
1431 OUString
ScChangeActionContent::GetRefString(
1432 ScDocument
& rDoc
, bool bFlag3D
) const
1434 ScRefFlags nFlags
= ( GetBigRange().IsValid( rDoc
) ? ScRefFlags::VALID
: ScRefFlags::ZERO
);
1435 if ( nFlags
!= ScRefFlags::ZERO
)
1437 const ScCellValue
& rCell
= GetNewCell();
1438 if ( GetContentCellType(rCell
) == SC_CACCT_MATORG
)
1440 ScBigRange
aLocalBigRange( GetBigRange() );
1443 rCell
.getFormula()->GetMatColsRows( nC
, nR
);
1444 aLocalBigRange
.aEnd
.IncCol( nC
-1 );
1445 aLocalBigRange
.aEnd
.IncRow( nR
-1 );
1446 return ScChangeAction::GetRefString( aLocalBigRange
, rDoc
, bFlag3D
);
1449 ScAddress
aTmpAddress( GetBigRange().aStart
.MakeAddress( rDoc
) );
1451 nFlags
|= ScRefFlags::TAB_3D
;
1452 OUString str
= aTmpAddress
.Format(nFlags
, &rDoc
, rDoc
.GetAddressConvention());
1453 if ( IsDeletedIn() )
1455 // Insert the parentheses.
1456 str
= "(" + str
+ ")";
1461 return ScCompiler::GetNativeSymbol(ocErrRef
);
1464 bool ScChangeActionContent::Reject( ScDocument
& rDoc
)
1466 if ( !aBigRange
.IsValid( rDoc
) )
1469 PutOldValueToDoc( &rDoc
, 0, 0 );
1471 SetState( SC_CAS_REJECTED
);
1477 bool ScChangeActionContent::Select( ScDocument
& rDoc
, ScChangeTrack
* pTrack
,
1478 bool bOldest
, ::std::stack
<ScChangeActionContent
*>* pRejectActions
)
1480 if ( !aBigRange
.IsValid( rDoc
) )
1483 ScChangeActionContent
* pContent
= this;
1484 // accept previous contents
1485 while ( ( pContent
= pContent
->pPrevContent
) != nullptr )
1487 if ( pContent
->IsVirgin() )
1488 pContent
->SetState( SC_CAS_ACCEPTED
);
1490 ScChangeActionContent
* pEnd
= pContent
= this;
1491 // reject subsequent contents
1492 while ( ( pContent
= pContent
->pNextContent
) != nullptr )
1494 // MatrixOrigin may have dependents, no dependency recursion needed
1495 const ScChangeActionLinkEntry
* pL
= pContent
->GetFirstDependentEntry();
1498 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pL
->GetAction());
1503 pContent
->SetRejected();
1507 // If not oldest: Is it anyone else than the last one?
1508 if ( bOldest
|| pEnd
!= this )
1509 { ScRange
aRange( aBigRange
.aStart
.MakeAddress( rDoc
) );
1510 const ScAddress
& rPos
= aRange
.aStart
;
1512 ScChangeActionContent
* pNew
= new ScChangeActionContent( aRange
);
1514 aCell
.assign(rDoc
, rPos
);
1515 pNew
->SetOldValue(aCell
, &rDoc
, &rDoc
);
1518 PutOldValueToDoc( &rDoc
, 0, 0 );
1520 PutNewValueToDoc( &rDoc
, 0, 0 );
1522 pNew
->SetRejectAction( bOldest
? GetActionNumber() : pEnd
->GetActionNumber() );
1523 pNew
->SetState( SC_CAS_ACCEPTED
);
1524 if ( pRejectActions
)
1525 pRejectActions
->push( pNew
);
1528 aCell
.assign(rDoc
, rPos
);
1529 pNew
->SetNewValue(aCell
, &rDoc
);
1530 pTrack
->Append( pNew
);
1537 SetState( SC_CAS_ACCEPTED
);
1542 OUString
ScChangeActionContent::GetStringOfCell(
1543 const ScCellValue
& rCell
, const ScDocument
* pDoc
, const ScAddress
& rPos
)
1545 if (NeedsNumberFormat(rCell
))
1546 return GetStringOfCell(rCell
, pDoc
, pDoc
->GetNumberFormat(rPos
));
1548 return GetStringOfCell(rCell
, pDoc
, 0);
1551 OUString
ScChangeActionContent::GetStringOfCell(
1552 const ScCellValue
& rCell
, const ScDocument
* pDoc
, sal_uLong nFormat
)
1554 if (!GetContentCellType(rCell
))
1557 switch (rCell
.getType())
1559 case CELLTYPE_VALUE
:
1562 pDoc
->GetFormatTable()->GetInputLineString(rCell
.getDouble(), nFormat
, str
);
1565 case CELLTYPE_STRING
:
1566 return rCell
.getSharedString()->getString();
1568 if (rCell
.getEditText())
1569 return ScEditUtil::GetString(*rCell
.getEditText(), pDoc
);
1571 case CELLTYPE_FORMULA
:
1572 return rCell
.getFormula()->GetFormula();
1578 ScChangeActionContentCellType
ScChangeActionContent::GetContentCellType( const ScCellValue
& rCell
)
1580 switch (rCell
.getType())
1582 case CELLTYPE_VALUE
:
1583 case CELLTYPE_STRING
:
1584 case CELLTYPE_EDIT
:
1585 return SC_CACCT_NORMAL
;
1586 case CELLTYPE_FORMULA
:
1587 switch (rCell
.getFormula()->GetMatrixFlag())
1589 case ScMatrixMode::NONE
:
1590 return SC_CACCT_NORMAL
;
1591 case ScMatrixMode::Formula
:
1592 return SC_CACCT_MATORG
;
1593 case ScMatrixMode::Reference
:
1594 return SC_CACCT_MATREF
;
1596 return SC_CACCT_NORMAL
;
1598 return SC_CACCT_NONE
;
1602 ScChangeActionContentCellType
ScChangeActionContent::GetContentCellType( const ScRefCellValue
& rCell
)
1604 switch (rCell
.getType())
1606 case CELLTYPE_VALUE
:
1607 case CELLTYPE_STRING
:
1609 return SC_CACCT_NORMAL
;
1610 case CELLTYPE_FORMULA
:
1612 const ScFormulaCell
* pCell
= rCell
.getFormula();
1613 switch (pCell
->GetMatrixFlag())
1615 case ScMatrixMode::NONE
:
1616 return SC_CACCT_NORMAL
;
1617 case ScMatrixMode::Formula
:
1618 return SC_CACCT_MATORG
;
1619 case ScMatrixMode::Reference
:
1620 return SC_CACCT_MATREF
;
1622 return SC_CACCT_NORMAL
;
1628 return SC_CACCT_NONE
;
1631 bool ScChangeActionContent::NeedsNumberFormat( const ScCellValue
& rVal
)
1633 return rVal
.getType() == CELLTYPE_VALUE
;
1636 void ScChangeActionContent::SetValue(
1637 OUString
& rStr
, ScCellValue
& rCell
, const ScAddress
& rPos
, const ScCellValue
& rOrgCell
,
1638 const ScDocument
* pFromDoc
, ScDocument
* pToDoc
)
1640 sal_uInt32 nFormat
= NeedsNumberFormat(rOrgCell
) ? pFromDoc
->GetNumberFormat(rPos
) : 0;
1641 SetValue(rStr
, rCell
, nFormat
, rOrgCell
, pFromDoc
, pToDoc
);
1644 void ScChangeActionContent::SetValue(
1645 OUString
& rStr
, ScCellValue
& rCell
, sal_uLong nFormat
, const ScCellValue
& rOrgCell
,
1646 const ScDocument
* pFromDoc
, ScDocument
* pToDoc
)
1650 if (GetContentCellType(rOrgCell
))
1652 rCell
.assign(rOrgCell
, *pToDoc
);
1653 switch (rOrgCell
.getType())
1655 case CELLTYPE_VALUE
:
1656 { // E.g.: Remember date as such
1657 pFromDoc
->GetFormatTable()->GetInputLineString(
1658 rOrgCell
.getDouble(), nFormat
, rStr
);
1661 case CELLTYPE_FORMULA
:
1662 rCell
.getFormula()->SetInChangeTrack(true);
1666 // added to avoid warnings
1674 void ScChangeActionContent::SetCell( OUString
& rStr
, ScCellValue
& rCell
, sal_uLong nFormat
, const ScDocument
* pDoc
)
1677 if (rCell
.isEmpty())
1680 switch (rCell
.getType())
1682 case CELLTYPE_VALUE
:
1683 // e.g. remember date as date string
1684 pDoc
->GetFormatTable()->GetInputLineString(rCell
.getDouble(), nFormat
, rStr
);
1686 case CELLTYPE_FORMULA
:
1687 rCell
.getFormula()->SetInChangeTrack(true);
1691 // added to avoid warnings
1696 OUString
ScChangeActionContent::GetValueString(
1697 const OUString
& rValue
, const ScCellValue
& rCell
, const ScDocument
* pDoc
) const
1699 if (!rValue
.isEmpty())
1704 switch (rCell
.getType())
1706 case CELLTYPE_STRING
:
1707 return rCell
.getSharedString()->getString();
1708 case CELLTYPE_EDIT
:
1709 if (rCell
.getEditText())
1710 return ScEditUtil::GetString(*rCell
.getEditText(), pDoc
);
1712 case CELLTYPE_VALUE
: // Is always in rValue
1714 case CELLTYPE_FORMULA
:
1715 return GetFormulaString(rCell
.getFormula());
1722 OUString
ScChangeActionContent::GetFormulaString(
1723 const ScFormulaCell
* pCell
) const
1725 ScAddress
aPos( aBigRange
.aStart
.MakeAddress( pCell
->GetDocument()) );
1726 if ( aPos
== pCell
->aPos
|| IsDeletedIn() )
1727 return pCell
->GetFormula();
1730 OSL_FAIL( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" );
1731 ScFormulaCell
aNew( *pCell
, pCell
->GetDocument(), aPos
);
1732 return aNew
.GetFormula();
1736 void ScChangeActionContent::PutOldValueToDoc( ScDocument
* pDoc
,
1737 SCCOL nDx
, SCROW nDy
) const
1739 PutValueToDoc(maOldCell
, maOldValue
, pDoc
, nDx
, nDy
);
1742 void ScChangeActionContent::PutNewValueToDoc( ScDocument
* pDoc
,
1743 SCCOL nDx
, SCROW nDy
) const
1745 PutValueToDoc(maNewCell
, maNewValue
, pDoc
, nDx
, nDy
);
1748 void ScChangeActionContent::PutValueToDoc(
1749 const ScCellValue
& rCell
, const OUString
& rValue
, ScDocument
* pDoc
,
1750 SCCOL nDx
, SCROW nDy
) const
1752 ScAddress
aPos( aBigRange
.aStart
.MakeAddress( *pDoc
) );
1758 if (!rValue
.isEmpty())
1760 pDoc
->SetString(aPos
, rValue
);
1764 if (rCell
.isEmpty())
1766 pDoc
->SetEmptyCell(aPos
);
1770 if (rCell
.getType() == CELLTYPE_VALUE
)
1772 pDoc
->SetString( aPos
.Col(), aPos
.Row(), aPos
.Tab(), rValue
);
1776 switch (GetContentCellType(rCell
))
1778 case SC_CACCT_MATORG
:
1782 rCell
.getFormula()->GetMatColsRows(nC
, nR
);
1783 OSL_ENSURE( nC
>0 && nR
>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" );
1784 ScRange
aRange( aPos
);
1786 aRange
.aEnd
.IncCol( nC
-1 );
1788 aRange
.aEnd
.IncRow( nR
-1 );
1789 ScMarkData
aDestMark(pDoc
->GetSheetLimits());
1790 aDestMark
.SelectOneTable( aPos
.Tab() );
1791 aDestMark
.SetMarkArea( aRange
);
1792 pDoc
->InsertMatrixFormula( aPos
.Col(), aPos
.Row(),
1793 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(),
1794 aDestMark
, OUString(), rCell
.getFormula()->GetCode());
1797 case SC_CACCT_MATREF
:
1801 rCell
.commit(*pDoc
, aPos
);
1805 static void lcl_InvalidateReference( const ScDocument
& rDoc
, formula::FormulaToken
& rTok
, const ScBigAddress
& rPos
)
1807 ScSingleRefData
& rRef1
= *rTok
.GetSingleRef();
1808 if ( rPos
.Col() < 0 || rDoc
.MaxCol() < rPos
.Col() )
1810 rRef1
.SetColDeleted( true );
1812 if ( rPos
.Row() < 0 || rDoc
.MaxRow() < rPos
.Row() )
1814 rRef1
.SetRowDeleted( true );
1816 if ( rPos
.Tab() < 0 || MAXTAB
< rPos
.Tab() )
1818 rRef1
.SetTabDeleted( true );
1820 if ( rTok
.GetType() != formula::svDoubleRef
)
1823 ScSingleRefData
& rRef2
= rTok
.GetDoubleRef()->Ref2
;
1824 if ( rPos
.Col() < 0 || rDoc
.MaxCol() < rPos
.Col() )
1826 rRef2
.SetColDeleted( true );
1828 if ( rPos
.Row() < 0 || rDoc
.MaxRow() < rPos
.Row() )
1830 rRef2
.SetRowDeleted( true );
1832 if ( rPos
.Tab() < 0 || MAXTAB
< rPos
.Tab() )
1834 rRef2
.SetTabDeleted( true );
1838 void ScChangeActionContent::UpdateReference( const ScChangeTrack
* pTrack
,
1839 UpdateRefMode eMode
, const ScBigRange
& rRange
,
1840 sal_Int32 nDx
, sal_Int32 nDy
, sal_Int32 nDz
)
1842 SCSIZE nOldSlot
= pTrack
->ComputeContentSlot( aBigRange
.aStart
.Row() );
1843 ScRefUpdate::Update( eMode
, rRange
, nDx
, nDy
, nDz
, aBigRange
);
1844 SCSIZE nNewSlot
= pTrack
->ComputeContentSlot( aBigRange
.aStart
.Row() );
1845 if ( nNewSlot
!= nOldSlot
)
1848 InsertInSlot( &(pTrack
->GetContentSlots()[nNewSlot
]) );
1851 if ( pTrack
->IsInDelete() && !pTrack
->IsInDeleteTop() )
1852 return ; // Formula only update whole range
1854 bool bOldFormula
= maOldCell
.getType() == CELLTYPE_FORMULA
;
1855 bool bNewFormula
= maNewCell
.getType() == CELLTYPE_FORMULA
;
1856 if ( !(bOldFormula
|| bNewFormula
) )
1859 // Adjust UpdateReference via ScFormulaCell (there)
1860 if ( pTrack
->IsInDelete() )
1862 const ScRange
& rDelRange
= pTrack
->GetInDeleteRange();
1864 nDx
= rDelRange
.aEnd
.Col() - rDelRange
.aStart
.Col() + 1;
1866 nDx
= -(rDelRange
.aEnd
.Col() - rDelRange
.aStart
.Col() + 1);
1868 nDy
= rDelRange
.aEnd
.Row() - rDelRange
.aStart
.Row() + 1;
1870 nDy
= -(rDelRange
.aEnd
.Row() - rDelRange
.aStart
.Row() + 1);
1872 nDz
= rDelRange
.aEnd
.Tab() - rDelRange
.aStart
.Tab() + 1;
1874 nDz
= -(rDelRange
.aEnd
.Tab() - rDelRange
.aStart
.Tab() + 1);
1876 ScBigRange
aTmpRange( rRange
);
1880 if ( nDx
< 0 || nDy
< 0 || nDz
< 0 )
1881 { // Delete starts there after removed range
1882 // Position is changed there
1884 aTmpRange
.aStart
.IncCol( -nDx
);
1886 aTmpRange
.aStart
.IncRow( -nDy
);
1888 aTmpRange
.aStart
.IncTab( -nDz
);
1892 // Move is Source here and Target there
1893 // Position needs to be adjusted before that
1895 maOldCell
.getFormula()->aPos
= aBigRange
.aStart
.MakeAddress(pTrack
->GetDocument());
1897 maNewCell
.getFormula()->aPos
= aBigRange
.aStart
.MakeAddress(pTrack
->GetDocument());
1900 aTmpRange
.aStart
.IncCol( nDx
);
1901 aTmpRange
.aEnd
.IncCol( nDx
);
1905 aTmpRange
.aStart
.IncRow( nDy
);
1906 aTmpRange
.aEnd
.IncRow( nDy
);
1910 aTmpRange
.aStart
.IncTab( nDz
);
1911 aTmpRange
.aEnd
.IncTab( nDz
);
1916 // added to avoid warnings
1919 ScRange
aRange( aTmpRange
.MakeRange(pTrack
->GetDocument()) );
1921 sc::RefUpdateContext
aRefCxt(pTrack
->GetDocument());
1922 aRefCxt
.meMode
= eMode
;
1923 aRefCxt
.maRange
= aRange
;
1924 aRefCxt
.mnColDelta
= nDx
;
1925 aRefCxt
.mnRowDelta
= nDy
;
1926 aRefCxt
.mnTabDelta
= nDz
;
1929 maOldCell
.getFormula()->UpdateReference(aRefCxt
);
1931 maNewCell
.getFormula()->UpdateReference(aRefCxt
);
1933 if ( aBigRange
.aStart
.IsValid( pTrack
->GetDocument() ) )
1937 // UpdateReference cannot handle positions outside of the Document.
1938 // Therefore set everything to #REF!
1939 //TODO: Remove the need for this hack! This means big changes to ScAddress etc.!
1940 const ScBigAddress
& rPos
= aBigRange
.aStart
;
1943 formula::FormulaToken
* t
;
1944 ScTokenArray
* pArr
= maOldCell
.getFormula()->GetCode();
1945 formula::FormulaTokenArrayPlainIterator
aIter(*pArr
);
1946 while ( ( t
= aIter
.GetNextReference() ) != nullptr )
1947 lcl_InvalidateReference( pTrack
->GetDocument(), *t
, rPos
);
1949 while ( ( t
= aIter
.GetNextReferenceRPN() ) != nullptr )
1950 lcl_InvalidateReference( pTrack
->GetDocument(), *t
, rPos
);
1954 formula::FormulaToken
* t
;
1955 ScTokenArray
* pArr
= maNewCell
.getFormula()->GetCode();
1956 formula::FormulaTokenArrayPlainIterator
aIter(*pArr
);
1957 while ( ( t
= aIter
.GetNextReference() ) != nullptr )
1958 lcl_InvalidateReference( pTrack
->GetDocument(), *t
, rPos
);
1960 while ( ( t
= aIter
.GetNextReferenceRPN() ) != nullptr )
1961 lcl_InvalidateReference( pTrack
->GetDocument(), *t
, rPos
);
1965 bool ScChangeActionContent::IsMatrixOrigin() const
1967 return GetContentCellType(GetNewCell()) == SC_CACCT_MATORG
;
1970 bool ScChangeActionContent::IsOldMatrixReference() const
1972 return GetContentCellType(GetOldCell()) == SC_CACCT_MATREF
;
1975 // ScChangeActionReject
1976 ScChangeActionReject::ScChangeActionReject(
1977 const sal_uLong nActionNumber
, const ScChangeActionState eStateP
,
1978 const sal_uLong nRejectingNumber
,
1979 const ScBigRange
& aBigRangeP
, const OUString
& aUserP
,
1980 const DateTime
& aDateTimeP
, const OUString
& sComment
) :
1981 ScChangeAction(SC_CAT_CONTENT
, aBigRangeP
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
)
1985 bool ScChangeActionReject::Reject(ScDocument
& /*rDoc*/)
1990 SCSIZE
ScChangeTrack::ComputeContentSlot( sal_Int32 nRow
) const
1992 if ( nRow
< 0 || nRow
> rDoc
.GetSheetLimits().mnMaxRow
)
1993 return mnContentSlots
- 1;
1994 return static_cast< SCSIZE
>( nRow
/ mnContentRowsPerSlot
);
1997 SCROW
ScChangeTrack::InitContentRowsPerSlot()
1999 const SCSIZE nMaxSlots
= 0xffe0 / sizeof( ScChangeActionContent
* ) - 2;
2000 SCROW nRowsPerSlot
= rDoc
.GetMaxRowCount() / nMaxSlots
;
2001 if ( nRowsPerSlot
* nMaxSlots
< sal::static_int_cast
<SCSIZE
>(rDoc
.GetMaxRowCount()) )
2003 return nRowsPerSlot
;
2006 ScChangeTrack::ScChangeTrack( ScDocument
& rDocP
) :
2007 aFixDateTime( DateTime::SYSTEM
),
2011 SC_MOD()->GetUserOptions().AddListener(this);
2013 ppContentSlots
.reset( new ScChangeActionContent
* [ mnContentSlots
] );
2014 memset( ppContentSlots
.get(), 0, mnContentSlots
* sizeof( ScChangeActionContent
* ) );
2017 ScChangeTrack::ScChangeTrack( ScDocument
& rDocP
, std::set
<OUString
>&& aTempUserCollection
) :
2018 maUserCollection(std::move(aTempUserCollection
)),
2019 aFixDateTime( DateTime::SYSTEM
),
2023 SC_MOD()->GetUserOptions().AddListener(this);
2024 ppContentSlots
.reset( new ScChangeActionContent
* [ mnContentSlots
] );
2025 memset( ppContentSlots
.get(), 0, mnContentSlots
* sizeof( ScChangeActionContent
* ) );
2028 ScChangeTrack::~ScChangeTrack()
2030 SC_MOD()->GetUserOptions().RemoveListener(this);
2034 void ScChangeTrack::Init()
2036 mnContentRowsPerSlot
= InitContentRowsPerSlot();
2037 mnContentSlots
= rDoc
.GetMaxRowCount() / InitContentRowsPerSlot() + 2;
2041 pFirstGeneratedDelContent
= nullptr;
2042 pLastCutMove
= nullptr;
2043 pLinkInsertCol
= nullptr;
2044 pLinkInsertRow
= nullptr;
2045 pLinkInsertTab
= nullptr;
2046 pLinkMove
= nullptr;
2047 xBlockModifyMsg
.reset();
2049 nGeneratedMin
= SC_CHGTRACK_GENERATED_START
;
2054 eMergeState
= SC_CTMS_NONE
;
2056 bInDeleteTop
= false;
2057 bInDeleteUndo
= false;
2058 bInPasteCut
= false;
2059 bUseFixDateTime
= false;
2060 bTimeNanoSeconds
= true;
2065 void ScChangeTrack::DtorClear()
2068 ScChangeAction
* pNext
;
2069 for ( p
= GetFirst(); p
; p
= pNext
)
2071 pNext
= p
->GetNext();
2074 for ( p
= pFirstGeneratedDelContent
; p
; p
= pNext
)
2076 pNext
= p
->GetNext();
2079 for( const auto& rEntry
: aPasteCutMap
)
2081 delete rEntry
.second
;
2083 pLastCutMove
.reset();
2087 void ScChangeTrack::ClearMsgQueue()
2089 xBlockModifyMsg
.reset();
2090 aMsgStackTmp
.clear();
2091 aMsgStackFinal
.clear();
2095 void ScChangeTrack::Clear()
2099 aGeneratedMap
.clear();
2100 aPasteCutMap
.clear();
2101 maUserCollection
.clear();
2106 bool ScChangeTrack::IsGenerated( sal_uLong nAction
) const
2108 return nAction
>= nGeneratedMin
;
2111 ScChangeAction
* ScChangeTrack::GetAction( sal_uLong nAction
) const
2113 ScChangeActionMap::const_iterator it
= aMap
.find( nAction
);
2114 if( it
!= aMap
.end() )
2120 ScChangeAction
* ScChangeTrack::GetGenerated( sal_uLong nGenerated
) const
2122 ScChangeActionMap::const_iterator it
= aGeneratedMap
.find( nGenerated
);
2123 if( it
!= aGeneratedMap
.end() )
2129 ScChangeAction
* ScChangeTrack::GetActionOrGenerated( sal_uLong nAction
) const
2131 return IsGenerated( nAction
) ?
2132 GetGenerated( nAction
) :
2133 GetAction( nAction
);
2135 sal_uLong
ScChangeTrack::GetLastSavedActionNumber() const
2137 return nMarkLastSaved
;
2140 void ScChangeTrack::SetLastSavedActionNumber(sal_uLong nNew
)
2142 nMarkLastSaved
= nNew
;
2145 ScChangeAction
* ScChangeTrack::GetLastSaved() const
2147 ScChangeActionMap::const_iterator it
= aMap
.find( nMarkLastSaved
);
2148 if( it
!= aMap
.end() )
2154 void ScChangeTrack::ConfigurationChanged( utl::ConfigurationBroadcaster
*, ConfigurationHints
)
2156 if ( rDoc
.IsInDtorClear() )
2159 size_t nOldCount
= maUserCollection
.size();
2163 if ( maUserCollection
.size() != nOldCount
)
2165 // New user in collection -> have to repaint because
2166 // colors may be different now (#106697#).
2167 // (Has to be done in the Notify handler, to be sure
2168 // the user collection has already been updated)
2170 ScDocShell
* pDocSh
= rDoc
.GetDocumentShell();
2172 pDocSh
->Broadcast( ScPaintHint( ScRange(0,0,0,rDoc
.MaxCol(),rDoc
.MaxRow(),MAXTAB
), PaintPartFlags::Grid
) );
2176 void ScChangeTrack::CreateAuthorName()
2178 const SvtUserOptions
& rUserOptions
= SC_MOD()->GetUserOptions();
2179 OUString
aFirstName(rUserOptions
.GetFirstName());
2180 OUString
aLastName(rUserOptions
.GetLastName());
2181 if (aFirstName
.isEmpty() && aLastName
.isEmpty())
2182 SetUser(ScResId(STR_CHG_UNKNOWN_AUTHOR
));
2183 else if(!aFirstName
.isEmpty() && aLastName
.isEmpty())
2184 SetUser(aFirstName
);
2185 else if(aFirstName
.isEmpty() && !aLastName
.isEmpty())
2188 SetUser(aFirstName
+ " " + aLastName
);
2192 void ScChangeTrack::SetUser( const OUString
& rUser
)
2195 maUserCollection
.insert(maUser
);
2198 void ScChangeTrack::StartBlockModify( ScChangeTrackMsgType eMsgType
,
2199 sal_uLong nStartAction
)
2201 if ( aModifiedLink
.IsSet() )
2203 if ( xBlockModifyMsg
)
2204 aMsgStackTmp
.push_back( *xBlockModifyMsg
); // Block in Block
2205 xBlockModifyMsg
= ScChangeTrackMsgInfo();
2206 xBlockModifyMsg
->eMsgType
= eMsgType
;
2207 xBlockModifyMsg
->nStartAction
= nStartAction
;
2208 xBlockModifyMsg
->nEndAction
= 0;
2212 void ScChangeTrack::EndBlockModify( sal_uLong nEndAction
)
2214 if ( !aModifiedLink
.IsSet() )
2217 if ( xBlockModifyMsg
)
2219 if ( xBlockModifyMsg
->nStartAction
<= nEndAction
)
2221 xBlockModifyMsg
->nEndAction
= nEndAction
;
2222 // Blocks dissolved in Blocks
2223 aMsgStackFinal
.push_back( *xBlockModifyMsg
);
2226 xBlockModifyMsg
.reset();
2227 if (aMsgStackTmp
.empty())
2228 xBlockModifyMsg
.reset();
2231 xBlockModifyMsg
= aMsgStackTmp
.back(); // Maybe Block in Block
2232 aMsgStackTmp
.pop_back();
2235 if ( !xBlockModifyMsg
)
2237 bool bNew
= !aMsgStackFinal
.empty();
2238 aMsgQueue
.reserve(aMsgQueue
.size() + aMsgStackFinal
.size());
2239 aMsgQueue
.insert(aMsgQueue
.end(), aMsgStackFinal
.rbegin(), aMsgStackFinal
.rend());
2240 aMsgStackFinal
.clear();
2242 aModifiedLink
.Call( *this );
2246 ScChangeTrackMsgQueue
& ScChangeTrack::GetMsgQueue()
2251 void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType
,
2252 sal_uLong nStartAction
, sal_uLong nEndAction
)
2254 if ( aModifiedLink
.IsSet() )
2256 if ( !xBlockModifyMsg
|| xBlockModifyMsg
->eMsgType
!= eMsgType
||
2257 (IsGenerated( nStartAction
) &&
2258 (eMsgType
== ScChangeTrackMsgType::Append
|| eMsgType
== ScChangeTrackMsgType::Remove
)) )
2259 { // Append within Append e.g. not
2260 StartBlockModify( eMsgType
, nStartAction
);
2261 EndBlockModify( nEndAction
);
2266 void ScChangeTrack::MasterLinks( ScChangeAction
* pAppend
)
2268 ScChangeActionType eType
= pAppend
->GetType();
2270 if ( eType
== SC_CAT_CONTENT
)
2272 if ( !IsGenerated( pAppend
->GetActionNumber() ) )
2274 SCSIZE nSlot
= ComputeContentSlot(
2275 pAppend
->GetBigRange().aStart
.Row() );
2276 static_cast<ScChangeActionContent
*>(pAppend
)->InsertInSlot(
2277 &ppContentSlots
[nSlot
] );
2282 if ( pAppend
->IsRejecting() )
2283 return ; // Rejects do not have dependencies
2287 case SC_CAT_INSERT_COLS
:
2289 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2290 &pLinkInsertCol
, pAppend
);
2291 pAppend
->AddLink( nullptr, pLink
);
2294 case SC_CAT_INSERT_ROWS
:
2296 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2297 &pLinkInsertRow
, pAppend
);
2298 pAppend
->AddLink( nullptr, pLink
);
2301 case SC_CAT_INSERT_TABS
:
2303 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2304 &pLinkInsertTab
, pAppend
);
2305 pAppend
->AddLink( nullptr, pLink
);
2310 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2311 &pLinkMove
, pAppend
);
2312 pAppend
->AddLink( nullptr, pLink
);
2317 // added to avoid warnings
2322 void ScChangeTrack::AppendLoaded( std::unique_ptr
<ScChangeAction
> pActionParam
)
2324 ScChangeAction
* pAppend
= pActionParam
.release();
2325 aMap
.insert( ::std::make_pair( pAppend
->GetActionNumber(), pAppend
) );
2327 pFirst
= pLast
= pAppend
;
2330 pLast
->pNext
= pAppend
;
2331 pAppend
->pPrev
= pLast
;
2334 MasterLinks( pAppend
);
2337 void ScChangeTrack::Append( ScChangeAction
* pAppend
, sal_uLong nAction
)
2339 if ( nActionMax
< nAction
)
2340 nActionMax
= nAction
;
2341 pAppend
->SetUser( maUser
);
2342 if ( bUseFixDateTime
)
2343 pAppend
->SetDateTimeUTC( aFixDateTime
);
2344 pAppend
->SetActionNumber( nAction
);
2345 aMap
.insert( ::std::make_pair( nAction
, pAppend
) );
2346 // UpdateReference Inserts before Dependencies.
2347 // Delete rejecting Insert which had UpdateReference with Delete Undo.
2348 // UpdateReference also with pLast==NULL, as pAppend can be a Delete,
2349 // which could have generated DelContents.
2350 if ( pAppend
->IsInsertType() && !pAppend
->IsRejecting() )
2351 UpdateReference( pAppend
, false );
2353 pFirst
= pLast
= pAppend
;
2356 pLast
->pNext
= pAppend
;
2357 pAppend
->pPrev
= pLast
;
2359 Dependencies( pAppend
);
2361 // UpdateReference does not Insert() after Dependencies.
2362 // Move rejecting Move, which had UpdateReference with Move Undo.
2363 // Do not delete content in ToRange.
2364 if ( !pAppend
->IsInsertType() &&
2365 !(pAppend
->GetType() == SC_CAT_MOVE
&& pAppend
->IsRejecting()) )
2366 UpdateReference( pAppend
, false );
2367 MasterLinks( pAppend
);
2369 if ( !aModifiedLink
.IsSet() )
2372 NotifyModified( ScChangeTrackMsgType::Append
, nAction
, nAction
);
2373 if ( pAppend
->GetType() == SC_CAT_CONTENT
)
2375 ScChangeActionContent
* pContent
= static_cast<ScChangeActionContent
*>(pAppend
);
2376 if ( ( pContent
= pContent
->GetPrevContent() ) != nullptr )
2378 sal_uLong nMod
= pContent
->GetActionNumber();
2379 NotifyModified( ScChangeTrackMsgType::Change
, nMod
, nMod
);
2383 NotifyModified( ScChangeTrackMsgType::Change
, pFirst
->GetActionNumber(),
2384 pLast
->GetActionNumber() );
2387 void ScChangeTrack::Append( ScChangeAction
* pAppend
)
2389 Append( pAppend
, ++nActionMax
);
2392 void ScChangeTrack::AppendDeleteRange( const ScRange
& rRange
,
2393 ScDocument
* pRefDoc
, sal_uLong
& nStartAction
, sal_uLong
& nEndAction
, SCTAB nDz
)
2395 nStartAction
= GetActionMax() + 1;
2396 AppendDeleteRange( rRange
, pRefDoc
, nDz
, 0 );
2397 nEndAction
= GetActionMax();
2400 void ScChangeTrack::AppendDeleteRange( const ScRange
& rRange
,
2401 ScDocument
* pRefDoc
, SCTAB nDz
, sal_uLong nRejectingInsert
)
2403 SetInDeleteRange( rRange
);
2404 StartBlockModify( ScChangeTrackMsgType::Append
, GetActionMax() + 1 );
2411 rRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
2412 for ( SCTAB nTab
= nTab1
; nTab
<= nTab2
; nTab
++ )
2414 if ( !pRefDoc
|| nTab
< pRefDoc
->GetTableCount() )
2416 if ( nCol1
== 0 && nCol2
== rDoc
.MaxCol() )
2417 { // Whole Row and/or Tables
2418 if ( nRow1
== 0 && nRow2
== rDoc
.MaxRow() )
2420 // TODO: Can't we do the whole Table as a whole?
2421 ScRange
aRange( 0, 0, nTab
, 0, rDoc
.MaxRow(), nTab
);
2422 for ( SCCOL nCol
= nCol1
; nCol
<= nCol2
; nCol
++ )
2423 { // Column by column is less than row by row
2424 aRange
.aStart
.SetCol( nCol
);
2425 aRange
.aEnd
.SetCol( nCol
);
2426 if ( nCol
== nCol2
)
2427 SetInDeleteTop( true );
2428 AppendOneDeleteRange( aRange
, pRefDoc
, nCol
-nCol1
, 0,
2429 nTab
-nTab1
+ nDz
, nRejectingInsert
);
2431 // Still InDeleteTop!
2432 AppendOneDeleteRange( rRange
, pRefDoc
, 0, 0,
2433 nTab
-nTab1
+ nDz
, nRejectingInsert
);
2437 ScRange
aRange( 0, 0, nTab
, rDoc
.MaxCol(), 0, nTab
);
2438 for ( SCROW nRow
= nRow1
; nRow
<= nRow2
; nRow
++ )
2440 aRange
.aStart
.SetRow( nRow
);
2441 aRange
.aEnd
.SetRow( nRow
);
2442 if ( nRow
== nRow2
)
2443 SetInDeleteTop( true );
2444 AppendOneDeleteRange( aRange
, pRefDoc
, 0, nRow
-nRow1
,
2445 0, nRejectingInsert
);
2449 else if ( nRow1
== 0 && nRow2
== rDoc
.MaxRow() )
2451 ScRange
aRange( 0, 0, nTab
, 0, rDoc
.MaxRow(), nTab
);
2452 for ( SCCOL nCol
= nCol1
; nCol
<= nCol2
; nCol
++ )
2454 aRange
.aStart
.SetCol( nCol
);
2455 aRange
.aEnd
.SetCol( nCol
);
2456 if ( nCol
== nCol2
)
2457 SetInDeleteTop( true );
2458 AppendOneDeleteRange( aRange
, pRefDoc
, nCol
-nCol1
, 0,
2459 0, nRejectingInsert
);
2464 OSL_FAIL( "ScChangeTrack::AppendDeleteRange: Block not supported!" );
2466 SetInDeleteTop( false );
2469 EndBlockModify( GetActionMax() );
2472 void ScChangeTrack::AppendOneDeleteRange( const ScRange
& rOrgRange
,
2473 ScDocument
* pRefDoc
, SCCOL nDx
, SCROW nDy
, SCTAB nDz
,
2474 sal_uLong nRejectingInsert
)
2476 ScRange
aTrackRange( rOrgRange
);
2479 aTrackRange
.aStart
.IncCol( -nDx
);
2480 aTrackRange
.aEnd
.IncCol( -nDx
);
2484 aTrackRange
.aStart
.IncRow( -nDy
);
2485 aTrackRange
.aEnd
.IncRow( -nDy
);
2489 aTrackRange
.aStart
.IncTab( -nDz
);
2490 aTrackRange
.aEnd
.IncTab( -nDz
);
2492 ScChangeActionDel
* pAct
= new ScChangeActionDel( &rDoc
, aTrackRange
, nDx
, nDy
,
2494 // TabDelete not Contents; they are in separate columns
2495 if ( !(rOrgRange
.aStart
.Col() == 0 && rOrgRange
.aStart
.Row() == 0 &&
2496 rOrgRange
.aEnd
.Col() == rDoc
.MaxCol() && rOrgRange
.aEnd
.Row() == rDoc
.MaxRow()) )
2497 LookUpContents( rOrgRange
, pRefDoc
, -nDx
, -nDy
, -nDz
);
2498 if ( nRejectingInsert
)
2500 pAct
->SetRejectAction( nRejectingInsert
);
2501 pAct
->SetState( SC_CAS_ACCEPTED
);
2506 void ScChangeTrack::LookUpContents( const ScRange
& rOrgRange
,
2507 ScDocument
* pRefDoc
, SCCOL nDx
, SCROW nDy
, SCTAB nDz
)
2513 ScBigAddress aBigPos
;
2514 ScCellIterator
aIter( *pRefDoc
, rOrgRange
);
2515 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
2517 if (!ScChangeActionContent::GetContentCellType(aIter
.getRefCellValue()))
2520 aBigPos
.Set( aIter
.GetPos().Col() + nDx
, aIter
.GetPos().Row() + nDy
,
2521 aIter
.GetPos().Tab() + nDz
);
2522 ScChangeActionContent
* pContent
= SearchContentAt( aBigPos
, nullptr );
2526 // Untracked Contents
2527 aPos
.Set( aIter
.GetPos().Col() + nDx
, aIter
.GetPos().Row() + nDy
,
2528 aIter
.GetPos().Tab() + nDz
);
2530 GenerateDelContent(aPos
, aIter
.getCellValue(), pRefDoc
);
2531 // The Content is _not_ added with AddContent here, but in UpdateReference.
2532 // We do this in order to e.g. handle intersecting Deletes correctly
2536 void ScChangeTrack::AppendMove( const ScRange
& rFromRange
,
2537 const ScRange
& rToRange
, ScDocument
* pRefDoc
)
2539 ScChangeActionMove
* pAct
= new ScChangeActionMove( rFromRange
, rToRange
, this );
2540 LookUpContents( rToRange
, pRefDoc
, 0, 0, 0 ); // Overwritten Contents
2544 bool ScChangeTrack::IsMatrixFormulaRangeDifferent(
2545 const ScCellValue
& rOldCell
, const ScCellValue
& rNewCell
)
2552 if (rOldCell
.getType() == CELLTYPE_FORMULA
&& rOldCell
.getFormula()->GetMatrixFlag() == ScMatrixMode::Formula
)
2553 rOldCell
.getFormula()->GetMatColsRows(nC1
, nR1
);
2555 if (rNewCell
.getType() == CELLTYPE_FORMULA
&& rNewCell
.getFormula()->GetMatrixFlag() == ScMatrixMode::Formula
)
2556 rNewCell
.getFormula()->GetMatColsRows(nC1
, nR1
);
2558 return nC1
!= nC2
|| nR1
!= nR2
;
2561 void ScChangeTrack::AppendContent(
2562 const ScAddress
& rPos
, const ScCellValue
& rOldCell
, sal_uLong nOldFormat
, ScDocument
* pRefDoc
)
2567 OUString aOldValue
= ScChangeActionContent::GetStringOfCell(rOldCell
, pRefDoc
, nOldFormat
);
2569 ScCellValue aNewCell
;
2570 aNewCell
.assign(rDoc
, rPos
);
2571 OUString aNewValue
= ScChangeActionContent::GetStringOfCell(aNewCell
, &rDoc
, rPos
);
2573 if (aOldValue
!= aNewValue
|| IsMatrixFormulaRangeDifferent(rOldCell
, aNewCell
))
2574 { // Only track real changes
2575 ScRange
aRange( rPos
);
2576 ScChangeActionContent
* pAct
= new ScChangeActionContent( aRange
);
2577 pAct
->SetOldValue(rOldCell
, pRefDoc
, &rDoc
, nOldFormat
);
2578 pAct
->SetNewValue(aNewCell
, &rDoc
);
2583 void ScChangeTrack::AppendContent( const ScAddress
& rPos
,
2584 const ScDocument
* pRefDoc
)
2586 ScCellValue aOldCell
;
2587 aOldCell
.assign(*pRefDoc
, rPos
);
2588 OUString aOldValue
= ScChangeActionContent::GetStringOfCell(aOldCell
, pRefDoc
, rPos
);
2590 ScCellValue aNewCell
;
2591 aNewCell
.assign(rDoc
, rPos
);
2592 OUString aNewValue
= ScChangeActionContent::GetStringOfCell(aNewCell
, &rDoc
, rPos
);
2594 if (aOldValue
!= aNewValue
|| IsMatrixFormulaRangeDifferent(aOldCell
, aNewCell
))
2595 { // Only track real changes
2596 ScRange
aRange( rPos
);
2597 ScChangeActionContent
* pAct
= new ScChangeActionContent( aRange
);
2598 pAct
->SetOldValue(aOldCell
, pRefDoc
, &rDoc
);
2599 pAct
->SetNewValue(aNewCell
, &rDoc
);
2604 void ScChangeTrack::AppendContent( const ScAddress
& rPos
, const ScCellValue
& rOldCell
)
2606 if (ScChangeActionContent::NeedsNumberFormat(rOldCell
))
2607 AppendContent(rPos
, rOldCell
, rDoc
.GetNumberFormat(rPos
), &rDoc
);
2609 AppendContent(rPos
, rOldCell
, 0, &rDoc
);
2612 void ScChangeTrack::SetLastCutMoveRange( const ScRange
& rRange
,
2613 ScDocument
* pRefDoc
)
2615 if ( !pLastCutMove
)
2618 // Do not link ToRange with Deletes and don't change its size
2619 // This is actually unnecessary, as a delete triggers a ResetLastCut
2620 // in ScViewFunc::PasteFromClip before that
2621 ScBigRange
& r
= pLastCutMove
->GetBigRange();
2622 r
.aEnd
.SetCol( -1 );
2623 r
.aEnd
.SetRow( -1 );
2624 r
.aEnd
.SetTab( -1 );
2625 r
.aStart
.SetCol( -1 - (rRange
.aEnd
.Col() - rRange
.aStart
.Col()) );
2626 r
.aStart
.SetRow( -1 - (rRange
.aEnd
.Row() - rRange
.aStart
.Row()) );
2627 r
.aStart
.SetTab( -1 - (rRange
.aEnd
.Tab() - rRange
.aStart
.Tab()) );
2628 // Contents in FromRange we should overwrite
2629 LookUpContents( rRange
, pRefDoc
, 0, 0, 0 );
2632 void ScChangeTrack::AppendContentRange( const ScRange
& rRange
,
2633 ScDocument
* pRefDoc
, sal_uLong
& nStartAction
, sal_uLong
& nEndAction
,
2634 ScChangeActionClipMode eClipMode
)
2636 if ( eClipMode
== SC_CACM_CUT
)
2639 pLastCutMove
.reset(new ScChangeActionMove( rRange
, rRange
, this ));
2640 SetLastCutMoveRange( rRange
, pRefDoc
);
2648 rRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
2650 if ( eClipMode
== SC_CACM_PASTE
&& HasLastCut() )
2652 bDoContents
= false;
2653 SetInPasteCut( true );
2654 // Adjust Paste and Cut; Paste can be larger a Range
2655 ScRange
aRange( rRange
);
2656 ScBigRange
& r
= pLastCutMove
->GetBigRange();
2658 if ( (nTmpCol
= static_cast<SCCOL
>(r
.aEnd
.Col() - r
.aStart
.Col())) != (nCol2
- nCol1
) )
2660 aRange
.aEnd
.SetCol( aRange
.aStart
.Col() + nTmpCol
);
2661 nCol1
+= nTmpCol
+ 1;
2665 if ( (nTmpRow
= static_cast<SCROW
>(r
.aEnd
.Row() - r
.aStart
.Row())) != (nRow2
- nRow1
) )
2667 aRange
.aEnd
.SetRow( aRange
.aStart
.Row() + nTmpRow
);
2668 nRow1
+= nTmpRow
+ 1;
2672 if ( (nTmpTab
= static_cast<SCTAB
>(r
.aEnd
.Tab() - r
.aStart
.Tab())) != (nTab2
- nTab1
) )
2674 aRange
.aEnd
.SetTab( aRange
.aStart
.Tab() + nTmpTab
);
2675 nTab1
+= nTmpTab
+ 1;
2679 Undo( nStartLastCut
, nEndLastCut
); // Remember Cuts here
2680 // StartAction only after Undo!
2681 nStartAction
= GetActionMax() + 1;
2682 StartBlockModify( ScChangeTrackMsgType::Append
, nStartAction
);
2683 // Contents to overwrite in ToRange
2684 LookUpContents( aRange
, pRefDoc
, 0, 0, 0 );
2685 pLastCutMove
->SetStartLastCut( nStartLastCut
);
2686 pLastCutMove
->SetEndLastCut( nEndLastCut
);
2687 Append( pLastCutMove
.release() );
2689 SetInPasteCut( false );
2694 nStartAction
= GetActionMax() + 1;
2695 StartBlockModify( ScChangeTrackMsgType::Append
, nStartAction
);
2700 for ( SCTAB nTab
= nTab1
; nTab
<= nTab2
; nTab
++ )
2702 aPos
.SetTab( nTab
);
2703 // AppendContent() is a no-op if both cells are empty.
2704 SCCOL lastCol
= std::max( pRefDoc
->ClampToAllocatedColumns( nTab
, nCol2
),
2705 rDoc
.ClampToAllocatedColumns( nTab
, nCol2
));
2706 for ( SCCOL nCol
= nCol1
; nCol
<= lastCol
; nCol
++ )
2708 aPos
.SetCol( nCol
);
2709 SCROW lastRow
= std::max( pRefDoc
->GetLastDataRow( nTab
, nCol
, nCol
, nRow2
),
2710 rDoc
.GetLastDataRow( nTab
, nCol
, nCol
, nRow2
));
2711 for ( SCROW nRow
= nRow1
; nRow
<= lastRow
; nRow
++ )
2713 aPos
.SetRow( nRow
);
2714 AppendContent( aPos
, pRefDoc
);
2719 nEndAction
= GetActionMax();
2720 EndBlockModify( nEndAction
);
2721 if ( eClipMode
== SC_CACM_CUT
)
2723 nStartLastCut
= nStartAction
;
2724 nEndLastCut
= nEndAction
;
2728 void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument
& rRefDoc
,
2729 sal_uLong
& nStartAction
, sal_uLong
& nEndAction
)
2731 ScCellIterator
aIter(rRefDoc
, ScRange(0,0,0,rDoc
.MaxCol(),rDoc
.MaxRow(),MAXTAB
));
2734 nStartAction
= GetActionMax() + 1;
2735 StartBlockModify( ScChangeTrackMsgType::Append
, nStartAction
);
2736 SvNumberFormatter
* pFormatter
= rRefDoc
.GetFormatTable();
2739 const ScAddress
& rPos
= aIter
.GetPos();
2740 const ScPatternAttr
* pPat
= rRefDoc
.GetPattern(rPos
);
2742 rPos
, aIter
.getCellValue(), pPat
->GetNumberFormat(pFormatter
), &rRefDoc
);
2744 while (aIter
.next());
2746 nEndAction
= GetActionMax();
2747 EndBlockModify( nEndAction
);
2750 nStartAction
= nEndAction
= 0;
2753 ScChangeActionContent
* ScChangeTrack::AppendContentOnTheFly(
2754 const ScAddress
& rPos
, const ScCellValue
& rOldCell
, const ScCellValue
& rNewCell
,
2755 sal_uLong nOldFormat
, sal_uLong nNewFormat
)
2757 ScRange
aRange( rPos
);
2758 ScChangeActionContent
* pAct
= new ScChangeActionContent( aRange
);
2759 pAct
->SetOldNewCells(rOldCell
, nOldFormat
, rNewCell
, nNewFormat
, &rDoc
);
2764 void ScChangeTrack::AppendInsert( const ScRange
& rRange
, bool bEndOfList
)
2766 ScChangeActionIns
* pAct
= new ScChangeActionIns(&rDoc
, rRange
, bEndOfList
);
2770 void ScChangeTrack::DeleteCellEntries( std::vector
<ScChangeActionContent
*>& rCellList
,
2771 const ScChangeAction
* pDeletor
)
2773 for (ScChangeActionContent
* pContent
: rCellList
)
2775 pContent
->RemoveDeletedIn( pDeletor
);
2776 if ( IsGenerated( pContent
->GetActionNumber() ) &&
2777 !pContent
->IsDeletedIn() )
2778 DeleteGeneratedDelContent( pContent
);
2783 ScChangeActionContent
* ScChangeTrack::GenerateDelContent(
2784 const ScAddress
& rPos
, const ScCellValue
& rCell
, const ScDocument
* pFromDoc
)
2786 ScChangeActionContent
* pContent
= new ScChangeActionContent(
2788 pContent
->SetActionNumber( --nGeneratedMin
);
2790 ScChangeActionContent::SetValue( pContent
->maNewValue
, pContent
->maNewCell
,
2791 rPos
, rCell
, pFromDoc
, &rDoc
);
2792 // pNextContent and pPrevContent are not set
2793 if ( pFirstGeneratedDelContent
)
2794 { // Insert at front
2795 pFirstGeneratedDelContent
->pPrev
= pContent
;
2796 pContent
->pNext
= pFirstGeneratedDelContent
;
2798 pFirstGeneratedDelContent
= pContent
;
2799 aGeneratedMap
.insert( std::make_pair( nGeneratedMin
, pContent
) );
2800 NotifyModified( ScChangeTrackMsgType::Append
, nGeneratedMin
, nGeneratedMin
);
2804 void ScChangeTrack::DeleteGeneratedDelContent( ScChangeActionContent
* pContent
)
2806 sal_uLong nAct
= pContent
->GetActionNumber();
2807 aGeneratedMap
.erase( nAct
);
2808 if ( pFirstGeneratedDelContent
== pContent
)
2809 pFirstGeneratedDelContent
= static_cast<ScChangeActionContent
*>(pContent
->pNext
);
2810 if ( pContent
->pNext
)
2811 pContent
->pNext
->pPrev
= pContent
->pPrev
;
2812 if ( pContent
->pPrev
)
2813 pContent
->pPrev
->pNext
= pContent
->pNext
;
2815 NotifyModified( ScChangeTrackMsgType::Remove
, nAct
, nAct
);
2816 if ( nAct
== nGeneratedMin
)
2817 ++nGeneratedMin
; // Only after NotifyModified due to IsGenerated!
2820 ScChangeActionContent
* ScChangeTrack::SearchContentAt(
2821 const ScBigAddress
& rPos
, const ScChangeAction
* pButNotThis
) const
2823 SCSIZE nSlot
= ComputeContentSlot( rPos
.Row() );
2824 for ( ScChangeActionContent
* p
= ppContentSlots
[nSlot
]; p
;
2825 p
= p
->GetNextInSlot() )
2827 if ( p
!= pButNotThis
&& !p
->IsDeletedIn() &&
2828 p
->GetBigRange().aStart
== rPos
)
2830 ScChangeActionContent
* pContent
= p
->GetTopContent();
2831 if ( !pContent
->IsDeletedIn() )
2838 void ScChangeTrack::AddDependentWithNotify( ScChangeAction
* pParent
,
2839 ScChangeAction
* pDependent
)
2841 ScChangeActionLinkEntry
* pLink
= pParent
->AddDependent( pDependent
);
2842 pDependent
->AddLink( pParent
, pLink
);
2843 if ( aModifiedLink
.IsSet() )
2845 sal_uLong nMod
= pParent
->GetActionNumber();
2846 NotifyModified( ScChangeTrackMsgType::Parent
, nMod
, nMod
);
2850 void ScChangeTrack::Dependencies( ScChangeAction
* pAct
)
2852 // Find the last dependency for Col/Row/Tab each
2853 // Concatenate Content at the same position
2854 // Move dependencies
2855 ScChangeActionType eActType
= pAct
->GetType();
2856 if ( eActType
== SC_CAT_REJECT
||
2857 (eActType
== SC_CAT_MOVE
&& pAct
->IsRejecting()) )
2858 return ; // These Rejects are not dependent
2860 if ( eActType
== SC_CAT_CONTENT
)
2862 if ( !(static_cast<ScChangeActionContent
*>(pAct
)->GetNextContent() ||
2863 static_cast<ScChangeActionContent
*>(pAct
)->GetPrevContent()) )
2864 { // Concatenate Contents at same position
2865 ScChangeActionContent
* pContent
= SearchContentAt(
2866 pAct
->GetBigRange().aStart
, pAct
);
2869 pContent
->SetNextContent( static_cast<ScChangeActionContent
*>(pAct
) );
2870 static_cast<ScChangeActionContent
*>(pAct
)->SetPrevContent( pContent
);
2873 const ScCellValue
& rCell
= static_cast<ScChangeActionContent
*>(pAct
)->GetNewCell();
2874 if ( ScChangeActionContent::GetContentCellType(rCell
) == SC_CACCT_MATREF
)
2877 bool bOrgFound
= rCell
.getFormula()->GetMatrixOrigin(rDoc
, aOrg
);
2878 ScChangeActionContent
* pContent
= (bOrgFound
? SearchContentAt( aOrg
, pAct
) : nullptr);
2879 if ( pContent
&& pContent
->IsMatrixOrigin() )
2881 AddDependentWithNotify( pContent
, pAct
);
2885 OSL_FAIL( "ScChangeTrack::Dependencies: MatOrg not found" );
2890 if ( !(pLinkInsertCol
|| pLinkInsertRow
|| pLinkInsertTab
|| pLinkMove
) )
2891 return ; // No Dependencies
2892 if ( pAct
->IsRejecting() )
2893 return ; // Except for Content no Dependencies
2895 // Insert in a corresponding Insert depends on it or else we would need
2896 // to split the preceding one.
2897 // Intersecting Inserts and Deletes are not dependent, everything else
2899 // The Insert last linked in is at the beginning of a chain, just the way we need it
2901 const ScBigRange
& rRange
= pAct
->GetBigRange();
2902 bool bActNoInsert
= !pAct
->IsInsertType();
2903 bool bActColDel
= ( eActType
== SC_CAT_DELETE_COLS
);
2904 bool bActRowDel
= ( eActType
== SC_CAT_DELETE_ROWS
);
2905 bool bActTabDel
= ( eActType
== SC_CAT_DELETE_TABS
);
2907 if ( pLinkInsertCol
&& (eActType
== SC_CAT_INSERT_COLS
||
2908 (bActNoInsert
&& !bActRowDel
&& !bActTabDel
)) )
2910 for ( ScChangeActionLinkEntry
* pL
= pLinkInsertCol
; pL
; pL
= pL
->GetNext() )
2912 ScChangeActionIns
* pTest
= static_cast<ScChangeActionIns
*>(pL
->GetAction());
2913 if ( !pTest
->IsRejected() &&
2914 pTest
->GetBigRange().Intersects( rRange
) )
2916 AddDependentWithNotify( pTest
, pAct
);
2921 if ( pLinkInsertRow
&& (eActType
== SC_CAT_INSERT_ROWS
||
2922 (bActNoInsert
&& !bActColDel
&& !bActTabDel
)) )
2924 for ( ScChangeActionLinkEntry
* pL
= pLinkInsertRow
; pL
; pL
= pL
->GetNext() )
2926 ScChangeActionIns
* pTest
= static_cast<ScChangeActionIns
*>(pL
->GetAction());
2927 if ( !pTest
->IsRejected() &&
2928 pTest
->GetBigRange().Intersects( rRange
) )
2930 AddDependentWithNotify( pTest
, pAct
);
2935 if ( pLinkInsertTab
&& (eActType
== SC_CAT_INSERT_TABS
||
2936 (bActNoInsert
&& !bActColDel
&& !bActRowDel
)) )
2938 for ( ScChangeActionLinkEntry
* pL
= pLinkInsertTab
; pL
; pL
= pL
->GetNext() )
2940 ScChangeActionIns
* pTest
= static_cast<ScChangeActionIns
*>(pL
->GetAction());
2941 if ( !pTest
->IsRejected() &&
2942 pTest
->GetBigRange().Intersects( rRange
) )
2944 AddDependentWithNotify( pTest
, pAct
);
2953 if ( eActType
== SC_CAT_CONTENT
)
2954 { // Content is depending on FromRange
2955 const ScBigAddress
& rPos
= rRange
.aStart
;
2956 for ( ScChangeActionLinkEntry
* pL
= pLinkMove
; pL
; pL
= pL
->GetNext() )
2958 ScChangeActionMove
* pTest
= static_cast<ScChangeActionMove
*>(pL
->GetAction());
2959 if ( !pTest
->IsRejected() &&
2960 pTest
->GetFromRange().Contains( rPos
) )
2962 AddDependentWithNotify( pTest
, pAct
);
2966 else if ( eActType
== SC_CAT_MOVE
)
2967 { // Move FromRange is depending on ToRange
2968 const ScBigRange
& rFromRange
= static_cast<ScChangeActionMove
*>(pAct
)->GetFromRange();
2969 for ( ScChangeActionLinkEntry
* pL
= pLinkMove
; pL
; pL
= pL
->GetNext() )
2971 ScChangeActionMove
* pTest
= static_cast<ScChangeActionMove
*>(pL
->GetAction());
2972 if ( !pTest
->IsRejected() &&
2973 pTest
->GetBigRange().Intersects( rFromRange
) )
2975 AddDependentWithNotify( pTest
, pAct
);
2980 { // Inserts and Deletes are depending as soon as they cross FromRange or
2982 for ( ScChangeActionLinkEntry
* pL
= pLinkMove
; pL
; pL
= pL
->GetNext() )
2984 ScChangeActionMove
* pTest
= static_cast<ScChangeActionMove
*>(pL
->GetAction());
2985 if ( !pTest
->IsRejected() &&
2986 (pTest
->GetFromRange().Intersects( rRange
) ||
2987 pTest
->GetBigRange().Intersects( rRange
)) )
2989 AddDependentWithNotify( pTest
, pAct
);
2995 void ScChangeTrack::Remove( ScChangeAction
* pRemove
)
2997 // Remove from Track
2998 sal_uLong nAct
= pRemove
->GetActionNumber();
3000 if ( nAct
== nActionMax
)
3002 if ( pRemove
== pLast
)
3003 pLast
= pRemove
->pPrev
;
3004 if ( pRemove
== pFirst
)
3005 pFirst
= pRemove
->pNext
;
3006 if ( nAct
== nMarkLastSaved
)
3008 ( pRemove
->pPrev
? pRemove
->pPrev
->GetActionNumber() : 0 );
3010 // Remove from global chain
3011 if ( pRemove
->pNext
)
3012 pRemove
->pNext
->pPrev
= pRemove
->pPrev
;
3013 if ( pRemove
->pPrev
)
3014 pRemove
->pPrev
->pNext
= pRemove
->pNext
;
3016 // Don't delete Dependencies
3017 // That happens automatically on delete by LinkEntry without traversing lists
3018 if ( aModifiedLink
.IsSet() )
3020 NotifyModified( ScChangeTrackMsgType::Remove
, nAct
, nAct
);
3021 if ( pRemove
->GetType() == SC_CAT_CONTENT
)
3023 ScChangeActionContent
* pContent
= static_cast<ScChangeActionContent
*>(pRemove
);
3024 if ( ( pContent
= pContent
->GetPrevContent() ) != nullptr )
3026 sal_uLong nMod
= pContent
->GetActionNumber();
3027 NotifyModified( ScChangeTrackMsgType::Change
, nMod
, nMod
);
3031 NotifyModified( ScChangeTrackMsgType::Change
, pFirst
->GetActionNumber(),
3032 pLast
->GetActionNumber() );
3035 if ( IsInPasteCut() && pRemove
->GetType() == SC_CAT_CONTENT
)
3036 { // Content is reused!
3037 ScChangeActionContent
* pContent
= static_cast<ScChangeActionContent
*>(pRemove
);
3038 pContent
->RemoveAllLinks();
3039 pContent
->ClearTrack();
3040 pContent
->pNext
= pContent
->pPrev
= nullptr;
3041 pContent
->pNextContent
= pContent
->pPrevContent
= nullptr;
3045 void ScChangeTrack::Undo( sal_uLong nStartAction
, sal_uLong nEndAction
, bool bMerge
)
3047 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3050 SetMergeState( SC_CTMS_UNDO
);
3053 if ( nStartAction
== 0 )
3055 if ( nEndAction
> nActionMax
)
3056 nEndAction
= nActionMax
;
3057 if ( nEndAction
&& nStartAction
<= nEndAction
)
3059 if ( nStartAction
== nStartLastCut
&& nEndAction
== nEndLastCut
&&
3062 StartBlockModify( ScChangeTrackMsgType::Remove
, nStartAction
);
3063 for ( sal_uLong j
= nEndAction
; j
>= nStartAction
; --j
)
3064 { // Traverse backwards to recycle nActionMax and for faster access via pLast
3065 // Deletes are in right order
3066 ScChangeAction
* pAct
= IsLastAction(j
) ? pLast
: GetAction(j
);
3071 if ( pAct
->IsDeleteType() )
3073 if (j
== nEndAction
|| (pAct
!= pLast
&& static_cast<ScChangeActionDel
*>(pAct
)->IsTopDelete()))
3075 SetInDeleteTop( true );
3076 SetInDeleteRange( static_cast<ScChangeActionDel
*>(pAct
)->GetOverAllRange().MakeRange( rDoc
) );
3079 UpdateReference( pAct
, true );
3080 SetInDeleteTop( false );
3082 if ( IsInPasteCut() )
3084 aPasteCutMap
.insert( ::std::make_pair( pAct
->GetActionNumber(), pAct
) );
3088 if ( j
== nStartAction
&& pAct
->GetType() == SC_CAT_MOVE
)
3090 ScChangeActionMove
* pMove
= static_cast<ScChangeActionMove
*>(pAct
);
3091 sal_uLong nStart
= pMove
->GetStartLastCut();
3092 sal_uLong nEnd
= pMove
->GetEndLastCut();
3093 if ( nStart
&& nStart
<= nEnd
)
3094 { // Recover LastCut
3095 // Break Links before Cut Append!
3096 pMove
->RemoveAllLinks();
3097 StartBlockModify( ScChangeTrackMsgType::Append
, nStart
);
3098 for ( sal_uLong nCut
= nStart
; nCut
<= nEnd
; nCut
++ )
3100 ScChangeActionMap::iterator itCut
= aPasteCutMap
.find( nCut
);
3102 if ( itCut
!= aPasteCutMap
.end() )
3104 OSL_ENSURE( aMap
.find( nCut
) == aMap
.end(), "ScChangeTrack::Undo: nCut dup" );
3105 Append( itCut
->second
, nCut
);
3106 aPasteCutMap
.erase( itCut
);
3110 OSL_FAIL( "ScChangeTrack::Undo: nCut not found" );
3113 EndBlockModify( nEnd
);
3115 nStartLastCut
= nStart
;
3117 pLastCutMove
.reset(pMove
);
3118 SetLastCutMoveRange(
3119 pMove
->GetFromRange().MakeRange( rDoc
), &rDoc
);
3127 EndBlockModify( nEndAction
);
3130 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3133 SetMergeState( SC_CTMS_OTHER
);
3137 bool ScChangeTrack::MergeIgnore( const ScChangeAction
& rAction
, sal_uLong nFirstMerge
)
3139 if ( rAction
.IsRejected() )
3140 return true; // There's still a suitable Reject Action coming
3142 if ( rAction
.IsRejecting() && rAction
.GetRejectAction() >= nFirstMerge
)
3143 return true; // There it is
3145 return false; // Everything else
3148 void ScChangeTrack::MergePrepare( const ScChangeAction
* pFirstMerge
, bool bShared
)
3150 SetMergeState( SC_CTMS_PREPARE
);
3151 sal_uLong nFirstMerge
= pFirstMerge
->GetActionNumber();
3152 ScChangeAction
* pAct
= GetLast();
3155 SetLastMerge( pAct
->GetActionNumber() );
3157 { // Traverse backwards; Deletes in right order
3158 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3159 if ( bShared
|| !ScChangeTrack::MergeIgnore( *pAct
, nFirstMerge
) )
3161 if ( pAct
->IsDeleteType() )
3163 if ( static_cast<ScChangeActionDel
*>(pAct
)->IsTopDelete() )
3165 SetInDeleteTop( true );
3166 SetInDeleteRange( static_cast<ScChangeActionDel
*>(pAct
)->
3167 GetOverAllRange().MakeRange( rDoc
) );
3170 UpdateReference( pAct
, true );
3171 SetInDeleteTop( false );
3172 pAct
->DeleteCellEntries(); // Else segfault in Track Clear()
3174 pAct
= ( pAct
== pFirstMerge
? nullptr : pAct
->GetPrev() );
3177 SetMergeState( SC_CTMS_OTHER
); // Preceding by default MergeOther!
3180 void ScChangeTrack::MergeOwn( ScChangeAction
* pAct
, sal_uLong nFirstMerge
, bool bShared
)
3182 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3183 if ( !bShared
&& ScChangeTrack::MergeIgnore( *pAct
, nFirstMerge
) )
3186 SetMergeState( SC_CTMS_OWN
);
3187 if ( pAct
->IsDeleteType() )
3189 if ( static_cast<ScChangeActionDel
*>(pAct
)->IsTopDelete() )
3191 SetInDeleteTop( true );
3192 SetInDeleteRange( static_cast<ScChangeActionDel
*>(pAct
)->
3193 GetOverAllRange().MakeRange( rDoc
) );
3196 UpdateReference( pAct
, false );
3197 SetInDeleteTop( false );
3198 SetMergeState( SC_CTMS_OTHER
); // Preceding by default MergeOther!
3201 void ScChangeTrack::UpdateReference( ScChangeAction
* pAct
, bool bUndo
)
3203 ScChangeActionType eActType
= pAct
->GetType();
3204 if ( eActType
== SC_CAT_CONTENT
|| eActType
== SC_CAT_REJECT
)
3207 // Formula cells are not in the Document!
3208 bool bOldAutoCalc
= rDoc
.GetAutoCalc();
3209 rDoc
.SetAutoCalc( false );
3210 bool bOldNoListening
= rDoc
.GetNoListening();
3211 rDoc
.SetNoListening( true );
3213 // Formula cells ExpandRefs synchronized to the ones in the Document!
3214 bool bOldExpandRefs
= rDoc
.IsExpandRefs();
3215 if ( (!bUndo
&& pAct
->IsInsertType()) || (bUndo
&& pAct
->IsDeleteType()) )
3216 rDoc
.SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
3218 if ( pAct
->IsDeleteType() )
3220 SetInDeleteUndo( bUndo
);
3221 SetInDelete( true );
3223 else if ( GetMergeState() == SC_CTMS_OWN
)
3225 // Recover references of formula cells
3226 // Previous MergePrepare behaved like a Delete when Inserting
3227 if ( pAct
->IsInsertType() )
3228 SetInDeleteUndo( true );
3231 // First the generated ones, as if they were tracked previously!
3232 if ( pFirstGeneratedDelContent
)
3233 UpdateReference( reinterpret_cast<ScChangeAction
**>(&pFirstGeneratedDelContent
), pAct
,
3235 UpdateReference( &pFirst
, pAct
, bUndo
);
3237 SetInDelete( false );
3238 SetInDeleteUndo( false );
3240 rDoc
.SetExpandRefs( bOldExpandRefs
);
3241 rDoc
.SetNoListening( bOldNoListening
);
3242 rDoc
.SetAutoCalc( bOldAutoCalc
);
3245 void ScChangeTrack::UpdateReference( ScChangeAction
** ppFirstAction
,
3246 ScChangeAction
* pAct
, bool bUndo
)
3248 ScChangeActionType eActType
= pAct
->GetType();
3249 bool bGeneratedDelContents
=
3250 ( ppFirstAction
== reinterpret_cast<ScChangeAction
**>(&pFirstGeneratedDelContent
) );
3251 const ScBigRange
& rOrgRange
= pAct
->GetBigRange();
3252 ScBigRange
aRange( rOrgRange
);
3253 ScBigRange
aDelRange( rOrgRange
);
3254 sal_Int32 nDx
, nDy
, nDz
;
3255 nDx
= nDy
= nDz
= 0;
3256 UpdateRefMode eMode
= URM_INSDEL
;
3260 case SC_CAT_INSERT_COLS
:
3261 aRange
.aEnd
.SetCol( ScBigRange::nRangeMax
);
3262 nDx
= rOrgRange
.aEnd
.Col() - rOrgRange
.aStart
.Col() + 1;
3264 case SC_CAT_INSERT_ROWS
:
3265 aRange
.aEnd
.SetRow( ScBigRange::nRangeMax
);
3266 nDy
= rOrgRange
.aEnd
.Row() - rOrgRange
.aStart
.Row() + 1;
3268 case SC_CAT_INSERT_TABS
:
3269 aRange
.aEnd
.SetTab( ScBigRange::nRangeMax
);
3270 nDz
= rOrgRange
.aEnd
.Tab() - rOrgRange
.aStart
.Tab() + 1;
3272 case SC_CAT_DELETE_COLS
:
3273 aRange
.aEnd
.SetCol( ScBigRange::nRangeMax
);
3274 nDx
= -(rOrgRange
.aEnd
.Col() - rOrgRange
.aStart
.Col() + 1);
3275 aDelRange
.aEnd
.SetCol( aDelRange
.aStart
.Col() - nDx
- 1 );
3278 case SC_CAT_DELETE_ROWS
:
3279 aRange
.aEnd
.SetRow( ScBigRange::nRangeMax
);
3280 nDy
= -(rOrgRange
.aEnd
.Row() - rOrgRange
.aStart
.Row() + 1);
3281 aDelRange
.aEnd
.SetRow( aDelRange
.aStart
.Row() - nDy
- 1 );
3284 case SC_CAT_DELETE_TABS
:
3285 aRange
.aEnd
.SetTab( ScBigRange::nRangeMax
);
3286 nDz
= -(rOrgRange
.aEnd
.Tab() - rOrgRange
.aStart
.Tab() + 1);
3287 aDelRange
.aEnd
.SetTab( aDelRange
.aStart
.Tab() - nDz
- 1 );
3292 static_cast<ScChangeActionMove
*>(pAct
)->GetDelta( nDx
, nDy
, nDz
);
3295 OSL_FAIL( "ScChangeTrack::UpdateReference: unknown Type" );
3304 { // For this mechanism we assume:
3305 // There's only a whole, simple deleted row/column
3306 ScChangeActionDel
* pActDel
= static_cast<ScChangeActionDel
*>(pAct
);
3309 ScChangeActionType eInsType
= SC_CAT_NONE
; // for Insert Undo "Deletes"
3312 case SC_CAT_DELETE_COLS
:
3313 eInsType
= SC_CAT_INSERT_COLS
;
3315 case SC_CAT_DELETE_ROWS
:
3316 eInsType
= SC_CAT_INSERT_ROWS
;
3318 case SC_CAT_DELETE_TABS
:
3319 eInsType
= SC_CAT_INSERT_TABS
;
3323 // added to avoid warnings
3326 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3330 bool bUpdate
= true;
3331 if ( GetMergeState() == SC_CTMS_OTHER
&&
3332 p
->GetActionNumber() <= GetLastMerge() )
3333 { // Delete in merged Document, Action in the one to be merged
3334 if ( p
->IsInsertType() )
3336 // On Insert only adjust references if the Delete does
3337 // not intersect the Insert
3338 if ( !aDelRange
.Intersects( p
->GetBigRange() ) )
3339 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3342 else if ( p
->GetType() == SC_CAT_CONTENT
&&
3343 p
->IsDeletedInDelType( eInsType
) )
3344 { // Content in Insert Undo "Delete"
3345 // Do not adjust if this Delete would be in the Insert "Delete" (was just moved)
3346 if ( aDelRange
.Contains( p
->GetBigRange().aStart
) )
3350 const ScChangeActionLinkEntry
* pLink
= p
->GetDeletedIn();
3351 while ( pLink
&& bUpdate
)
3353 const ScChangeAction
* pDel
= pLink
->GetAction();
3354 if ( pDel
&& pDel
->GetType() == eInsType
&&
3355 pDel
->GetBigRange().Contains( aDelRange
) )
3357 pLink
= pLink
->GetNext();
3364 if ( aDelRange
.Contains( p
->GetBigRange() ) )
3366 // Do not adjust within a just deleted range,
3367 // instead assign the range.
3368 // Stack up ranges that have been deleted multiple times.
3369 // Intersecting Deletes cause "multiple delete" to be set.
3370 if ( !p
->IsDeletedInDelType( eActType
) )
3372 p
->SetDeletedIn( pActDel
);
3373 // Add GeneratedDelContent to the to-be-deleted list
3374 if ( bGeneratedDelContents
)
3375 pActDel
->AddContent( static_cast<ScChangeActionContent
*>(p
) );
3381 // Cut off inserted ranges, if Start/End is within the Delete,
3382 // but the Insert is not completely within the Delete or
3383 // the Delete is not completely within the Insert.
3384 // The Delete remembers which Insert it has cut off from;
3385 // it can also just be a single Insert (because Delete has
3386 // a single column/is a single row).
3387 // There can be a lot of cut-off Moves.
3389 // ! A Delete is always a single column/a single row, therefore
3390 // ! 1 without calculating the intersection.
3391 switch ( p
->GetType() )
3393 case SC_CAT_INSERT_COLS
:
3394 if ( eActType
== SC_CAT_DELETE_COLS
)
3396 if ( aDelRange
.Contains( p
->GetBigRange().aStart
) )
3398 pActDel
->SetCutOffInsert(
3399 static_cast<ScChangeActionIns
*>(p
), 1 );
3400 p
->GetBigRange().aStart
.IncCol();
3402 else if ( aDelRange
.Contains( p
->GetBigRange().aEnd
) )
3404 pActDel
->SetCutOffInsert(
3405 static_cast<ScChangeActionIns
*>(p
), -1 );
3406 p
->GetBigRange().aEnd
.IncCol( -1 );
3410 case SC_CAT_INSERT_ROWS
:
3411 if ( eActType
== SC_CAT_DELETE_ROWS
)
3413 if ( aDelRange
.Contains( p
->GetBigRange().aStart
) )
3415 pActDel
->SetCutOffInsert(
3416 static_cast<ScChangeActionIns
*>(p
), 1 );
3417 p
->GetBigRange().aStart
.IncRow();
3419 else if ( aDelRange
.Contains( p
->GetBigRange().aEnd
) )
3421 pActDel
->SetCutOffInsert(
3422 static_cast<ScChangeActionIns
*>(p
), -1 );
3423 p
->GetBigRange().aEnd
.IncRow( -1 );
3427 case SC_CAT_INSERT_TABS
:
3428 if ( eActType
== SC_CAT_DELETE_TABS
)
3430 if ( aDelRange
.Contains( p
->GetBigRange().aStart
) )
3432 pActDel
->SetCutOffInsert(
3433 static_cast<ScChangeActionIns
*>(p
), 1 );
3434 p
->GetBigRange().aStart
.IncTab();
3436 else if ( aDelRange
.Contains( p
->GetBigRange().aEnd
) )
3438 pActDel
->SetCutOffInsert(
3439 static_cast<ScChangeActionIns
*>(p
), -1 );
3440 p
->GetBigRange().aEnd
.IncTab( -1 );
3446 ScChangeActionMove
* pMove
= static_cast<ScChangeActionMove
*>(p
);
3449 if ( aDelRange
.Contains( pMove
->GetBigRange().aStart
) )
3451 else if ( aDelRange
.Contains( pMove
->GetBigRange().aEnd
) )
3453 if ( aDelRange
.Contains( pMove
->GetFromRange().aStart
) )
3455 else if ( aDelRange
.Contains( pMove
->GetFromRange().aEnd
) )
3461 case SC_CAT_DELETE_COLS
:
3463 pMove
->GetFromRange().aStart
.IncCol( nFrom
);
3465 pMove
->GetFromRange().aEnd
.IncCol( nFrom
);
3467 case SC_CAT_DELETE_ROWS
:
3469 pMove
->GetFromRange().aStart
.IncRow( nFrom
);
3471 pMove
->GetFromRange().aEnd
.IncRow( nFrom
);
3473 case SC_CAT_DELETE_TABS
:
3475 pMove
->GetFromRange().aStart
.IncTab( nFrom
);
3477 pMove
->GetFromRange().aEnd
.IncTab( nFrom
);
3481 // added to avoid warnings
3489 case SC_CAT_DELETE_COLS
:
3491 pMove
->GetBigRange().aStart
.IncCol( nTo
);
3493 pMove
->GetBigRange().aEnd
.IncCol( nTo
);
3495 case SC_CAT_DELETE_ROWS
:
3497 pMove
->GetBigRange().aStart
.IncRow( nTo
);
3499 pMove
->GetBigRange().aEnd
.IncRow( nTo
);
3501 case SC_CAT_DELETE_TABS
:
3503 pMove
->GetBigRange().aStart
.IncTab( nTo
);
3505 pMove
->GetBigRange().aEnd
.IncTab( nTo
);
3509 // added to avoid warnings
3515 ScChangeActionDelMoveEntry
* pLink
=
3516 pActDel
->AddCutOffMove( pMove
, nFrom
, nTo
);
3517 pMove
->AddLink( pActDel
, pLink
);
3523 // added to avoid warnings
3529 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3530 if ( p
->GetType() == eActType
&& !p
->IsRejected() &&
3531 !pActDel
->IsDeletedIn() &&
3532 p
->GetBigRange().Contains( aDelRange
) )
3533 pActDel
->SetDeletedIn( p
); // Slipped underneath it
3539 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3543 bool bUpdate
= true;
3544 if ( aDelRange
.Contains( p
->GetBigRange() ) )
3546 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3547 if ( GetMergeState() == SC_CTMS_UNDO
&& !p
->IsDeletedIn( pAct
) && pAct
->IsDeleteType() &&
3548 ( p
->GetType() == SC_CAT_CONTENT
||
3549 p
->GetType() == SC_CAT_DELETE_ROWS
|| p
->GetType() == SC_CAT_DELETE_COLS
||
3550 p
->GetType() == SC_CAT_INSERT_ROWS
|| p
->GetType() == SC_CAT_INSERT_COLS
) )
3552 p
->SetDeletedIn( pAct
);
3555 if ( p
->IsDeletedInDelType( eActType
) )
3557 if ( p
->IsDeletedIn( pActDel
) )
3559 if ( p
->GetType() != SC_CAT_CONTENT
||
3560 static_cast<ScChangeActionContent
*>(p
)->IsTopContent() )
3561 { // First really remove the TopContent
3562 p
->RemoveDeletedIn( pActDel
);
3563 // Do NOT delete GeneratedDelContent from the list, we might need
3564 // it later on for Reject; we delete in DeleteCellEntries
3569 else if ( eActType
!= SC_CAT_DELETE_TABS
&&
3570 p
->IsDeletedInDelType( SC_CAT_DELETE_TABS
) )
3571 { // Do not update in deleted Tables except for when moving Tables
3574 if ( p
->GetType() == eActType
&& pActDel
->IsDeletedIn( p
) )
3576 pActDel
->RemoveDeletedIn( p
);// Slipped underneath
3581 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3583 if ( !bGeneratedDelContents
)
3584 { // These are else also needed for the real Undo
3585 pActDel
->UndoCutOffInsert();
3586 pActDel
->UndoCutOffMoves();
3590 else if ( eActType
== SC_CAT_MOVE
)
3592 ScChangeActionMove
* pActMove
= static_cast<ScChangeActionMove
*>(pAct
);
3593 bool bLastCutMove
= ( pActMove
== pLastCutMove
.get() );
3594 const ScBigRange
& rTo
= pActMove
->GetBigRange();
3595 const ScBigRange
& rFrom
= pActMove
->GetFromRange();
3598 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3602 if ( p
->GetType() == SC_CAT_CONTENT
)
3604 // Delete content in Target (Move Content to Source)
3605 if ( rTo
.Contains( p
->GetBigRange() ) )
3607 if ( !p
->IsDeletedIn( pActMove
) )
3609 p
->SetDeletedIn( pActMove
);
3610 // Add GeneratedDelContent to the to-be-deleted list
3611 if ( bGeneratedDelContents
)
3612 pActMove
->AddContent( static_cast<ScChangeActionContent
*>(p
) );
3615 else if ( bLastCutMove
&&
3616 p
->GetActionNumber() > nEndLastCut
&&
3617 rFrom
.Contains( p
->GetBigRange() ) )
3618 { // Paste Cut: insert new Content inserted after stays
3619 // Split up the ContentChain
3620 ScChangeActionContent
*pHere
, *pTmp
;
3621 pHere
= static_cast<ScChangeActionContent
*>(p
);
3624 pTmp
= pHere
->GetPrevContent();
3625 if (!pTmp
|| pTmp
->GetActionNumber() <= nEndLastCut
)
3630 { // Becomes TopContent of the Move
3631 pTmp
->SetNextContent( nullptr );
3632 pHere
->SetPrevContent( nullptr );
3635 { // Recover dependency from FromRange
3636 AddDependentWithNotify( pActMove
, pHere
);
3637 } while ( ( pHere
= pHere
->GetNextContent() ) != nullptr );
3639 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3640 else if ( ( GetMergeState() != SC_CTMS_PREPARE
&& GetMergeState() != SC_CTMS_OWN
) || p
->GetActionNumber() <= pAct
->GetActionNumber() )
3641 p
->UpdateReference( this, eMode
, rFrom
, nDx
, nDy
, nDz
);
3647 bool bActRejected
= pActMove
->IsRejected();
3648 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3652 if ( p
->GetType() == SC_CAT_CONTENT
)
3654 // Move Content into Target if not deleted else to delete (FIXME: What?)
3655 if ( p
->IsDeletedIn( pActMove
) )
3657 if ( static_cast<ScChangeActionContent
*>(p
)->IsTopContent() )
3658 { // First really remove the TopContent
3659 p
->RemoveDeletedIn( pActMove
);
3660 // Do NOT delete GeneratedDelContent from the list, we might need
3661 // it later on for Reject; we delete in DeleteCellEntries
3664 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3665 else if ( ( GetMergeState() != SC_CTMS_PREPARE
&& GetMergeState() != SC_CTMS_OWN
) || p
->GetActionNumber() <= pAct
->GetActionNumber() )
3666 p
->UpdateReference( this, eMode
, rTo
, nDx
, nDy
, nDz
);
3667 if ( bActRejected
&&
3668 static_cast<ScChangeActionContent
*>(p
)->IsTopContent() &&
3669 rFrom
.Contains( p
->GetBigRange() ) )
3670 { // Recover dependency to write Content
3671 ScChangeActionLinkEntry
* pLink
=
3672 pActMove
->AddDependent( p
);
3673 p
->AddLink( pActMove
, pLink
);
3680 { // Insert/Undo Insert
3681 switch ( GetMergeState() )
3684 case SC_CTMS_OTHER
:
3686 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3690 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3694 case SC_CTMS_PREPARE
:
3696 // "Delete" in Insert-Undo
3697 const ScChangeActionLinkEntry
* pLink
= pAct
->GetFirstDependentEntry();
3700 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pLink
->GetAction());
3702 p
->SetDeletedIn( pAct
);
3703 pLink
= pLink
->GetNext();
3706 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3707 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3709 if ( !p
->IsDeletedIn( pAct
) && pAct
->IsInsertType() &&
3710 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3711 ( p
->GetType() == SC_CAT_CONTENT
||
3712 p
->GetType() == SC_CAT_DELETE_ROWS
|| p
->GetType() == SC_CAT_DELETE_COLS
||
3713 p
->GetType() == SC_CAT_INSERT_ROWS
|| p
->GetType() == SC_CAT_INSERT_COLS
) &&
3714 pAct
->GetBigRange().Intersects( p
->GetBigRange() ) )
3716 p
->SetDeletedIn( pAct
);
3720 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3724 if ( !p
->IsDeletedIn( pAct
)
3725 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3726 && p
->GetActionNumber() <= pAct
->GetActionNumber() )
3728 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3735 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3739 if ( !p
->IsDeletedIn( pAct
)
3740 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3741 && p
->GetActionNumber() <= pAct
->GetActionNumber() )
3743 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3746 // Undo "Delete" in Insert-Undo
3747 const ScChangeActionLinkEntry
* pLink
= pAct
->GetFirstDependentEntry();
3750 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pLink
->GetAction());
3752 p
->RemoveDeletedIn( pAct
);
3753 pLink
= pLink
->GetNext();
3756 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3757 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3759 if ( p
->IsDeletedIn( pAct
) && pAct
->IsInsertType() &&
3760 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3761 ( p
->GetType() == SC_CAT_CONTENT
||
3762 p
->GetType() == SC_CAT_DELETE_ROWS
|| p
->GetType() == SC_CAT_DELETE_COLS
||
3763 p
->GetType() == SC_CAT_INSERT_ROWS
|| p
->GetType() == SC_CAT_INSERT_COLS
) &&
3764 pAct
->GetBigRange().Intersects( p
->GetBigRange() ) )
3766 p
->RemoveDeletedIn( pAct
);
3771 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3774 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3776 if ( !p
->IsDeletedIn( pAct
) && pAct
->IsInsertType() &&
3777 ( p
->GetType() == SC_CAT_CONTENT
||
3778 p
->GetType() == SC_CAT_DELETE_ROWS
|| p
->GetType() == SC_CAT_DELETE_COLS
||
3779 p
->GetType() == SC_CAT_INSERT_ROWS
|| p
->GetType() == SC_CAT_INSERT_COLS
) &&
3780 pAct
->GetBigRange().Intersects( p
->GetBigRange() ) )
3782 p
->SetDeletedIn( pAct
);
3786 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3792 if ( !p
->IsDeletedIn( pAct
) && p
->GetActionNumber() <= pAct
->GetActionNumber() )
3794 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3803 void ScChangeTrack::GetDependents( ScChangeAction
* pAct
,
3804 ScChangeActionMap
& rMap
, bool bListMasterDelete
, bool bAllFlat
) const
3806 //TODO: bAllFlat==TRUE: called internally from Accept or Reject
3807 //TODO: => Generated will not be added
3808 bool bIsDelete
= pAct
->IsDeleteType();
3809 bool bIsMasterDelete
= ( bListMasterDelete
&& pAct
->IsMasterDelete() );
3811 const ScChangeAction
* pCur
= nullptr;
3812 ::std::stack
<ScChangeAction
*> cStack
;
3815 while ( !cStack
.empty() )
3817 pCur
= cStack
.top();
3820 if ( pCur
->IsInsertType() )
3822 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDependentEntry();
3825 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pL
->GetAction());
3830 sal_uLong n
= p
->GetActionNumber();
3831 if ( !IsGenerated( n
) && rMap
.insert( ::std::make_pair( n
, p
) ).second
)
3832 if ( p
->HasDependent() )
3837 if ( p
->GetType() == SC_CAT_CONTENT
)
3839 if ( static_cast<ScChangeActionContent
*>(p
)->IsTopContent() )
3840 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3843 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3849 else if ( pCur
->IsDeleteType() )
3852 { // Contents of deleted Ranges are only of interest on Delete
3853 ScChangeActionDel
* pDel
= const_cast<ScChangeActionDel
*>(static_cast<const ScChangeActionDel
*>(pCur
));
3854 if ( !bAllFlat
&& bIsMasterDelete
&& pCur
== pAct
)
3856 // Corresponding Deletes to this Delete to the same level,
3857 // if this Delete is at the top of a Row
3858 ScChangeActionType eType
= pDel
->GetType();
3859 ScChangeAction
* p
= pDel
;
3863 if (!p
|| p
->GetType() != eType
||
3864 static_cast<ScChangeActionDel
*>(p
)->IsTopDelete() )
3866 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3868 // delete this in the map too
3869 rMap
.insert( ::std::make_pair( pAct
->GetActionNumber(), pAct
) );
3873 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDeletedEntry();
3876 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pL
->GetAction());
3881 // Only a TopContent of a chain is in LinkDeleted
3882 sal_uLong n
= p
->GetActionNumber();
3883 if ( !IsGenerated( n
) && rMap
.insert( ::std::make_pair( n
, p
) ).second
)
3884 if ( p
->HasDeleted() ||
3885 p
->GetType() == SC_CAT_CONTENT
)
3890 if ( p
->IsDeleteType() )
3891 { // Further TopDeletes to same level: it's not rejectable
3892 if ( static_cast<ScChangeActionDel
*>(p
)->IsTopDelete() )
3893 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3896 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3904 else if ( pCur
->GetType() == SC_CAT_MOVE
)
3906 // Deleted Contents in ToRange
3907 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDeletedEntry();
3910 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pL
->GetAction());
3911 if ( p
!= pAct
&& rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) ).second
)
3913 // Only one TopContent of a chain is in LinkDeleted
3914 if ( bAllFlat
&& (p
->HasDeleted() ||
3915 p
->GetType() == SC_CAT_CONTENT
) )
3920 // New Contents in FromRange or new FromRange in ToRange
3921 // or Inserts/Deletes in FromRange/ToRange
3922 pL
= pCur
->GetFirstDependentEntry();
3925 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pL
->GetAction());
3930 sal_uLong n
= p
->GetActionNumber();
3931 if ( !IsGenerated( n
) && rMap
.insert( ::std::make_pair( n
, p
) ).second
)
3932 if ( p
->HasDependent() || p
->HasDeleted() )
3937 if ( p
->GetType() == SC_CAT_CONTENT
)
3939 if ( static_cast<ScChangeActionContent
*>(p
)->IsTopContent() )
3940 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3943 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3949 else if ( pCur
->GetType() == SC_CAT_CONTENT
)
3950 { // All changes at same position
3951 ScChangeActionContent
* pContent
= const_cast<ScChangeActionContent
*>(static_cast<const ScChangeActionContent
*>(pCur
));
3952 // All preceding ones
3953 while ( ( pContent
= pContent
->GetPrevContent() ) != nullptr )
3955 if ( !pContent
->IsRejected() )
3956 rMap
.insert( ::std::make_pair( pContent
->GetActionNumber(), pContent
) );
3958 pContent
= const_cast<ScChangeActionContent
*>(static_cast<const ScChangeActionContent
*>(pCur
));
3959 // All succeeding ones
3960 while ( ( pContent
= pContent
->GetNextContent() ) != nullptr )
3962 if ( !pContent
->IsRejected() )
3963 rMap
.insert( ::std::make_pair( pContent
->GetActionNumber(), pContent
) );
3965 // all MatrixReferences of a MatrixOrigin
3966 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDependentEntry();
3969 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pL
->GetAction());
3974 sal_uLong n
= p
->GetActionNumber();
3975 if ( !IsGenerated( n
) && rMap
.insert( ::std::make_pair( n
, p
) ).second
)
3976 if ( p
->HasDependent() )
3980 rMap
.insert( ::std::make_pair( p
->GetActionNumber(), p
) );
3985 else if ( pCur
->GetType() == SC_CAT_REJECT
)
3989 ScChangeAction
* p
= GetAction(
3990 static_cast<const ScChangeActionReject
*>(pCur
)->GetRejectAction() );
3991 if (p
!= pAct
&& rMap
.find( p
->GetActionNumber() ) == rMap
.end())
3998 bool ScChangeTrack::SelectContent( ScChangeAction
* pAct
, bool bOldest
)
4000 if ( pAct
->GetType() != SC_CAT_CONTENT
)
4003 ScChangeActionContent
* pContent
= static_cast<ScChangeActionContent
*>(pAct
);
4006 pContent
= pContent
->GetTopContent();
4009 ScChangeActionContent
* pPrevContent
= pContent
->GetPrevContent();
4010 if ( !pPrevContent
|| !pPrevContent
->IsVirgin() )
4012 pContent
= pPrevContent
;
4016 if ( !pContent
->IsClickable() )
4019 ScBigRange
aBigRange( pContent
->GetBigRange() );
4020 const ScCellValue
& rCell
= (bOldest
? pContent
->GetOldCell() : pContent
->GetNewCell());
4021 if ( ScChangeActionContent::GetContentCellType(rCell
) == SC_CACCT_MATORG
)
4025 rCell
.getFormula()->GetMatColsRows(nC
, nR
);
4026 aBigRange
.aEnd
.IncCol( nC
-1 );
4027 aBigRange
.aEnd
.IncRow( nR
-1 );
4030 if ( !aBigRange
.IsValid( rDoc
) )
4033 ScRange
aRange( aBigRange
.MakeRange( rDoc
) );
4034 if ( !rDoc
.IsBlockEditable( aRange
.aStart
.Tab(), aRange
.aStart
.Col(),
4035 aRange
.aStart
.Row(), aRange
.aEnd
.Col(), aRange
.aEnd
.Row() ) )
4038 if ( pContent
->HasDependent() )
4041 ::std::stack
<ScChangeActionContent
*> aRejectActions
;
4042 const ScChangeActionLinkEntry
* pL
= pContent
->GetFirstDependentEntry();
4045 ScChangeAction
* p
= const_cast<ScChangeAction
*>(pL
->GetAction());
4046 if ( p
!= pContent
)
4048 if ( p
->GetType() == SC_CAT_CONTENT
)
4050 // we don't need no recursion here, do we?
4051 bOk
&= static_cast<ScChangeActionContent
*>(p
)->Select( rDoc
, this,
4052 bOldest
, &aRejectActions
);
4056 OSL_FAIL( "ScChangeTrack::SelectContent: content dependent no content" );
4062 bOk
&= pContent
->Select( rDoc
, this, bOldest
, nullptr );
4063 // now the matrix is inserted and new content values are ready
4065 while ( !aRejectActions
.empty() )
4067 ScChangeActionContent
* pNew
= aRejectActions
.top();
4068 aRejectActions
.pop();
4069 ScAddress
aPos( pNew
->GetBigRange().aStart
.MakeAddress( rDoc
) );
4071 aCell
.assign(rDoc
, aPos
);
4072 pNew
->SetNewValue(aCell
, &rDoc
);
4078 return pContent
->Select( rDoc
, this, bOldest
, nullptr );
4081 void ScChangeTrack::AcceptAll()
4083 for ( ScChangeAction
* p
= GetFirst(); p
; p
= p
->GetNext() )
4089 bool ScChangeTrack::Accept( ScChangeAction
* pAct
)
4091 if ( !pAct
->IsClickable() )
4094 if ( pAct
->IsDeleteType() || pAct
->GetType() == SC_CAT_CONTENT
)
4096 ScChangeActionMap aActionMap
;
4098 GetDependents( pAct
, aActionMap
, false, true );
4100 for( auto& rEntry
: aActionMap
)
4102 rEntry
.second
->Accept();
4109 bool ScChangeTrack::RejectAll()
4112 for ( ScChangeAction
* p
= GetLast(); p
&& bOk
; p
= p
->GetPrev() )
4113 { //TODO: Traverse backwards as dependencies attached to RejectActions
4114 if ( p
->IsInternalRejectable() )
4120 bool ScChangeTrack::Reject( ScChangeAction
* pAct
, bool bShared
)
4122 // #i100895# When collaboration changes are reversed, it must be possible
4123 // to reject a deleted row above another deleted row.
4124 if ( bShared
&& pAct
->IsDeletedIn() )
4125 pAct
->RemoveAllDeletedIn();
4127 if ( !pAct
->IsRejectable() )
4130 std::unique_ptr
<ScChangeActionMap
> pMap
;
4131 if ( pAct
->HasDependent() )
4133 pMap
.reset(new ScChangeActionMap
);
4134 GetDependents( pAct
, *pMap
, false, true );
4136 bool bRejected
= Reject( pAct
, pMap
.get(), false );
4140 bool ScChangeTrack::Reject(
4141 ScChangeAction
* pAct
, ScChangeActionMap
* pMap
, bool bRecursion
)
4143 if ( !pAct
->IsInternalRejectable() )
4147 bool bRejected
= false;
4148 if ( pAct
->IsInsertType() )
4150 if ( pAct
->HasDependent() && !bRecursion
)
4152 OSL_ENSURE( pMap
, "ScChangeTrack::Reject: Insert without map" );
4153 ScChangeActionMap::reverse_iterator itChangeAction
;
4154 for (itChangeAction
= pMap
->rbegin();
4155 itChangeAction
!= pMap
->rend() && bOk
; ++itChangeAction
)
4157 // Do not restore Contents which would end up being deleted anyways
4158 if ( itChangeAction
->second
->GetType() == SC_CAT_CONTENT
)
4159 itChangeAction
->second
->SetRejected();
4160 else if ( itChangeAction
->second
->IsDeleteType() )
4161 itChangeAction
->second
->Accept(); // Deleted to Nirvana
4163 bOk
= Reject( itChangeAction
->second
, nullptr, true ); // Recursion!
4168 bRejected
= pAct
->Reject( rDoc
);
4171 // pRefDoc NULL := Do not save deleted Cells
4172 AppendDeleteRange( pAct
->GetBigRange().MakeRange( rDoc
), nullptr, short(0),
4173 pAct
->GetActionNumber() );
4177 else if ( pAct
->IsDeleteType() )
4179 OSL_ENSURE( !pMap
, "ScChangeTrack::Reject: Delete with map" );
4180 ScBigRange aDelRange
;
4181 sal_uLong nRejectAction
= pAct
->GetActionNumber();
4182 bool bTabDel
, bTabDelOk
;
4183 if ( pAct
->GetType() == SC_CAT_DELETE_TABS
)
4186 aDelRange
= pAct
->GetBigRange();
4187 bTabDelOk
= pAct
->Reject( rDoc
);
4191 pAct
= pAct
->GetPrev();
4192 bOk
= ( pAct
&& pAct
->GetType() == SC_CAT_DELETE_COLS
);
4196 bTabDel
= bTabDelOk
= false;
4197 ScChangeActionDel
* pDel
= static_cast<ScChangeActionDel
*>(pAct
);
4200 aDelRange
= pDel
->GetOverAllRange();
4201 bOk
= aDelRange
.IsValid( rDoc
);
4203 bool bOneOk
= false;
4206 ScChangeActionType eActType
= pAct
->GetType();
4209 case SC_CAT_DELETE_COLS
:
4210 aDelRange
.aStart
.SetCol( aDelRange
.aEnd
.Col() );
4212 case SC_CAT_DELETE_ROWS
:
4213 aDelRange
.aStart
.SetRow( aDelRange
.aEnd
.Row() );
4215 case SC_CAT_DELETE_TABS
:
4216 aDelRange
.aStart
.SetTab( aDelRange
.aEnd
.Tab() );
4220 // added to avoid warnings
4223 ScChangeAction
* p
= pAct
;
4227 pDel
= static_cast<ScChangeActionDel
*>(p
);
4228 bOk
= pDel
->Reject( rDoc
);
4233 switch ( pDel
->GetType() )
4235 case SC_CAT_DELETE_COLS
:
4236 aDelRange
.aStart
.IncCol( -1 );
4238 case SC_CAT_DELETE_ROWS
:
4239 aDelRange
.aStart
.IncRow( -1 );
4241 case SC_CAT_DELETE_TABS
:
4242 aDelRange
.aStart
.IncTab( -1 );
4246 // added to avoid warnings
4253 if ( pDel
->IsBaseDelete() )
4257 } while ( bOk
&& bLoop
&& p
&& p
->GetType() == eActType
&&
4258 !static_cast<ScChangeActionDel
*>(p
)->IsTopDelete() );
4261 if ( bOneOk
|| (bTabDel
&& bTabDelOk
) )
4263 // Delete Reject made UpdateReference Undo
4264 ScChangeActionIns
* pReject
= new ScChangeActionIns( &rDoc
,
4265 aDelRange
.MakeRange( rDoc
) );
4266 pReject
->SetRejectAction( nRejectAction
);
4267 pReject
->SetState( SC_CAS_ACCEPTED
);
4271 else if ( pAct
->GetType() == SC_CAT_MOVE
)
4273 if ( pAct
->HasDependent() && !bRecursion
)
4275 OSL_ENSURE( pMap
, "ScChangeTrack::Reject: Move without Map" );
4276 ScChangeActionMap::reverse_iterator itChangeAction
;
4278 for( itChangeAction
= pMap
->rbegin(); itChangeAction
!= pMap
->rend() && bOk
; ++itChangeAction
)
4280 bOk
= Reject( itChangeAction
->second
, nullptr, true ); // Recursion!
4285 bRejected
= pAct
->Reject( rDoc
);
4288 ScChangeActionMove
* pReject
= new ScChangeActionMove(
4289 pAct
->GetBigRange().MakeRange( rDoc
),
4290 static_cast<ScChangeActionMove
*>(pAct
)->GetFromRange().MakeRange( rDoc
), this );
4291 pReject
->SetRejectAction( pAct
->GetActionNumber() );
4292 pReject
->SetState( SC_CAS_ACCEPTED
);
4297 else if ( pAct
->GetType() == SC_CAT_CONTENT
)
4300 ScChangeActionContent
* pReject
;
4305 aRange
= pAct
->GetBigRange().aStart
.MakeAddress( rDoc
);
4306 pReject
= new ScChangeActionContent( aRange
);
4308 aCell
.assign(rDoc
, aRange
.aStart
);
4309 pReject
->SetOldValue(aCell
, &rDoc
, &rDoc
);
4311 bRejected
= pAct
->Reject( rDoc
);
4312 if ( bRejected
&& !bRecursion
)
4315 aCell
.assign(rDoc
, aRange
.aStart
);
4316 pReject
->SetNewValue(aCell
, &rDoc
);
4317 pReject
->SetRejectAction( pAct
->GetActionNumber() );
4318 pReject
->SetState( SC_CAS_ACCEPTED
);
4326 OSL_FAIL( "ScChangeTrack::Reject: say what?" );
4332 bool ScChangeTrack::IsLastAction( sal_uLong nNum
) const
4334 return nNum
== nActionMax
&& pLast
&& pLast
->GetActionNumber() == nNum
;
4337 sal_uLong
ScChangeTrack::AddLoadedGenerated(
4338 const ScCellValue
& rNewCell
, const ScBigRange
& aBigRange
, const OUString
& sNewValue
)
4340 ScChangeActionContent
* pAct
= new ScChangeActionContent( --nGeneratedMin
, rNewCell
, aBigRange
, &rDoc
, sNewValue
);
4341 if ( pFirstGeneratedDelContent
)
4342 pFirstGeneratedDelContent
->pPrev
= pAct
;
4343 pAct
->pNext
= pFirstGeneratedDelContent
;
4344 pFirstGeneratedDelContent
= pAct
;
4345 aGeneratedMap
.insert( ::std::make_pair( pAct
->GetActionNumber(), pAct
) );
4346 return pAct
->GetActionNumber();
4349 void ScChangeTrack::AppendCloned( ScChangeAction
* pAppend
)
4351 aMap
.insert( ::std::make_pair( pAppend
->GetActionNumber(), pAppend
) );
4353 pFirst
= pLast
= pAppend
;
4356 pLast
->pNext
= pAppend
;
4357 pAppend
->pPrev
= pLast
;
4362 ScChangeTrack
* ScChangeTrack::Clone( ScDocument
* pDocument
) const
4369 std::unique_ptr
<ScChangeTrack
> pClonedTrack(new ScChangeTrack( *pDocument
));
4370 pClonedTrack
->SetTimeNanoSeconds( IsTimeNanoSeconds() );
4372 // clone generated actions
4373 ::std::stack
< const ScChangeAction
* > aGeneratedStack
;
4374 const ScChangeAction
* pGenerated
= GetFirstGenerated();
4375 while ( pGenerated
)
4377 aGeneratedStack
.push( pGenerated
);
4378 pGenerated
= pGenerated
->GetNext();
4380 while ( !aGeneratedStack
.empty() )
4382 pGenerated
= aGeneratedStack
.top();
4383 aGeneratedStack
.pop();
4384 const ScChangeActionContent
& rContent
= dynamic_cast<const ScChangeActionContent
&>(*pGenerated
);
4385 const ScCellValue
& rNewCell
= rContent
.GetNewCell();
4386 if (!rNewCell
.isEmpty())
4388 ScCellValue aClonedNewCell
;
4389 aClonedNewCell
.assign(rNewCell
, *pDocument
);
4390 OUString aNewValue
= rContent
.GetNewString( pDocument
);
4391 pClonedTrack
->nGeneratedMin
= pGenerated
->GetActionNumber() + 1;
4392 pClonedTrack
->AddLoadedGenerated(aClonedNewCell
, pGenerated
->GetBigRange(), aNewValue
);
4397 const ScChangeAction
* pAction
= GetFirst();
4400 ScChangeAction
* pClonedAction
= nullptr;
4402 switch ( pAction
->GetType() )
4404 case SC_CAT_INSERT_COLS
:
4405 case SC_CAT_INSERT_ROWS
:
4406 case SC_CAT_INSERT_TABS
:
4408 bool bEndOfList
= static_cast<const ScChangeActionIns
*>(pAction
)->IsEndOfList();
4409 pClonedAction
= new ScChangeActionIns(
4410 pAction
->GetActionNumber(),
4411 pAction
->GetState(),
4412 pAction
->GetRejectAction(),
4413 pAction
->GetBigRange(),
4415 pAction
->GetDateTimeUTC(),
4416 pAction
->GetComment(),
4421 case SC_CAT_DELETE_COLS
:
4422 case SC_CAT_DELETE_ROWS
:
4423 case SC_CAT_DELETE_TABS
:
4425 const ScChangeActionDel
& rDelete
= dynamic_cast<const ScChangeActionDel
&>(*pAction
);
4428 ScChangeActionType eType
= pAction
->GetType();
4429 if ( eType
== SC_CAT_DELETE_COLS
)
4431 nD
= static_cast< SCCOLROW
>( rDelete
.GetDx() );
4433 else if ( eType
== SC_CAT_DELETE_ROWS
)
4435 nD
= static_cast< SCCOLROW
>( rDelete
.GetDy() );
4438 pClonedAction
= new ScChangeActionDel(
4439 pAction
->GetActionNumber(),
4440 pAction
->GetState(),
4441 pAction
->GetRejectAction(),
4442 pAction
->GetBigRange(),
4444 pAction
->GetDateTimeUTC(),
4445 pAction
->GetComment(),
4448 pClonedTrack
.get() );
4453 auto pMove
= dynamic_cast<const ScChangeActionMove
*>(pAction
);
4454 assert(pMove
&& "ScChangeTrack::Clone: pMove is null!");
4456 pClonedAction
= new ScChangeActionMove(
4457 pAction
->GetActionNumber(),
4458 pAction
->GetState(),
4459 pAction
->GetRejectAction(),
4460 pAction
->GetBigRange(),
4462 pAction
->GetDateTimeUTC(),
4463 pAction
->GetComment(),
4464 pMove
->GetFromRange(),
4465 pClonedTrack
.get() );
4468 case SC_CAT_CONTENT
:
4470 const ScChangeActionContent
& rContent
= dynamic_cast<const ScChangeActionContent
&>(*pAction
);
4471 const ScCellValue
& rOldCell
= rContent
.GetOldCell();
4472 ScCellValue aClonedOldCell
;
4473 aClonedOldCell
.assign(rOldCell
, *pDocument
);
4474 OUString aOldValue
= rContent
.GetOldString( pDocument
);
4476 ScChangeActionContent
* pClonedContent
= new ScChangeActionContent(
4477 pAction
->GetActionNumber(),
4478 pAction
->GetState(),
4479 pAction
->GetRejectAction(),
4480 pAction
->GetBigRange(),
4482 pAction
->GetDateTimeUTC(),
4483 pAction
->GetComment(),
4484 std::move(aClonedOldCell
),
4488 const ScCellValue
& rNewCell
= rContent
.GetNewCell();
4489 if (!rNewCell
.isEmpty())
4491 ScCellValue aClonedNewCell
;
4492 aClonedNewCell
.assign(rNewCell
, *pDocument
);
4493 pClonedContent
->SetNewValue(aClonedNewCell
, pDocument
);
4496 pClonedAction
= pClonedContent
;
4501 pClonedAction
= new ScChangeActionReject(
4502 pAction
->GetActionNumber(),
4503 pAction
->GetState(),
4504 pAction
->GetRejectAction(),
4505 pAction
->GetBigRange(),
4507 pAction
->GetDateTimeUTC(),
4508 pAction
->GetComment() );
4517 if ( pClonedAction
)
4519 pClonedTrack
->AppendCloned( pClonedAction
);
4522 pAction
= pAction
->GetNext();
4525 if ( pClonedTrack
->GetLast() )
4527 pClonedTrack
->SetActionMax( pClonedTrack
->GetLast()->GetActionNumber() );
4530 // set dependencies for Deleted/DeletedIn
4531 pAction
= GetFirst();
4534 if ( pAction
->HasDeleted() )
4536 ::std::stack
< sal_uLong
> aStack
;
4537 const ScChangeActionLinkEntry
* pL
= pAction
->GetFirstDeletedEntry();
4540 const ScChangeAction
* pDeleted
= pL
->GetAction();
4543 aStack
.push( pDeleted
->GetActionNumber() );
4547 ScChangeAction
* pClonedAction
= pClonedTrack
->GetAction( pAction
->GetActionNumber() );
4548 if ( pClonedAction
)
4550 while ( !aStack
.empty() )
4552 ScChangeAction
* pClonedDeleted
= pClonedTrack
->GetActionOrGenerated( aStack
.top() );
4554 if ( pClonedDeleted
)
4556 pClonedDeleted
->SetDeletedIn( pClonedAction
);
4561 pAction
= pAction
->GetNext();
4564 // set dependencies for Dependent/Any
4565 pAction
= GetLast();
4568 if ( pAction
->HasDependent() )
4570 ::std::stack
< sal_uLong
> aStack
;
4571 const ScChangeActionLinkEntry
* pL
= pAction
->GetFirstDependentEntry();
4574 const ScChangeAction
* pDependent
= pL
->GetAction();
4577 aStack
.push( pDependent
->GetActionNumber() );
4581 ScChangeAction
* pClonedAction
= pClonedTrack
->GetAction( pAction
->GetActionNumber() );
4582 if ( pClonedAction
)
4584 while ( !aStack
.empty() )
4586 ScChangeAction
* pClonedDependent
= pClonedTrack
->GetActionOrGenerated( aStack
.top() );
4588 if ( pClonedDependent
)
4590 ScChangeActionLinkEntry
* pLink
= pClonedAction
->AddDependent( pClonedDependent
);
4591 pClonedDependent
->AddLink( pClonedAction
, pLink
);
4596 pAction
= pAction
->GetPrev();
4600 ScChangeAction
* pClonedAction
= pClonedTrack
->GetFirst();
4601 while ( pClonedAction
)
4603 pClonedTrack
->MasterLinks( pClonedAction
);
4604 pClonedAction
= pClonedAction
->GetNext();
4607 if ( IsProtected() )
4609 pClonedTrack
->SetProtection( GetProtection() );
4612 if ( pClonedTrack
->GetLast() )
4614 pClonedTrack
->SetLastSavedActionNumber( pClonedTrack
->GetLast()->GetActionNumber() );
4617 auto tmp
= pClonedTrack
.get();
4618 pDocument
->SetChangeTrack( std::move(pClonedTrack
) );
4623 void ScChangeTrack::MergeActionState( ScChangeAction
* pAct
, const ScChangeAction
* pOtherAct
)
4625 if ( !pAct
->IsVirgin() )
4628 if ( pOtherAct
->IsAccepted() )
4631 if ( pOtherAct
->IsRejecting() )
4633 pAct
->SetRejectAction( pOtherAct
->GetRejectAction() );
4636 else if ( pOtherAct
->IsRejected() )
4638 pAct
->SetRejected();
4642 /// Get info about a single ScChangeAction element.
4643 static void lcl_getTrackedChange(ScDocument
& rDoc
, int nIndex
, const ScChangeAction
* pAction
, tools::JsonWriter
& rRedlines
)
4645 if (pAction
->GetType() != SC_CAT_CONTENT
)
4648 auto redlinesNode
= rRedlines
.startStruct();
4649 rRedlines
.put("index", static_cast<sal_Int64
>(nIndex
));
4651 rRedlines
.put("author", pAction
->GetUser());
4653 rRedlines
.put("type", "Modify");
4655 rRedlines
.put("comment", pAction
->GetComment());
4657 OUString aDescription
= pAction
->GetDescription(rDoc
, true);
4658 rRedlines
.put("description", aDescription
);
4660 OUString sDateTime
= utl::toISO8601(pAction
->GetDateTimeUTC().GetUNODateTime());
4661 rRedlines
.put("dateTime", sDateTime
);
4664 void ScChangeTrack::GetChangeTrackInfo(tools::JsonWriter
& aRedlines
)
4666 auto redlinesNode
= aRedlines
.startArray("redlines");
4668 ScChangeAction
* pAction
= GetFirst();
4672 lcl_getTrackedChange(rDoc
, i
++, pAction
, aRedlines
);
4673 ScChangeAction
* pLastAction
= GetLast();
4674 while (pAction
!= pLastAction
)
4676 pAction
= pAction
->GetNext();
4677 lcl_getTrackedChange(rDoc
, i
++, pAction
, aRedlines
);
4682 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */