summaryrefslogtreecommitdiffstats
path: root/sc/inc/chgtrack.hxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sc/inc/chgtrack.hxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sc/inc/chgtrack.hxx')
-rw-r--r--sc/inc/chgtrack.hxx1142
1 files changed, 1142 insertions, 0 deletions
diff --git a/sc/inc/chgtrack.hxx b/sc/inc/chgtrack.hxx
new file mode 100644
index 000000000..6cbb7a0d8
--- /dev/null
+++ b/sc/inc/chgtrack.hxx
@@ -0,0 +1,1142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <set>
+#include <stack>
+#include <vector>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <tools/color.hxx>
+#include <tools/datetime.hxx>
+#include <tools/link.hxx>
+#include <tools/solar.h>
+#include <unotools/options.hxx>
+#include <optional>
+#include "global.hxx"
+#include "bigrange.hxx"
+#include "scdllapi.h"
+#include "cellvalue.hxx"
+
+class ScDocument;
+class ScFormulaCell;
+class ScChangeAction;
+class ScChangeTrack;
+class ScAppOptions;
+namespace tools { class JsonWriter; }
+
+class ScActionColorChanger
+{
+private:
+ const ScAppOptions& rOpt;
+ const std::set<OUString>& rUsers;
+ OUString aLastUserName;
+ sal_uInt16 nLastUserIndex;
+ Color nColor;
+
+public:
+ ScActionColorChanger( const ScChangeTrack& rTrack );
+ void Update( const ScChangeAction& rAction );
+ Color GetColor() const { return nColor; }
+};
+
+enum ScChangeActionType
+{
+ SC_CAT_NONE,
+ SC_CAT_INSERT_COLS,
+ SC_CAT_INSERT_ROWS,
+ SC_CAT_INSERT_TABS,
+ SC_CAT_DELETE_COLS,
+ SC_CAT_DELETE_ROWS,
+ SC_CAT_DELETE_TABS,
+ SC_CAT_MOVE,
+ SC_CAT_CONTENT,
+ SC_CAT_REJECT
+};
+
+enum ScChangeActionState
+{
+ SC_CAS_VIRGIN,
+ SC_CAS_ACCEPTED,
+ SC_CAS_REJECTED
+};
+
+enum ScChangeActionClipMode
+{
+ SC_CACM_NONE,
+ SC_CACM_CUT,
+ SC_CACM_PASTE
+};
+
+/** A link/connection/dependency between change actions.
+
+ Upon construction inserts itself as the head of a chain / linked list,
+ respectively between existing link entries.
+
+ Upon destruction removes itself from the list and connects the previous and
+ next entry, if it was the first entry automatically maintaining the head
+ pointer to the list.
+
+ ppPrev == &previous->pNext or address of pointer to head of linked list,
+ *ppPrev == this
+ */
+class ScChangeActionLinkEntry
+{
+ ScChangeActionLinkEntry( const ScChangeActionLinkEntry& ) = delete;
+ ScChangeActionLinkEntry& operator=( const ScChangeActionLinkEntry& ) = delete;
+
+protected:
+
+ ScChangeActionLinkEntry* pNext;
+ ScChangeActionLinkEntry** ppPrev;
+ ScChangeAction* pAction;
+ ScChangeActionLinkEntry* pLink;
+
+public:
+
+ ScChangeActionLinkEntry(
+ ScChangeActionLinkEntry** ppPrevP,
+ ScChangeAction* pActionP )
+ : pNext( *ppPrevP ),
+ ppPrev( ppPrevP ),
+ pAction( pActionP ),
+ pLink( nullptr )
+ {
+ if ( pNext )
+ pNext->ppPrev = &pNext;
+ *ppPrevP = this;
+ }
+
+ virtual ~ScChangeActionLinkEntry()
+ {
+ ScChangeActionLinkEntry* p = pLink;
+ UnLink();
+ Remove();
+ if ( p )
+ delete p;
+ }
+
+ void SetLink( ScChangeActionLinkEntry* pLinkP )
+ {
+ UnLink();
+ if ( pLinkP )
+ {
+ pLink = pLinkP;
+ pLinkP->pLink = this;
+ }
+ }
+
+ void UnLink()
+ {
+ if ( pLink )
+ {
+ pLink->pLink = nullptr;
+ pLink = nullptr;
+ }
+ }
+
+ void Remove()
+ {
+ if ( ppPrev )
+ {
+ if ( ( *ppPrev = pNext ) != nullptr )
+ pNext->ppPrev = ppPrev;
+ ppPrev = nullptr; // not inserted
+ }
+ }
+
+ const ScChangeActionLinkEntry* GetNext() const { return pNext; }
+ ScChangeActionLinkEntry* GetNext() { return pNext; }
+ const ScChangeAction* GetAction() const { return pAction; }
+ ScChangeAction* GetAction() { return pAction; }
+};
+
+// ScChangeActionCellListEntry
+// this is only for the XML Export in the hxx
+class ScChangeActionContent;
+
+class SAL_DLLPUBLIC_RTTI ScChangeAction
+{
+ friend class ScChangeTrack;
+ friend class ScChangeActionIns;
+ friend class ScChangeActionDel;
+ friend class ScChangeActionMove;
+ friend class ScChangeActionContent;
+
+ ScChangeAction( const ScChangeAction& ) = delete;
+ ScChangeAction& operator=( const ScChangeAction& ) = delete;
+
+protected:
+
+ ScBigRange aBigRange; // Ins/Del/MoveTo/ContentPos
+ DateTime aDateTime; //! UTC
+ OUString aUser; // who?
+ OUString aComment; // user comment
+ ScChangeAction* pNext; // next in linked list
+ ScChangeAction* pPrev; // previous in linked list
+ ScChangeActionLinkEntry* pLinkAny; // arbitrary links
+ ScChangeActionLinkEntry* pLinkDeletedIn; // access to insert areas which were
+ // deleted or moved or rejected
+ ScChangeActionLinkEntry* pLinkDeleted; // links to deleted
+ ScChangeActionLinkEntry* pLinkDependent; // links to dependent
+ sal_uLong nAction;
+ sal_uLong nRejectAction;
+ ScChangeActionType eType;
+ ScChangeActionState eState;
+
+ ScChangeAction( ScChangeActionType, const ScRange& );
+
+ // only to be used in the XML import
+ ScChangeAction( ScChangeActionType,
+ const ScBigRange&,
+ const sal_uLong nAction,
+ const sal_uLong nRejectAction,
+ const ScChangeActionState eState,
+ const DateTime& aDateTime,
+ const OUString& aUser,
+ const OUString& aComment );
+
+ // only to be used in the XML import
+ ScChangeAction( ScChangeActionType, const ScBigRange&, const sal_uLong nAction);
+
+ OUString GetRefString(
+ const ScBigRange& rRange, const ScDocument& rDoc, bool bFlag3D = false) const;
+
+ void SetActionNumber( sal_uLong n ) { nAction = n; }
+ void SetRejectAction( sal_uLong n ) { nRejectAction = n; }
+ void SetUser( const OUString& r );
+ void SetType( ScChangeActionType e ) { eType = e; }
+ void SetState( ScChangeActionState e ) { eState = e; }
+ void SetRejected();
+
+ ScBigRange& GetBigRange() { return aBigRange; }
+
+ void AddLink( ScChangeAction* p, ScChangeActionLinkEntry* pL )
+ {
+ ScChangeActionLinkEntry* pLnk =
+ new ScChangeActionLinkEntry(
+ &pLinkAny, p );
+ pLnk->SetLink( pL );
+ }
+
+ virtual ScChangeActionLinkEntry* GetDeletedIn() const
+ { return pLinkDeletedIn; }
+ virtual ScChangeActionLinkEntry** GetDeletedInAddress()
+ { return &pLinkDeletedIn; }
+ bool RemoveDeletedIn( const ScChangeAction* );
+ void SetDeletedIn( ScChangeAction* );
+
+ ScChangeActionLinkEntry* AddDeleted( ScChangeAction* p )
+ {
+ return new ScChangeActionLinkEntry(&pLinkDeleted, p);
+ }
+
+ ScChangeActionLinkEntry* AddDependent( ScChangeAction* p )
+ {
+ return new ScChangeActionLinkEntry(&pLinkDependent, p);
+ }
+
+ void RemoveAllDependent();
+
+ void RemoveAllLinks();
+
+ virtual void AddContent( ScChangeActionContent* ) = 0;
+ virtual void DeleteCellEntries() = 0;
+
+ virtual void UpdateReference( const ScChangeTrack*,
+ UpdateRefMode, const ScBigRange&,
+ sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz );
+
+ void Accept();
+ virtual bool Reject(ScDocument& rDoc) = 0;
+ void RejectRestoreContents( ScChangeTrack*, SCCOL nDx, SCROW nDy );
+
+ // used in Reject() instead of IsRejectable()
+ bool IsInternalRejectable() const;
+
+ // Derived classes that hold a pointer to the
+ // ChangeTrack must return that. Otherwise NULL.
+ virtual const ScChangeTrack* GetChangeTrack() const = 0;
+
+public:
+ virtual ~ScChangeAction();
+
+ bool IsInsertType() const;
+ bool IsDeleteType() const;
+ bool IsVirgin() const;
+ SC_DLLPUBLIC bool IsAccepted() const;
+ bool IsRejected() const;
+
+ // Action rejects another Action
+ bool IsRejecting() const;
+
+ // if action is visible in the document
+ bool IsVisible() const;
+
+ // if action if touchable
+ bool IsTouchable() const;
+
+ // if action is an entry in dialog root
+ bool IsDialogRoot() const;
+
+ // if an entry in a dialog shall be a drop down entry
+ bool IsDialogParent() const;
+
+ // if action is a delete with subdeletes (aufgeklappt = open ?)
+ bool IsMasterDelete() const;
+
+ // if action is acceptable/selectable/rejectable
+ bool IsClickable() const;
+
+ // if action is rejectable
+ bool IsRejectable() const;
+
+ const ScBigRange& GetBigRange() const { return aBigRange; }
+ SC_DLLPUBLIC DateTime GetDateTime() const; // local time
+ const DateTime& GetDateTimeUTC() const // UTC time
+ { return aDateTime; }
+ ScChangeActionType GetType() const { return eType; }
+ ScChangeActionState GetState() const { return eState; }
+ sal_uLong GetActionNumber() const { return nAction; }
+ sal_uLong GetRejectAction() const { return nRejectAction; }
+
+ ScChangeAction* GetNext() const { return pNext; }
+ ScChangeAction* GetPrev() const { return pPrev; }
+
+ bool IsDeletedIn() const;
+ bool IsDeletedIn( const ScChangeAction* ) const;
+ bool IsDeletedInDelType( ScChangeActionType ) const;
+ void RemoveAllDeletedIn();
+
+ const ScChangeActionLinkEntry* GetFirstDeletedEntry() const
+ { return pLinkDeleted; }
+ const ScChangeActionLinkEntry* GetFirstDependentEntry() const
+ { return pLinkDependent; }
+ bool HasDependent() const;
+ bool HasDeleted() const;
+ // description will be appended to string
+ // with bSplitRange only one column/row will be considered for delete
+ // (for a listing of entries)
+ virtual OUString GetDescription(
+ ScDocument& rDoc, bool bSplitRange = false, bool bWarning = true ) const;
+
+ virtual OUString GetRefString( ScDocument& rDoc, bool bFlag3D = false ) const;
+
+ // for DocumentMerge set old date of the other
+ // action, fetched by GetDateTimeUTC
+ void SetDateTimeUTC( const DateTime& rDT )
+ { aDateTime = rDT; }
+
+ const OUString& GetUser() const { return aUser;}
+ const OUString& GetComment() const { return aComment;}
+
+ // set user comment
+ void SetComment( const OUString& rStr );
+
+ // only to be used in the XML import
+ void SetDeletedInThis( sal_uLong nActionNumber,
+ const ScChangeTrack* pTrack );
+ // only to be used in the XML import
+ void AddDependent( sal_uLong nActionNumber,
+ const ScChangeTrack* pTrack );
+};
+
+// ScChangeActionIns
+class SAL_DLLPUBLIC_RTTI ScChangeActionIns final : public ScChangeAction
+{
+ friend class ScChangeTrack;
+
+ bool mbEndOfList; /// whether or not a row was auto-inserted at the bottom.
+
+ ScChangeActionIns( const ScDocument* pDoc, const ScRange& rRange, bool bEndOfList = false );
+
+ virtual void AddContent( ScChangeActionContent* ) override {}
+ virtual void DeleteCellEntries() override {}
+
+ virtual bool Reject(ScDocument& rDoc) override;
+
+ virtual const ScChangeTrack* GetChangeTrack() const override { return nullptr; }
+
+public:
+ virtual ~ScChangeActionIns() override;
+ ScChangeActionIns(
+ const sal_uLong nActionNumber,
+ const ScChangeActionState eState,
+ const sal_uLong nRejectingNumber,
+ const ScBigRange& aBigRange,
+ const OUString& aUser,
+ const DateTime& aDateTime,
+ const OUString &sComment,
+ const ScChangeActionType eType,
+ bool bEndOfList = false );
+
+ virtual OUString GetDescription(
+ ScDocument& rDoc, bool bSplitRange = false, bool bWarning = true) const override;
+
+ SC_DLLPUBLIC bool IsEndOfList() const;
+};
+
+// ScChangeActionDel
+class SAL_DLLPUBLIC_RTTI ScChangeActionMove;
+
+class ScChangeActionDelMoveEntry final : public ScChangeActionLinkEntry
+{
+ friend class ScChangeActionDel;
+ friend class ScChangeTrack;
+
+ short nCutOffFrom;
+ short nCutOffTo;
+
+ inline ScChangeActionDelMoveEntry(
+ ScChangeActionDelMoveEntry** ppPrevP,
+ ScChangeActionMove* pMove,
+ short nFrom, short nTo );
+
+ inline ScChangeActionMove* GetMove();
+
+public:
+ const ScChangeActionDelMoveEntry* GetNext() const
+ {
+ return static_cast<const ScChangeActionDelMoveEntry*>(
+ ScChangeActionLinkEntry::GetNext());
+ }
+ inline const ScChangeActionMove* GetMove() const;
+ short GetCutOffFrom() const { return nCutOffFrom; }
+ short GetCutOffTo() const { return nCutOffTo; }
+};
+
+class ScChangeActionDel final : public ScChangeAction
+{
+ friend class ScChangeTrack;
+ friend void ScChangeAction::Accept();
+
+ ScChangeTrack* pTrack;
+ std::vector<ScChangeActionContent*> mvCells;
+ ScChangeActionIns* pCutOff; // cut insert
+ short nCutOff; // +: start -: end
+ ScChangeActionDelMoveEntry* pLinkMove;
+ SCCOL nDx;
+ SCROW nDy;
+
+ ScChangeActionDel( const ScDocument* pDoc, const ScRange& rRange, SCCOL nDx, SCROW nDy, ScChangeTrack* );
+
+ virtual void AddContent( ScChangeActionContent* ) override;
+ virtual void DeleteCellEntries() override;
+
+ void UndoCutOffMoves();
+ void UndoCutOffInsert();
+
+ virtual void UpdateReference( const ScChangeTrack*,
+ UpdateRefMode, const ScBigRange&,
+ sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) override;
+
+ virtual bool Reject(ScDocument& rDoc) override;
+
+ virtual const ScChangeTrack* GetChangeTrack() const override { return pTrack; }
+
+public:
+ ScChangeActionDel(
+ const sal_uLong nActionNumber, const ScChangeActionState eState,
+ const sal_uLong nRejectingNumber, const ScBigRange& aBigRange,
+ const OUString& aUser, const DateTime& aDateTime,
+ const OUString &sComment, const ScChangeActionType eType,
+ const SCCOLROW nD, ScChangeTrack* pTrack); // only to use in the XML import
+ // which of nDx and nDy is set is dependent on the type
+ virtual ~ScChangeActionDel() override;
+
+ // is the last in a row (or single)
+ bool IsBaseDelete() const;
+
+ // is the first in a row (or single)
+ bool IsTopDelete() const;
+
+ // is part of a row
+ bool IsMultiDelete() const;
+
+ // is col, belonging to a TabDelete
+ bool IsTabDeleteCol() const;
+
+ SCCOL GetDx() const { return nDx; }
+ SCROW GetDy() const { return nDy; }
+ ScBigRange GetOverAllRange() const; // BigRange + (nDx, nDy)
+
+ const ScChangeActionDelMoveEntry* GetFirstMoveEntry() const
+ { return pLinkMove; }
+ const ScChangeActionIns* GetCutOffInsert() const { return pCutOff; }
+ short GetCutOffCount() const { return nCutOff; }
+
+ virtual OUString GetDescription(
+ ScDocument& rDoc, bool bSplitRange = false, bool bWarning = true ) const override;
+
+ void SetCutOffInsert( ScChangeActionIns* p, short n )
+ { pCutOff = p; nCutOff = n; } // only to use in the XML import
+ // this should be protected, but for the XML import it is public
+ // only to use in the XML import
+ // this should be protected, but for the XML import it is public
+ ScChangeActionDelMoveEntry* AddCutOffMove(
+ ScChangeActionMove* pMove, short nFrom, short nTo );
+};
+
+// ScChangeActionMove
+class ScChangeActionMove final : public ScChangeAction
+{
+ friend class ScChangeTrack;
+ friend struct std::default_delete<ScChangeActionMove>; // for std::unique_ptr
+ friend class ScChangeActionDel;
+
+ ScBigRange aFromRange;
+ ScChangeTrack* pTrack;
+ std::vector<ScChangeActionContent*> mvCells;
+ sal_uLong nStartLastCut; // for PasteCut undo
+ sal_uLong nEndLastCut;
+
+ ScChangeActionMove( const ScRange& rFromRange,
+ const ScRange& rToRange,
+ ScChangeTrack* pTrackP )
+ : ScChangeAction( SC_CAT_MOVE, rToRange ),
+ aFromRange( rFromRange ),
+ pTrack( pTrackP ),
+ nStartLastCut(0),
+ nEndLastCut(0)
+ {}
+ virtual ~ScChangeActionMove() override;
+
+ virtual void AddContent( ScChangeActionContent* ) override;
+ virtual void DeleteCellEntries() override;
+
+ ScBigRange& GetFromRange() { return aFromRange; }
+
+ void SetStartLastCut( sal_uLong nVal ) { nStartLastCut = nVal; }
+ sal_uLong GetStartLastCut() const { return nStartLastCut; }
+ void SetEndLastCut( sal_uLong nVal ) { nEndLastCut = nVal; }
+ sal_uLong GetEndLastCut() const { return nEndLastCut; }
+
+ virtual void UpdateReference( const ScChangeTrack*,
+ UpdateRefMode, const ScBigRange&,
+ sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) override;
+
+ virtual bool Reject(ScDocument& rDoc) override;
+
+ virtual const ScChangeTrack* GetChangeTrack() const override { return pTrack; }
+
+protected:
+ using ScChangeAction::GetRefString;
+
+public:
+ ScChangeActionMove(const sal_uLong nActionNumber,
+ const ScChangeActionState eState,
+ const sal_uLong nRejectingNumber,
+ const ScBigRange& aToBigRange,
+ const OUString& aUser,
+ const DateTime& aDateTime,
+ const OUString &sComment,
+ const ScBigRange& aFromBigRange,
+ ScChangeTrack* pTrack); // only to use in the XML import
+
+ const ScBigRange& GetFromRange() const { return aFromRange; }
+ SC_DLLPUBLIC void GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const;
+
+ virtual OUString GetDescription(
+ ScDocument& rDoc, bool bSplitRange = false, bool bWarning = true ) const override;
+
+ virtual OUString GetRefString( ScDocument& rDoc, bool bFlag3D = false ) const override;
+};
+
+ScChangeActionDelMoveEntry::ScChangeActionDelMoveEntry(
+ ScChangeActionDelMoveEntry** ppPrevP,
+ ScChangeActionMove* pMove,
+ short nFrom, short nTo )
+ : ScChangeActionLinkEntry(
+ reinterpret_cast<ScChangeActionLinkEntry**>(
+ ppPrevP),
+ static_cast<ScChangeAction*>(pMove) ),
+ nCutOffFrom( nFrom ),
+ nCutOffTo( nTo )
+{}
+
+inline ScChangeActionMove* ScChangeActionDelMoveEntry::GetMove()
+ {
+ return static_cast<ScChangeActionMove*>(
+ ScChangeActionLinkEntry::GetAction());
+ }
+
+inline const ScChangeActionMove* ScChangeActionDelMoveEntry::GetMove() const
+ {
+ return static_cast<const ScChangeActionMove*>(
+ ScChangeActionLinkEntry::GetAction());
+ }
+// ScChangeActionContent
+enum ScChangeActionContentCellType
+{
+ SC_CACCT_NONE = 0,
+ SC_CACCT_NORMAL,
+ SC_CACCT_MATORG,
+ SC_CACCT_MATREF
+};
+
+class SAL_DLLPUBLIC_RTTI ScChangeActionContent final : public ScChangeAction
+{
+ friend class ScChangeTrack;
+
+ ScCellValue maOldCell;
+ ScCellValue maNewCell;
+
+ OUString maOldValue;
+ OUString maNewValue;
+ ScChangeActionContent* pNextContent; // at the same position
+ ScChangeActionContent* pPrevContent;
+ ScChangeActionContent* pNextInSlot; // in the same slot
+ ScChangeActionContent** ppPrevInSlot;
+
+ void InsertInSlot( ScChangeActionContent** pp )
+ {
+ if ( !ppPrevInSlot )
+ {
+ ppPrevInSlot = pp;
+ if ( ( pNextInSlot = *pp ) != nullptr )
+ pNextInSlot->ppPrevInSlot = &pNextInSlot;
+ *pp = this;
+ }
+ }
+
+ void RemoveFromSlot()
+ {
+ if ( ppPrevInSlot )
+ {
+ if ( ( *ppPrevInSlot = pNextInSlot ) != nullptr )
+ pNextInSlot->ppPrevInSlot = ppPrevInSlot;
+ ppPrevInSlot = nullptr; // not inserted
+ }
+ }
+
+ ScChangeActionContent* GetNextInSlot() { return pNextInSlot; }
+
+ void ClearTrack();
+
+ static OUString GetStringOfCell(
+ const ScCellValue& rCell, const ScDocument* pDoc, const ScAddress& rPos );
+
+ static OUString GetStringOfCell(
+ const ScCellValue& rCell, const ScDocument* pDoc, sal_uLong nFormat );
+
+ static void SetValue( OUString& rStr, ScCellValue& rCell, const ScAddress& rPos,
+ const ScCellValue& rOrgCell, const ScDocument* pFromDoc,
+ ScDocument* pToDoc );
+
+ static void SetValue( OUString& rStr, ScCellValue& rCell, sal_uLong nFormat,
+ const ScCellValue& rOrgCell, const ScDocument* pFromDoc,
+ ScDocument* pToDoc );
+
+ static void SetCell( OUString& rStr, ScCellValue& rCell, sal_uLong nFormat, const ScDocument* pDoc );
+
+ static bool NeedsNumberFormat( const ScCellValue& rVal );
+
+ void SetValueString( OUString& rValue, ScCellValue& rCell, const OUString& rStr, ScDocument* pDoc );
+
+ OUString GetValueString( const OUString& rValue, const ScCellValue& rCell,
+ const ScDocument* pDoc ) const;
+
+ OUString GetFormulaString( const ScFormulaCell* pCell ) const;
+
+ virtual void AddContent( ScChangeActionContent* ) override {}
+ virtual void DeleteCellEntries() override {}
+
+ virtual void UpdateReference( const ScChangeTrack*,
+ UpdateRefMode, const ScBigRange&,
+ sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) override;
+
+ virtual bool Reject(ScDocument& rDoc) override;
+
+ virtual const ScChangeTrack* GetChangeTrack() const override { return nullptr; }
+
+ // pRejectActions!=NULL: reject actions get
+ // stacked, no SetNewValue, no Append
+ bool Select( ScDocument&, ScChangeTrack*,
+ bool bOldest, ::std::stack<ScChangeActionContent*>* pRejectActions );
+
+ void PutValueToDoc(
+ const ScCellValue& rCell, const OUString& rValue, ScDocument* pDoc, SCCOL nDx, SCROW nDy ) const;
+
+protected:
+ using ScChangeAction::GetRefString;
+
+public:
+ ScChangeActionContent( const ScRange& rRange );
+
+ ScChangeActionContent(
+ const sal_uLong nActionNumber, const ScChangeActionState eState,
+ const sal_uLong nRejectingNumber, const ScBigRange& aBigRange,
+ const OUString& aUser, const DateTime& aDateTime,
+ const OUString &sComment, const ScCellValue& rOldCell,
+ const ScDocument* pDoc, const OUString& sOldValue ); // to use for XML Import
+
+ ScChangeActionContent(
+ const sal_uLong nActionNumber, const ScCellValue& rNewCell,
+ const ScBigRange& aBigRange, const ScDocument* pDoc,
+ const OUString& sNewValue ); // to use for XML Import of Generated Actions
+
+ virtual ~ScChangeActionContent() override;
+
+ ScChangeActionContent* GetNextContent() const { return pNextContent; }
+ ScChangeActionContent* GetPrevContent() const { return pPrevContent; }
+ ScChangeActionContent* GetTopContent() const;
+ bool IsTopContent() const { return pNextContent == nullptr; }
+
+ virtual ScChangeActionLinkEntry* GetDeletedIn() const override;
+ virtual ScChangeActionLinkEntry** GetDeletedInAddress() override;
+
+ void PutOldValueToDoc( ScDocument*,
+ SCCOL nDx, SCROW nDy ) const;
+ void PutNewValueToDoc( ScDocument*,
+ SCCOL nDx, SCROW nDy ) const;
+
+ void SetOldValue( const ScCellValue& rCell, const ScDocument* pFromDoc, ScDocument* pToDoc, sal_uLong nFormat );
+
+ void SetOldValue( const ScCellValue& rCell, const ScDocument* pFromDoc, ScDocument* pToDoc );
+
+ void SetNewValue( const ScCellValue& rCell, ScDocument* pDoc );
+
+ // Used in import filter AppendContentOnTheFly,
+ void SetOldNewCells(
+ const ScCellValue& rOldCell, sal_uLong nOldFormat,
+ const ScCellValue& rNewCell, sal_uLong nNewFormat, const ScDocument* pDoc );
+
+ // Use this only in the XML import,
+ // takes ownership of cell.
+ void SetNewCell(
+ const ScCellValue& rCell, const ScDocument* pDoc, const OUString& rFormatted );
+
+ // These functions should be protected but for
+ // the XML import they are public.
+ void SetNextContent( ScChangeActionContent* p )
+ { pNextContent = p; }
+ void SetPrevContent( ScChangeActionContent* p )
+ { pPrevContent = p; }
+
+ // don't use:
+ // assigns string / creates formula cell
+ void SetOldValue( const OUString& rOld, ScDocument* pDoc );
+
+ OUString GetOldString( const ScDocument* pDoc ) const;
+ OUString GetNewString( const ScDocument* pDoc ) const;
+ const ScCellValue& GetOldCell() const { return maOldCell;}
+ const ScCellValue& GetNewCell() const { return maNewCell;}
+ virtual OUString GetDescription(
+ ScDocument& rDoc, bool bSplitRange = false, bool bWarning = true ) const override;
+
+ virtual OUString GetRefString( ScDocument& rDoc, bool bFlag3D = false ) const override;
+
+ static ScChangeActionContentCellType GetContentCellType( const ScCellValue& rCell );
+ static ScChangeActionContentCellType GetContentCellType( const ScRefCellValue& rIter );
+
+ // NewCell
+ bool IsMatrixOrigin() const;
+ // OldCell
+ bool IsOldMatrixReference() const;
+};
+
+// ScChangeActionReject
+class ScChangeActionReject final : public ScChangeAction
+{
+ friend class ScChangeTrack;
+ friend class ScChangeActionContent;
+
+ virtual void AddContent( ScChangeActionContent* ) override {}
+ virtual void DeleteCellEntries() override {}
+
+ virtual bool Reject(ScDocument& rDoc) override;
+
+ virtual const ScChangeTrack* GetChangeTrack() const override { return nullptr; }
+
+public:
+ ScChangeActionReject(const sal_uLong nActionNumber,
+ const ScChangeActionState eState,
+ const sal_uLong nRejectingNumber,
+ const ScBigRange& aBigRange,
+ const OUString& aUser,
+ const DateTime& aDateTime,
+ const OUString &sComment); // only to use in the XML import
+};
+
+// ScChangeTrack
+enum class ScChangeTrackMsgType
+{
+ NONE,
+ Append, // Actions appended
+ Remove, // Actions removed
+ Change, // Actions changed
+ Parent // became a parent (and wasn't before)
+};
+
+struct ScChangeTrackMsgInfo
+{
+ ScChangeTrackMsgType eMsgType;
+ sal_uLong nStartAction;
+ sal_uLong nEndAction;
+};
+
+// MsgQueue for notification via ModifiedLink
+typedef std::vector<ScChangeTrackMsgInfo> ScChangeTrackMsgQueue;
+typedef std::vector<ScChangeTrackMsgInfo> ScChangeTrackMsgStack;
+typedef std::map<sal_uLong, ScChangeAction*> ScChangeActionMap;
+
+enum ScChangeTrackMergeState
+{
+ SC_CTMS_NONE,
+ SC_CTMS_PREPARE,
+ SC_CTMS_OWN,
+ SC_CTMS_UNDO,
+ SC_CTMS_OTHER
+};
+
+// Internally generated actions start at this value (nearly all bits set)
+// and are decremented, to keep values in a table separated from "normal" actions.
+#define SC_CHGTRACK_GENERATED_START (sal_uInt32(0xfffffff0))
+
+class SAL_DLLPUBLIC_RTTI ScChangeTrack final : public utl::ConfigurationListener
+{
+ friend void ScChangeAction::RejectRestoreContents( ScChangeTrack*, SCCOL, SCROW );
+ friend bool ScChangeActionDel::Reject( ScDocument& pDoc );
+ friend void ScChangeActionDel::DeleteCellEntries();
+ friend void ScChangeActionMove::DeleteCellEntries();
+ friend bool ScChangeActionMove::Reject( ScDocument& pDoc );
+
+ SCROW mnContentRowsPerSlot;
+ SCSIZE mnContentSlots;
+
+ css::uno::Sequence< sal_Int8 > aProtectPass;
+ ScChangeActionMap aMap;
+ ScChangeActionMap aGeneratedMap;
+ ScChangeActionMap aPasteCutMap;
+ ScChangeTrackMsgQueue aMsgQueue;
+ ScChangeTrackMsgStack aMsgStackTmp;
+ ScChangeTrackMsgStack aMsgStackFinal;
+ std::set<OUString> maUserCollection;
+ OUString maUser;
+ Link<ScChangeTrack&,void> aModifiedLink;
+ ScRange aInDeleteRange;
+ DateTime aFixDateTime;
+ ScChangeAction* pFirst;
+ ScChangeAction* pLast;
+ ScChangeActionContent* pFirstGeneratedDelContent;
+ std::unique_ptr<ScChangeActionContent*[]> ppContentSlots;
+ std::unique_ptr<ScChangeActionMove> pLastCutMove;
+ ScChangeActionLinkEntry* pLinkInsertCol;
+ ScChangeActionLinkEntry* pLinkInsertRow;
+ ScChangeActionLinkEntry* pLinkInsertTab;
+ ScChangeActionLinkEntry* pLinkMove;
+ std::optional<ScChangeTrackMsgInfo> xBlockModifyMsg;
+ ScDocument& rDoc;
+ sal_uLong nActionMax;
+ sal_uLong nGeneratedMin;
+ sal_uLong nMarkLastSaved;
+ sal_uLong nStartLastCut;
+ sal_uLong nEndLastCut;
+ sal_uLong nLastMerge;
+ ScChangeTrackMergeState eMergeState;
+ bool bInDelete:1;
+ bool bInDeleteUndo:1;
+ bool bInDeleteTop:1;
+ bool bInPasteCut:1;
+ bool bUseFixDateTime:1;
+ bool bTimeNanoSeconds:1;
+
+ ScChangeTrack( const ScChangeTrack& ) = delete;
+ ScChangeTrack& operator=( const ScChangeTrack& ) = delete;
+
+ SCROW InitContentRowsPerSlot();
+
+ // true if one is ScMatrixMode::Formula and the other is
+ // not, or if both are and range differs
+ static bool IsMatrixFormulaRangeDifferent(
+ const ScCellValue& rOldCell, const ScCellValue& rNewCell );
+
+ void Init();
+ void DtorClear();
+ void SetInDeleteRange( const ScRange& rRange )
+ { aInDeleteRange = rRange; }
+ void SetInDelete( bool bVal )
+ { bInDelete = bVal; }
+ void SetInDeleteTop( bool bVal )
+ { bInDeleteTop = bVal; }
+ void SetInDeleteUndo( bool bVal )
+ { bInDeleteUndo = bVal; }
+ void SetInPasteCut( bool bVal )
+ { bInPasteCut = bVal; }
+ void SetMergeState( ScChangeTrackMergeState eState )
+ { eMergeState = eState; }
+ ScChangeTrackMergeState GetMergeState() const { return eMergeState; }
+ void SetLastMerge( sal_uLong nVal ) { nLastMerge = nVal; }
+ sal_uLong GetLastMerge() const { return nLastMerge; }
+
+ void SetLastCutMoveRange( const ScRange&, ScDocument* );
+
+ // create block of ModifyMsg
+ void StartBlockModify( ScChangeTrackMsgType,
+ sal_uLong nStartAction );
+ void EndBlockModify( sal_uLong nEndAction );
+
+ void AddDependentWithNotify( ScChangeAction* pParent,
+ ScChangeAction* pDependent );
+
+ void Dependencies( ScChangeAction* );
+ void UpdateReference( ScChangeAction*, bool bUndo );
+ void UpdateReference( ScChangeAction** ppFirstAction, ScChangeAction* pAct, bool bUndo );
+ void Append( ScChangeAction* pAppend, sal_uLong nAction );
+ SC_DLLPUBLIC void AppendDeleteRange( const ScRange&,
+ ScDocument* pRefDoc, SCTAB nDz,
+ sal_uLong nRejectingInsert );
+ void AppendOneDeleteRange( const ScRange& rOrgRange,
+ ScDocument* pRefDoc,
+ SCCOL nDx, SCROW nDy, SCTAB nDz,
+ sal_uLong nRejectingInsert );
+ void LookUpContents( const ScRange& rOrgRange,
+ ScDocument* pRefDoc,
+ SCCOL nDx, SCROW nDy, SCTAB nDz );
+ void Remove( ScChangeAction* );
+ void MasterLinks( ScChangeAction* );
+
+ // Content on top at Position
+ ScChangeActionContent* SearchContentAt( const ScBigAddress&,
+ const ScChangeAction* pButNotThis ) const;
+ void DeleteGeneratedDelContent(
+ ScChangeActionContent* );
+
+ ScChangeActionContent* GenerateDelContent(
+ const ScAddress& rPos, const ScCellValue& rCell, const ScDocument* pFromDoc );
+
+ void DeleteCellEntries(
+ std::vector<ScChangeActionContent*>&,
+ const ScChangeAction* pDeletor );
+
+ // Reject action and all dependent actions,
+ // Table stems from previous GetDependents,
+ // only needed for Insert and Move (MasterType),
+ // is NULL otherwise.
+ // bRecursion == called from reject with table
+ bool Reject( ScChangeAction*, ScChangeActionMap*, bool bRecursion );
+
+ bool IsLastAction( sal_uLong nNum ) const;
+
+ void ClearMsgQueue();
+ virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) override;
+
+public:
+
+ SCSIZE ComputeContentSlot( sal_Int32 nRow ) const;
+
+ SC_DLLPUBLIC ScChangeTrack( ScDocument& );
+ ScChangeTrack(ScDocument& rDocP, std::set<OUString>&& aTempUserCollection); // only to use in the XML import
+ SC_DLLPUBLIC virtual ~ScChangeTrack() override;
+ void Clear();
+
+ ScChangeActionContent* GetFirstGenerated() const { return pFirstGeneratedDelContent; }
+ ScChangeAction* GetFirst() const { return pFirst; }
+ ScChangeAction* GetLast() const { return pLast; }
+ sal_uLong GetActionMax() const { return nActionMax; }
+ bool IsGenerated( sal_uLong nAction ) const;
+ SC_DLLPUBLIC ScChangeAction* GetAction( sal_uLong nAction ) const;
+ ScChangeAction* GetGenerated( sal_uLong nGenerated ) const;
+ ScChangeAction* GetActionOrGenerated( sal_uLong nAction ) const;
+ sal_uLong GetLastSavedActionNumber() const;
+ void SetLastSavedActionNumber(sal_uLong nNew);
+ ScChangeAction* GetLastSaved() const;
+ ScChangeActionContent** GetContentSlots() const { return ppContentSlots.get(); }
+
+ const ScRange& GetInDeleteRange() const
+ { return aInDeleteRange; }
+ bool IsInDelete() const { return bInDelete; }
+ bool IsInDeleteTop() const { return bInDeleteTop; }
+ bool IsInDeleteUndo() const { return bInDeleteUndo; }
+ bool IsInPasteCut() const { return bInPasteCut; }
+ SC_DLLPUBLIC void SetUser( const OUString& rUser );
+ const OUString& GetUser() const { return maUser;}
+ const std::set<OUString>& GetUserCollection() const { return maUserCollection;}
+ ScDocument& GetDocument() const { return rDoc; }
+ // for import filter
+ const DateTime& GetFixDateTime() const { return aFixDateTime; }
+
+ // set this if the date/time set with
+ // SetFixDateTime...() shall be applied to
+ // appended actions
+ void SetUseFixDateTime( bool bVal )
+ { bUseFixDateTime = bVal; }
+ // for MergeDocument, apply original date/time as UTC
+ void SetFixDateTimeUTC( const DateTime& rDT )
+ { aFixDateTime = rDT; }
+ // for import filter, apply original date/time as local time
+ void SetFixDateTimeLocal( const DateTime& rDT )
+ { aFixDateTime = rDT; aFixDateTime.ConvertToUTC(); }
+
+ void Append( ScChangeAction* );
+
+ // pRefDoc may be NULL => no lookup of contents
+ // => no generation of deleted contents
+ SC_DLLPUBLIC void AppendDeleteRange( const ScRange&,
+ ScDocument* pRefDoc,
+ sal_uLong& nStartAction, sal_uLong& nEndAction,
+ SCTAB nDz = 0 );
+ // nDz: multi TabDel, LookUpContent must be searched
+ // with an offset of -nDz
+
+ // after new value was set in the document,
+ // old value from RefDoc/UndoDoc
+ void AppendContent( const ScAddress& rPos,
+ const ScDocument* pRefDoc );
+ // after new values were set in the document,
+ // old values from RefDoc/UndoDoc
+ void AppendContentRange( const ScRange& rRange,
+ ScDocument* pRefDoc,
+ sal_uLong& nStartAction, sal_uLong& nEndAction,
+ ScChangeActionClipMode eMode = SC_CACM_NONE );
+ // after new value was set in the document,
+ // old value from pOldCell, nOldFormat,
+ // RefDoc==NULL => Doc
+ void AppendContent( const ScAddress& rPos, const ScCellValue& rOldCell,
+ sal_uLong nOldFormat, ScDocument* pRefDoc = nullptr );
+ // after new value was set in the document,
+ // old value from pOldCell, format from Doc
+ SC_DLLPUBLIC void AppendContent( const ScAddress& rPos, const ScCellValue& rOldCell );
+ // after new values were set in the document,
+ // old values from RefDoc/UndoDoc.
+ // All contents with a cell in RefDoc
+ void AppendContentsIfInRefDoc( ScDocument& rRefDoc,
+ sal_uLong& nStartAction, sal_uLong& nEndAction );
+
+ // Meant for import filter, creates and inserts
+ // an unconditional content action of the two
+ // cells without querying the document, not
+ // even for number formats (though the number
+ // formatter of the document may be used).
+ // The action is returned and may be used to
+ // set user name, description, date/time et al.
+ // Takes ownership of the cells!
+ SC_DLLPUBLIC ScChangeActionContent* AppendContentOnTheFly(
+ const ScAddress& rPos, const ScCellValue& rOldCell, const ScCellValue& rNewCell,
+ sal_uLong nOldFormat = 0, sal_uLong nNewFormat = 0 );
+
+ // Only use the following two if there is no different solution! (Assign
+ // string for NewValue or creation of a formula respectively)
+
+ SC_DLLPUBLIC void AppendInsert( const ScRange& rRange, bool bEndOfList = false );
+
+ // pRefDoc may be NULL => no lookup of contents
+ // => no generation of deleted contents
+ SC_DLLPUBLIC void AppendMove( const ScRange& rFromRange, const ScRange& rToRange,
+ ScDocument* pRefDoc );
+
+ // Cut to Clipboard
+ void ResetLastCut()
+ {
+ nStartLastCut = nEndLastCut = 0;
+ pLastCutMove.reset();
+ }
+ bool HasLastCut() const
+ {
+ return nEndLastCut > 0 &&
+ nStartLastCut <= nEndLastCut &&
+ pLastCutMove;
+ }
+
+ SC_DLLPUBLIC void Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge = false );
+
+ // adjust references for MergeDocument
+ //! may only be used in a temporary opened document.
+ //! the Track (?) is unclean afterwards
+ void MergePrepare( const ScChangeAction* pFirstMerge, bool bShared );
+ void MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared );
+ static bool MergeIgnore( const ScChangeAction&, sal_uLong nFirstMerge );
+
+ // This comment was already really strange in German.
+ // Tried to structure it a little. Hope no information got lost...
+ //
+ // Insert dependents into table.
+ // ScChangeAction is
+ // - "Insert": really dependents
+ // - "Move": dependent contents in FromRange /
+ // deleted contents in ToRange
+ // OR inserts in FromRange or ToRange
+ // - "Delete": a list of deleted (what?)
+ // OR for content, different contents at the same position
+ // OR MatrixReferences belonging to MatrixOrigin
+
+ // With bListMasterDelete (==TRUE ?) all Deletes of a row belonging
+ // to a MasterDelete are listed (possibly it is
+ // "all Deletes belonging...are listed in a row?)
+
+ // With bAllFlat (==TRUE ?) all dependents of dependents
+ // will be inserted flatly.
+
+ SC_DLLPUBLIC void GetDependents(
+ ScChangeAction*, ScChangeActionMap&, bool bListMasterDelete = false, bool bAllFlat = false ) const;
+
+ // Reject visible action (and dependents)
+ bool Reject( ScChangeAction*, bool bShared = false );
+
+ // Accept visible action (and dependents)
+ SC_DLLPUBLIC bool Accept( ScChangeAction* );
+
+ void AcceptAll(); // all Virgins
+ bool RejectAll(); // all Virgins
+
+ // Selects a content of several contents at the same
+ // position and accepts this one and
+ // the older ones, rejects the more recent ones.
+ // If bOldest==TRUE then the first OldValue
+ // of a Virgin-Content-List will be restored.
+ bool SelectContent( ScChangeAction*, bool bOldest = false );
+
+ // If ModifiedLink is set, changes go to
+ // ScChangeTrackMsgQueue
+ void SetModifiedLink( const Link<ScChangeTrack&,void>& r )
+ { aModifiedLink = r; ClearMsgQueue(); }
+ ScChangeTrackMsgQueue& GetMsgQueue();
+
+ void NotifyModified( ScChangeTrackMsgType eMsgType,
+ sal_uLong nStartAction, sal_uLong nEndAction );
+
+ sal_uLong AddLoadedGenerated( const ScCellValue& rNewCell,
+ const ScBigRange& aBigRange, const OUString& sNewValue ); // only to use in the XML import
+ void AppendLoaded( std::unique_ptr<ScChangeAction> pAppend ); // this is only for the XML import public, it should be protected
+ void SetActionMax(sal_uLong nTempActionMax)
+ { nActionMax = nTempActionMax; } // only to use in the XML import
+
+ void SetProtection( const css::uno::Sequence< sal_Int8 >& rPass )
+ { aProtectPass = rPass; }
+ const css::uno::Sequence< sal_Int8 >& GetProtection() const
+ { return aProtectPass; }
+ bool IsProtected() const { return aProtectPass.hasElements(); }
+
+ // If time stamps of actions of this
+ // ChangeTrack and a second one are to be
+ // compared including nanoseconds.
+ void SetTimeNanoSeconds( bool bVal ) { bTimeNanoSeconds = bVal; }
+ bool IsTimeNanoSeconds() const { return bTimeNanoSeconds; }
+
+ void AppendCloned( ScChangeAction* pAppend );
+ SC_DLLPUBLIC ScChangeTrack* Clone( ScDocument* pDocument ) const;
+ static void MergeActionState( ScChangeAction* pAct, const ScChangeAction* pOtherAct );
+ /// Get info about all ScChangeAction elements.
+ void GetChangeTrackInfo(tools::JsonWriter&);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */