summaryrefslogtreecommitdiff
path: root/svl
diff options
context:
space:
mode:
authorMathias Bauer <mba@openoffice.org>2011-02-03 15:53:56 +0100
committerMathias Bauer <mba@openoffice.org>2011-02-03 15:53:56 +0100
commit2e913ff4d61087475ddf3d15455a652cb50c0549 (patch)
tree9fc661cdf6462f6d245cd92ac2a20c747e1f9cd9 /svl
parentfd66c3fb05c8aa2031e6f859f6cfaef0ee7bfa87 (diff)
parent99ff7a9fb521895d6ba18ca4ca92d7eb0c3524fd (diff)
CWS gnumake3: resync to m99
Diffstat (limited to 'svl')
-rw-r--r--svl/inc/svl/undo.hxx352
-rw-r--r--svl/source/undo/undo.cxx1203
2 files changed, 1237 insertions, 318 deletions
diff --git a/svl/inc/svl/undo.hxx b/svl/inc/svl/undo.hxx
index 5aea03207626..08d2fa6c5b84 100644
--- a/svl/inc/svl/undo.hxx
+++ b/svl/inc/svl/undo.hxx
@@ -32,6 +32,10 @@
#include <tools/string.hxx>
#include <svl/svarray.hxx>
+#include <boost/scoped_ptr.hpp>
+
+#include <vector>
+
//====================================================================
class SVL_DLLPUBLIC SfxRepeatTarget
@@ -43,6 +47,14 @@ public:
//====================================================================
+class SVL_DLLPUBLIC SfxUndoContext
+{
+public:
+ virtual ~SfxUndoContext() = 0;
+};
+
+//====================================================================
+
class SVL_DLLPUBLIC SfxUndoAction
{
BOOL bLinked;
@@ -54,14 +66,16 @@ public:
virtual BOOL IsLinked();
virtual void SetLinked( BOOL bIsLinked = TRUE );
virtual void Undo();
+ virtual void UndoWithContext( SfxUndoContext& i_context );
virtual void Redo();
+ virtual void RedoWithContext( SfxUndoContext& i_context );
virtual void Repeat(SfxRepeatTarget&);
virtual BOOL CanRepeat(SfxRepeatTarget&) const;
virtual BOOL Merge( SfxUndoAction *pNextAction );
- virtual UniString GetComment() const;
- virtual UniString GetRepeatComment(SfxRepeatTarget&) const;
+ virtual UniString GetComment() const;
+ virtual UniString GetRepeatComment(SfxRepeatTarget&) const;
virtual USHORT GetId() const;
private:
@@ -70,19 +84,67 @@ private:
//========================================================================
-SV_DECL_PTRARR( SfxUndoActions, SfxUndoAction*, 20, 8 )
+/// is a mark on the Undo stack
+typedef sal_Int32 UndoStackMark;
+#define MARK_INVALID ::std::numeric_limits< UndoStackMark >::max()
+
+//========================================================================
+
+struct MarkedUndoAction
+{
+ SfxUndoAction* pAction;
+ ::std::vector< UndoStackMark > aMarks;
+
+ MarkedUndoAction( SfxUndoAction* i_action )
+ :pAction( i_action )
+ ,aMarks()
+ {
+ }
+};
+
+class SfxUndoActions
+{
+private:
+ ::std::vector< MarkedUndoAction > m_aActions;
+
+public:
+ SfxUndoActions()
+ {
+ }
+
+ bool empty() const { return m_aActions.empty(); }
+ size_t size() const { return m_aActions.size(); }
+
+ const MarkedUndoAction& operator[]( size_t i ) const { return m_aActions[i]; }
+ MarkedUndoAction& operator[]( size_t i ) { return m_aActions[i]; }
+
+ void Remove( size_t i_pos )
+ {
+ m_aActions.erase( m_aActions.begin() + i_pos );
+ }
+
+ void Remove( size_t i_pos, size_t i_count )
+ {
+ m_aActions.erase( m_aActions.begin() + i_pos, m_aActions.begin() + i_pos + i_count );
+ }
+
+ void Insert( SfxUndoAction* i_action, size_t i_pos )
+ {
+ m_aActions.insert( m_aActions.begin() + i_pos, MarkedUndoAction( i_action ) );
+ }
+};
//====================================================================
-/** do not make use of this implementation details, unless you
+/** do not make use of these implementation details, unless you
really really have to! */
struct SVL_DLLPUBLIC SfxUndoArray
{
SfxUndoActions aUndoActions;
- USHORT nMaxUndoActions;
- USHORT nCurUndoAction;
+ size_t nMaxUndoActions;
+ size_t nCurUndoAction;
SfxUndoArray *pFatherUndoArray;
- SfxUndoArray(USHORT nMax=0):
+ SfxUndoArray(size_t nMax=0):
nMaxUndoActions(nMax), nCurUndoAction(0),
pFatherUndoArray(0) {}
~SfxUndoArray();
@@ -90,7 +152,7 @@ struct SVL_DLLPUBLIC SfxUndoArray
//=========================================================================
-/** do not make use of this implementation details, unless you
+/** do not make use of these implementation details, unless you
really really have to! */
class SVL_DLLPUBLIC SfxListUndoAction : public SfxUndoAction, public SfxUndoArray
@@ -111,14 +173,16 @@ class SVL_DLLPUBLIC SfxListUndoAction : public SfxUndoAction, public SfxUndoArra
SfxListUndoAction( const UniString &rComment,
const UniString rRepeatComment, USHORT Id, SfxUndoArray *pFather);
virtual void Undo();
+ virtual void UndoWithContext( SfxUndoContext& i_context );
virtual void Redo();
+ virtual void RedoWithContext( SfxUndoContext& i_context );
virtual void Repeat(SfxRepeatTarget&);
virtual BOOL CanRepeat(SfxRepeatTarget&) const;
virtual BOOL Merge( SfxUndoAction *pNextAction );
- virtual UniString GetComment() const;
- virtual UniString GetRepeatComment(SfxRepeatTarget&) const;
+ virtual UniString GetComment() const;
+ virtual UniString GetRepeatComment(SfxRepeatTarget&) const;
virtual USHORT GetId() const;
void SetComment( const UniString& rComment );
@@ -126,70 +190,242 @@ class SVL_DLLPUBLIC SfxListUndoAction : public SfxUndoAction, public SfxUndoArra
private:
USHORT nId;
- UniString aComment, aRepeatComment;
+ UniString aComment;
+ UniString aRepeatComment;
};
//=========================================================================
-class SVL_DLLPUBLIC SfxUndoManager
+/** is a callback interface for notifications about state changes of an SfxUndoManager
+*/
+class SAL_NO_VTABLE SfxUndoListener
{
- friend class SfxLinkUndoAction;
+public:
+ virtual void actionUndone( const String& i_actionComment ) = 0;
+ virtual void actionRedone( const String& i_actionComment ) = 0;
+ virtual void undoActionAdded( const String& i_actionComment ) = 0;
+ virtual void cleared() = 0;
+ virtual void clearedRedo() = 0;
+ virtual void resetAll() = 0;
+ virtual void listActionEntered( const String& i_comment ) = 0;
+ virtual void listActionLeft( const String& i_comment ) = 0;
+ virtual void listActionLeftAndMerged() = 0;
+ virtual void listActionCancelled() = 0;
+ virtual void undoManagerDying() = 0;
+};
- SfxUndoArray *pUndoArray;
- SfxUndoArray *pActUndoArray;
- SfxUndoArray *pFatherUndoArray;
+//=========================================================================
- bool mbUndoEnabled;
-public:
- SfxUndoManager( USHORT nMaxUndoActionCount = 20 );
- virtual ~SfxUndoManager();
+namespace svl
+{
+ class SAL_NO_VTABLE IUndoManager
+ {
+ public:
+ enum
+ {
+ CurrentLevel = true,
+ TopLevel = false
+ };
- virtual void SetMaxUndoActionCount( USHORT nMaxUndoActionCount );
- virtual USHORT GetMaxUndoActionCount() const;
- virtual void Clear();
+ virtual ~IUndoManager() { };
- virtual void AddUndoAction( SfxUndoAction *pAction, BOOL bTryMerg=FALSE );
+ virtual void SetMaxUndoActionCount( size_t nMaxUndoActionCount ) = 0;
+ virtual size_t GetMaxUndoActionCount() const = 0;
- virtual USHORT GetUndoActionCount() const;
- virtual USHORT GetUndoActionId(USHORT nNo=0) const;
- virtual UniString GetUndoActionComment( USHORT nNo=0 ) const;
- /** returns the nNo'th undo action from the top */
- SfxUndoAction* GetUndoAction( USHORT nNo=0 ) const;
+ virtual void AddUndoAction( SfxUndoAction *pAction, BOOL bTryMerg=FALSE ) = 0;
- virtual BOOL Undo( USHORT nCount=1 );
- virtual void Undo( SfxUndoAction &rAction );
+ virtual size_t GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const = 0;
+ virtual USHORT GetUndoActionId() const = 0;
+ virtual UniString GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const = 0;
+ virtual SfxUndoAction* GetUndoAction( size_t nNo=0 ) const = 0;
- virtual USHORT GetRedoActionCount() const;
- virtual USHORT GetRedoActionId(USHORT nNo=0) const;
- virtual UniString GetRedoActionComment( USHORT nNo=0 ) const;
+ virtual size_t GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const = 0;
+ virtual UniString GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const = 0;
- virtual BOOL Redo( USHORT nCount=1 );
- virtual void Redo( SfxUndoAction &rAction );
- virtual void ClearRedo();
+ virtual BOOL Undo() = 0;
+ virtual BOOL Redo() = 0;
+
+ /** clears both the Redo and the Undo stack.
+
+ Will assert and bail out when called while within a list action (<member>IsInListAction</member>).
+ */
+ virtual void Clear() = 0;
+
+ /** clears the Redo stack.
- virtual USHORT GetRepeatActionCount() const;
- virtual UniString GetRepeatActionComment( SfxRepeatTarget &rTarget, USHORT nNo = 0) const;
- virtual BOOL Repeat( SfxRepeatTarget &rTarget, USHORT nFrom=0, USHORT nCount=1 );
- virtual void Repeat( SfxRepeatTarget &rTarget, SfxUndoAction &rAction );
- virtual BOOL CanRepeat( SfxRepeatTarget &rTarget, USHORT nNo = 0 ) const;
- virtual BOOL CanRepeat( SfxRepeatTarget &rTarget, SfxUndoAction &rAction ) const;
+ Will assert and bail out when called while within a list action (<member>IsInListAction</member>).
+ */
+ virtual void ClearRedo() = 0;
+ /** leaves any possible open list action (<member>IsInListAction</member>), and clears both the Undo and the
+ Redo stack.
+
+ Effectively, calling this method is equivalent to <code>while ( IsInListAction() ) LeaveListAction();</code>,
+ followed by <code>Clear()</code>. The only difference to this calling sequence is that Reset is an
+ atomar operation, also resulting in only one notification.
+ */
+ virtual void Reset() = 0;
+
+ /** determines whether an Undo or Redo is currently running
+ */
+ virtual bool IsDoing() const = 0;
+
+ virtual size_t GetRepeatActionCount() const = 0;
+ virtual UniString GetRepeatActionComment( SfxRepeatTarget &rTarget) const = 0;
+ virtual BOOL Repeat( SfxRepeatTarget &rTarget ) = 0;
+ virtual BOOL CanRepeat( SfxRepeatTarget &rTarget ) const = 0;
+
+ virtual void EnterListAction(const UniString &rComment, const UniString& rRepeatComment, USHORT nId=0) = 0;
+
+ /** leaves the list action entered with EnterListAction
+ @return the number of the sub actions in the list which has just been left. Note that in case no such
+ actions exist, the list action does not contribute to the Undo stack, but is silently removed.
+ */
+ virtual size_t LeaveListAction() = 0;
+
+ /** leaves the list action entered with EnterListAction, and forcefully merges the previous
+ action on the stack into the newly created list action.
+
+ Say you have an Undo action A on the stack, then call EnterListAction, followed by one or more calls to
+ AddUndoAction, followed by a call to LeaveAndMergeListAction. In opposite to LeaveListAction, your Undo
+ stack will now still contain one undo action: the newly created list action, whose first child is the
+ original A, whose other children are those you added via AddUndoAction, and whose comment is the same as
+ the comment of A.
+
+ Effectively, this means that all actions added between EnterListAction and LeaveAndMergeListAction are
+ hidden from the user.
+
+ @return the number of the sub actions in the list which has just been left. Note that in case no such
+ actions exist, the list action does not contribute to the Undo stack, but is silently removed.
+ */
+ virtual size_t LeaveAndMergeListAction() = 0;
+
+ /// determines whether we're within a ListAction context, i.e. a LeaveListAction/LeaveAndMergeListAction call is pending
+ virtual bool IsInListAction() const = 0;
+
+ /// determines how many nested list actions are currently open
+ virtual size_t GetListActionDepth() const = 0;
+
+ /** clears the redo stack and removes the top undo action */
+ virtual void RemoveLastUndoAction() = 0;
+
+ // enables (true) or disables (false) recording of undo actions
+ // If undo actions are added while undo is disabled, they are deleted.
+ // Disabling undo does not clear the current undo buffer!
+ virtual void EnableUndo( bool bEnable ) = 0;
+
+ // returns true if undo is currently enabled
+ // This returns false if undo was disabled using EnableUndo( false ) and
+ // also during the runtime of the Undo() and Redo() methods.
+ virtual bool IsUndoEnabled() const = 0;
+
+ /// adds a new listener to be notified about changes in the UndoManager's state
+ virtual void AddUndoListener( SfxUndoListener& i_listener ) = 0;
+ virtual void RemoveUndoListener( SfxUndoListener& i_listener ) = 0;
+ };
+}
+
+//=========================================================================
+
+namespace svl { namespace undo { namespace impl
+{
+ class UndoManagerGuard;
+ class LockGuard;
+} } }
+
+struct SfxUndoManager_Data;
+class SVL_DLLPUBLIC SfxUndoManager : public ::svl::IUndoManager
+{
+ friend class SfxLinkUndoAction;
+
+ ::boost::scoped_ptr< SfxUndoManager_Data >
+ m_pData;
+public:
+ SfxUndoManager( size_t nMaxUndoActionCount = 20 );
+ virtual ~SfxUndoManager();
+
+ // IUndoManager overridables
+ virtual void SetMaxUndoActionCount( size_t nMaxUndoActionCount );
+ virtual size_t GetMaxUndoActionCount() const;
+ virtual void AddUndoAction( SfxUndoAction *pAction, BOOL bTryMerg=FALSE );
+ virtual size_t GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const;
+ virtual USHORT GetUndoActionId() const;
+ virtual UniString GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const;
+ virtual SfxUndoAction* GetUndoAction( size_t nNo=0 ) const;
+ virtual size_t GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const;
+ virtual UniString GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const;
+ virtual BOOL Undo();
+ virtual BOOL Redo();
+ virtual void Clear();
+ virtual void ClearRedo();
+ virtual void Reset();
+ virtual bool IsDoing() const;
+ virtual size_t GetRepeatActionCount() const;
+ virtual UniString GetRepeatActionComment( SfxRepeatTarget &rTarget) const;
+ virtual BOOL Repeat( SfxRepeatTarget &rTarget );
+ virtual BOOL CanRepeat( SfxRepeatTarget &rTarget ) const;
virtual void EnterListAction(const UniString &rComment, const UniString& rRepeatComment, USHORT nId=0);
- virtual void LeaveListAction();
+ virtual size_t LeaveListAction();
+ virtual size_t LeaveAndMergeListAction();
+ virtual bool IsInListAction() const;
+ virtual size_t GetListActionDepth() const;
+ virtual void RemoveLastUndoAction();
+ virtual void EnableUndo( bool bEnable );
+ virtual bool IsUndoEnabled() const;
+ virtual void AddUndoListener( SfxUndoListener& i_listener );
+ virtual void RemoveUndoListener( SfxUndoListener& i_listener );
+
+ /** marks the current top-level element of the Undo stack, and returns a unique ID for it
+ */
+ UndoStackMark MarkTopUndoAction();
+
+ /** removes a mark given by its ID.
+
+ After the call, the mark ID is invalid.
+ */
+ void RemoveMark( UndoStackMark const i_mark );
+
+ /** determines whether the top action on the Undo stack has a given mark
+ */
+ bool HasTopUndoActionMark( UndoStackMark const i_mark );
+
+ /** removes the oldest Undo actions from the stack
+ */
+ void RemoveOldestUndoActions( size_t const i_count );
+
+protected:
+ BOOL UndoWithContext( SfxUndoContext& i_context );
+ BOOL RedoWithContext( SfxUndoContext& i_context );
+
+ void ImplClearRedo_NoLock( bool const i_currentLevel );
- /** clears the redo stack and removes the top undo action */
- void RemoveLastUndoAction();
+ /** clears all undo actions on the current level, plus all undo actions on superordinate levels,
+ as soon as those levels are reached.
- // enables (true) or disables (false) recording of undo actions
- // If undo actions are added while undo is disabled, they are deleted.
- // Disabling undo does not clear the current undo buffer!
- void EnableUndo( bool bEnable );
+ If no list action is active currently, i.e. we're on the top level already, this method is equivalent to
+ ->Clear.
- // returns true if undo is currently enabled
- // This returns false if undo was disabled using EnableUndo( false ) and
- // also during the runtime of the Undo() and Redo() methods.
- bool IsUndoEnabled() const { return mbUndoEnabled; }
+ Otherwise, the Undo actions on the current level are removed. Upon leaving the current list action, all
+ undo actions on the then-current level are removed, too. This is continued until the top level is reached.
+ */
+ void ClearAllLevels();
+
+private:
+ size_t ImplLeaveListAction( const bool i_merge, ::svl::undo::impl::UndoManagerGuard& i_guard );
+ bool ImplAddUndoAction_NoNotify( SfxUndoAction* pAction, bool bTryMerge, bool bClearRedo, ::svl::undo::impl::UndoManagerGuard& i_guard );
+ void ImplClearRedo( ::svl::undo::impl::UndoManagerGuard& i_guard, bool const i_currentLevel );
+ void ImplClearUndo( ::svl::undo::impl::UndoManagerGuard& i_guard );
+ void ImplClearCurrentLevel_NoNotify( ::svl::undo::impl::UndoManagerGuard& i_guard );
+ size_t ImplGetRedoActionCount_Lock( bool const i_currentLevel = CurrentLevel ) const;
+ bool ImplIsUndoEnabled_Lock() const;
+ bool ImplIsInListAction_Lock() const;
+ void ImplEnableUndo_Lock( bool const i_enable );
+
+ BOOL ImplUndo( SfxUndoContext* i_contextOrNull );
+ BOOL ImplRedo( SfxUndoContext* i_contextOrNull );
+
+ friend class ::svl::undo::impl::LockGuard;
};
//=========================================================================
@@ -213,7 +449,7 @@ class SVL_DLLPUBLIC SfxLinkUndoAction : public SfxUndoAction
{
public:
TYPEINFO();
- SfxLinkUndoAction(SfxUndoManager *pManager);
+ SfxLinkUndoAction(::svl::IUndoManager *pManager);
~SfxLinkUndoAction();
virtual void Undo();
@@ -222,14 +458,14 @@ public:
virtual void Repeat(SfxRepeatTarget&r);
- virtual UniString GetComment() const;
- virtual UniString GetRepeatComment(SfxRepeatTarget&r) const;
+ virtual UniString GetComment() const;
+ virtual UniString GetRepeatComment(SfxRepeatTarget&r) const;
virtual USHORT GetId() const;
SfxUndoAction* GetAction() const { return pAction; }
protected:
- SfxUndoManager *pUndoManager;
+ ::svl::IUndoManager *pUndoManager;
SfxUndoAction *pAction;
};
diff --git a/svl/source/undo/undo.cxx b/svl/source/undo/undo.cxx
index fa5eca964a8c..fd789e6a4aac 100644
--- a/svl/source/undo/undo.cxx
+++ b/svl/source/undo/undo.cxx
@@ -30,10 +30,16 @@
#include <com/sun/star/uno/Exception.hpp>
+#include <comphelper/flagguard.hxx>
#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
#include <svl/undo.hxx>
+#include <vector>
+#include <list>
+#include <limits>
+
using ::com::sun::star::uno::Exception;
// STATIC DATA -----------------------------------------------------------
@@ -55,6 +61,12 @@ SfxRepeatTarget::~SfxRepeatTarget()
//------------------------------------------------------------------------
+SfxUndoContext::~SfxUndoContext()
+{
+}
+
+//------------------------------------------------------------------------
+
BOOL SfxUndoAction::IsLinked()
{
return bLinked;
@@ -117,7 +129,6 @@ XubString SfxUndoAction::GetRepeatComment(SfxRepeatTarget&) const
//------------------------------------------------------------------------
-
void SfxUndoAction::Undo()
{
// die sind nur konzeptuell pure virtual
@@ -126,6 +137,14 @@ void SfxUndoAction::Undo()
//------------------------------------------------------------------------
+void SfxUndoAction::UndoWithContext( SfxUndoContext& i_context )
+{
+ (void)i_context;
+ Undo();
+}
+
+//------------------------------------------------------------------------
+
void SfxUndoAction::Redo()
{
// die sind nur konzeptuell pure virtual
@@ -134,6 +153,14 @@ void SfxUndoAction::Redo()
//------------------------------------------------------------------------
+void SfxUndoAction::RedoWithContext( SfxUndoContext& i_context )
+{
+ (void)i_context;
+ Redo();
+}
+
+//------------------------------------------------------------------------
+
void SfxUndoAction::Repeat(SfxRepeatTarget&)
{
// die sind nur konzeptuell pure virtual
@@ -150,206 +177,554 @@ BOOL SfxUndoAction::CanRepeat(SfxRepeatTarget&) const
//========================================================================
+typedef ::std::vector< SfxUndoListener* > UndoListeners;
+
+struct SVL_DLLPRIVATE SfxUndoManager_Data
+{
+ ::osl::Mutex aMutex;
+ SfxUndoArray* pUndoArray;
+ SfxUndoArray* pActUndoArray;
+ SfxUndoArray* pFatherUndoArray;
+
+ sal_Int32 mnLockCount;
+ sal_Int32 mnMarks;
+ sal_Int32 mnEmptyMark;
+ bool mbDoing;
+ bool mbClearUntilTopLevel;
+
+ UndoListeners aListeners;
+
+ SfxUndoManager_Data( size_t i_nMaxUndoActionCount )
+ :pUndoArray( new SfxUndoArray( i_nMaxUndoActionCount ) )
+ ,pActUndoArray( NULL )
+ ,pFatherUndoArray( NULL )
+ ,mnLockCount( 0 )
+ ,mnMarks( 0 )
+ ,mnEmptyMark(MARK_INVALID)
+ ,mbDoing( false )
+ ,mbClearUntilTopLevel( false )
+ {
+ pActUndoArray = pUndoArray;
+ }
+
+ ~SfxUndoManager_Data()
+ {
+ delete pUndoArray;
+ }
+};
+
+//========================================================================
-SfxUndoManager::SfxUndoManager( USHORT nMaxUndoActionCount )
- : pFatherUndoArray(0)
- , mbUndoEnabled( true )
+namespace svl { namespace undo { namespace impl
{
- pUndoArray=new SfxUndoArray(nMaxUndoActionCount);
- pActUndoArray=pUndoArray;
+ //--------------------------------------------------------------------
+ class SVL_DLLPRIVATE LockGuard
+ {
+ public:
+ LockGuard( SfxUndoManager& i_manager )
+ :m_manager( i_manager )
+ {
+ m_manager.ImplEnableUndo_Lock( false );
+ }
+
+ ~LockGuard()
+ {
+ m_manager.ImplEnableUndo_Lock( true );
+ }
+
+ private:
+ SfxUndoManager& m_manager;
+ };
+
+ //--------------------------------------------------------------------
+ typedef void ( SfxUndoListener::*UndoListenerVoidMethod )();
+ typedef void ( SfxUndoListener::*UndoListenerStringMethod )( const String& );
+
+ //--------------------------------------------------------------------
+ struct SVL_DLLPRIVATE NotifyUndoListener : public ::std::unary_function< SfxUndoListener*, void >
+ {
+ NotifyUndoListener()
+ :m_notificationMethod( NULL )
+ ,m_altNotificationMethod( NULL )
+ ,m_sActionComment()
+ {
+ }
+ NotifyUndoListener( UndoListenerVoidMethod i_notificationMethod )
+ :m_notificationMethod( i_notificationMethod )
+ ,m_altNotificationMethod( NULL )
+ ,m_sActionComment()
+ {
+ }
+
+ NotifyUndoListener( UndoListenerStringMethod i_notificationMethod, const String& i_actionComment )
+ :m_notificationMethod( NULL )
+ ,m_altNotificationMethod( i_notificationMethod )
+ ,m_sActionComment( i_actionComment )
+ {
+ }
+
+ bool is() const
+ {
+ return ( m_notificationMethod != NULL ) || ( m_altNotificationMethod != NULL );
+ }
+
+ void operator()( SfxUndoListener* i_listener ) const
+ {
+ OSL_PRECOND( is(), "NotifyUndoListener: this will crash!" );
+ if ( m_altNotificationMethod != NULL )
+ {
+ ( i_listener->*m_altNotificationMethod )( m_sActionComment );
+ }
+ else
+ {
+ ( i_listener->*m_notificationMethod )();
+ }
+ }
+
+ private:
+ UndoListenerVoidMethod m_notificationMethod;
+ UndoListenerStringMethod m_altNotificationMethod;
+ String m_sActionComment;
+ };
+
+ //--------------------------------------------------------------------
+ class SVL_DLLPRIVATE UndoManagerGuard
+ {
+ public:
+ UndoManagerGuard( SfxUndoManager_Data& i_managerData )
+ :m_rManagerData( i_managerData )
+ ,m_aGuard( i_managerData.aMutex )
+ ,m_notifiers()
+ {
+ }
+
+ ~UndoManagerGuard();
+
+ void clear()
+ {
+ m_aGuard.clear();
+ }
+
+ void reset()
+ {
+ m_aGuard.reset();
+ }
+
+ void cancelNotifications()
+ {
+ m_notifiers.clear();
+ }
+
+ /** marks the given Undo action for deletion
+
+ The Undo action will be put into a list, whose members will be deleted from within the destructor of the
+ UndoManagerGuard. This deletion will happen without the UndoManager's mutex locked.
+ */
+ void markForDeletion( SfxUndoAction* i_action )
+ {
+ // remember
+ if ( i_action )
+ m_aUndoActionsCleanup.push_back( i_action );
+ }
+
+ /** schedules the given SfxUndoListener method to be called for all registered listeners.
+
+ The notification will happen after the Undo manager's mutex has been released, and after all pending
+ deletions of Undo actions are done.
+ */
+ void scheduleNotification( UndoListenerVoidMethod i_notificationMethod )
+ {
+ m_notifiers.push_back( NotifyUndoListener( i_notificationMethod ) );
+ }
+
+ void scheduleNotification( UndoListenerStringMethod i_notificationMethod, const String& i_actionComment )
+ {
+ m_notifiers.push_back( NotifyUndoListener( i_notificationMethod, i_actionComment ) );
+ }
+
+ private:
+ SfxUndoManager_Data& m_rManagerData;
+ ::osl::ResettableMutexGuard m_aGuard;
+ ::std::list< SfxUndoAction* > m_aUndoActionsCleanup;
+ ::std::list< NotifyUndoListener > m_notifiers;
+ };
+
+ UndoManagerGuard::~UndoManagerGuard()
+ {
+ // copy members
+ UndoListeners aListenersCopy( m_rManagerData.aListeners );
+
+ // release mutex
+ m_aGuard.clear();
+
+ // delete all actions
+ while ( !m_aUndoActionsCleanup.empty() )
+ {
+ SfxUndoAction* pAction = m_aUndoActionsCleanup.front();
+ m_aUndoActionsCleanup.pop_front();
+ try
+ {
+ delete pAction;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+ }
+
+ // handle scheduled notification
+ for ( ::std::list< NotifyUndoListener >::const_iterator notifier = m_notifiers.begin();
+ notifier != m_notifiers.end();
+ ++notifier
+ )
+ {
+ if ( notifier->is() )
+ ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(), *notifier );
+ }
+ }
+} } }
+
+using namespace ::svl::undo::impl;
+
+//========================================================================
+
+SfxUndoManager::SfxUndoManager( size_t nMaxUndoActionCount )
+ :m_pData( new SfxUndoManager_Data( nMaxUndoActionCount ) )
+{
}
//------------------------------------------------------------------------
-
SfxUndoManager::~SfxUndoManager()
{
- delete pUndoArray;
+ UndoListeners aListenersCopy;
+ {
+ UndoManagerGuard aGuard( *m_pData );
+ aListenersCopy = m_pData->aListeners;
+ }
+
+ ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(),
+ NotifyUndoListener( &SfxUndoListener::undoManagerDying ) );
}
//------------------------------------------------------------------------
-void SfxUndoManager::EnableUndo( bool bEnable )
+void SfxUndoManager::EnableUndo( bool i_enable )
{
- mbUndoEnabled = bEnable;
+ UndoManagerGuard aGuard( *m_pData );
+ ImplEnableUndo_Lock( i_enable );
+
}
//------------------------------------------------------------------------
+void SfxUndoManager::ImplEnableUndo_Lock( bool const i_enable )
+{
+ if ( !i_enable )
+ ++m_pData->mnLockCount;
+ else
+ {
+ OSL_PRECOND( m_pData->mnLockCount > 0, "SfxUndoManager::ImplEnableUndo_NoNotify: not disabled, so why enabling?" );
+ if ( m_pData->mnLockCount > 0 )
+ --m_pData->mnLockCount;
+ }
+}
-void SfxUndoManager::SetMaxUndoActionCount( USHORT nMaxUndoActionCount )
+//------------------------------------------------------------------------
+
+bool SfxUndoManager::IsUndoEnabled() const
{
+ UndoManagerGuard aGuard( *m_pData );
+ return ImplIsUndoEnabled_Lock();
+}
+
+//------------------------------------------------------------------------
+
+bool SfxUndoManager::ImplIsUndoEnabled_Lock() const
+{
+ return m_pData->mnLockCount == 0;
+}
+
+//------------------------------------------------------------------------
+
+void SfxUndoManager::SetMaxUndoActionCount( size_t nMaxUndoActionCount )
+{
+ UndoManagerGuard aGuard( *m_pData );
+
// Remove entries from the pActUndoArray when we have to reduce
// the number of entries due to a lower nMaxUndoActionCount.
// Both redo and undo action entries will be removed until we reached the
// new nMaxUndoActionCount.
- long nNumToDelete = pActUndoArray->aUndoActions.Count() - nMaxUndoActionCount;
- if ( nNumToDelete > 0 )
+ long nNumToDelete = m_pData->pActUndoArray->aUndoActions.size() - nMaxUndoActionCount;
+ while ( nNumToDelete > 0 )
{
- while ( nNumToDelete > 0 )
+ size_t nPos = m_pData->pActUndoArray->aUndoActions.size();
+ if ( nPos > m_pData->pActUndoArray->nCurUndoAction )
{
- USHORT nPos = pActUndoArray->aUndoActions.Count();
- if ( nPos > pActUndoArray->nCurUndoAction )
+ SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[nPos-1].pAction;
+ if ( !pAction->IsLinked() )
{
- if ( !pActUndoArray->aUndoActions[nPos-1]->IsLinked() )
- {
- delete pActUndoArray->aUndoActions[nPos-1];
- pActUndoArray->aUndoActions.Remove( nPos-1 );
- --nNumToDelete;
- }
+ aGuard.markForDeletion( pAction );
+ m_pData->pActUndoArray->aUndoActions.Remove( nPos-1 );
+ --nNumToDelete;
}
+ }
- if ( nNumToDelete > 0 && pActUndoArray->nCurUndoAction > 0 )
+ if ( nNumToDelete > 0 && m_pData->pActUndoArray->nCurUndoAction > 0 )
+ {
+ SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[0].pAction;
+ if ( !pAction->IsLinked() )
{
- if ( !pActUndoArray->aUndoActions[0]->IsLinked() )
- {
- delete pActUndoArray->aUndoActions[0];
- pActUndoArray->aUndoActions.Remove(0);
- --pActUndoArray->nCurUndoAction;
- --nNumToDelete;
- }
+ aGuard.markForDeletion( pAction );
+ m_pData->pActUndoArray->aUndoActions.Remove(0);
+ --m_pData->pActUndoArray->nCurUndoAction;
+ --nNumToDelete;
}
-
- if ( nPos == pActUndoArray->aUndoActions.Count() )
- break; // Cannot delete more entries
}
+
+ if ( nPos == m_pData->pActUndoArray->aUndoActions.size() )
+ break; // Cannot delete more entries
}
- pActUndoArray->nMaxUndoActions = nMaxUndoActionCount;
+ m_pData->pActUndoArray->nMaxUndoActions = nMaxUndoActionCount;
}
//------------------------------------------------------------------------
-USHORT SfxUndoManager::GetMaxUndoActionCount() const
+size_t SfxUndoManager::GetMaxUndoActionCount() const
{
- return pActUndoArray->nMaxUndoActions;
+ UndoManagerGuard aGuard( *m_pData );
+ return m_pData->pActUndoArray->nMaxUndoActions;
}
//------------------------------------------------------------------------
-void SfxUndoManager::Clear()
+void SfxUndoManager::ImplClearCurrentLevel_NoNotify( UndoManagerGuard& i_guard )
{
- while ( pActUndoArray->aUndoActions.Count() )
+ // clear array
+ while ( !m_pData->pActUndoArray->aUndoActions.empty() )
{
- SfxUndoAction *pAction=
- pActUndoArray->aUndoActions[pActUndoArray->aUndoActions.Count() - 1];
- pActUndoArray->aUndoActions.Remove( pActUndoArray->aUndoActions.Count() - 1 );
- delete pAction;
+ size_t deletePos = m_pData->pActUndoArray->aUndoActions.size() - 1;
+ SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ deletePos ].pAction;
+ i_guard.markForDeletion( pAction );
+ m_pData->pActUndoArray->aUndoActions.Remove( deletePos );
}
- pActUndoArray->nCurUndoAction = 0;
+ m_pData->pActUndoArray->nCurUndoAction = 0;
+
+ m_pData->mnMarks = 0;
+ m_pData->mnEmptyMark = MARK_INVALID;
}
//------------------------------------------------------------------------
-void SfxUndoManager::ClearRedo()
+void SfxUndoManager::Clear()
{
- while ( pActUndoArray->aUndoActions.Count() > pActUndoArray->nCurUndoAction )
- {
- SfxUndoAction *pAction=
- pActUndoArray->aUndoActions[pActUndoArray->aUndoActions.Count() - 1];
- pActUndoArray->aUndoActions.Remove( pActUndoArray->aUndoActions.Count() - 1 );
- delete pAction;
- }
+ UndoManagerGuard aGuard( *m_pData );
+
+ OSL_ENSURE( !ImplIsInListAction_Lock(), "SfxUndoManager::Clear: suspicious call - do you really wish to clear the current level?" );
+ ImplClearCurrentLevel_NoNotify( aGuard );
+
+ // notify listeners
+ aGuard.scheduleNotification( &SfxUndoListener::cleared );
}
//------------------------------------------------------------------------
-void SfxUndoManager::AddUndoAction( SfxUndoAction *pAction, BOOL bTryMerge )
+void SfxUndoManager::ClearAllLevels()
{
- if( mbUndoEnabled )
+ UndoManagerGuard aGuard( *m_pData );
+ ImplClearCurrentLevel_NoNotify( aGuard );
+
+ if ( ImplIsInListAction_Lock() )
+ {
+ m_pData->mbClearUntilTopLevel = true;
+ }
+ else
{
- // Redo-Actions loeschen
- for ( USHORT nPos = pActUndoArray->aUndoActions.Count();
- nPos > pActUndoArray->nCurUndoAction; --nPos )
- delete pActUndoArray->aUndoActions[nPos-1];
+ aGuard.scheduleNotification( &SfxUndoListener::cleared );
+ }
+}
- pActUndoArray->aUndoActions.Remove(
- pActUndoArray->nCurUndoAction,
- pActUndoArray->aUndoActions.Count() - pActUndoArray->nCurUndoAction );
+//------------------------------------------------------------------------
- if ( pActUndoArray->nMaxUndoActions )
- {
- SfxUndoAction *pTmpAction = pActUndoArray->nCurUndoAction ?
- pActUndoArray->aUndoActions[pActUndoArray->nCurUndoAction-1] : 0;
+void SfxUndoManager::ImplClearRedo_NoLock( bool const i_currentLevel )
+{
+ UndoManagerGuard aGuard( *m_pData );
+ ImplClearRedo( aGuard, i_currentLevel );
+}
- if ( !bTryMerge || !(pTmpAction && pTmpAction->Merge(pAction)) )
- {
- // auf Max-Anzahl anpassen
- if( pActUndoArray == pUndoArray )
- while( pActUndoArray->aUndoActions.Count() >=
- pActUndoArray->nMaxUndoActions &&
- !pActUndoArray->aUndoActions[0]->IsLinked() )
- {
- delete pActUndoArray->aUndoActions[0];
- pActUndoArray->aUndoActions.Remove(0);
- --pActUndoArray->nCurUndoAction;
- }
-
- // neue Action anh"angen
- const SfxUndoAction* pTemp = pAction;
- pActUndoArray->aUndoActions.Insert(
- pTemp, pActUndoArray->nCurUndoAction++ );
- return;
- }
- }
- }
- delete pAction;
+//------------------------------------------------------------------------
+
+void SfxUndoManager::ClearRedo()
+{
+ OSL_ENSURE( !IsInListAction(), "SfxUndoManager::ClearRedo: suspicious call - do you really wish to clear the current level?" );
+ ImplClearRedo_NoLock( CurrentLevel );
}
//------------------------------------------------------------------------
-USHORT SfxUndoManager::GetUndoActionCount() const
+void SfxUndoManager::Reset()
{
- return pActUndoArray->nCurUndoAction;
+ UndoManagerGuard aGuard( *m_pData );
+
+ // clear all locks
+ while ( !ImplIsUndoEnabled_Lock() )
+ ImplEnableUndo_Lock( true );
+
+ // cancel all list actions
+ while ( IsInListAction() )
+ ImplLeaveListAction( false, aGuard );
+
+ // clear both stacks
+ ImplClearCurrentLevel_NoNotify( aGuard );
+
+ // cancel the notifications scheduled by ImplLeaveListAction,
+ // as we want to do an own, dedicated notification
+ aGuard.cancelNotifications();
+
+ // schedule notification
+ aGuard.scheduleNotification( &SfxUndoListener::resetAll );
}
//------------------------------------------------------------------------
-XubString SfxUndoManager::GetUndoActionComment( USHORT nNo ) const
+void SfxUndoManager::ImplClearUndo( UndoManagerGuard& i_guard )
{
- DBG_ASSERT( nNo < pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoActionComment(), illegal id!" );
- if( nNo < pActUndoArray->nCurUndoAction )
+ while ( m_pData->pActUndoArray->nCurUndoAction > 0 )
{
- return pActUndoArray->aUndoActions[pActUndoArray->nCurUndoAction-1-nNo]->GetComment(); //!
+ SfxUndoAction* pUndoAction = m_pData->pActUndoArray->aUndoActions[0].pAction;
+ m_pData->pActUndoArray->aUndoActions.Remove( 0 );
+ i_guard.markForDeletion( pUndoAction );
+ --m_pData->pActUndoArray->nCurUndoAction;
}
- else
+ // TODO: notifications? We don't have clearedUndo, only cleared and clearedRedo at the SfxUndoListener
+}
+
+//------------------------------------------------------------------------
+
+void SfxUndoManager::ImplClearRedo( UndoManagerGuard& i_guard, bool const i_currentLevel )
+{
+ SfxUndoArray* pUndoArray = ( i_currentLevel == IUndoManager::CurrentLevel ) ? m_pData->pActUndoArray : m_pData->pUndoArray;
+
+ // clearance
+ while ( pUndoArray->aUndoActions.size() > pUndoArray->nCurUndoAction )
{
- XubString aEmpty;
- return aEmpty;
+ size_t deletePos = pUndoArray->aUndoActions.size() - 1;
+ SfxUndoAction* pAction = pUndoArray->aUndoActions[ deletePos ].pAction;
+ pUndoArray->aUndoActions.Remove( deletePos );
+ i_guard.markForDeletion( pAction );
}
+
+ // notification - only if the top level's stack was cleared
+ if ( i_currentLevel == IUndoManager::TopLevel )
+ i_guard.scheduleNotification( &SfxUndoListener::clearedRedo );
}
//------------------------------------------------------------------------
-USHORT SfxUndoManager::GetUndoActionId( USHORT nNo ) const
+bool SfxUndoManager::ImplAddUndoAction_NoNotify( SfxUndoAction *pAction, bool bTryMerge, bool bClearRedo, UndoManagerGuard& i_guard )
{
- DBG_ASSERT( nNo < pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoActionId(), illegal id!" );
- if( nNo < pActUndoArray->nCurUndoAction )
+ if ( !ImplIsUndoEnabled_Lock() || ( m_pData->pActUndoArray->nMaxUndoActions == 0 ) )
{
- return pActUndoArray->aUndoActions[pActUndoArray->nCurUndoAction-1-nNo]->GetId(); //!
+ i_guard.markForDeletion( pAction );
+ return false;
}
- else
+
+ // merge, if required
+ SfxUndoAction* pMergeWithAction = m_pData->pActUndoArray->nCurUndoAction ?
+ m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1].pAction : NULL;
+ if ( bTryMerge && ( !pMergeWithAction || !pMergeWithAction->Merge( pAction ) ) )
{
- return 0;
+ i_guard.markForDeletion( pAction );
+ return false;
}
+
+ // clear redo stack, if requested
+ if ( bClearRedo && ( ImplGetRedoActionCount_Lock( CurrentLevel ) > 0 ) )
+ ImplClearRedo( i_guard, IUndoManager::CurrentLevel );
+
+ // respect max number
+ if( m_pData->pActUndoArray == m_pData->pUndoArray )
+ {
+ while( m_pData->pActUndoArray->aUndoActions.size() >=
+ m_pData->pActUndoArray->nMaxUndoActions &&
+ !m_pData->pActUndoArray->aUndoActions[0].pAction->IsLinked() )
+ {
+ i_guard.markForDeletion( m_pData->pActUndoArray->aUndoActions[0].pAction );
+ m_pData->pActUndoArray->aUndoActions.Remove(0);
+ --m_pData->pActUndoArray->nCurUndoAction;
+ }
+ }
+
+ // append new action
+ m_pData->pActUndoArray->aUndoActions.Insert( pAction, m_pData->pActUndoArray->nCurUndoAction++ );
+ return true;
}
//------------------------------------------------------------------------
-SfxUndoAction* SfxUndoManager::GetUndoAction( USHORT nNo ) const
+void SfxUndoManager::AddUndoAction( SfxUndoAction *pAction, BOOL bTryMerge )
{
- DBG_ASSERT( nNo < pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoAction(), illegal id!" );
- if( nNo < pActUndoArray->nCurUndoAction )
+ UndoManagerGuard aGuard( *m_pData );
+
+ // add
+ if ( ImplAddUndoAction_NoNotify( pAction, bTryMerge, true, aGuard ) )
{
- return pActUndoArray->aUndoActions[pActUndoArray->nCurUndoAction-1-nNo]; //!
+ // notify listeners
+ aGuard.scheduleNotification( &SfxUndoListener::undoActionAdded, pAction->GetComment() );
}
- else
+}
+
+//------------------------------------------------------------------------
+
+size_t SfxUndoManager::GetUndoActionCount( bool const i_currentLevel ) const
+{
+ UndoManagerGuard aGuard( *m_pData );
+ const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
+ return pUndoArray->nCurUndoAction;
+}
+
+//------------------------------------------------------------------------
+
+XubString SfxUndoManager::GetUndoActionComment( size_t nNo, bool const i_currentLevel ) const
+{
+ UndoManagerGuard aGuard( *m_pData );
+
+ String sComment;
+ const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
+ DBG_ASSERT( nNo < pUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoActionComment: illegal index!" );
+ if( nNo < pUndoArray->nCurUndoAction )
{
- return 0;
+ sComment = pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction - 1 - nNo ].pAction->GetComment();
}
+ return sComment;
+}
+
+//------------------------------------------------------------------------
+
+USHORT SfxUndoManager::GetUndoActionId() const
+{
+ UndoManagerGuard aGuard( *m_pData );
+
+ DBG_ASSERT( m_pData->pActUndoArray->nCurUndoAction > 0, "svl::SfxUndoManager::GetUndoActionId(), illegal id!" );
+ if ( m_pData->pActUndoArray->nCurUndoAction == 0 )
+ return NULL;
+ return m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1].pAction->GetId();
+}
+
+//------------------------------------------------------------------------
+
+SfxUndoAction* SfxUndoManager::GetUndoAction( size_t nNo ) const
+{
+ UndoManagerGuard aGuard( *m_pData );
+
+ DBG_ASSERT( nNo < m_pData->pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoAction(), illegal id!" );
+ if( nNo >= m_pData->pActUndoArray->nCurUndoAction )
+ return NULL;
+ return m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1-nNo].pAction;
}
//------------------------------------------------------------------------
@@ -357,158 +732,235 @@ SfxUndoAction* SfxUndoManager::GetUndoAction( USHORT nNo ) const
/** clears the redo stack and removes the top undo action */
void SfxUndoManager::RemoveLastUndoAction()
{
- DBG_ASSERT( pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::RemoveLastUndoAction(), no action to remove?!" );
- if( pActUndoArray->nCurUndoAction )
- {
- pActUndoArray->nCurUndoAction--;
+ UndoManagerGuard aGuard( *m_pData );
- // delete redo-actions and top action
- USHORT nPos;
- for ( nPos = pActUndoArray->aUndoActions.Count(); nPos > pActUndoArray->nCurUndoAction; --nPos )
- delete pActUndoArray->aUndoActions[nPos-1];
+ ENSURE_OR_RETURN_VOID( m_pData->pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::RemoveLastUndoAction(), no action to remove?!" );
- pActUndoArray->aUndoActions.Remove(
- pActUndoArray->nCurUndoAction,
- pActUndoArray->aUndoActions.Count() - pActUndoArray->nCurUndoAction );
+ m_pData->pActUndoArray->nCurUndoAction--;
+
+ // delete redo-actions and top action
+ for ( size_t nPos = m_pData->pActUndoArray->aUndoActions.size(); nPos > m_pData->pActUndoArray->nCurUndoAction; --nPos )
+ {
+ aGuard.markForDeletion( m_pData->pActUndoArray->aUndoActions[nPos-1].pAction );
}
+
+ m_pData->pActUndoArray->aUndoActions.Remove(
+ m_pData->pActUndoArray->nCurUndoAction,
+ m_pData->pActUndoArray->aUndoActions.size() - m_pData->pActUndoArray->nCurUndoAction );
}
//------------------------------------------------------------------------
-BOOL SfxUndoManager::Undo( USHORT )
+bool SfxUndoManager::IsDoing() const
{
- bool bUndoWasEnabled = mbUndoEnabled;
- mbUndoEnabled = false;
+ UndoManagerGuard aGuard( *m_pData );
+ return m_pData->mbDoing;
+}
- BOOL bRet = FALSE;
+//------------------------------------------------------------------------
- try
- {
- DBG_ASSERT( pActUndoArray == pUndoArray, "svl::SfxUndoManager::Undo(), LeaveListAction() not yet called!" );
- if ( pActUndoArray->nCurUndoAction )
- {
- Undo( *pActUndoArray->aUndoActions[ --pActUndoArray->nCurUndoAction ] );
- bRet = TRUE;
- }
- }
- catch( Exception& e )
- {
- mbUndoEnabled = bUndoWasEnabled;
- throw e;
- }
- mbUndoEnabled = bUndoWasEnabled;
- return bRet;
+BOOL SfxUndoManager::Undo()
+{
+ return ImplUndo( NULL );
+}
+
+//------------------------------------------------------------------------
+
+BOOL SfxUndoManager::UndoWithContext( SfxUndoContext& i_context )
+{
+ return ImplUndo( &i_context );
}
//------------------------------------------------------------------------
-void SfxUndoManager::Undo( SfxUndoAction &rAction )
+BOOL SfxUndoManager::ImplUndo( SfxUndoContext* i_contextOrNull )
{
- bool bUndoWasEnabled = mbUndoEnabled;
- mbUndoEnabled = false;
+ UndoManagerGuard aGuard( *m_pData );
+ OSL_ENSURE( !IsDoing(), "SfxUndoManager::Undo: *nested* Undo/Redo actions? How this?" );
+
+ ::comphelper::FlagGuard aDoingGuard( m_pData->mbDoing );
+ LockGuard aLockGuard( *this );
+
+ if ( ImplIsInListAction_Lock() )
+ {
+ OSL_ENSURE( false, "SfxUndoManager::Undo: not possible when within a list action!" );
+ return FALSE;
+ }
+
+ if ( m_pData->pActUndoArray->nCurUndoAction == 0 )
+ {
+ OSL_ENSURE( false, "SfxUndoManager::Undo: undo stack is empty!" );
+ return FALSE;
+ }
+
+ SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ --m_pData->pActUndoArray->nCurUndoAction ].pAction;
+ const String sActionComment = pAction->GetComment();
try
{
- rAction.Undo();
+ // clear the guard/mutex before calling into the SfxUndoAction - this can be an extension-implemented UNO component
+ // nowadays ...
+ aGuard.clear();
+ if ( i_contextOrNull != NULL )
+ pAction->UndoWithContext( *i_contextOrNull );
+ else
+ pAction->Undo();
+ aGuard.reset();
}
- catch( Exception& e )
+ catch( ... )
{
- mbUndoEnabled = bUndoWasEnabled;
- throw e;
+ aGuard.reset();
+
+ // in theory, somebody might have tampered with all of *m_pData while the mutex was unlocked. So, see if
+ // we still find pAction in our current Undo array
+ size_t nCurAction = 0;
+ while ( nCurAction < m_pData->pActUndoArray->aUndoActions.size() )
+ {
+ if ( m_pData->pActUndoArray->aUndoActions[ nCurAction++ ].pAction == pAction )
+ {
+ // the Undo action is still there ...
+ // assume the error is a permanent failure, and clear the Undo stack
+ ImplClearUndo( aGuard );
+ throw;
+ }
+ }
+ OSL_ENSURE( false, "SfxUndoManager::Undo: can't clear the Undo stack after the failure - some other party was faster ..." );
+ throw;
}
- mbUndoEnabled = bUndoWasEnabled;
+ aGuard.scheduleNotification( &SfxUndoListener::actionUndone, sActionComment );
+
+ return TRUE;
}
//------------------------------------------------------------------------
-USHORT SfxUndoManager::GetRedoActionCount() const
+size_t SfxUndoManager::GetRedoActionCount( bool const i_currentLevel ) const
{
- return pActUndoArray->aUndoActions.Count() - pActUndoArray->nCurUndoAction; //!
+ UndoManagerGuard aGuard( *m_pData );
+ return ImplGetRedoActionCount_Lock( i_currentLevel );
}
//------------------------------------------------------------------------
-XubString SfxUndoManager::GetRedoActionComment( USHORT nNo ) const
+size_t SfxUndoManager::ImplGetRedoActionCount_Lock( bool const i_currentLevel ) const
{
- return pActUndoArray->aUndoActions[pActUndoArray->nCurUndoAction+nNo]->GetComment(); //!
+ const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
+ return pUndoArray->aUndoActions.size() - pUndoArray->nCurUndoAction;
}
//------------------------------------------------------------------------
-USHORT SfxUndoManager::GetRedoActionId( USHORT nNo ) const
+XubString SfxUndoManager::GetRedoActionComment( size_t nNo, bool const i_currentLevel ) const
{
- return pActUndoArray->aUndoActions[pActUndoArray->nCurUndoAction+nNo]->GetId(); //!
+ UndoManagerGuard aGuard( *m_pData );
+ const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
+ return pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction + nNo ].pAction->GetComment();
}
//------------------------------------------------------------------------
-BOOL SfxUndoManager::Redo( USHORT )
+BOOL SfxUndoManager::Redo()
{
- bool bUndoWasEnabled = mbUndoEnabled;
- mbUndoEnabled = false;
-
- BOOL bRet = FALSE;
+ return ImplRedo( NULL );
+}
- try
- {
- if ( pActUndoArray->aUndoActions.Count() > pActUndoArray->nCurUndoAction )
- {
- Redo( *pActUndoArray->aUndoActions[pActUndoArray->nCurUndoAction++] );
- bRet = TRUE;
- }
- }
- catch( Exception& e )
- {
- mbUndoEnabled = bUndoWasEnabled;
- throw e;
- }
+//------------------------------------------------------------------------
- mbUndoEnabled = bUndoWasEnabled;
- return bRet;
+BOOL SfxUndoManager::RedoWithContext( SfxUndoContext& i_context )
+{
+ return ImplRedo( &i_context );
}
//------------------------------------------------------------------------
-void SfxUndoManager::Redo( SfxUndoAction &rAction )
+BOOL SfxUndoManager::ImplRedo( SfxUndoContext* i_contextOrNull )
{
- bool bUndoWasEnabled = mbUndoEnabled;
- mbUndoEnabled = false;
+ UndoManagerGuard aGuard( *m_pData );
+ OSL_ENSURE( !IsDoing(), "SfxUndoManager::Redo: *nested* Undo/Redo actions? How this?" );
+ ::comphelper::FlagGuard aDoingGuard( m_pData->mbDoing );
+ LockGuard aLockGuard( *this );
+
+ if ( ImplIsInListAction_Lock() )
+ {
+ OSL_ENSURE( false, "SfxUndoManager::Redo: not possible when within a list action!" );
+ return FALSE;
+ }
+
+ if ( m_pData->pActUndoArray->nCurUndoAction >= m_pData->pActUndoArray->aUndoActions.size() )
+ {
+ OSL_ENSURE( false, "SfxUndoManager::Redo: redo stack is empty!" );
+ return FALSE;
+ }
+
+ SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction++ ].pAction;
+ const String sActionComment = pAction->GetComment();
try
{
- rAction.Redo();
+ // clear the guard/mutex before calling into the SfxUndoAction - this can be a extension-implemented UNO component
+ // nowadays ...
+ aGuard.clear();
+ if ( i_contextOrNull != NULL )
+ pAction->RedoWithContext( *i_contextOrNull );
+ else
+ pAction->Redo();
+ aGuard.reset();
}
- catch( Exception& e )
+ catch( ... )
{
- mbUndoEnabled = bUndoWasEnabled;
- throw e;
+ aGuard.reset();
+
+ // in theory, somebody might have tampered with all of *m_pData while the mutex was unlocked. So, see if
+ // we still find pAction in our current Undo array
+ size_t nCurAction = 0;
+ while ( nCurAction < m_pData->pActUndoArray->aUndoActions.size() )
+ {
+ if ( m_pData->pActUndoArray->aUndoActions[ nCurAction ].pAction == pAction )
+ {
+ // the Undo action is still there ...
+ // assume the error is a permanent failure, and clear the Undo stack
+ ImplClearRedo( aGuard, IUndoManager::CurrentLevel );
+ throw;
+ }
+ ++nCurAction;
+ }
+ OSL_ENSURE( false, "SfxUndoManager::Redo: can't clear the Undo stack after the failure - some other party was faster ..." );
+ throw;
}
- mbUndoEnabled = bUndoWasEnabled;
+ aGuard.scheduleNotification( &SfxUndoListener::actionRedone, sActionComment );
+
+ return TRUE;
}
//------------------------------------------------------------------------
-USHORT SfxUndoManager::GetRepeatActionCount() const
+size_t SfxUndoManager::GetRepeatActionCount() const
{
- return pActUndoArray->aUndoActions.Count();
+ UndoManagerGuard aGuard( *m_pData );
+ return m_pData->pActUndoArray->aUndoActions.size();
}
//------------------------------------------------------------------------
-XubString SfxUndoManager::GetRepeatActionComment( SfxRepeatTarget &rTarget, USHORT nNo ) const
+XubString SfxUndoManager::GetRepeatActionComment( SfxRepeatTarget &rTarget) const
{
- return pActUndoArray->aUndoActions[ pActUndoArray->aUndoActions.Count() - 1 - nNo ]
+ UndoManagerGuard aGuard( *m_pData );
+ return m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->aUndoActions.size() - 1 ].pAction
->GetRepeatComment(rTarget);
}
//------------------------------------------------------------------------
-BOOL SfxUndoManager::Repeat( SfxRepeatTarget &rTarget, USHORT /*nFrom*/, USHORT /*nCount*/ )
+BOOL SfxUndoManager::Repeat( SfxRepeatTarget &rTarget )
{
- if ( pActUndoArray->aUndoActions.Count() )
+ UndoManagerGuard aGuard( *m_pData );
+ if ( !m_pData->pActUndoArray->aUndoActions.empty() )
{
- Repeat( rTarget, *pActUndoArray->aUndoActions[ pActUndoArray->aUndoActions.Count() - 1 ] );
+ SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->aUndoActions.size() - 1 ].pAction;
+ aGuard.clear();
+ if ( pAction->CanRepeat( rTarget ) )
+ pAction->Repeat( rTarget );
return TRUE;
}
@@ -517,30 +969,41 @@ BOOL SfxUndoManager::Repeat( SfxRepeatTarget &rTarget, USHORT /*nFrom*/, USHORT
//------------------------------------------------------------------------
-void SfxUndoManager::Repeat( SfxRepeatTarget &rTarget, SfxUndoAction &rAction )
+BOOL SfxUndoManager::CanRepeat( SfxRepeatTarget &rTarget ) const
{
- if ( rAction.CanRepeat(rTarget) )
- rAction.Repeat(rTarget);
+ UndoManagerGuard aGuard( *m_pData );
+ if ( !m_pData->pActUndoArray->aUndoActions.empty() )
+ {
+ size_t nActionNo = m_pData->pActUndoArray->aUndoActions.size() - 1;
+ return m_pData->pActUndoArray->aUndoActions[nActionNo].pAction->CanRepeat(rTarget);
+ }
+ return FALSE;
}
//------------------------------------------------------------------------
-BOOL SfxUndoManager::CanRepeat( SfxRepeatTarget &rTarget, SfxUndoAction &rAction ) const
+void SfxUndoManager::AddUndoListener( SfxUndoListener& i_listener )
{
- return rAction.CanRepeat(rTarget);
+ UndoManagerGuard aGuard( *m_pData );
+ m_pData->aListeners.push_back( &i_listener );
}
//------------------------------------------------------------------------
-BOOL SfxUndoManager::CanRepeat( SfxRepeatTarget &rTarget, USHORT nNo ) const
+void SfxUndoManager::RemoveUndoListener( SfxUndoListener& i_listener )
{
- if ( pActUndoArray->aUndoActions.Count() > nNo )
+ UndoManagerGuard aGuard( *m_pData );
+ for ( UndoListeners::iterator lookup = m_pData->aListeners.begin();
+ lookup != m_pData->aListeners.end();
+ ++lookup
+ )
{
- USHORT nActionNo = pActUndoArray->aUndoActions.Count() - 1 - nNo;
- return pActUndoArray->aUndoActions[nActionNo]->CanRepeat(rTarget);
+ if ( (*lookup) == &i_listener )
+ {
+ m_pData->aListeners.erase( lookup );
+ break;
+ }
}
-
- return FALSE;
}
//------------------------------------------------------------------------
@@ -554,69 +1017,270 @@ void SfxUndoManager::EnterListAction(
*/
{
- if( !mbUndoEnabled )
+ UndoManagerGuard aGuard( *m_pData );
+
+ if( !ImplIsUndoEnabled_Lock() )
return;
- if ( !pUndoArray->nMaxUndoActions )
+ if ( !m_pData->pUndoArray->nMaxUndoActions )
return;
- pFatherUndoArray=pActUndoArray;
- SfxListUndoAction *pAction=new SfxListUndoAction(
- rComment, rRepeatComment, nId, pActUndoArray);
- AddUndoAction( pAction );
- pActUndoArray=pAction;
+ m_pData->pFatherUndoArray = m_pData->pActUndoArray;
+ SfxListUndoAction* pAction = new SfxListUndoAction( rComment, rRepeatComment, nId, m_pData->pActUndoArray );
+ OSL_VERIFY( ImplAddUndoAction_NoNotify( pAction, false, false, aGuard ) );
+ // expected to succeed: all conditions under which it could fail should have been checked already
+ m_pData->pActUndoArray = pAction;
+
+ // notification
+ aGuard.scheduleNotification( &SfxUndoListener::listActionEntered, rComment );
}
//------------------------------------------------------------------------
-void SfxUndoManager::LeaveListAction()
+bool SfxUndoManager::IsInListAction() const
+{
+ UndoManagerGuard aGuard( *m_pData );
+ return ImplIsInListAction_Lock();
+}
-/* [Beschreibung]
+//------------------------------------------------------------------------
- Verlaesst die aktuelle ListAction und geht eine Ebene nach oben.
-*/
+bool SfxUndoManager::ImplIsInListAction_Lock() const
{
- if ( !mbUndoEnabled )
- return;
+ return ( m_pData->pActUndoArray != m_pData->pUndoArray );
+}
- if ( !pUndoArray->nMaxUndoActions )
- return;
+//------------------------------------------------------------------------
+
+size_t SfxUndoManager::GetListActionDepth() const
+{
+ UndoManagerGuard aGuard( *m_pData );
+ size_t nDepth(0);
- if( pActUndoArray == pUndoArray )
+ SfxUndoArray* pLookup( m_pData->pActUndoArray );
+ while ( pLookup != m_pData->pUndoArray )
{
- DBG_ERROR( "svl::SfxUndoManager::LeaveListAction(), called without calling EnterListAction()!" );
- return;
+ pLookup = pLookup->pFatherUndoArray;
+ ++nDepth;
}
- DBG_ASSERT(pActUndoArray->pFatherUndoArray,"svl::SfxUndoManager::LeaveListAction(), no father undo array!?");
+ return nDepth;
+}
+
+//------------------------------------------------------------------------
- SfxUndoArray* pTmp=pActUndoArray;
- pActUndoArray=pActUndoArray->pFatherUndoArray;
+size_t SfxUndoManager::LeaveListAction()
+{
+ UndoManagerGuard aGuard( *m_pData );
+ size_t nCount = ImplLeaveListAction( false, aGuard );
- // If no undo action where added, delete the undo list action
- SfxUndoAction *pTmpAction= pActUndoArray->aUndoActions[pActUndoArray->nCurUndoAction-1];
- if(!pTmp->nCurUndoAction)
+ if ( m_pData->mbClearUntilTopLevel )
{
- pActUndoArray->aUndoActions.Remove( --pActUndoArray->nCurUndoAction);
- delete pTmpAction;
+ ImplClearCurrentLevel_NoNotify( aGuard );
+ if ( !ImplIsInListAction_Lock() )
+ {
+ m_pData->mbClearUntilTopLevel = false;
+ aGuard.scheduleNotification( &SfxUndoListener::cleared );
+ }
+ nCount = 0;
}
- else
+
+ return nCount;
+}
+
+//------------------------------------------------------------------------
+
+size_t SfxUndoManager::LeaveAndMergeListAction()
+{
+ UndoManagerGuard aGuard( *m_pData );
+ return ImplLeaveListAction( true, aGuard );
+}
+
+//------------------------------------------------------------------------
+
+size_t SfxUndoManager::ImplLeaveListAction( const bool i_merge, UndoManagerGuard& i_guard )
+{
+ if ( !ImplIsUndoEnabled_Lock() )
+ return 0;
+
+ if ( !m_pData->pUndoArray->nMaxUndoActions )
+ return 0;
+
+ if( !ImplIsInListAction_Lock() )
+ {
+ DBG_ERROR( "svl::SfxUndoManager::ImplLeaveListAction, called without calling EnterListAction()!" );
+ return 0;
+ }
+
+ DBG_ASSERT( m_pData->pActUndoArray->pFatherUndoArray, "SfxUndoManager::ImplLeaveListAction, no father undo array!?" );
+
+ // the array/level which we're about to leave
+ SfxUndoArray* pArrayToLeave = m_pData->pActUndoArray;
+ // one step up
+ m_pData->pActUndoArray = m_pData->pActUndoArray->pFatherUndoArray;
+
+ // If no undo actions were added to the list, delete the list action
+ const size_t nListActionElements = pArrayToLeave->nCurUndoAction;
+ if ( nListActionElements == 0 )
+ {
+ SfxUndoAction* pCurrentAction= m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction-1 ].pAction;
+ m_pData->pActUndoArray->aUndoActions.Remove( --m_pData->pActUndoArray->nCurUndoAction );
+ i_guard.markForDeletion( pCurrentAction );
+
+ i_guard.scheduleNotification( &SfxUndoListener::listActionCancelled );
+ return 0;
+ }
+
+ // now that it is finally clear the list action is non-trivial, and does participate in the Undo stack, clear
+ // the redo stack
+ ImplClearRedo( i_guard, IUndoManager::CurrentLevel );
+
+ SfxUndoAction* pCurrentAction= m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction-1 ].pAction;
+ SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction * >( pCurrentAction );
+ ENSURE_OR_RETURN( pListAction, "SfxUndoManager::ImplLeaveListAction: list action expected at this position!", nListActionElements );
+
+ if ( i_merge )
+ {
+ // merge the list action with its predecessor on the same level
+ OSL_ENSURE( m_pData->pActUndoArray->nCurUndoAction > 1,
+ "SfxUndoManager::ImplLeaveListAction: cannot merge the list action if there's no other action on the same level - check this beforehand!" );
+ if ( m_pData->pActUndoArray->nCurUndoAction > 1 )
+ {
+ SfxUndoAction* pPreviousAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction - 2 ].pAction;
+ m_pData->pActUndoArray->aUndoActions.Remove( m_pData->pActUndoArray->nCurUndoAction - 2 );
+ --m_pData->pActUndoArray->nCurUndoAction;
+ pListAction->aUndoActions.Insert( pPreviousAction, 0 );
+ ++pListAction->nCurUndoAction;
+
+ pListAction->SetComment( pPreviousAction->GetComment() );
+ }
+ }
+
+ // if the undo array has no comment, try to get it from its children
+ if ( pListAction->GetComment().Len() == 0 )
+ {
+ for( size_t n = 0; n < pListAction->aUndoActions.size(); n++ )
+ {
+ if( pListAction->aUndoActions[n].pAction->GetComment().Len() )
+ {
+ pListAction->SetComment( pListAction->aUndoActions[n].pAction->GetComment() );
+ break;
+ }
+ }
+ }
+
+ // notify listeners
+ i_guard.scheduleNotification( &SfxUndoListener::listActionLeft, pListAction->GetComment() );
+
+ // outta here
+ return nListActionElements;
+}
+
+//------------------------------------------------------------------------
+UndoStackMark SfxUndoManager::MarkTopUndoAction()
+{
+ UndoManagerGuard aGuard( *m_pData );
+
+ OSL_ENSURE( !IsInListAction(),
+ "SfxUndoManager::MarkTopUndoAction(): suspicious call!" );
+ OSL_ENSURE((m_pData->mnMarks + 1) < (m_pData->mnEmptyMark - 1),
+ "SfxUndoManager::MarkTopUndoAction(): mark overflow!");
+
+ size_t const nActionPos = m_pData->pUndoArray->nCurUndoAction;
+ if (0 == nActionPos)
+ {
+ --m_pData->mnEmptyMark;
+ return m_pData->mnEmptyMark;
+ }
+
+ m_pData->pUndoArray->aUndoActions[ nActionPos-1 ].aMarks.push_back(
+ ++m_pData->mnMarks );
+ return m_pData->mnMarks;
+}
+
+//------------------------------------------------------------------------
+void SfxUndoManager::RemoveMark( UndoStackMark const i_mark )
+{
+ UndoManagerGuard aGuard( *m_pData );
+
+ if ((m_pData->mnEmptyMark < i_mark) || (MARK_INVALID == i_mark))
{
- // if the undo array has no comment, try to get it from its children
- SfxListUndoAction* pList = dynamic_cast< SfxListUndoAction * >( pTmpAction );
- if( pList && pList->GetComment().Len() == 0 )
+ return; // nothing to remove
+ }
+ else if (i_mark == m_pData->mnEmptyMark)
+ {
+ --m_pData->mnEmptyMark; // never returned from MarkTop => invalid
+ return;
+ }
+
+ for ( size_t i=0; i<m_pData->pUndoArray->aUndoActions.size(); ++i )
+ {
+ MarkedUndoAction& rAction = m_pData->pUndoArray->aUndoActions[i];
+ for ( ::std::vector< UndoStackMark >::iterator markPos = rAction.aMarks.begin();
+ markPos != rAction.aMarks.end();
+ ++markPos
+ )
{
- USHORT n;
- for( n = 0; n < pList->aUndoActions.Count(); n++ )
+ if ( *markPos == i_mark )
{
- if( pList->aUndoActions[n]->GetComment().Len() )
- {
- pList->SetComment( pList->aUndoActions[n]->GetComment() );
- break;
- }
+ rAction.aMarks.erase( markPos );
+ return;
}
}
}
+ OSL_ENSURE( false, "SfxUndoManager::RemoveMark: mark not found!" );
+ // TODO: this might be too offensive. There are situations where we implicitly remove marks
+ // without our clients, in particular the client which created the mark, having a chance to know
+ // about this.
+}
+
+//------------------------------------------------------------------------
+bool SfxUndoManager::HasTopUndoActionMark( UndoStackMark const i_mark )
+{
+ UndoManagerGuard aGuard( *m_pData );
+
+ size_t nActionPos = m_pData->pUndoArray->nCurUndoAction;
+ if ( nActionPos == 0 )
+ {
+ return (i_mark == m_pData->mnEmptyMark);
+ }
+
+ const MarkedUndoAction& rAction =
+ m_pData->pUndoArray->aUndoActions[ nActionPos-1 ];
+ for ( ::std::vector< UndoStackMark >::const_iterator markPos = rAction.aMarks.begin();
+ markPos != rAction.aMarks.end();
+ ++markPos
+ )
+ {
+ if ( *markPos == i_mark )
+ return true;
+ }
+
+ return false;
+}
+
+//------------------------------------------------------------------------
+
+void SfxUndoManager::RemoveOldestUndoActions( size_t const i_count )
+{
+ UndoManagerGuard aGuard( *m_pData );
+
+ size_t nActionsToRemove = i_count;
+ while ( nActionsToRemove )
+ {
+ SfxUndoAction* pActionToRemove = m_pData->pUndoArray->aUndoActions[0].pAction;
+
+ if ( IsInListAction() && ( m_pData->pUndoArray->nCurUndoAction == 1 ) )
+ {
+ OSL_ENSURE( false, "SfxUndoManager::RemoveOldestUndoActions: cannot remove a not-yet-closed list action!" );
+ return;
+ }
+
+ aGuard.markForDeletion( pActionToRemove );
+ m_pData->pUndoArray->aUndoActions.Remove( 0 );
+ --m_pData->pUndoArray->nCurUndoAction;
+ --nActionsToRemove;
+ }
}
//------------------------------------------------------------------------
@@ -667,8 +1331,17 @@ SfxListUndoAction::SfxListUndoAction
void SfxListUndoAction::Undo()
{
- for(INT16 i=nCurUndoAction-1;i>=0;i--)
- aUndoActions[i]->Undo();
+ for(size_t i=nCurUndoAction;i>0;)
+ aUndoActions[--i].pAction->Undo();
+ nCurUndoAction=0;
+}
+
+//------------------------------------------------------------------------
+
+void SfxListUndoAction::UndoWithContext( SfxUndoContext& i_context )
+{
+ for(size_t i=nCurUndoAction;i>0;)
+ aUndoActions[--i].pAction->UndoWithContext( i_context );
nCurUndoAction=0;
}
@@ -676,25 +1349,34 @@ void SfxListUndoAction::Undo()
void SfxListUndoAction::Redo()
{
- for(USHORT i=nCurUndoAction;i<aUndoActions.Count();i++)
- aUndoActions[i]->Redo();
- nCurUndoAction = aUndoActions.Count();
+ for(size_t i=nCurUndoAction;i<aUndoActions.size();i++)
+ aUndoActions[i].pAction->Redo();
+ nCurUndoAction = aUndoActions.size();
+}
+
+//------------------------------------------------------------------------
+
+void SfxListUndoAction::RedoWithContext( SfxUndoContext& i_context )
+{
+ for(size_t i=nCurUndoAction;i<aUndoActions.size();i++)
+ aUndoActions[i].pAction->RedoWithContext( i_context );
+ nCurUndoAction = aUndoActions.size();
}
//------------------------------------------------------------------------
void SfxListUndoAction::Repeat(SfxRepeatTarget&rTarget)
{
- for(USHORT i=0;i<nCurUndoAction;i++)
- aUndoActions[i]->Repeat(rTarget);
+ for(size_t i=0;i<nCurUndoAction;i++)
+ aUndoActions[i].pAction->Repeat(rTarget);
}
//------------------------------------------------------------------------
BOOL SfxListUndoAction::CanRepeat(SfxRepeatTarget&r) const
{
- for(USHORT i=0;i<nCurUndoAction;i++)
- if(!aUndoActions[i]->CanRepeat(r))
+ for(size_t i=0;i<nCurUndoAction;i++)
+ if(!aUndoActions[i].pAction->CanRepeat(r))
return FALSE;
return TRUE;
}
@@ -703,12 +1385,12 @@ BOOL SfxListUndoAction::CanRepeat(SfxRepeatTarget&r) const
BOOL SfxListUndoAction::Merge( SfxUndoAction *pNextAction )
{
- return aUndoActions.Count() && aUndoActions[aUndoActions.Count()-1]->Merge( pNextAction );
+ return !aUndoActions.empty() && aUndoActions[aUndoActions.size()-1].pAction->Merge( pNextAction );
}
//------------------------------------------------------------------------
-SfxLinkUndoAction::SfxLinkUndoAction(SfxUndoManager *pManager)
+SfxLinkUndoAction::SfxLinkUndoAction(::svl::IUndoManager *pManager)
/* [Beschreibung]
Richtet eine LinkAction ein, die auf einen weiteren UndoManager zeigt.
@@ -718,10 +1400,15 @@ SfxLinkUndoAction::SfxLinkUndoAction(SfxUndoManager *pManager)
{
pUndoManager = pManager;
+ SfxUndoManager* pUndoManagerImplementation = dynamic_cast< SfxUndoManager* >( pManager );
+ ENSURE_OR_THROW( pUndoManagerImplementation != NULL, "unsupported undo manager implementation!" );
+ // yes, this cast is dirty. But reaching into the the SfxUndoManager's implementation,
+ // directly accessing its internal stack, and tampering with an action on that stack
+ // is dirty, too.
if ( pManager->GetMaxUndoActionCount() )
{
- USHORT nPos = pManager->GetUndoActionCount()-1;
- pAction = pManager->pActUndoArray->aUndoActions[nPos];
+ size_t nPos = pManager->GetUndoActionCount()-1;
+ pAction = pUndoManagerImplementation->m_pData->pActUndoArray->aUndoActions[nPos].pAction;
pAction->SetLinked();
}
else
@@ -733,7 +1420,7 @@ SfxLinkUndoAction::SfxLinkUndoAction(SfxUndoManager *pManager)
void SfxLinkUndoAction::Undo()
{
if ( pAction )
- pUndoManager->Undo(1);
+ pUndoManager->Undo();
}
//------------------------------------------------------------------------
@@ -741,7 +1428,7 @@ void SfxLinkUndoAction::Undo()
void SfxLinkUndoAction::Redo()
{
if ( pAction )
- pUndoManager->Redo(1);
+ pUndoManager->Redo();
}
//------------------------------------------------------------------------
@@ -749,7 +1436,7 @@ void SfxLinkUndoAction::Redo()
BOOL SfxLinkUndoAction::CanRepeat(SfxRepeatTarget& r) const
{
- return pAction && pUndoManager->CanRepeat(r,*pAction);
+ return pAction && pAction->CanRepeat(r);
}
@@ -758,8 +1445,8 @@ BOOL SfxLinkUndoAction::CanRepeat(SfxRepeatTarget& r) const
void SfxLinkUndoAction::Repeat(SfxRepeatTarget&r)
{
- if ( pAction )
- pUndoManager->Repeat(r,*pAction);
+ if ( pAction && pAction->CanRepeat( r ) )
+ pAction->Repeat( r );
}
@@ -797,11 +1484,10 @@ SfxLinkUndoAction::~SfxLinkUndoAction()
SfxUndoArray::~SfxUndoArray()
{
- while ( aUndoActions.Count() )
+ while ( !aUndoActions.empty() )
{
- SfxUndoAction *pAction =
- aUndoActions[ aUndoActions.Count() - 1 ];
- aUndoActions.Remove( aUndoActions.Count() - 1 );
+ SfxUndoAction *pAction = aUndoActions[ aUndoActions.size() - 1 ].pAction;
+ aUndoActions.Remove( aUndoActions.size() - 1 );
delete pAction;
}
}
@@ -811,6 +1497,3 @@ USHORT SfxLinkUndoAction::GetId() const
{
return pAction ? pAction->GetId() : 0;
}
-
-
-