blob: 5919b45a578c9bfa19dc237ff0dbdb5b3f7958e9 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#ifndef SC_CHGTRACK_HXX
#define SC_CHGTRACK_HXX
#include <tools/string.hxx>
#include <tools/datetime.hxx>
#include <tools/table.hxx>
#include <tools/stack.hxx>
#include <tools/queue.hxx>
#include <tools/mempool.hxx>
#include <tools/link.hxx>
#include <unotools/options.hxx>
#include "global.hxx"
#include "bigrange.hxx"
#include "collect.hxx"
#include "scdllapi.h"
#ifdef SC_CHGTRACK_CXX
// core/inc
#include "refupdat.hxx"
#endif
#define DEBUG_CHANGETRACK 0
class ScChangeAction;
class ScAppOptions;
class ScActionColorChanger
{
private:
const ScAppOptions& rOpt;
const ScStrCollection& rUsers;
String aLastUserName;
sal_uInt16 nLastUserIndex;
ColorData nColor;
public:
ScActionColorChanger( const ScChangeTrack& rTrack );
~ScActionColorChanger() {}
void Update( const ScChangeAction& rAction );
ColorData GetColor() const { return nColor; }
};
class ScBaseCell;
class ScDocument;
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_COPY,
SC_CACM_PASTE
};
class SvStream;
// --- ScChangeActionLinkEntry ---------------------------------------------
// Fuegt sich selbst am Beginn einer Kette ein, bzw. vor einem anderen
// LinkEntry, on delete selbstaendiges ausklinken auch des gelinkten.
// ppPrev == &previous->pNext oder Adresse des Pointers auf Beginn der Kette,
// *ppPrev == this
class ScChangeAction;
class ScChangeActionLinkEntry
{
// not implemented, prevent usage
ScChangeActionLinkEntry(
const ScChangeActionLinkEntry& );
ScChangeActionLinkEntry& operator=( const ScChangeActionLinkEntry& );
protected:
ScChangeActionLinkEntry* pNext;
ScChangeActionLinkEntry** ppPrev;
ScChangeAction* pAction;
ScChangeActionLinkEntry* pLink;
public:
DECL_FIXEDMEMPOOL_NEWDEL( ScChangeActionLinkEntry )
ScChangeActionLinkEntry(
ScChangeActionLinkEntry** ppPrevP,
ScChangeAction* pActionP )
: pNext( *ppPrevP ),
ppPrev( ppPrevP ),
pAction( pActionP ),
pLink( NULL )
{
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 = NULL;
pLink = NULL;
}
}
void Remove()
{
if ( ppPrev )
{
if ( ( *ppPrev = pNext ) != NULL )
pNext->ppPrev = ppPrev;
ppPrev = NULL; // not inserted
}
}
void Insert( ScChangeActionLinkEntry** ppPrevP )
{
if ( !ppPrev )
{
ppPrev = ppPrevP;
if ( (pNext = *ppPrevP) )
pNext->ppPrev = &pNext;
*ppPrevP = this;
}
}
const ScChangeActionLinkEntry* GetLink() const { return pLink; }
ScChangeActionLinkEntry* GetLink() { return pLink; }
const ScChangeActionLinkEntry* GetNext() const { return pNext; }
ScChangeActionLinkEntry* GetNext() { return pNext; }
const ScChangeAction* GetAction() const { return pAction; }
ScChangeAction* GetAction() { return pAction; }
#if DEBUG_CHANGETRACK
String ToString() const;
#endif // DEBUG_CHANGETRACK
};
// --- ScChangeActionCellListEntry -----------------------------------------
// this is only for the XML Export in the hxx
class ScChangeActionContent;
class ScChangeActionCellListEntry
{
friend class ScChangeAction;
friend class ScChangeActionDel;
friend class ScChangeActionMove;
friend class ScChangeTrack;
ScChangeActionCellListEntry* pNext;
ScChangeActionContent* pContent;
ScChangeActionCellListEntry(
ScChangeActionContent* pContentP,
ScChangeActionCellListEntry* pNextP )
: pNext( pNextP ),
pContent( pContentP )
{}
public:
const ScChangeActionCellListEntry* GetNext() const { return pNext; } // this is only for the XML Export public
const ScChangeActionContent* GetContent() const { return pContent; } // this is only for the XML Export public
DECL_FIXEDMEMPOOL_NEWDEL( ScChangeActionCellListEntry )
};
// --- ScChangeAction -------------------------------------------------------
class ScChangeTrack;
class ScChangeActionIns;
class ScChangeActionDel;
class ScChangeActionContent;
class ScChangeAction
{
friend class ScChangeTrack;
friend class ScChangeActionIns;
friend class ScChangeActionDel;
friend class ScChangeActionMove;
friend class ScChangeActionContent;
// not implemented, prevent usage
ScChangeAction( const ScChangeAction& );
ScChangeAction& operator=( const ScChangeAction& );
protected:
ScBigRange aBigRange; // Ins/Del/MoveTo/ContentPos
DateTime aDateTime; //! UTC
String aUser; // wer war's
String aComment; // Benutzerkommentar
ScChangeAction* pNext; // naechster in Kette
ScChangeAction* pPrev; // vorheriger in Kette
ScChangeActionLinkEntry* pLinkAny; // irgendwelche Links
ScChangeActionLinkEntry* pLinkDeletedIn; // Zuordnung zu
// geloeschten oder
// druebergemoveten oder
// rejecteten Insert
// Bereichen
ScChangeActionLinkEntry* pLinkDeleted; // Links zu geloeschten
ScChangeActionLinkEntry* pLinkDependent; // Links zu abhaengigen
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 String& aUser,
const String& aComment );
// only to be used in the XML import
ScChangeAction( ScChangeActionType,
const ScBigRange&,
const sal_uLong nAction);
virtual ~ScChangeAction();
String GetRefString( const ScBigRange&,
ScDocument*, sal_Bool bFlag3D = sal_False ) const;
void SetActionNumber( sal_uLong n ) { nAction = n; }
void SetRejectAction( sal_uLong n ) { nRejectAction = n; }
void SetUser( const String& r ) { aUser = r; }
void SetType( ScChangeActionType e ) { eType = e; }
void SetState( ScChangeActionState e ) { eState = e; }
void SetRejected();
ScBigRange& GetBigRange() { return aBigRange; }
ScChangeActionLinkEntry* AddLink( ScChangeAction* p,
ScChangeActionLinkEntry* pL )
{
ScChangeActionLinkEntry* pLnk =
new ScChangeActionLinkEntry(
&pLinkAny, p );
pLnk->SetLink( pL );
return pLnk;
}
void RemoveAllAnyLinks();
virtual ScChangeActionLinkEntry* GetDeletedIn() const
{ return pLinkDeletedIn; }
virtual ScChangeActionLinkEntry** GetDeletedInAddress()
{ return &pLinkDeletedIn; }
ScChangeActionLinkEntry* AddDeletedIn( ScChangeAction* p )
{
return new ScChangeActionLinkEntry(
GetDeletedInAddress(), p );
}
sal_Bool RemoveDeletedIn( const ScChangeAction* );
void SetDeletedIn( ScChangeAction* );
ScChangeActionLinkEntry* AddDeleted( ScChangeAction* p )
{
return new ScChangeActionLinkEntry(
&pLinkDeleted, p );
}
void RemoveAllDeleted();
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 sal_Bool Reject( ScDocument* ) = 0;
void RejectRestoreContents( ScChangeTrack*,
SCsCOL nDx, SCsROW nDy );
// used in Reject() instead of IsRejectable()
sal_Bool IsInternalRejectable() const;
// Derived classes that hold a pointer to the
// ChangeTrack must return that. Otherwise NULL.
virtual const ScChangeTrack* GetChangeTrack() const = 0;
public:
sal_Bool IsInsertType() const
{
return eType == SC_CAT_INSERT_COLS ||
eType == SC_CAT_INSERT_ROWS ||
eType == SC_CAT_INSERT_TABS;
}
sal_Bool IsDeleteType() const
{
return eType == SC_CAT_DELETE_COLS ||
eType == SC_CAT_DELETE_ROWS ||
eType == SC_CAT_DELETE_TABS;
}
sal_Bool IsVirgin() const
{ return eState == SC_CAS_VIRGIN; }
sal_Bool IsAccepted() const
{ return eState == SC_CAS_ACCEPTED; }
sal_Bool IsRejected() const
{ return eState == SC_CAS_REJECTED; }
// Action rejects another Action
sal_Bool IsRejecting() const
{ return nRejectAction != 0; }
// ob Action im Dokument sichtbar ist
sal_Bool IsVisible() const;
// ob Action anfassbar ist
sal_Bool IsTouchable() const;
// ob Action ein Eintrag in Dialog-Root ist
sal_Bool IsDialogRoot() const;
// ob ein Eintrag im Dialog aufklappbar sein soll
sal_Bool IsDialogParent() const;
// ob Action ein Delete ist, unter dem
// aufgeklappt mehrere einzelne Deletes sind
sal_Bool IsMasterDelete() const;
// ob Action akzeptiert/selektiert/abgelehnt
// werden kann
sal_Bool IsClickable() const;
// ob Action abgelehnt werden kann
sal_Bool IsRejectable() const;
const ScBigRange& GetBigRange() const { return aBigRange; }
SC_DLLPUBLIC DateTime GetDateTime() const; // local time
const DateTime& GetDateTimeUTC() const // UTC time
{ return aDateTime; }
const String& GetUser() const { return aUser; }
const String& GetComment() const { return aComment; }
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; }
sal_Bool IsDeletedIn() const
{ return GetDeletedIn() != NULL; }
sal_Bool IsDeleted() const
{ return IsDeleteType() || IsDeletedIn(); }
sal_Bool IsDeletedIn( const ScChangeAction* ) const;
sal_Bool IsDeletedInDelType( ScChangeActionType ) const;
void RemoveAllDeletedIn();
const ScChangeActionLinkEntry* GetFirstDeletedEntry() const
{ return pLinkDeleted; }
const ScChangeActionLinkEntry* GetFirstDependentEntry() const
{ return pLinkDependent; }
sal_Bool HasDependent() const
{ return pLinkDependent != NULL; }
sal_Bool HasDeleted() const
{ return pLinkDeleted != NULL; }
// Description wird an String angehaengt.
// Mit bSplitRange wird bei Delete nur
// eine Spalte/Zeile beruecksichtigt (fuer
// Auflistung der einzelnen Eintraege).
virtual void GetDescription( String&, ScDocument*,
sal_Bool bSplitRange = sal_False, bool bWarning = true ) const;
virtual void GetRefString( String&, ScDocument*,
sal_Bool bFlag3D = sal_False ) const;
// fuer DocumentMerge altes Datum einer anderen
// Action setzen, mit GetDateTimeUTC geholt
void SetDateTimeUTC( const DateTime& rDT )
{ aDateTime = rDT; }
// Benutzerkommentar setzen
void SetComment( const String& rStr )
{ aComment = 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 );
#if DEBUG_CHANGETRACK
String ToString( ScDocument* pDoc ) const;
#endif // DEBUG_CHANGETRACK
};
// --- ScChangeActionIns ----------------------------------------------------
class ScChangeActionIns : public ScChangeAction
{
friend class ScChangeTrack;
ScChangeActionIns( const ScRange& rRange );
virtual ~ScChangeActionIns();
virtual void AddContent( ScChangeActionContent* ) {}
virtual void DeleteCellEntries() {}
virtual sal_Bool Reject( ScDocument* );
virtual const ScChangeTrack* GetChangeTrack() const { return 0; }
public:
ScChangeActionIns(const sal_uLong nActionNumber,
const ScChangeActionState eState,
const sal_uLong nRejectingNumber,
const ScBigRange& aBigRange,
const String& aUser,
const DateTime& aDateTime,
const String &sComment,
const ScChangeActionType eType); // only to use in the XML import
virtual void GetDescription( String&, ScDocument*,
sal_Bool bSplitRange = sal_False, bool bWarning = true ) const;
};
// --- ScChangeActionDel ----------------------------------------------------
class ScChangeActionMove;
class ScChangeActionDelMoveEntry : public ScChangeActionLinkEntry
{
friend class ScChangeActionDel;
friend class ScChangeTrack;
short nCutOffFrom;
short nCutOffTo;
ScChangeActionDelMoveEntry(
ScChangeActionDelMoveEntry** ppPrevP,
ScChangeActionMove* pMove,
short nFrom, short nTo )
: ScChangeActionLinkEntry(
(ScChangeActionLinkEntry**)
ppPrevP,
(ScChangeAction*) pMove ),
nCutOffFrom( nFrom ),
nCutOffTo( nTo )
{}
ScChangeActionDelMoveEntry* GetNext()
{
return (ScChangeActionDelMoveEntry*)
ScChangeActionLinkEntry::GetNext();
}
ScChangeActionMove* GetMove()
{
return (ScChangeActionMove*)
ScChangeActionLinkEntry::GetAction();
}
public:
const ScChangeActionDelMoveEntry* GetNext() const
{
return (const ScChangeActionDelMoveEntry*)
ScChangeActionLinkEntry::GetNext();
}
const ScChangeActionMove* GetMove() const
{
return (const ScChangeActionMove*)
ScChangeActionLinkEntry::GetAction();
}
short GetCutOffFrom() const { return nCutOffFrom; }
short GetCutOffTo() const { return nCutOffTo; }
};
class ScChangeActionDel : public ScChangeAction
{
friend class ScChangeTrack;
friend void ScChangeAction::Accept();
ScChangeTrack* pTrack;
ScChangeActionCellListEntry* pFirstCell;
ScChangeActionIns* pCutOff; // abgeschnittener Insert
short nCutOff; // +: Start -: End
ScChangeActionDelMoveEntry* pLinkMove;
SCsCOL nDx;
SCsROW nDy;
ScChangeActionDel( const ScRange& rRange,
SCsCOL nDx, SCsROW nDy, ScChangeTrack* );
virtual ~ScChangeActionDel();
ScChangeActionIns* GetCutOffInsert() { return pCutOff; }
virtual void AddContent( ScChangeActionContent* );
virtual void DeleteCellEntries();
void UndoCutOffMoves();
void UndoCutOffInsert();
virtual void UpdateReference( const ScChangeTrack*,
UpdateRefMode, const ScBigRange&,
sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz );
virtual sal_Bool Reject( ScDocument* );
virtual const ScChangeTrack* GetChangeTrack() const { return pTrack; }
public:
ScChangeActionDel(const sal_uLong nActionNumber,
const ScChangeActionState eState,
const sal_uLong nRejectingNumber,
const ScBigRange& aBigRange,
const String& aUser,
const DateTime& aDateTime,
const String &sComment,
const ScChangeActionType eType,
const SCsCOLROW nD,
ScChangeTrack* pTrack); // only to use in the XML import
// wich of nDx and nDy is set is depend on the type
// ob dieses das unterste einer Reihe (oder
// auch einzeln) ist
sal_Bool IsBaseDelete() const;
// ob dieses das oberste einer Reihe (oder
// auch einzeln) ist
sal_Bool IsTopDelete() const;
// ob dieses ein Teil einer Reihe ist
sal_Bool IsMultiDelete() const;
// ob es eine Col ist, die zu einem TabDelete gehoert
sal_Bool IsTabDeleteCol() const;
SCsCOL GetDx() const { return nDx; }
SCsROW GetDy() const { return nDy; }
ScBigRange GetOverAllRange() const; // BigRange + (nDx, nDy)
const ScChangeActionCellListEntry* GetFirstCellEntry() const
{ return pFirstCell; }
const ScChangeActionDelMoveEntry* GetFirstMoveEntry() const
{ return pLinkMove; }
const ScChangeActionIns* GetCutOffInsert() const { return pCutOff; }
short GetCutOffCount() const { return nCutOff; }
virtual void GetDescription( String&, ScDocument*,
sal_Bool bSplitRange = sal_False, bool bWarning = true ) const;
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 )
{
return new ScChangeActionDelMoveEntry(
&pLinkMove, pMove, nFrom, nTo );
}
};
// --- ScChangeActionMove ---------------------------------------------------
class ScChangeActionMove : public ScChangeAction
{
friend class ScChangeTrack;
friend class ScChangeActionDel;
ScBigRange aFromRange;
ScChangeTrack* pTrack;
ScChangeActionCellListEntry* pFirstCell;
sal_uLong nStartLastCut; // fuer PasteCut Undo
sal_uLong nEndLastCut;
ScChangeActionMove( const ScRange& rFromRange,
const ScRange& rToRange,
ScChangeTrack* pTrackP )
: ScChangeAction( SC_CAT_MOVE, rToRange ),
aFromRange( rFromRange ),
pTrack( pTrackP ),
pFirstCell( NULL ),
nStartLastCut(0),
nEndLastCut(0)
{}
virtual ~ScChangeActionMove();
virtual void AddContent( ScChangeActionContent* );
virtual void DeleteCellEntries();
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 );
virtual sal_Bool Reject( ScDocument* );
virtual const ScChangeTrack* GetChangeTrack() const { return pTrack; }
protected:
using ScChangeAction::GetRefString;
public:
ScChangeActionMove(const sal_uLong nActionNumber,
const ScChangeActionState eState,
const sal_uLong nRejectingNumber,
const ScBigRange& aToBigRange,
const String& aUser,
const DateTime& aDateTime,
const String &sComment,
const ScBigRange& aFromBigRange,
ScChangeTrack* pTrack); // only to use in the XML import
const ScChangeActionCellListEntry* GetFirstCellEntry() const
{ return pFirstCell; } // only to use in the XML export
const ScBigRange& GetFromRange() const { return aFromRange; }
SC_DLLPUBLIC void GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const;
virtual void GetDescription( String&, ScDocument*,
sal_Bool bSplitRange = sal_False, bool bWarning = true ) const;
virtual void GetRefString( String&, ScDocument*,
sal_Bool bFlag3D = sal_False ) const;
};
// --- ScChangeActionContent ------------------------------------------------
enum ScChangeActionContentCellType
{
SC_CACCT_NONE = 0,
SC_CACCT_NORMAL,
SC_CACCT_MATORG,
SC_CACCT_MATREF
};
class Stack;
class ScChangeActionContent : public ScChangeAction
{
friend class ScChangeTrack;
String aOldValue;
String aNewValue;
ScBaseCell* pOldCell;
ScBaseCell* pNewCell;
ScChangeActionContent* pNextContent; // an gleicher Position
ScChangeActionContent* pPrevContent;
ScChangeActionContent* pNextInSlot; // in gleichem Slot
ScChangeActionContent** ppPrevInSlot;
void InsertInSlot( ScChangeActionContent** pp )
{
if ( !ppPrevInSlot )
{
ppPrevInSlot = pp;
if ( ( pNextInSlot = *pp ) != NULL )
pNextInSlot->ppPrevInSlot = &pNextInSlot;
*pp = this;
}
}
void RemoveFromSlot()
{
if ( ppPrevInSlot )
{
if ( ( *ppPrevInSlot = pNextInSlot ) != NULL )
pNextInSlot->ppPrevInSlot = ppPrevInSlot;
ppPrevInSlot = NULL; // not inserted
}
}
ScChangeActionContent* GetNextInSlot() { return pNextInSlot; }
void ClearTrack();
static void GetStringOfCell( String& rStr,
const ScBaseCell* pCell,
const ScDocument* pDoc,
const ScAddress& rPos );
static void GetStringOfCell( String& rStr,
const ScBaseCell* pCell,
const ScDocument* pDoc,
sal_uLong nFormat );
static void SetValue( String& rStr, ScBaseCell*& pCell,
const ScAddress& rPos,
const ScBaseCell* pOrgCell,
const ScDocument* pFromDoc,
ScDocument* pToDoc );
static void SetValue( String& rStr, ScBaseCell*& pCell,
sal_uLong nFormat,
const ScBaseCell* pOrgCell,
const ScDocument* pFromDoc,
ScDocument* pToDoc );
static void SetCell( String& rStr, ScBaseCell* pCell,
sal_uLong nFormat, const ScDocument* pDoc );
static sal_Bool NeedsNumberFormat( const ScBaseCell* );
void SetValueString( String& rValue,
ScBaseCell*& pCell, const String& rStr,
ScDocument* pDoc );
void GetValueString( String& rStr,
const String& rValue,
const ScBaseCell* pCell ) const;
void GetFormulaString( String& rStr,
const ScFormulaCell* pCell ) const;
virtual void AddContent( ScChangeActionContent* ) {}
virtual void DeleteCellEntries() {}
virtual void UpdateReference( const ScChangeTrack*,
UpdateRefMode, const ScBigRange&,
sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz );
virtual sal_Bool Reject( ScDocument* );
virtual const ScChangeTrack* GetChangeTrack() const { return 0; }
// pRejectActions!=NULL: reject actions get
// stacked, no SetNewValue, no Append
sal_Bool Select( ScDocument*, ScChangeTrack*,
sal_Bool bOldest, Stack* pRejectActions );
void PutValueToDoc( ScBaseCell*, const String&,
ScDocument*, SCsCOL nDx, SCsROW nDy ) const;
protected:
using ScChangeAction::GetRefString;
public:
DECL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent )
ScChangeActionContent( const ScRange& rRange )
: ScChangeAction( SC_CAT_CONTENT, rRange ),
pOldCell( NULL ),
pNewCell( NULL ),
pNextContent( NULL ),
pPrevContent( NULL ),
pNextInSlot( NULL ),
ppPrevInSlot( NULL )
{}
ScChangeActionContent(const sal_uLong nActionNumber,
const ScChangeActionState eState,
const sal_uLong nRejectingNumber,
const ScBigRange& aBigRange,
const String& aUser,
const DateTime& aDateTime,
const String &sComment,
ScBaseCell* pOldCell,
ScDocument* pDoc,
const String& sOldValue); // to use for XML Import
ScChangeActionContent(const sal_uLong nActionNumber,
ScBaseCell* pNewCell,
const ScBigRange& aBigRange,
ScDocument* pDoc,
const String& sNewValue); // to use for XML Import of Generated Actions
virtual ~ScChangeActionContent();
ScChangeActionContent* GetNextContent() const { return pNextContent; }
ScChangeActionContent* GetPrevContent() const { return pPrevContent; }
ScChangeActionContent* GetTopContent() const;
sal_Bool IsTopContent() const
{ return pNextContent == NULL; }
virtual ScChangeActionLinkEntry* GetDeletedIn() const;
virtual ScChangeActionLinkEntry** GetDeletedInAddress();
void PutOldValueToDoc( ScDocument*,
SCsCOL nDx, SCsROW nDy ) const;
void PutNewValueToDoc( ScDocument*,
SCsCOL nDx, SCsROW nDy ) const;
void SetOldValue( const ScBaseCell*,
const ScDocument* pFromDoc,
ScDocument* pToDoc,
sal_uLong nFormat );
void SetOldValue( const ScBaseCell*,
const ScDocument* pFromDoc,
ScDocument* pToDoc );
void SetNewValue( const ScBaseCell*, ScDocument* );
// Used in import filter AppendContentOnTheFly,
// takes ownership of cells.
void SetOldNewCells( ScBaseCell* pOldCell,
sal_uLong nOldFormat, ScBaseCell* pNewCell,
sal_uLong nNewFormat, ScDocument* pDoc );
// Use this only in the XML import,
// takes ownership of cell.
void SetNewCell( ScBaseCell* pCell, ScDocument* pDoc, const String& 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; }
// moeglichst nicht verwenden,
// setzt nur String bzw. generiert Formelzelle
void SetOldValue( const String& rOld, ScDocument* );
void SetNewValue( const String& rNew, ScDocument* );
void GetOldString( String& ) const;
void GetNewString( String& ) const;
const ScBaseCell* GetOldCell() const { return pOldCell; }
const ScBaseCell* GetNewCell() const { return pNewCell; }
virtual void GetDescription( String&, ScDocument*,
sal_Bool bSplitRange = sal_False, bool bWarning = true ) const;
virtual void GetRefString( String&, ScDocument*,
sal_Bool bFlag3D = sal_False ) const;
static ScChangeActionContentCellType GetContentCellType( const ScBaseCell* );
// NewCell
sal_Bool IsMatrixOrigin() const
{
return GetContentCellType( GetNewCell() )
== SC_CACCT_MATORG;
}
sal_Bool IsMatrixReference() const
{
return GetContentCellType( GetNewCell() )
== SC_CACCT_MATREF;
}
// OldCell
sal_Bool IsOldMatrixOrigin() const
{
return GetContentCellType( GetOldCell() )
== SC_CACCT_MATORG;
}
sal_Bool IsOldMatrixReference() const
{
return GetContentCellType( GetOldCell() )
== SC_CACCT_MATREF;
}
};
// --- ScChangeActionReject -------------------------------------------------
class Stack;
class ScChangeActionReject : public ScChangeAction
{
friend class ScChangeTrack;
friend class ScChangeActionContent;
ScChangeActionReject( sal_uLong nReject )
: ScChangeAction( SC_CAT_REJECT, ScRange() )
{
SetRejectAction( nReject );
SetState( SC_CAS_ACCEPTED );
}
virtual void AddContent( ScChangeActionContent* ) {}
virtual void DeleteCellEntries() {}
virtual sal_Bool Reject( ScDocument* ) { return sal_False; }
virtual const ScChangeTrack* GetChangeTrack() const { return 0; }
public:
ScChangeActionReject(const sal_uLong nActionNumber,
const ScChangeActionState eState,
const sal_uLong nRejectingNumber,
const ScBigRange& aBigRange,
const String& aUser,
const DateTime& aDateTime,
const String &sComment); // only to use in the XML import
};
// --- ScChangeTrack --------------------------------------------------------
enum ScChangeTrackMsgType
{
SC_CTM_NONE,
SC_CTM_APPEND, // Actions angehaengt
SC_CTM_REMOVE, // Actions weggenommen
SC_CTM_CHANGE, // Actions geaendert
SC_CTM_PARENT // war kein Parent und ist jetzt einer
};
struct ScChangeTrackMsgInfo
{
DECL_FIXEDMEMPOOL_NEWDEL( ScChangeTrackMsgInfo )
ScChangeTrackMsgType eMsgType;
sal_uLong nStartAction;
sal_uLong nEndAction;
};
// MsgQueue fuer Benachrichtigung via ModifiedLink
DECLARE_QUEUE( ScChangeTrackMsgQueue, ScChangeTrackMsgInfo* )
DECLARE_STACK( ScChangeTrackMsgStack, ScChangeTrackMsgInfo* )
enum ScChangeTrackMergeState
{
SC_CTMS_NONE,
SC_CTMS_PREPARE,
SC_CTMS_OWN,
SC_CTMS_UNDO,
SC_CTMS_OTHER
};
// zusaetzlich zu pFirst/pNext/pLast/pPrev eine Table, um schnell sowohl
// per ActionNumber als auch ueber Liste zugreifen zu koennen
DECLARE_TABLE( ScChangeActionTable, ScChangeAction* )
// Intern generierte Actions beginnen bei diesem Wert (fast alle Bits gesetzt)
// und werden runtergezaehlt, um sich in einer Table wertemaessig nicht mit den
// "normalen" Actions in die Quere zu kommen.
#define SC_CHGTRACK_GENERATED_START ((sal_uInt32) 0xfffffff0)
class ScChangeTrack : public utl::ConfigurationListener
{
friend void ScChangeAction::RejectRestoreContents( ScChangeTrack*, SCsCOL, SCsROW );
friend sal_Bool ScChangeActionDel::Reject( ScDocument* pDoc );
friend void ScChangeActionDel::DeleteCellEntries();
friend void ScChangeActionMove::DeleteCellEntries();
friend sal_Bool ScChangeActionMove::Reject( ScDocument* pDoc );
static const SCROW nContentRowsPerSlot;
static const SCSIZE nContentSlots;
com::sun::star::uno::Sequence< sal_Int8 > aProtectPass;
ScChangeActionTable aTable;
ScChangeActionTable aGeneratedTable;
ScChangeActionTable aPasteCutTable;
ScChangeTrackMsgQueue aMsgQueue;
ScChangeTrackMsgStack aMsgStackTmp;
ScChangeTrackMsgStack aMsgStackFinal;
ScStrCollection aUserCollection;
String aUser;
Link aModifiedLink;
ScRange aInDeleteRange;
DateTime aFixDateTime;
ScChangeAction* pFirst;
ScChangeAction* pLast;
ScChangeActionContent* pFirstGeneratedDelContent;
ScChangeActionContent** ppContentSlots;
ScChangeActionMove* pLastCutMove;
ScChangeActionLinkEntry* pLinkInsertCol;
ScChangeActionLinkEntry* pLinkInsertRow;
ScChangeActionLinkEntry* pLinkInsertTab;
ScChangeActionLinkEntry* pLinkMove;
ScChangeTrackMsgInfo* pBlockModifyMsg;
ScDocument* pDoc;
sal_uLong nActionMax;
sal_uLong nGeneratedMin;
sal_uLong nMarkLastSaved;
sal_uLong nStartLastCut;
sal_uLong nEndLastCut;
sal_uLong nLastMerge;
ScChangeTrackMergeState eMergeState;
sal_uInt16 nLoadedFileFormatVersion;
sal_Bool bLoadSave;
sal_Bool bInDelete;
sal_Bool bInDeleteUndo;
sal_Bool bInDeleteTop;
sal_Bool bInPasteCut;
sal_Bool bUseFixDateTime;
sal_Bool bTime100thSeconds;
// not implemented, prevent usage
ScChangeTrack( const ScChangeTrack& );
ScChangeTrack& operator=( const ScChangeTrack& );
#ifdef SC_CHGTRACK_CXX
static SCROW InitContentRowsPerSlot();
// sal_True if one is MM_FORMULA and the other is
// not, or if both are and range differs
static sal_Bool IsMatrixFormulaRangeDifferent(
const ScBaseCell* pOldCell,
const ScBaseCell* pNewCell );
void Init();
void DtorClear();
void SetLoadSave( sal_Bool bVal ) { bLoadSave = bVal; }
void SetInDeleteRange( const ScRange& rRange )
{ aInDeleteRange = rRange; }
void SetInDelete( sal_Bool bVal )
{ bInDelete = bVal; }
void SetInDeleteTop( sal_Bool bVal )
{ bInDeleteTop = bVal; }
void SetInDeleteUndo( sal_Bool bVal )
{ bInDeleteUndo = bVal; }
void SetInPasteCut( sal_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* );
// ModifyMsg blockweise und nicht einzeln erzeugen
void StartBlockModify( ScChangeTrackMsgType,
sal_uLong nStartAction );
void EndBlockModify( sal_uLong nEndAction );
void AddDependentWithNotify( ScChangeAction* pParent,
ScChangeAction* pDependent );
void Dependencies( ScChangeAction* );
void UpdateReference( ScChangeAction*, sal_Bool bUndo );
void UpdateReference( ScChangeAction** ppFirstAction,
ScChangeAction* pAct, sal_Bool bUndo );
void Append( ScChangeAction* pAppend, sal_uLong nAction );
SC_DLLPUBLIC void AppendDeleteRange( const ScRange&,
ScDocument* pRefDoc, SCsTAB nDz,
sal_uLong nRejectingInsert );
void AppendOneDeleteRange( const ScRange& rOrgRange,
ScDocument* pRefDoc,
SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
sal_uLong nRejectingInsert );
void LookUpContents( const ScRange& rOrgRange,
ScDocument* pRefDoc,
SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
void Remove( ScChangeAction* );
void MasterLinks( ScChangeAction* );
// Content on top an Position
ScChangeActionContent* SearchContentAt( const ScBigAddress&,
ScChangeAction* pButNotThis ) const;
void DeleteGeneratedDelContent(
ScChangeActionContent* );
ScChangeActionContent* GenerateDelContent( const ScAddress&,
const ScBaseCell*,
const ScDocument* pFromDoc );
void DeleteCellEntries(
ScChangeActionCellListEntry*&,
ScChangeAction* pDeletor );
// Action und alle abhaengigen rejecten,
// Table stammt aus vorherigem GetDependents,
// ist nur bei Insert und Move (MasterType)
// noetig, kann ansonsten NULL sein.
// bRecursion == Aufruf aus Reject mit Table
sal_Bool Reject( ScChangeAction*,
ScChangeActionTable*, sal_Bool bRecursion );
#endif // SC_CHGTRACK_CXX
void ClearMsgQueue();
virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 );
public:
static SCSIZE ComputeContentSlot( sal_Int32 nRow )
{
if ( nRow < 0 || nRow > MAXROW )
return nContentSlots - 1;
return static_cast< SCSIZE >( nRow / nContentRowsPerSlot );
}
SC_DLLPUBLIC ScChangeTrack( ScDocument* );
ScChangeTrack( ScDocument*,
const ScStrCollection& ); // only to use in the XML import
SC_DLLPUBLIC virtual ~ScChangeTrack();
void Clear();
ScChangeActionContent* GetFirstGenerated() const { return pFirstGeneratedDelContent; }
ScChangeAction* GetFirst() const { return pFirst; }
ScChangeAction* GetLast() const { return pLast; }
sal_uLong GetActionMax() const { return nActionMax; }
sal_Bool IsGenerated( sal_uLong nAction ) const
{ return nAction >= nGeneratedMin; }
ScChangeAction* GetAction( sal_uLong nAction ) const
{ return aTable.Get( nAction ); }
ScChangeAction* GetGenerated( sal_uLong nGenerated ) const
{ return aGeneratedTable.Get( nGenerated ); }
ScChangeAction* GetActionOrGenerated( sal_uLong nAction ) const
{
return IsGenerated( nAction ) ?
GetGenerated( nAction ) :
GetAction( nAction );
}
sal_uLong GetLastSavedActionNumber() const
{ return nMarkLastSaved; }
void SetLastSavedActionNumber(sal_uLong nNew)
{ nMarkLastSaved = nNew; }
ScChangeAction* GetLastSaved() const
{ return aTable.Get( nMarkLastSaved ); }
ScChangeActionContent** GetContentSlots() const { return ppContentSlots; }
sal_Bool IsLoadSave() const { return bLoadSave; }
const ScRange& GetInDeleteRange() const
{ return aInDeleteRange; }
sal_Bool IsInDelete() const { return bInDelete; }
sal_Bool IsInDeleteTop() const { return bInDeleteTop; }
sal_Bool IsInDeleteUndo() const { return bInDeleteUndo; }
sal_Bool IsInPasteCut() const { return bInPasteCut; }
SC_DLLPUBLIC void SetUser( const String& );
const String& GetUser() const { return aUser; }
const ScStrCollection& GetUserCollection() const
{ return aUserCollection; }
ScDocument* GetDocument() const { return pDoc; }
// 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( sal_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,
SCsTAB nDz = 0 );
// nDz: Multi-TabDel, LookUpContent ist
// um -nDz verschoben zu suchen
// nachdem neuer Wert im Dokument gesetzt wurde,
// alter Wert aus RefDoc/UndoDoc
void AppendContent( const ScAddress& rPos,
ScDocument* pRefDoc );
// nachdem neue Werte im Dokument gesetzt wurden,
// alte Werte aus RefDoc/UndoDoc
void AppendContentRange( const ScRange& rRange,
ScDocument* pRefDoc,
sal_uLong& nStartAction, sal_uLong& nEndAction,
ScChangeActionClipMode eMode = SC_CACM_NONE );
// nachdem neuer Wert im Dokument gesetzt wurde,
// alter Wert aus pOldCell, nOldFormat,
// RefDoc==NULL => Doc
void AppendContent( const ScAddress& rPos,
const ScBaseCell* pOldCell,
sal_uLong nOldFormat, ScDocument* pRefDoc = NULL );
// nachdem neuer Wert im Dokument gesetzt wurde,
// alter Wert aus pOldCell, Format aus Doc
void AppendContent( const ScAddress& rPos,
const ScBaseCell* pOldCell );
// nachdem neue Werte im Dokument gesetzt wurden,
// alte Werte aus RefDoc/UndoDoc.
// Alle Contents, wo im RefDoc eine Zelle steht.
void AppendContentsIfInRefDoc( ScDocument* pRefDoc,
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,
ScBaseCell* pOldCell,
ScBaseCell* pNewCell,
sal_uLong nOldFormat = 0,
sal_uLong nNewFormat = 0 );
// die folgenden beiden nur benutzen wenn's
// nicht anders geht (setzen nur String fuer
// NewValue bzw. Formelerzeugung)
// bevor neuer Wert im Dokument gesetzt wird
void AppendContent( const ScAddress& rPos,
const String& rNewValue,
ScBaseCell* pOldCell );
SC_DLLPUBLIC void AppendInsert( const ScRange& );
// 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;
if ( pLastCutMove )
{
delete pLastCutMove;
pLastCutMove = NULL;
}
}
sal_Bool HasLastCut() const
{
return nEndLastCut > 0 &&
nStartLastCut <= nEndLastCut &&
pLastCutMove;
}
SC_DLLPUBLIC void Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge = false );
// fuer MergeDocument, Referenzen anpassen,
//! darf nur in einem temporaer geoeffneten
//! Dokument verwendet werden, der Track
//! ist danach verhunzt
void MergePrepare( ScChangeAction* pFirstMerge, bool bShared = false );
void MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared = false );
static sal_Bool MergeIgnore( const ScChangeAction&, sal_uLong nFirstMerge );
// Abhaengige in Table einfuegen.
// Bei Insert sind es echte Abhaengige,
// bei Move abhaengige Contents im FromRange
// und geloeschte im ToRange bzw. Inserts in
// FromRange oder ToRange,
// bei Delete eine Liste der geloeschten,
// bei Content andere Contents an gleicher
// Position oder MatrixReferences zu MatrixOrigin.
// Mit bListMasterDelete werden unter einem
// MasterDelete alle zu diesem Delete gehoerenden
// Deletes einer Reihe gelistet.
// Mit bAllFlat werden auch alle Abhaengigen
// der Abhaengigen flach eingefuegt.
SC_DLLPUBLIC void GetDependents( ScChangeAction*,
ScChangeActionTable&,
sal_Bool bListMasterDelete = sal_False,
sal_Bool bAllFlat = sal_False ) const;
// Reject visible Action (und abhaengige)
sal_Bool Reject( ScChangeAction*, bool bShared = false );
// Accept visible Action (und abhaengige)
SC_DLLPUBLIC sal_Bool Accept( ScChangeAction* );
void AcceptAll(); // alle Virgins
sal_Bool RejectAll(); // alle Virgins
// Selektiert einen Content von mehreren an
// gleicher Position und akzeptiert diesen und
// die aelteren, rejected die neueren.
// Mit bOldest==sal_True wird der erste OldValue
// einer Virgin-Content-Kette restauriert.
sal_Bool SelectContent( ScChangeAction*,
sal_Bool bOldest = sal_False );
// wenn ModifiedLink gesetzt, landen
// Aenderungen in ScChangeTrackMsgQueue
void SetModifiedLink( const Link& r )
{ aModifiedLink = r; ClearMsgQueue(); }
const Link& GetModifiedLink() const { return aModifiedLink; }
ScChangeTrackMsgQueue& GetMsgQueue() { return aMsgQueue; }
void NotifyModified( ScChangeTrackMsgType eMsgType,
sal_uLong nStartAction, sal_uLong nEndAction );
sal_uInt16 GetLoadedFileFormatVersion() const
{ return nLoadedFileFormatVersion; }
sal_uLong AddLoadedGenerated(ScBaseCell* pOldCell,
const ScBigRange& aBigRange, const String& sNewValue ); // only to use in the XML import
void AppendLoaded( 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 com::sun::star::uno::Sequence< sal_Int8 >& rPass )
{ aProtectPass = rPass; }
com::sun::star::uno::Sequence< sal_Int8 > GetProtection() const
{ return aProtectPass; }
sal_Bool IsProtected() const
{ return aProtectPass.getLength() != 0; }
// If time stamps of actions of this
// ChangeTrack and a second one are to be
// compared including 100th seconds.
void SetTime100thSeconds( sal_Bool bVal )
{ bTime100thSeconds = bVal; }
sal_Bool IsTime100thSeconds() const
{ return bTime100thSeconds; }
void AppendCloned( ScChangeAction* pAppend );
SC_DLLPUBLIC ScChangeTrack* Clone( ScDocument* pDocument ) const;
void MergeActionState( ScChangeAction* pAct, const ScChangeAction* pOtherAct );
#if DEBUG_CHANGETRACK
String ToString() const;
#endif // DEBUG_CHANGETRACK
};
#endif