diff options
-rwxr-xr-x | canvas/source/directx/dx_canvashelper_texturefill.cxx | 2 | ||||
-rw-r--r-- | comphelper/inc/comphelper/TypeGeneration.hxx | 1 | ||||
-rw-r--r-- | comphelper/inc/comphelper/asyncnotification.hxx | 3 | ||||
-rwxr-xr-x | comphelper/inc/comphelper/flagguard.hxx | 83 | ||||
-rw-r--r-- | comphelper/inc/comphelper/scopeguard.hxx | 15 | ||||
-rw-r--r-- | comphelper/source/misc/scopeguard.cxx | 10 | ||||
-rw-r--r-- | comphelper/source/property/TypeGeneration.cxx | 4 | ||||
-rw-r--r-- | svl/inc/svl/undo.hxx | 352 | ||||
-rw-r--r-- | svl/source/undo/undo.cxx | 1203 | ||||
-rw-r--r-- | svtools/inc/svtools/textdata.hxx | 20 | ||||
-rw-r--r-- | svtools/inc/svtools/texteng.hxx | 13 | ||||
-rw-r--r-- | svtools/inc/svtools/xtextedt.hxx | 4 | ||||
-rw-r--r-- | svtools/source/edit/texteng.cxx | 16 | ||||
-rw-r--r-- | svtools/source/edit/textundo.cxx | 29 | ||||
-rw-r--r-- | svtools/source/edit/textundo.hxx | 8 | ||||
-rw-r--r-- | svtools/source/edit/textview.cxx | 32 | ||||
-rw-r--r-- | svtools/source/edit/xtextedt.cxx | 8 | ||||
-rw-r--r-- | toolkit/source/awt/vclxwindow.cxx | 29 |
18 files changed, 1389 insertions, 443 deletions
diff --git a/canvas/source/directx/dx_canvashelper_texturefill.cxx b/canvas/source/directx/dx_canvashelper_texturefill.cxx index 80224aa3d53c..17d5a2983f7c 100755 --- a/canvas/source/directx/dx_canvashelper_texturefill.cxx +++ b/canvas/source/directx/dx_canvashelper_texturefill.cxx @@ -227,6 +227,7 @@ namespace dxcanvas Gdiplus::SolidBrush aBackgroundBrush( rColors[0] ); rGraphics->FillPath( &aBackgroundBrush, pFillPath.get() ); + Gdiplus::Matrix aMatrix; // scale focus according to aspect ratio: for wider-than-tall // bounds (nAspectRatio > 1.0), the focus must have non-zero // width. Specifically, a bound rect twice as wide as tall has @@ -383,7 +384,6 @@ namespace dxcanvas // one sets both, only the translational components of the // texture is respected. - Gdiplus::Matrix aMatrix; tools::gdiPlusMatrixFromAffineMatrix2D( aMatrix, texture.AffineTransform ); GraphicsPathSharedPtr pGradientPath( diff --git a/comphelper/inc/comphelper/TypeGeneration.hxx b/comphelper/inc/comphelper/TypeGeneration.hxx index 6660e560f4af..08401cb39944 100644 --- a/comphelper/inc/comphelper/TypeGeneration.hxx +++ b/comphelper/inc/comphelper/TypeGeneration.hxx @@ -115,6 +115,7 @@ namespace comphelper CPPUTYPE_SEQNAMEDVALUE, //getCppuType( (Sequence<beans::NamedValue>*)0 ) CPPUTYPE_REFXGRAPHIC, //getCppuType( Reference< graphic::XGraphic >*)0) CPPUTYPE_TABLEBORDERDISTANCES, //getCppuType( (table::TableBorderDistances*)0 ) + CPPUTPYE_REFEMBEDDEDOBJECT, // XEmbeddedObject::static_type CPPUTYPE_END }; diff --git a/comphelper/inc/comphelper/asyncnotification.hxx b/comphelper/inc/comphelper/asyncnotification.hxx index fc4dfcd48dd9..22d901728ef7 100644 --- a/comphelper/inc/comphelper/asyncnotification.hxx +++ b/comphelper/inc/comphelper/asyncnotification.hxx @@ -131,8 +131,9 @@ namespace comphelper virtual oslInterlockedCount SAL_CALL acquire(); virtual oslInterlockedCount SAL_CALL release(); - /// creates (starts) the thread using AsyncEventNotifier_TBASE::create; + using AsyncEventNotifier_TBASE::join; + using AsyncEventNotifier_TBASE::getIdentifier; using AsyncEventNotifier_TBASE::operator new; using AsyncEventNotifier_TBASE::operator delete; diff --git a/comphelper/inc/comphelper/flagguard.hxx b/comphelper/inc/comphelper/flagguard.hxx new file mode 100755 index 000000000000..4fc1f4e97833 --- /dev/null +++ b/comphelper/inc/comphelper/flagguard.hxx @@ -0,0 +1,83 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef COMPHELPER_FLAGGUARD_HXX +#define COMPHELPER_FLAGGUARD_HXX + +#include "comphelper/scopeguard.hxx" + +//...................................................................................................................... +namespace comphelper +{ +//...................................................................................................................... + + //================================================================================================================== + //= FlagRestorationGuard + //================================================================================================================== + class COMPHELPER_DLLPUBLIC FlagRestorationGuard : public ScopeGuard + { + public: + FlagRestorationGuard( bool& i_flagRef, bool i_temporaryValue, exc_handling i_excHandling = IGNORE_EXCEPTIONS ) + :ScopeGuard( ::boost::bind( RestoreFlag, ::boost::ref( i_flagRef ), !!i_flagRef ), i_excHandling ) + { + i_flagRef = i_temporaryValue; + } + + ~FlagRestorationGuard(); + + private: + static void RestoreFlag( bool& i_flagRef, bool i_originalValue ) + { + i_flagRef = i_originalValue; + } + }; + + //================================================================================================================== + //= FlagGuard + //================================================================================================================== + class COMPHELPER_DLLPUBLIC FlagGuard : public ScopeGuard + { + public: + explicit FlagGuard( bool& i_flagRef, exc_handling i_excHandling = IGNORE_EXCEPTIONS ) + :ScopeGuard( ::boost::bind( ResetFlag, ::boost::ref( i_flagRef ) ), i_excHandling ) + { + i_flagRef = true; + } + + ~FlagGuard(); + + private: + static void ResetFlag( bool& i_flagRef ) + { + i_flagRef = false; + } + }; + +//...................................................................................................................... +} // namespace comphelper +//...................................................................................................................... + +#endif // COMPHELPER_FLAGGUARD_HXX diff --git a/comphelper/inc/comphelper/scopeguard.hxx b/comphelper/inc/comphelper/scopeguard.hxx index 1fdd179404a2..e9c8f7ecc625 100644 --- a/comphelper/inc/comphelper/scopeguard.hxx +++ b/comphelper/inc/comphelper/scopeguard.hxx @@ -67,21 +67,6 @@ private: exc_handling const m_excHandling; }; -class COMPHELPER_DLLPUBLIC FlagGuard : ScopeGuard -{ -public: - explicit FlagGuard( bool& i_flagRef, exc_handling i_excHandling = IGNORE_EXCEPTIONS ) - :ScopeGuard( ::boost::bind( ResetFlag, ::boost::ref( i_flagRef ) ), i_excHandling ) - { - } - -private: - static void ResetFlag( bool& i_flagRef ) - { - i_flagRef = false; - } -}; - } // namespace comphelper #endif // ! defined(INCLUDED_COMPHELPER_SCOPEGUARD_HXX) diff --git a/comphelper/source/misc/scopeguard.cxx b/comphelper/source/misc/scopeguard.cxx index 7ce478d8bea0..ccd5b618605b 100644 --- a/comphelper/source/misc/scopeguard.cxx +++ b/comphelper/source/misc/scopeguard.cxx @@ -28,7 +28,7 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_comphelper.hxx" -#include "comphelper/scopeguard.hxx" +#include "comphelper/flagguard.hxx" #include "osl/diagnose.h" #include "com/sun/star/uno/Exception.hpp" @@ -67,5 +67,13 @@ void ScopeGuard::dismiss() m_func.clear(); } +FlagGuard::~FlagGuard() +{ +} + +FlagRestorationGuard::~FlagRestorationGuard() +{ +} + } // namespace comphelper diff --git a/comphelper/source/property/TypeGeneration.cxx b/comphelper/source/property/TypeGeneration.cxx index bf880330ce75..649e50711d28 100644 --- a/comphelper/source/property/TypeGeneration.cxx +++ b/comphelper/source/property/TypeGeneration.cxx @@ -132,7 +132,8 @@ // --> OD 2004-08-09 #i28749# #include <com/sun/star/drawing/HomogenMatrix3.hpp> // <-- -#include <com/sun/star/graphic/XGraphicProvider.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> using ::rtl::OUString; using namespace ::com::sun::star; @@ -230,6 +231,7 @@ namespace comphelper case CPPUTYPE_SEQNAMEDVALUE: pType = &::getCppuType( (Sequence<beans::NamedValue>*)0 ); break; case CPPUTYPE_REFXGRAPHIC: pType = &::getCppuType( (Reference< graphic::XGraphic >*)0); break; case CPPUTYPE_TABLEBORDERDISTANCES: pType = &::getCppuType( (table::TableBorderDistances*)0 ); break; + case CPPUTPYE_REFEMBEDDEDOBJECT: pType = &embed::XEmbeddedObject::static_type(); break; default: OSL_ASSERT( "Unknown CPPU type" ); } 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; } - - - diff --git a/svtools/inc/svtools/textdata.hxx b/svtools/inc/svtools/textdata.hxx index 809d64248eb6..d0182e6a2c77 100644 --- a/svtools/inc/svtools/textdata.hxx +++ b/svtools/inc/svtools/textdata.hxx @@ -33,26 +33,6 @@ #include <svl/smplhint.hxx> #include <tools/string.hxx> -#define TEXTUNDO_START 100 -#define TEXTUNDO_REMOVECHARS 100 -#define TEXTUNDO_CONNECTPARAS 101 -#define TEXTUNDO_SPLITPARA 102 -#define TEXTUNDO_INSERTCHARS 103 -#define TEXTUNDO_DELCONTENT 104 -#define TEXTUNDO_DELETE 105 -#define TEXTUNDO_CUT 106 -#define TEXTUNDO_PASTE 107 -#define TEXTUNDO_INSERT 108 -#define TEXTUNDO_ATTRIBS 109 -#define TEXTUNDO_DRAGANDDROP 110 -#define TEXTUNDO_READ 111 -#define TEXTUNDO_END 149 - -#define XTEXTUNDO_START 150 -#define XTEXTUNDO_END 199 - -#define TEXTUNDO_USER 200 - // Fuer Notify, wenn alle Absaetze geloescht wurden... #define TEXT_PARA_ALL 0xFFFFFFFF diff --git a/svtools/inc/svtools/texteng.hxx b/svtools/inc/svtools/texteng.hxx index ef27edee2efe..ee49316c317f 100644 --- a/svtools/inc/svtools/texteng.hxx +++ b/svtools/inc/svtools/texteng.hxx @@ -39,7 +39,6 @@ class TextAttrib; class TextCharAttrib; class TextUndo; class TextUndoManager; -class SfxUndoManager; class EditSelFunctionSet; class EditSelEngine; class IdleFormatter; @@ -49,6 +48,11 @@ class SfxUndoAction; class KeyEvent; class Timer; +namespace svl +{ + class IUndoManager; +} + class TextLine; class TETextPortion; #include <svl/brdcst.hxx> @@ -280,9 +284,10 @@ public: BOOL IsRightToLeft() const { return mbRightToLeft; } BOOL HasUndoManager() const { return mpUndoManager ? TRUE : FALSE; } - SfxUndoManager& GetUndoManager(); - void UndoActionStart( USHORT nId ); - void UndoActionEnd( USHORT nId ); + ::svl::IUndoManager& + GetUndoManager(); + void UndoActionStart( USHORT nId = 0 ); + void UndoActionEnd(); void InsertUndo( TextUndo* pUndo, BOOL bTryMerge = FALSE ); BOOL IsInUndo() { return mbIsInUndo; } void SetIsInUndo( BOOL bInUndo ) { mbIsInUndo = bInUndo; } diff --git a/svtools/inc/svtools/xtextedt.hxx b/svtools/inc/svtools/xtextedt.hxx index 46c6441e005e..e95ba0b09359 100644 --- a/svtools/inc/svtools/xtextedt.hxx +++ b/svtools/inc/svtools/xtextedt.hxx @@ -31,10 +31,6 @@ #include <svtools/texteng.hxx> #include <svtools/textview.hxx> -#define XTEXTUNDO_REPLACEALL (XTEXTUNDO_START+1) -#define XTEXTUNDO_INDENTBLOCK 122 -#define XTEXTUNDO_UNINDENTBLOCK 123 - namespace com { namespace sun { namespace star { diff --git a/svtools/source/edit/texteng.cxx b/svtools/source/edit/texteng.cxx index e0e136089d78..c0afe8962009 100644 --- a/svtools/source/edit/texteng.cxx +++ b/svtools/source/edit/texteng.cxx @@ -763,7 +763,7 @@ TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, BOOL bUndoAction = ( rCurSel.HasRange() || bDoOverwrite ); if ( bUndoAction ) - UndoActionStart( TEXTUNDO_INSERT ); + UndoActionStart(); if ( rCurSel.HasRange() ) { @@ -847,7 +847,7 @@ TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, TextModified(); if ( bUndoAction ) - UndoActionEnd( TEXTUNDO_INSERT ); + UndoActionEnd(); } return aPaM; @@ -856,7 +856,7 @@ TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const XubString& rStr ) { - UndoActionStart( TEXTUNDO_INSERT ); + UndoActionStart(); TextPaM aPaM; @@ -908,7 +908,7 @@ TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const XubString break; } - UndoActionEnd( TEXTUNDO_INSERT ); + UndoActionEnd(); TextModified(); return aPaM; @@ -1430,7 +1430,7 @@ void TextEngine::EnableUndo( BOOL bEnable ) mbUndoEnabled = bEnable; } -SfxUndoManager& TextEngine::GetUndoManager() +::svl::IUndoManager& TextEngine::GetUndoManager() { if ( !mpUndoManager ) mpUndoManager = new TextUndoManager( this ); @@ -1447,7 +1447,7 @@ void TextEngine::UndoActionStart( USHORT nId ) } } -void TextEngine::UndoActionEnd( USHORT ) +void TextEngine::UndoActionEnd() { if ( IsUndoEnabled() && !IsInUndo() ) GetUndoManager().LeaveListAction(); @@ -2640,7 +2640,7 @@ BOOL TextEngine::Read( SvStream& rInput, const TextSelection* pSel ) BOOL bUpdate = GetUpdateMode(); SetUpdateMode( FALSE ); - UndoActionStart( TEXTUNDO_READ ); + UndoActionStart(); TextSelection aSel; if ( pSel ) aSel = *pSel; @@ -2666,7 +2666,7 @@ BOOL TextEngine::Read( SvStream& rInput, const TextSelection* pSel ) aSel = ImpInsertParaBreak( aSel.GetEnd() ); } - UndoActionEnd( TEXTUNDO_READ ); + UndoActionEnd(); TextSelection aNewSel( aSel.GetEnd(), aSel.GetEnd() ); diff --git a/svtools/source/edit/textundo.cxx b/svtools/source/edit/textundo.cxx index 4c243de16c31..2ad5e318e92f 100644 --- a/svtools/source/edit/textundo.cxx +++ b/svtools/source/edit/textundo.cxx @@ -54,7 +54,7 @@ TextUndoManager::~TextUndoManager() { } -BOOL __EXPORT TextUndoManager::Undo( USHORT nCount ) +BOOL __EXPORT TextUndoManager::Undo() { if ( GetUndoActionCount() == 0 ) return FALSE; @@ -62,7 +62,7 @@ BOOL __EXPORT TextUndoManager::Undo( USHORT nCount ) UndoRedoStart(); mpTextEngine->SetIsInUndo( TRUE ); - BOOL bDone = SfxUndoManager::Undo( nCount ); + BOOL bDone = SfxUndoManager::Undo(); mpTextEngine->SetIsInUndo( FALSE ); UndoRedoEnd(); @@ -70,7 +70,7 @@ BOOL __EXPORT TextUndoManager::Undo( USHORT nCount ) return bDone; } -BOOL __EXPORT TextUndoManager::Redo( USHORT nCount ) +BOOL __EXPORT TextUndoManager::Redo() { if ( GetRedoActionCount() == 0 ) return FALSE; @@ -79,7 +79,7 @@ BOOL __EXPORT TextUndoManager::Redo( USHORT nCount ) UndoRedoStart(); mpTextEngine->SetIsInUndo( TRUE ); - BOOL bDone = SfxUndoManager::Redo( nCount ); + BOOL bDone = SfxUndoManager::Redo(); mpTextEngine->SetIsInUndo( FALSE ); UndoRedoEnd(); @@ -110,9 +110,8 @@ void TextUndoManager::UndoRedoEnd() } -TextUndo::TextUndo( USHORT nI, TextEngine* p ) +TextUndo::TextUndo( TextEngine* p ) { - mnId = nI; mpTextEngine = p; } @@ -120,12 +119,6 @@ TextUndo::~TextUndo() { } -USHORT __EXPORT TextUndo::GetId() const -{ - //nId sollte mal entfallen => GetId ueberall ueberladen... - return mnId; -} - XubString __EXPORT TextUndo::GetComment() const { // return mpTextEngine->GetUndoComment( this ); @@ -140,7 +133,7 @@ void TextUndo::SetSelection( const TextSelection& rSel ) TextUndoDelPara::TextUndoDelPara( TextEngine* pTextEngine, TextNode* pNode, ULONG nPara ) - : TextUndo( TEXTUNDO_DELCONTENT, pTextEngine ) + : TextUndo( pTextEngine ) { mpNode = pNode; mnPara = nPara; @@ -191,7 +184,7 @@ void __EXPORT TextUndoDelPara::Redo() // TextUndoConnectParas // ------------------------------------------------------------------------ TextUndoConnectParas::TextUndoConnectParas( TextEngine* pTextEngine, ULONG nPara, USHORT nPos ) - : TextUndo( TEXTUNDO_CONNECTPARAS, pTextEngine ) + : TextUndo( pTextEngine ) { mnPara = nPara; mnSepPos = nPos; @@ -215,7 +208,7 @@ void __EXPORT TextUndoConnectParas::Redo() TextUndoSplitPara::TextUndoSplitPara( TextEngine* pTextEngine, ULONG nPara, USHORT nPos ) - : TextUndo( TEXTUNDO_SPLITPARA, pTextEngine ) + : TextUndo( pTextEngine ) { mnPara = nPara; mnSepPos = nPos; @@ -239,7 +232,7 @@ void __EXPORT TextUndoSplitPara::Redo() TextUndoInsertChars::TextUndoInsertChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const XubString& rStr ) - : TextUndo( TEXTUNDO_INSERTCHARS, pTextEngine ), + : TextUndo( pTextEngine ), maTextPaM( rTextPaM ), maText( rStr ) { } @@ -281,7 +274,7 @@ BOOL __EXPORT TextUndoInsertChars::Merge( SfxUndoAction* pNextAction ) TextUndoRemoveChars::TextUndoRemoveChars( TextEngine* pTextEngine, const TextPaM& rTextPaM, const XubString& rStr ) - : TextUndo( TEXTUNDO_REMOVECHARS, pTextEngine ), + : TextUndo( pTextEngine ), maTextPaM( rTextPaM ), maText( rStr ) { } @@ -304,7 +297,7 @@ void __EXPORT TextUndoRemoveChars::Redo() TextUndoSetAttribs::TextUndoSetAttribs( TextEngine* pTextEngine, const TextSelection& rSel ) - : TextUndo( TEXTUNDO_ATTRIBS, pTextEngine ), maSelection( rSel ) + : TextUndo( pTextEngine ), maSelection( rSel ) { maSelection.Justify(); // aNewAttribs.Set( rNewItems ); diff --git a/svtools/source/edit/textundo.hxx b/svtools/source/edit/textundo.hxx index cc26c0b51ef6..69b5fc393744 100644 --- a/svtools/source/edit/textundo.hxx +++ b/svtools/source/edit/textundo.hxx @@ -47,16 +47,15 @@ public: ~TextUndoManager(); using SfxUndoManager::Undo; - virtual BOOL Undo( USHORT nCount=1 ); + virtual BOOL Undo(); using SfxUndoManager::Redo; - virtual BOOL Redo( USHORT nCount=1 ); + virtual BOOL Redo(); }; class TextUndo : public SfxUndoAction { private: - USHORT mnId; TextEngine* mpTextEngine; protected: @@ -69,7 +68,7 @@ protected: public: TYPEINFO(); - TextUndo( USHORT nId, TextEngine* pTextEngine ); + TextUndo( TextEngine* pTextEngine ); virtual ~TextUndo(); TextEngine* GetTextEngine() const { return mpTextEngine; } @@ -78,7 +77,6 @@ public: virtual void Redo() = 0; virtual XubString GetComment() const; - virtual USHORT GetId() const; }; #endif // _TEXTUNDO_HXX diff --git a/svtools/source/edit/textview.cxx b/svtools/source/edit/textview.cxx index 48cd23bdcc6f..64c6470be1e8 100644 --- a/svtools/source/edit/textview.cxx +++ b/svtools/source/edit/textview.cxx @@ -311,9 +311,9 @@ void TextView::DeleteSelected() { // HideSelection(); - mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_DELETE ); + mpImpl->mpTextEngine->UndoActionStart(); TextPaM aPaM = mpImpl->mpTextEngine->ImpDeleteText( mpImpl->maSelection ); - mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_DELETE ); + mpImpl->mpTextEngine->UndoActionEnd(); ImpSetSelection( aPaM ); mpImpl->mpTextEngine->FormatAndUpdate( this ); @@ -695,7 +695,7 @@ BOOL TextView::KeyInput( const KeyEvent& rKeyEvent ) default: break; } - mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_DELETE ); + mpImpl->mpTextEngine->UndoActionStart(); if(mpImpl->mbSupportProtectAttribute) { //expand selection to include all protected content - if there is any @@ -717,7 +717,7 @@ BOOL TextView::KeyInput( const KeyEvent& rKeyEvent ) } } aCurSel = ImpDelete( nDel, nMode ); - mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_DELETE ); + mpImpl->mpTextEngine->UndoActionEnd(); bModified = TRUE; bAllowIdle = FALSE; } @@ -745,7 +745,7 @@ BOOL TextView::KeyInput( const KeyEvent& rKeyEvent ) if ( !mpImpl->mbReadOnly && !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() && ImplCheckTextLen( 'x' ) ) { - mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT ); + mpImpl->mpTextEngine->UndoActionStart(); aCurSel = mpImpl->mpTextEngine->ImpInsertParaBreak( aCurSel ); if ( mpImpl->mbAutoIndent ) { @@ -760,7 +760,7 @@ BOOL TextView::KeyInput( const KeyEvent& rKeyEvent ) if ( n ) aCurSel = mpImpl->mpTextEngine->ImpInsertText( aCurSel, pPrev->GetText().Copy( 0, n ) ); } - mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT ); + mpImpl->mpTextEngine->UndoActionEnd(); bModified = TRUE; } else @@ -1122,21 +1122,21 @@ void TextView::Scroll( long ndX, long ndY ) void TextView::Undo() { mpImpl->mpTextEngine->SetActiveView( this ); - mpImpl->mpTextEngine->GetUndoManager().Undo( 1 ); + mpImpl->mpTextEngine->GetUndoManager().Undo(); } void TextView::Redo() { mpImpl->mpTextEngine->SetActiveView( this ); - mpImpl->mpTextEngine->GetUndoManager().Redo( 0 ); + mpImpl->mpTextEngine->GetUndoManager().Redo(); } void TextView::Cut() { - mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_CUT ); + mpImpl->mpTextEngine->UndoActionStart(); Copy(); DeleteSelected(); - mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_CUT ); + mpImpl->mpTextEngine->UndoActionEnd(); } void TextView::Copy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard ) @@ -1370,7 +1370,7 @@ void TextView::InsertText( const XubString& rStr, BOOL bSelect ) void TextView::InsertNewText( const rtl::OUString& rStr, BOOL bSelect ) { // HideSelection(); - mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT ); + mpImpl->mpTextEngine->UndoActionStart(); /* #i87633# break inserted text into chunks that fit into the underlying String @@ -1405,7 +1405,7 @@ void TextView::InsertNewText( const rtl::OUString& rStr, BOOL bSelect ) nLen -= nChunkLen; nPos += nChunkLen; } - mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT ); + mpImpl->mpTextEngine->UndoActionEnd(); mpImpl->mpTextEngine->FormatAndUpdate( this ); } @@ -1417,9 +1417,9 @@ void TextView::InsertText( const XubString& rStr, BOOL bSelect ) TextSelection aNewSel( mpImpl->maSelection ); - mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_INSERT ); + mpImpl->mpTextEngine->UndoActionStart(); TextPaM aPaM = mpImpl->mpTextEngine->ImpInsertText( mpImpl->maSelection, rStr ); - mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_INSERT ); + mpImpl->mpTextEngine->UndoActionEnd(); if ( bSelect ) { @@ -2169,7 +2169,7 @@ void TextView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEv HideSelection(); ImpSetSelection( mpImpl->mpDDInfo->maDropPos ); - mpImpl->mpTextEngine->UndoActionStart( TEXTUNDO_DRAGANDDROP ); + mpImpl->mpTextEngine->UndoActionStart(); String aText; uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable; @@ -2247,7 +2247,7 @@ void TextView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEv mpImpl->mpTextEngine->ImpDeleteText( aPrevSel ); } - mpImpl->mpTextEngine->UndoActionEnd( TEXTUNDO_DRAGANDDROP ); + mpImpl->mpTextEngine->UndoActionEnd(); delete mpImpl->mpDDInfo; mpImpl->mpDDInfo = 0; diff --git a/svtools/source/edit/xtextedt.cxx b/svtools/source/edit/xtextedt.cxx index 0a4907edcadd..10e05a58676a 100644 --- a/svtools/source/edit/xtextedt.cxx +++ b/svtools/source/edit/xtextedt.cxx @@ -327,7 +327,7 @@ USHORT ExtTextView::Replace( const util::SearchOptions& rSearchOptions, BOOL bAl BOOL bFound = pTextEngine->Search( aSel, rSearchOptions, TRUE ); if ( bFound ) - pTextEngine->UndoActionStart( XTEXTUNDO_REPLACEALL ); + pTextEngine->UndoActionStart(); while ( bFound ) { nFound++; @@ -341,7 +341,7 @@ USHORT ExtTextView::Replace( const util::SearchOptions& rSearchOptions, BOOL bAl { SetSelection( aSel.GetStart() ); pTextEngine->FormatAndUpdate( this ); - pTextEngine->UndoActionEnd( XTEXTUNDO_REPLACEALL ); + pTextEngine->UndoActionEnd(); } } return nFound; @@ -355,7 +355,7 @@ BOOL ExtTextView::ImpIndentBlock( BOOL bRight ) aSel.Justify(); HideSelection(); - GetTextEngine()->UndoActionStart( bRight ? XTEXTUNDO_INDENTBLOCK : XTEXTUNDO_UNINDENTBLOCK ); + GetTextEngine()->UndoActionStart(); ULONG nStartPara = aSel.GetStart().GetPara(); ULONG nEndPara = aSel.GetEnd().GetPara(); @@ -386,7 +386,7 @@ BOOL ExtTextView::ImpIndentBlock( BOOL bRight ) } } - GetTextEngine()->UndoActionEnd( bRight ? XTEXTUNDO_INDENTBLOCK : XTEXTUNDO_UNINDENTBLOCK ); + GetTextEngine()->UndoActionEnd(); BOOL bRange = aSel.HasRange(); if ( bRight ) diff --git a/toolkit/source/awt/vclxwindow.cxx b/toolkit/source/awt/vclxwindow.cxx index 808f3578ef97..5d25e2f7b29b 100644 --- a/toolkit/source/awt/vclxwindow.cxx +++ b/toolkit/source/awt/vclxwindow.cxx @@ -65,6 +65,7 @@ #include <vcl/tabpage.hxx> #include <vcl/button.hxx> #include <comphelper/asyncnotification.hxx> +#include <comphelper/flagguard.hxx> #include <toolkit/helper/solarrelease.hxx> #include "stylesettings.hxx" #include <tools/urlobj.hxx> @@ -95,32 +96,6 @@ namespace MouseWheelBehavior = ::com::sun::star::awt::MouseWheelBehavior; using ::toolkit::ReleaseSolarMutex; //==================================================================== -//= misc helpers -//==================================================================== -namespace -{ - //................................................................ - //. FlagGuard - //................................................................ - class FlagGuard - { - private: - bool& m_rFlag; - - public: - FlagGuard( bool& _rFlag ) - :m_rFlag( _rFlag ) - { - m_rFlag = true; - } - ~FlagGuard() - { - m_rFlag = false; - } - }; -} - -//==================================================================== //= VCLXWindowImpl //==================================================================== class SAL_DLLPRIVATE VCLXWindowImpl @@ -2347,7 +2322,7 @@ void VCLXWindow::draw( sal_Int32 nX, sal_Int32 nY ) throw(::com::sun::star::uno: // #i40647# / 2005-01-18 / frank.schoenheit@sun.com if ( !mpImpl->getDrawingOntoParent_ref() ) { - FlagGuard aDrawingflagGuard( mpImpl->getDrawingOntoParent_ref() ); + ::comphelper::FlagGuard aDrawingflagGuard( mpImpl->getDrawingOntoParent_ref() ); BOOL bWasVisible = pWindow->IsVisible(); Point aOldPos( pWindow->GetPosPixel() ); |