From d729112009418c02a2659b367bcb35a81ee9307c Mon Sep 17 00:00:00 2001 From: "Frank Schoenheit [fs]" Date: Tue, 9 Nov 2010 21:36:57 +0100 Subject: [PATCH] undoapi: step 1 of the migration of css.chart2.XUndoManager to css.document.XUndoManager: separate the DocumentUndoManager into a (SFX-independent) UndoManagerHelper (which later on can be used in chart2) and the SFX-dependent part --- framework/inc/helper/undomanagerhelper.hxx | 147 ++++ framework/prj/d.lst | 1 + framework/source/helper/makefile.mk | 49 +- framework/source/helper/undomanagerhelper.cxx | 754 ++++++++++++++++++ framework/util/makefile.mk | 4 +- sfx2/qa/complex/sfx2/UndoManager.java | 2 - sfx2/source/doc/docundomanager.cxx | 699 ++++------------ sfx2/source/inc/docundomanager.hxx | 28 - 8 files changed, 1064 insertions(+), 620 deletions(-) create mode 100755 framework/inc/helper/undomanagerhelper.hxx create mode 100755 framework/source/helper/undomanagerhelper.cxx diff --git a/framework/inc/helper/undomanagerhelper.hxx b/framework/inc/helper/undomanagerhelper.hxx new file mode 100755 index 000000000000..98503e08144f --- /dev/null +++ b/framework/inc/helper/undomanagerhelper.hxx @@ -0,0 +1,147 @@ +/************************************************************************* + * 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef FRAMEWORK_UNDOMANAGERHELPER_HXX +#define FRAMEWORK_UNDOMANAGERHELPER_HXX + +/** === begin UNO includes === **/ +#include +/** === end UNO includes === **/ + +#include + +namespace osl +{ + class Mutex; +} + +namespace svl +{ + class IUndoManager; +} + +//...................................................................................................................... +namespace framework +{ +//...................................................................................................................... + + //================================================================================================================== + //= IUndoManagerImplementation + //================================================================================================================== + class SAL_NO_VTABLE IUndoManagerImplementation + { + public: + /** returns the mutex which is protecting the instance. Needed for listener administration synchronization. + + Note that the mutex will not be used for multi-threading safety of the UndoManagerHelper. + */ + virtual ::osl::Mutex& getMutex() = 0; + + /** returns the IUndoManager interface to the actual Undo stack + + @throws com::sun::star::lang::DisposedException + when the instance is already disposed, and no IUndoManager can be provided + + @throws com::sun::star::lang::NotInitializedException + when the instance is not initialized, yet, and no IUndoManager can be provided + */ + virtual ::svl::IUndoManager& getImplUndoManager() = 0; + + /** provides access to an UNO interface for the XUndoManager implementation. Used when throwing exceptions. + */ + virtual ::com::sun::star::uno::Reference< ::com::sun::star::document::XUndoManager > + getThis() = 0; + }; + + //================================================================================================================== + //= IClearableInstanceLock + //================================================================================================================== + /** helper class for releasing a lock + + Since clients of UndoManagerHelper are responsible for locking their instance, but the UndoManagerHelper + needs to notify its listeners, and this needs to happen without any instance lock, all affected methods + take an IClearableInstanceLock parameter, to be able to clear the owner's lock before doing any notifications. + */ + class SAL_NO_VTABLE IClearableInstanceLock + { + public: + virtual void clear() = 0; + }; + + //================================================================================================================== + //= UndoManagerHelper + //================================================================================================================== + class UndoManagerHelper_Impl; + /** helper class for implementing an XUndoManager + + The class defines the same methods as an XUndoManager does, but lacks certain aspects of a full-blown UNO + component. In particular, it is the responsibility of the owner of the instance to care for multi-threading + safety, and for disposal checks. + */ + class UndoManagerHelper + { + public: + UndoManagerHelper( IUndoManagerImplementation& i_undoManagerImpl ); + ~UndoManagerHelper(); + + // life time control + void disposing(); + + // XUndoManager equivalents + void enterUndoContext( const ::rtl::OUString& i_title, IClearableInstanceLock& i_instanceLock ); + void enterHiddenUndoContext( IClearableInstanceLock& i_instanceLock ); + void leaveUndoContext( IClearableInstanceLock& i_instanceLock ); + void addUndoAction( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XUndoAction >& i_action, IClearableInstanceLock& i_instanceLock ); + void undo( IClearableInstanceLock& i_instanceLock ); + void redo( IClearableInstanceLock& i_instanceLock ); + ::sal_Bool isUndoPossible() const; + ::sal_Bool isRedoPossible() const; + ::rtl::OUString getCurrentUndoActionTitle() const; + ::rtl::OUString getCurrentRedoActionTitle() const; + ::com::sun::star::uno::Sequence< ::rtl::OUString > + getAllUndoActionTitles() const; + ::com::sun::star::uno::Sequence< ::rtl::OUString > + getAllRedoActionTitles() const; + void clear( IClearableInstanceLock& i_instanceLock ); + void clearRedo( IClearableInstanceLock& i_instanceLock ); + void reset( IClearableInstanceLock& i_instanceLock ); + void addUndoManagerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XUndoManagerListener >& i_listener ); + void removeUndoManagerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::document::XUndoManagerListener >& i_listener ); + + // XLockable, base of XUndoManager, equivalents + void lock(); + void unlock(); + ::sal_Bool isLocked(); + + private: + ::boost::scoped_ptr< UndoManagerHelper_Impl > m_pImpl; + }; + +//...................................................................................................................... +} // namespace framework +//...................................................................................................................... + +#endif // FRAMEWORK_UNDOMANAGERHELPER_HXX diff --git a/framework/prj/d.lst b/framework/prj/d.lst index d9d030d95b5e..fb83f9a205e5 100644 --- a/framework/prj/d.lst +++ b/framework/prj/d.lst @@ -44,6 +44,7 @@ mkdir: %_DEST%\xml%_EXT%\uiconfig\modules\StartModule\statusbar ..\inc\helper\titlehelper.hxx %_DEST%\inc%_EXT%\framework\titlehelper.hxx ..\inc\classes\framelistanalyzer.hxx %_DEST%\inc%_EXT%\framework\framelistanalyzer.hxx ..\inc\helper\documentundoguard.hxx %_DEST%\inc%_EXT%\framework\documentundoguard.hxx +..\inc\helper\undomanagerhelper.hxx %_DEST%\inc%_EXT%\framework\undomanagerhelper.hxx ..\uiconfig\startmodule\menubar\*.xml %_DEST%\xml%_EXT%\uiconfig\modules\StartModule\menubar\*.xml ..\uiconfig\startmodule\toolbar\*.xml %_DEST%\xml%_EXT%\uiconfig\modules\StartModule\toolbar\*.xml diff --git a/framework/source/helper/makefile.mk b/framework/source/helper/makefile.mk index 158fba424c51..9199f556ff2d 100644 --- a/framework/source/helper/makefile.mk +++ b/framework/source/helper/makefile.mk @@ -24,7 +24,7 @@ # for a copy of the LGPLv3 License. # #************************************************************************* -PRJ=..$/.. +PRJ=../.. PRJNAME= framework TARGET= fwk_helper @@ -41,29 +41,30 @@ CDEFS+=-DCOMPMOD_NAMESPACE=framework # --- Generate ----------------------------------------------------- -SLOFILES= $(SLO)$/ocomponentaccess.obj \ - $(SLO)$/ocomponentenumeration.obj \ - $(SLO)$/oframes.obj \ - $(SLO)$/statusindicatorfactory.obj \ - $(SLO)$/statusindicator.obj \ - $(SLO)$/imageproducer.obj \ - $(SLO)$/propertysetcontainer.obj \ - $(SLO)$/actiontriggerhelper.obj \ - $(SLO)$/persistentwindowstate.obj \ - $(SLO)$/networkdomain.obj \ - $(SLO)$/acceleratorinfo.obj \ - $(SLO)$/uielementwrapperbase.obj \ - $(SLO)$/dockingareadefaultacceptor.obj \ - $(SLO)$/uiconfigelementwrapperbase.obj \ - $(SLO)$/shareablemutex.obj \ - $(SLO)$/vclstatusindicator.obj \ - $(SLO)$/wakeupthread.obj \ - $(SLO)$/configimporter.obj \ - $(SLO)$/tagwindowasmodified.obj \ - $(SLO)$/titlebarupdate.obj \ - $(SLO)$/titlehelper.obj \ - $(SLO)$/mischelper.obj \ - $(SLO)$/documentundoguard.obj \ +SLOFILES= $(SLO)/ocomponentaccess.obj \ + $(SLO)/ocomponentenumeration.obj \ + $(SLO)/oframes.obj \ + $(SLO)/statusindicatorfactory.obj \ + $(SLO)/statusindicator.obj \ + $(SLO)/imageproducer.obj \ + $(SLO)/propertysetcontainer.obj \ + $(SLO)/actiontriggerhelper.obj \ + $(SLO)/persistentwindowstate.obj \ + $(SLO)/networkdomain.obj \ + $(SLO)/acceleratorinfo.obj \ + $(SLO)/uielementwrapperbase.obj \ + $(SLO)/dockingareadefaultacceptor.obj \ + $(SLO)/uiconfigelementwrapperbase.obj \ + $(SLO)/shareablemutex.obj \ + $(SLO)/vclstatusindicator.obj \ + $(SLO)/wakeupthread.obj \ + $(SLO)/configimporter.obj \ + $(SLO)/tagwindowasmodified.obj \ + $(SLO)/titlebarupdate.obj \ + $(SLO)/titlehelper.obj \ + $(SLO)/mischelper.obj \ + $(SLO)/documentundoguard.obj \ + $(SLO)/undomanagerhelper.obj \ # --- Targets ------------------------------------------------------ diff --git a/framework/source/helper/undomanagerhelper.cxx b/framework/source/helper/undomanagerhelper.cxx new file mode 100755 index 000000000000..4831d3fff43d --- /dev/null +++ b/framework/source/helper/undomanagerhelper.cxx @@ -0,0 +1,754 @@ +/************************************************************************* + * 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 + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_framework.hxx" + +#include "helper/undomanagerhelper.hxx" + +/** === begin UNO includes === **/ +#include +/** === end UNO includes === **/ + +#include +#include +#include +#include + +#include + +//...................................................................................................................... +namespace framework +{ +//...................................................................................................................... + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::document::XUndoManagerListener; + using ::com::sun::star::document::UndoManagerEvent; + using ::com::sun::star::document::EmptyUndoStackException; + using ::com::sun::star::document::UndoContextNotClosedException; + using ::com::sun::star::document::UndoFailedException; + using ::com::sun::star::util::NotLockedException; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::document::XUndoAction; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::document::XUndoManager; + using ::com::sun::star::util::InvalidStateException; + using ::com::sun::star::lang::IllegalArgumentException; + /** === end UNO using === **/ + using ::svl::IUndoManager; + + //================================================================================================================== + //= UndoActionWrapper + //================================================================================================================== + class UndoActionWrapper : public SfxUndoAction + { + public: + UndoActionWrapper( + Reference< XUndoAction > const& i_undoAction + ); + virtual ~UndoActionWrapper(); + + virtual String GetComment() const; + virtual void Undo(); + virtual void Redo(); + virtual BOOL CanRepeat(SfxRepeatTarget&) const; + + private: + const Reference< XUndoAction > m_xUndoAction; + }; + + //------------------------------------------------------------------------------------------------------------------ + UndoActionWrapper::UndoActionWrapper( Reference< XUndoAction > const& i_undoAction ) + :SfxUndoAction() + ,m_xUndoAction( i_undoAction ) + { + ENSURE_OR_THROW( m_xUndoAction.is(), "illegal undo action" ); + } + + //------------------------------------------------------------------------------------------------------------------ + UndoActionWrapper::~UndoActionWrapper() + { + try + { + Reference< XComponent > xComponent( m_xUndoAction, UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + //------------------------------------------------------------------------------------------------------------------ + String UndoActionWrapper::GetComment() const + { + String sComment; + try + { + sComment = m_xUndoAction->getTitle(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sComment; + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoActionWrapper::Undo() + { + m_xUndoAction->undo(); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoActionWrapper::Redo() + { + m_xUndoAction->redo(); + } + + //------------------------------------------------------------------------------------------------------------------ + BOOL UndoActionWrapper::CanRepeat(SfxRepeatTarget&) const + { + return FALSE; + } + + //================================================================================================================== + //= UndoManagerHelper_Impl + //================================================================================================================== + class UndoManagerHelper_Impl : public SfxUndoListener + { + public: + ::cppu::OInterfaceContainerHelper aUndoListeners; + IUndoManagerImplementation& rUndoManagerImplementation; + UndoManagerHelper& rAntiImpl; + bool bAPIActionRunning; + ::std::stack< bool > aContextVisibilities; +#if OSL_DEBUG_LEVEL > 0 + ::std::stack< bool > aContextAPIFlags; +#endif + + UndoManagerHelper_Impl( UndoManagerHelper& i_antiImpl, IUndoManagerImplementation& i_undoManagerImpl ) + :aUndoListeners( i_undoManagerImpl.getMutex() ) + ,rUndoManagerImplementation( i_undoManagerImpl ) + ,rAntiImpl( i_antiImpl ) + ,bAPIActionRunning( false ) + { + getUndoManager().AddUndoListener( *this ); + } + + virtual ~UndoManagerHelper_Impl() + { + } + + //.............................................................................................................. + IUndoManager& getUndoManager() + { + return rUndoManagerImplementation.getImplUndoManager(); + } + + //.............................................................................................................. + Reference< XUndoManager > getXUndoManager() + { + return rUndoManagerImplementation.getThis(); + } + + //.............................................................................................................. + void disposing() + { + EventObject aEvent; + aEvent.Source = getXUndoManager(); + aUndoListeners.disposeAndClear( aEvent ); + + getUndoManager().RemoveUndoListener( *this ); + } + + // SfxUndoListener + virtual void actionUndone( SfxUndoAction& i_action ); + virtual void actionRedone( SfxUndoAction& i_action ); + virtual void undoActionAdded( SfxUndoAction& i_action ); + virtual void cleared(); + virtual void clearedRedo(); + virtual void listActionEntered( const String& i_comment ); + virtual void listActionLeft(); + virtual void listActionLeftAndMerged(); + virtual void listActionCancelled(); + virtual void undoManagerDying(); + + // public operations + void enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden, IClearableInstanceLock& i_instanceLock ); + + void doUndoRedo( + USHORT ( ::svl::IUndoManager::*i_checkMethod )( bool const ) const, + BOOL ( ::svl::IUndoManager::*i_doMethod )(), + UniString ( ::svl::IUndoManager::*i_titleRetriever )( USHORT, bool const ) const, + void ( SAL_CALL ::com::sun::star::document::XUndoManagerListener::*i_notificationMethod )( const ::com::sun::star::document::UndoManagerEvent& ), + IClearableInstanceLock& i_instanceLock + ); + void notify( ::rtl::OUString const& i_title, + void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ), + IClearableInstanceLock& i_instanceLock + ); + void notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ), + IClearableInstanceLock& i_instanceLock + ); + void notify( ::rtl::OUString const& i_title, + void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) + ); + void notify( + void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ) + ); + }; + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::notify( ::rtl::OUString const& i_title, void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ), + IClearableInstanceLock& i_instanceLock ) + { + UndoManagerEvent aEvent; + aEvent.Source = getXUndoManager(); + aEvent.UndoActionTitle = i_title; + aEvent.UndoContextDepth = getUndoManager().GetListActionDepth(); + + i_instanceLock.clear(); + aUndoListeners.notifyEach( i_notificationMethod, aEvent ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ), + IClearableInstanceLock& i_instanceLock ) + { + EventObject aEvent; + aEvent.Source = getXUndoManager(); + i_instanceLock.clear(); + aUndoListeners.notifyEach( i_notificationMethod, aEvent ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::notify( ::rtl::OUString const& i_title, + void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) ) + { + UndoManagerEvent aEvent; + aEvent.Source = getXUndoManager(); + aEvent.UndoActionTitle = i_title; + aEvent.UndoContextDepth = getUndoManager().GetListActionDepth(); + + // TODO: this notification method here is used by UndoManagerHelper_Impl, to multiplex the notifications we + // receive from the IUndoManager. Those notitications are sent with a locked SolarMutex, which means + // we're doing the multiplexing here with a locked SM, too. Which is Bad (TM). + // Fixing this properly would require outsourcing all the notifications into an own thread - which might lead + // to problems of its own, since clients might expect synchronous notifications. + + aUndoListeners.notifyEach( i_notificationMethod, aEvent ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ) ) + { + EventObject aEvent; + aEvent.Source = getXUndoManager(); + + // TODO: the same comment as in the other notify, regarding SM locking applies here ... + + aUndoListeners.notifyEach( i_notificationMethod, aEvent ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden, IClearableInstanceLock& i_instanceLock ) + { + // SYNCHRONIZED ---> + IUndoManager& rUndoManager = getUndoManager(); + if ( !rUndoManager.IsUndoEnabled() ) + // ignore this request if the manager is locked + return; + + if ( i_hidden && ( rUndoManager.GetUndoActionCount( IUndoManager::CurrentLevel ) == 0 ) ) + throw EmptyUndoStackException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "can't enter a hidden context without a previous Undo action" ) ), + rUndoManagerImplementation.getThis() + ); + + { + ::comphelper::FlagGuard aNotificationGuard( bAPIActionRunning ); + rUndoManager.EnterListAction( i_title, ::rtl::OUString() ); + } + + aContextVisibilities.push( i_hidden ); + + notify( i_title, i_hidden ? &XUndoManagerListener::enteredHiddenContext : &XUndoManagerListener::enteredContext, i_instanceLock ); + // <--- SYNCHRONIZED + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::doUndoRedo( + USHORT ( IUndoManager::*i_checkMethod )( bool const ) const, BOOL ( IUndoManager::*i_doMethod )(), + String ( IUndoManager::*i_titleRetriever )( USHORT, bool const ) const, + void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ), + IClearableInstanceLock& i_instanceLock ) + { + // SYNCHRONIZED ---> + IUndoManager& rUndoManager = getUndoManager(); + if ( rUndoManager.IsInListAction() ) + throw UndoContextNotClosedException( ::rtl::OUString(), getXUndoManager() ); + + if ( (rUndoManager.*i_checkMethod)( IUndoManager::TopLevel ) == 0 ) + throw EmptyUndoStackException( ::rtl::OUString::createFromAscii( "stack is empty" ), getXUndoManager() ); + + const ::rtl::OUString sUndoActionTitle = (rUndoManager.*i_titleRetriever)( 0, IUndoManager::TopLevel ); + { + ::comphelper::FlagGuard aNotificationGuard( bAPIActionRunning ); + try + { + (rUndoManager.*i_doMethod)(); + } + catch( const RuntimeException& ) { /* allowed to leave here */ throw; } + catch( const UndoFailedException& ) { /* allowed to leave here */ throw; } + catch( const Exception& ) + { + // not allowed to leave + const Any aError( ::cppu::getCaughtException() ); + throw UndoFailedException( ::rtl::OUString(), getXUndoManager(), aError ); + } + } + + notify( sUndoActionTitle, i_notificationMethod, i_instanceLock ); + // <--- SYNCHRONIZED + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::actionUndone( SfxUndoAction& i_action ) + { + if ( bAPIActionRunning ) + return; + + notify( i_action.GetComment(), &XUndoManagerListener::actionUndone ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::actionRedone( SfxUndoAction& i_action ) + { + if ( bAPIActionRunning ) + return; + + notify( i_action.GetComment(), &XUndoManagerListener::actionRedone ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::undoActionAdded( SfxUndoAction& i_action ) + { + if ( bAPIActionRunning ) + return; + + notify( i_action.GetComment(), &XUndoManagerListener::undoActionAdded ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::cleared() + { + if ( bAPIActionRunning ) + return; + + notify( &XUndoManagerListener::allActionsCleared ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::clearedRedo() + { + if ( bAPIActionRunning ) + return; + + notify( &XUndoManagerListener::redoActionsCleared ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::listActionEntered( const String& i_comment ) + { +#if OSL_DEBUG_LEVEL > 0 + aContextAPIFlags.push( bAPIActionRunning ); +#endif + + if ( bAPIActionRunning ) + return; + + notify( i_comment, &XUndoManagerListener::enteredContext ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::listActionLeft() + { +#if OSL_DEBUG_LEVEL > 0 + const bool bCurrentContextIsAPIContext = aContextAPIFlags.top(); + aContextAPIFlags.pop(); + OSL_ENSURE( bCurrentContextIsAPIContext == bAPIActionRunning, "UndoManagerHelper_Impl::listActionLeft: API and non-API contexts interwoven!" ); +#endif + + if ( bAPIActionRunning ) + return; + + notify( getUndoManager().GetUndoActionComment( 0, IUndoManager::CurrentLevel ), &XUndoManagerListener::leftContext ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::listActionLeftAndMerged() + { +#if OSL_DEBUG_LEVEL > 0 + const bool bCurrentContextIsAPIContext = aContextAPIFlags.top(); + aContextAPIFlags.pop(); + OSL_ENSURE( bCurrentContextIsAPIContext == bAPIActionRunning, "UndoManagerHelper_Impl::listActionLeftAndMerged: API and non-API contexts interwoven!" ); +#endif + + if ( bAPIActionRunning ) + return; + + notify( ::rtl::OUString(), &XUndoManagerListener::leftHiddenContext ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::listActionCancelled() + { +#if OSL_DEBUG_LEVEL > 0 + const bool bCurrentContextIsAPIContext = aContextAPIFlags.top(); + aContextAPIFlags.pop(); + OSL_ENSURE( bCurrentContextIsAPIContext == bAPIActionRunning, "UndoManagerHelper_Impl::listActionCancelled: API and non-API contexts interwoven!" ); +#endif + + if ( bAPIActionRunning ) + return; + + notify( ::rtl::OUString(), &XUndoManagerListener::cancelledContext ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper_Impl::undoManagerDying() + { + // TODO: do we need to care? Or is this the responsibility of our owner? + } + + //================================================================================================================== + //= UndoManagerHelper + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + UndoManagerHelper::UndoManagerHelper( IUndoManagerImplementation& i_undoManagerImpl ) + :m_pImpl( new UndoManagerHelper_Impl( *this, i_undoManagerImpl ) ) + { + } + + //------------------------------------------------------------------------------------------------------------------ + UndoManagerHelper::~UndoManagerHelper() + { + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::disposing() + { + m_pImpl->disposing(); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::enterUndoContext( const ::rtl::OUString& i_title, IClearableInstanceLock& i_instanceLock ) + { + m_pImpl->enterUndoContext( i_title, false, i_instanceLock ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::enterHiddenUndoContext( IClearableInstanceLock& i_instanceLock ) + { + m_pImpl->enterUndoContext( ::rtl::OUString(), true, i_instanceLock ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::leaveUndoContext( IClearableInstanceLock& i_instanceLock ) + { + // SYNCHRONIZED ---> + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + if ( !rUndoManager.IsUndoEnabled() ) + // ignore this request if the manager is locked + return; + + if ( !rUndoManager.IsInListAction() ) + throw InvalidStateException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no active undo context" ) ), + m_pImpl->getXUndoManager() + ); + + USHORT nContextElements = 0; + bool isHiddenContext = false; + { + ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); + + isHiddenContext = m_pImpl->aContextVisibilities.top(); + m_pImpl->aContextVisibilities.pop(); + if ( isHiddenContext ) + nContextElements = rUndoManager.LeaveAndMergeListAction(); + else + nContextElements = rUndoManager.LeaveListAction(); + } + + if ( nContextElements == 0 ) + m_pImpl->notify( ::rtl::OUString(), &XUndoManagerListener::cancelledContext, i_instanceLock ); + else if ( isHiddenContext ) + m_pImpl->notify( ::rtl::OUString(), &XUndoManagerListener::leftHiddenContext, i_instanceLock ); + else + m_pImpl->notify( rUndoManager.GetUndoActionComment( 0, IUndoManager::CurrentLevel ), &XUndoManagerListener::leftContext, i_instanceLock ); + // <--- SYNCHRONIZED + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::addUndoAction( const Reference< XUndoAction >& i_action, IClearableInstanceLock& i_instanceLock ) + { + // SYNCHRONIZED ---> + if ( !i_action.is() ) + throw IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "illegal undo action object" ) ), + m_pImpl->getXUndoManager(), + 1 + ); + + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + if ( !rUndoManager.IsUndoEnabled() ) + // ignore the request if the manager is locked + return; + + const bool bHadRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 ); + { + ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); + rUndoManager.AddUndoAction( new UndoActionWrapper( i_action ) ); + } + const bool bHasRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 ); + + m_pImpl->notify( i_action->getTitle(), &XUndoManagerListener::undoActionAdded, i_instanceLock ); + // <--- SYNCHRONIZED + + if ( bHadRedoActions && !bHasRedoActions ) + m_pImpl->notify( &XUndoManagerListener::redoActionsCleared ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::undo( IClearableInstanceLock& i_instanceLock ) + { + m_pImpl->doUndoRedo( + &IUndoManager::GetUndoActionCount, + &IUndoManager::Undo, + &IUndoManager::GetUndoActionComment, + &XUndoManagerListener::actionUndone, + i_instanceLock + ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::redo( IClearableInstanceLock& i_instanceLock ) + { + m_pImpl->doUndoRedo( + &IUndoManager::GetRedoActionCount, + &IUndoManager::Redo, + &IUndoManager::GetRedoActionComment, + &XUndoManagerListener::actionRedone, + i_instanceLock + ); + } + + //------------------------------------------------------------------------------------------------------------------ + ::sal_Bool UndoManagerHelper::isUndoPossible() const + { + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + if ( rUndoManager.IsInListAction() ) + return sal_False; + return rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) > 0; + } + + //------------------------------------------------------------------------------------------------------------------ + ::sal_Bool UndoManagerHelper::isRedoPossible() const + { + const IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + if ( rUndoManager.IsInListAction() ) + return sal_False; + return rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0; + } + + //------------------------------------------------------------------------------------------------------------------ + namespace + { + //.............................................................................................................. + ::rtl::OUString lcl_getCurrentActionTitle( UndoManagerHelper_Impl& i_impl, const bool i_undo ) + { + const IUndoManager& rUndoManager = i_impl.getUndoManager(); + const USHORT nActionCount = i_undo + ? rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) + : rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ); + if ( nActionCount == 0 ) + throw EmptyUndoStackException( + i_undo ? ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no action on the undo stack" ) ) + : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no action on the redo stack" ) ), + i_impl.getXUndoManager() + ); + return i_undo + ? rUndoManager.GetUndoActionComment( 0, IUndoManager::TopLevel ) + : rUndoManager.GetRedoActionComment( 0, IUndoManager::TopLevel ); + } + + //.............................................................................................................. + Sequence< ::rtl::OUString > lcl_getAllActionTitles( UndoManagerHelper_Impl& i_impl, const bool i_undo ) + { + const IUndoManager& rUndoManager = i_impl.getUndoManager(); + const USHORT nCount = i_undo + ? rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) + : rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ); + + Sequence< ::rtl::OUString > aTitles( nCount ); + for ( USHORT i=0; i UndoManagerHelper::getAllUndoActionTitles() const + { + return lcl_getAllActionTitles( *m_pImpl, true ); + } + + //------------------------------------------------------------------------------------------------------------------ + Sequence< ::rtl::OUString > UndoManagerHelper::getAllRedoActionTitles() const + { + return lcl_getAllActionTitles( *m_pImpl, false ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::clear( IClearableInstanceLock& i_instanceLock ) + { + // SYNCHRONIZED ---> + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + if ( rUndoManager.IsInListAction() ) + throw UndoContextNotClosedException( ::rtl::OUString(), m_pImpl->getXUndoManager() ); + + { + ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); + rUndoManager.Clear(); + } + + m_pImpl->notify( &XUndoManagerListener::allActionsCleared, i_instanceLock ); + // <--- SYNCHRONIZED + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::clearRedo( IClearableInstanceLock& i_instanceLock ) + { + // SYNCHRONIZED ---> + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + if ( rUndoManager.IsInListAction() ) + throw UndoContextNotClosedException( ::rtl::OUString(), m_pImpl->getXUndoManager() ); + + { + ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); + rUndoManager.ClearRedo(); + } + + m_pImpl->notify( &XUndoManagerListener::redoActionsCleared, i_instanceLock ); + // <--- SYNCHRONIZED + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::reset( IClearableInstanceLock& i_instanceLock ) + { + // SYNCHRONIZED ---> + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + { + ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); + while ( rUndoManager.IsInListAction() ) + rUndoManager.LeaveListAction(); + rUndoManager.Clear(); + } + + m_pImpl->notify( &XUndoManagerListener::resetAll, i_instanceLock ); + // <--- SYNCHRONIZED + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::lock() + { + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + rUndoManager.EnableUndo( false ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::unlock() + { + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + if ( rUndoManager.IsUndoEnabled() ) + throw NotLockedException( ::rtl::OUString::createFromAscii( "Undo manager is not locked" ), m_pImpl->getXUndoManager() ); + rUndoManager.EnableUndo( true ); + } + + //------------------------------------------------------------------------------------------------------------------ + ::sal_Bool UndoManagerHelper::isLocked() + { + IUndoManager& rUndoManager = m_pImpl->getUndoManager(); + return !rUndoManager.IsUndoEnabled(); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + if ( i_listener.is() ) + m_pImpl->aUndoListeners.addInterface( i_listener ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UndoManagerHelper::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + if ( i_listener.is() ) + m_pImpl->aUndoListeners.removeInterface( i_listener ); + } + +//...................................................................................................................... +} // namespace framework +//...................................................................................................................... diff --git a/framework/util/makefile.mk b/framework/util/makefile.mk index 3df1e6493c9f..13c3d70d0d3c 100644 --- a/framework/util/makefile.mk +++ b/framework/util/makefile.mk @@ -101,6 +101,7 @@ LIB2OBJFILES= \ $(SLO)$/framelistanalyzer.obj \ $(SLO)$/titlehelper.obj \ $(SLO)$/documentundoguard.obj \ + $(SLO)$/undomanagerhelper.obj \ # --- import classes library --------------------------------------------------- @@ -158,7 +159,7 @@ SHL2STDLIBS= \ $(CPPUHELPERLIB) \ $(CPPULIB) \ $(VOSLIB) \ - $(SALLIB) + $(SALLIB) \ SHL2DEF= $(MISC)$/$(SHL2TARGET).def SHL2DEPN= $(SHL1IMPLIBN) $(SHL1TARGETN) @@ -422,6 +423,7 @@ $(MISC)$/$(SHL2TARGET).flt: makefile.mk @echo WEP>>$@ @echo m_pLoader>$@ @echo _TI2>>$@ + @echo _TI3>>$@ @echo LIBMAIN>>$@ @echo LibMain>>$@ diff --git a/sfx2/qa/complex/sfx2/UndoManager.java b/sfx2/qa/complex/sfx2/UndoManager.java index 548d2cb31591..421111e88f4e 100755 --- a/sfx2/qa/complex/sfx2/UndoManager.java +++ b/sfx2/qa/complex/sfx2/UndoManager.java @@ -85,8 +85,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; diff --git a/sfx2/source/doc/docundomanager.cxx b/sfx2/source/doc/docundomanager.cxx index ade11d18b05f..39534bf9f90c 100755 --- a/sfx2/source/doc/docundomanager.cxx +++ b/sfx2/source/doc/docundomanager.cxx @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -80,311 +81,136 @@ namespace sfx2 using ::svl::IUndoManager; - //================================================================================================================== - //= UndoActionWrapper - //================================================================================================================== - class UndoActionWrapper : public SfxUndoAction - { - public: - UndoActionWrapper( - Reference< XUndoAction > const& i_undoAction - ); - virtual ~UndoActionWrapper(); - - virtual String GetComment() const; - virtual void Undo(); - virtual void Redo(); - virtual BOOL CanRepeat(SfxRepeatTarget&) const; - - private: - const Reference< XUndoAction > m_xUndoAction; - }; - - //------------------------------------------------------------------------------------------------------------------ - UndoActionWrapper::UndoActionWrapper( Reference< XUndoAction > const& i_undoAction ) - :SfxUndoAction() - ,m_xUndoAction( i_undoAction ) - { - ENSURE_OR_THROW( m_xUndoAction.is(), "illegal undo action" ); - } - - //------------------------------------------------------------------------------------------------------------------ - UndoActionWrapper::~UndoActionWrapper() - { - try - { - Reference< XComponent > xComponent( m_xUndoAction, UNO_QUERY ); - if ( xComponent.is() ) - xComponent->dispose(); - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION(); - } - } - - //------------------------------------------------------------------------------------------------------------------ - String UndoActionWrapper::GetComment() const - { - String sComment; - try - { - sComment = m_xUndoAction->getTitle(); - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION(); - } - return sComment; - } - - //------------------------------------------------------------------------------------------------------------------ - void UndoActionWrapper::Undo() - { - m_xUndoAction->undo(); - } - - //------------------------------------------------------------------------------------------------------------------ - void UndoActionWrapper::Redo() - { - m_xUndoAction->redo(); - } - - //------------------------------------------------------------------------------------------------------------------ - BOOL UndoActionWrapper::CanRepeat(SfxRepeatTarget&) const - { - return FALSE; - } - //================================================================================================================== //= DocumentUndoManager_Impl //================================================================================================================== - struct DocumentUndoManager_Impl : public SfxUndoListener + struct DocumentUndoManager_Impl : public ::framework::IUndoManagerImplementation { - ::cppu::OInterfaceContainerHelper aUndoListeners; - IUndoManager* pUndoManager; DocumentUndoManager& rAntiImpl; - bool bAPIActionRunning; - ::std::stack< bool > aContextVisibilities; -#if OSL_DEBUG_LEVEL > 0 - ::std::stack< bool > aContextAPIFlags; -#endif + IUndoManager* pUndoManager; + ::framework::UndoManagerHelper aUndoHelper; DocumentUndoManager_Impl( DocumentUndoManager& i_antiImpl ) - :aUndoListeners( i_antiImpl.getMutex() ) - ,pUndoManager( NULL ) - ,rAntiImpl( i_antiImpl ) - ,bAPIActionRunning( false ) + :rAntiImpl( i_antiImpl ) + ,pUndoManager( impl_retrieveUndoManager( i_antiImpl.getBaseModel() ) ) + // do this *before* the construction of aUndoHelper (which actually means: put pUndoManager before + // aUndoHelper in the member list)! + ,aUndoHelper( *this ) { - SfxObjectShell* pObjectShell = i_antiImpl.getBaseModel().GetObjectShell(); - if ( pObjectShell != NULL ) - pUndoManager = pObjectShell->GetUndoManager(); - if ( !pUndoManager ) - throw NotInitializedException( ::rtl::OUString(), *&i_antiImpl.getBaseModel() ); - // TODO: we probably should add ourself as listener to the SfxObjectShell, in case somebody sets a new - // UndoManager - // (well, adding a listener for this is not possible currently, but I also think that setting a new - // UndoManager does not happen in real life) - pUndoManager->AddUndoListener( *this ); } const SfxObjectShell* getObjectShell() const { return rAntiImpl.getBaseModel().GetObjectShell(); } SfxObjectShell* getObjectShell() { return rAntiImpl.getBaseModel().GetObjectShell(); } - //.............................................................................................................. - IUndoManager& getUndoManager() - { - ENSURE_OR_THROW( pUndoManager != NULL, "DocumentUndoManager_Impl::getUndoManager: no access to the doc's UndoManager implementation!" ); - -#if OSL_DEBUG_LEVEL > 0 - // in a non-product build, assert if the current UndoManager at the shell is not the same we obtained - // (and cached) at construction time - SfxObjectShell* pObjectShell = rAntiImpl.getBaseModel().GetObjectShell(); - OSL_ENSURE( ( pObjectShell != NULL ) && ( pUndoManager == pObjectShell->GetUndoManager() ), - "DocumentUndoManager_Impl::getUndoManager: the UndoManager changed meanwhile - what about our listener?" ); -#endif - - return *pUndoManager; - } + // IUndoManagerImplementation + virtual ::osl::Mutex& getMutex(); + virtual ::svl::IUndoManager& getImplUndoManager(); + virtual Reference< XUndoManager > getThis(); void disposing() { + aUndoHelper.disposing(); ENSURE_OR_RETURN_VOID( pUndoManager, "DocumentUndoManager_Impl::disposing: already disposed!" ); - pUndoManager->RemoveUndoListener( *this ); pUndoManager = NULL; } - // SfxUndoListener - virtual void actionUndone( SfxUndoAction& i_action ); - virtual void actionRedone( SfxUndoAction& i_action ); - virtual void undoActionAdded( SfxUndoAction& i_action ); - virtual void cleared(); - virtual void clearedRedo(); - virtual void listActionEntered( const String& i_comment ); - virtual void listActionLeft(); - virtual void listActionLeftAndMerged(); - virtual void listActionCancelled(); - virtual void undoManagerDying(); + void invalidateXDo_nolck(); + void enterViewStandardMode(); - // public operations - void enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden ); + private: + static IUndoManager* impl_retrieveUndoManager( SfxBaseModel& i_baseModel ) + { + IUndoManager* pUndoManager( NULL ); + SfxObjectShell* pObjectShell = i_baseModel.GetObjectShell(); + if ( pObjectShell != NULL ) + pUndoManager = pObjectShell->GetUndoManager(); + if ( !pUndoManager ) + throw NotInitializedException( ::rtl::OUString(), *&i_baseModel ); + return pUndoManager; + } }; - //================================================================================================================== - namespace + //------------------------------------------------------------------------------------------------------------------ + ::osl::Mutex& DocumentUndoManager_Impl::getMutex() { - //.............................................................................................................. - void lcl_invalidateXDo( const DocumentUndoManager_Impl& i_impl ) - { - const SfxObjectShell* pDocShell = i_impl.getObjectShell(); - ENSURE_OR_THROW( pDocShell != NULL, "lcl_invalidateUndo: no access to the doc shell!" ); - SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( pDocShell ); - while ( pViewFrame ) - { - pViewFrame->GetBindings().Invalidate( SID_UNDO ); - pViewFrame->GetBindings().Invalidate( SID_REDO ); - pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDocShell ); - } - } - + return rAntiImpl.getMutex(); } //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden ) + ::svl::IUndoManager& DocumentUndoManager_Impl::getImplUndoManager() + { + ENSURE_OR_THROW( pUndoManager != NULL, "DocumentUndoManager_Impl::getImplUndoManager: no access to the doc's UndoManager implementation!" ); + +#if OSL_DEBUG_LEVEL > 0 + // in a non-product build, assert if the current UndoManager at the shell is not the same we obtained + // (and cached) at construction time + SfxObjectShell* pObjectShell = rAntiImpl.getBaseModel().GetObjectShell(); + OSL_ENSURE( ( pObjectShell != NULL ) && ( pUndoManager == pObjectShell->GetUndoManager() ), + "DocumentUndoManager_Impl::getImplUndoManager: the UndoManager changed meanwhile - what about our listener?" ); +#endif + + return *pUndoManager; + } + + //------------------------------------------------------------------------------------------------------------------ + Reference< XUndoManager > DocumentUndoManager_Impl::getThis() + { + return static_cast< XUndoManager* >( &rAntiImpl ); + } + + //------------------------------------------------------------------------------------------------------------------ + void DocumentUndoManager_Impl::invalidateXDo_nolck() { - // SYNCHRONIZED ---> SfxModelGuard aGuard( rAntiImpl ); - IUndoManager& rUndoManager = getUndoManager(); - if ( !rUndoManager.IsUndoEnabled() ) - // ignore this request if the manager is locked - return; - - if ( i_hidden && ( rUndoManager.GetUndoActionCount( IUndoManager::CurrentLevel ) == 0 ) ) - throw EmptyUndoStackException( - ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "can't enter a hidden context without a previous Undo action" ) ), - static_cast< XUndoManager* >( &rAntiImpl ) - ); - + const SfxObjectShell* pDocShell = getObjectShell(); + ENSURE_OR_THROW( pDocShell != NULL, "lcl_invalidateUndo: no access to the doc shell!" ); + SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( pDocShell ); + while ( pViewFrame ) { - ::comphelper::FlagGuard aNotificationGuard( bAPIActionRunning ); - rUndoManager.EnterListAction( i_title, ::rtl::OUString() ); + pViewFrame->GetBindings().Invalidate( SID_UNDO ); + pViewFrame->GetBindings().Invalidate( SID_REDO ); + pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDocShell ); } - - aContextVisibilities.push( i_hidden ); - - rAntiImpl.impl_notify( i_title, i_hidden ? &XUndoManagerListener::enteredHiddenContext : &XUndoManagerListener::enteredContext, aGuard ); - // <--- SYNCHRONIZED } //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::actionUndone( SfxUndoAction& i_action ) + void DocumentUndoManager_Impl::enterViewStandardMode() { - if ( bAPIActionRunning ) - return; - - rAntiImpl.impl_notify( i_action.GetComment(), &XUndoManagerListener::actionUndone ); + // TODO: not sure this is a good idea: This might add another action to the Undo/Redo stack, which + // will render the current call somewhat meaningless - finally, the caller can't be sure that really the action + // is undone/redone which s/he intended to. + SfxObjectShell* pDocShell = getObjectShell(); + ENSURE_OR_RETURN_VOID( pDocShell, "DocumentUndoManager_Impl::enterViewStandardMode: do doc shell!" ); + SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( pDocShell ); + while ( pViewFrame ) + { + SfxViewShell* pViewShell = pViewFrame->GetViewShell(); + ENSURE_OR_CONTINUE( pViewShell, "DocumentUndoManager_Impl::enterViewStandardMode: no view shell in the frame!" ); + pViewShell->EnterStandardMode(); + pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDocShell ); + } } - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::actionRedone( SfxUndoAction& i_action ) + //================================================================================================================== + //= SfxModelGuardFacade + //================================================================================================================== + class SfxModelGuardFacade : public ::framework::IClearableInstanceLock { - if ( bAPIActionRunning ) - return; + public: + SfxModelGuardFacade( SfxModelGuard& i_guard ) + :m_guard( i_guard ) + { + } - rAntiImpl.impl_notify( i_action.GetComment(), &XUndoManagerListener::actionRedone ); - } + virtual void clear() + { + m_guard.clear(); + } - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::undoActionAdded( SfxUndoAction& i_action ) - { - if ( bAPIActionRunning ) - return; - - rAntiImpl.impl_notify( i_action.GetComment(), &XUndoManagerListener::undoActionAdded ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::cleared() - { - if ( bAPIActionRunning ) - return; - - rAntiImpl.impl_notify( &XUndoManagerListener::allActionsCleared ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::clearedRedo() - { - if ( bAPIActionRunning ) - return; - - rAntiImpl.impl_notify( &XUndoManagerListener::redoActionsCleared ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::listActionEntered( const String& i_comment ) - { -#if OSL_DEBUG_LEVEL > 0 - aContextAPIFlags.push( bAPIActionRunning ); -#endif - - if ( bAPIActionRunning ) - return; - - rAntiImpl.impl_notify( i_comment, &XUndoManagerListener::enteredContext ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::listActionLeft() - { -#if OSL_DEBUG_LEVEL > 0 - const bool bCurrentContextIsAPIContext = aContextAPIFlags.top(); - aContextAPIFlags.pop(); - OSL_ENSURE( bCurrentContextIsAPIContext == bAPIActionRunning, "DocumentUndoManager_Impl::listActionLeft: API and non-API contexts interwoven!" ); -#endif - - if ( bAPIActionRunning ) - return; - - rAntiImpl.impl_notify( pUndoManager->GetUndoActionComment( 0, IUndoManager::CurrentLevel ), &XUndoManagerListener::leftContext ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::listActionLeftAndMerged() - { -#if OSL_DEBUG_LEVEL > 0 - const bool bCurrentContextIsAPIContext = aContextAPIFlags.top(); - aContextAPIFlags.pop(); - OSL_ENSURE( bCurrentContextIsAPIContext == bAPIActionRunning, "DocumentUndoManager_Impl::listActionLeftAndMerged: API and non-API contexts interwoven!" ); -#endif - - if ( bAPIActionRunning ) - return; - - rAntiImpl.impl_notify( ::rtl::OUString(), &XUndoManagerListener::leftHiddenContext ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::listActionCancelled() - { -#if OSL_DEBUG_LEVEL > 0 - const bool bCurrentContextIsAPIContext = aContextAPIFlags.top(); - aContextAPIFlags.pop(); - OSL_ENSURE( bCurrentContextIsAPIContext == bAPIActionRunning, "DocumentUndoManager_Impl::listActionCancelled: API and non-API contexts interwoven!" ); -#endif - - if ( bAPIActionRunning ) - return; - - rAntiImpl.impl_notify( ::rtl::OUString(), &XUndoManagerListener::cancelledContext ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager_Impl::undoManagerDying() - { - pUndoManager = NULL; - } + private: + SfxModelGuard& m_guard; + }; //================================================================================================================== //= DocumentUndoManager @@ -404,10 +230,6 @@ namespace sfx2 //------------------------------------------------------------------------------------------------------------------ void DocumentUndoManager::disposing() { - EventObject aEvent; - aEvent.Source = static_cast< XUndoManager* >( this ); - m_pImpl->aUndoListeners.disposeAndClear( aEvent ); - m_pImpl->disposing(); } @@ -423,67 +245,21 @@ namespace sfx2 SfxModelSubComponent::release(); } - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager::impl_notify( ::rtl::OUString const& i_title, void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ), - SfxModelGuard& i_instanceLock ) - { - UndoManagerEvent aEvent; - aEvent.Source = static_cast< XUndoManager* >( this ); - aEvent.UndoActionTitle = i_title; - aEvent.UndoContextDepth = m_pImpl->getUndoManager().GetListActionDepth(); - - i_instanceLock.clear(); - m_pImpl->aUndoListeners.notifyEach( i_notificationMethod, aEvent ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager::impl_notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ), - SfxModelGuard& i_instanceLock ) - { - EventObject aEvent; - aEvent.Source = static_cast< XUndoManager* >( this ); - i_instanceLock.clear(); - m_pImpl->aUndoListeners.notifyEach( i_notificationMethod, aEvent ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager::impl_notify( ::rtl::OUString const& i_title, void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) ) - { - UndoManagerEvent aEvent; - aEvent.Source = static_cast< XUndoManager* >( this ); - aEvent.UndoActionTitle = i_title; - aEvent.UndoContextDepth = m_pImpl->getUndoManager().GetListActionDepth(); - - // TODO: this notification method here is used by DocumentUndoManager_Impl, to multiplex the notifications we - // receive from the IUndoManager. Those notitications are sent with a locked SolarMutex, which means - // we're doing the multiplexing here with a locked SM, too. Which is Bad (TM). - // Fixing this properly would require outsourcing all the notifications into an own thread - which might lead - // to problems of its own, since clients might expect synchronous notifications. - - m_pImpl->aUndoListeners.notifyEach( i_notificationMethod, aEvent ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager::impl_notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ) ) - { - EventObject aEvent; - aEvent.Source = static_cast< XUndoManager* >( this ); - - // TODO: the same comment as in the other impl_notify, regarding SM locking applies here ... - - m_pImpl->aUndoListeners.notifyEach( i_notificationMethod, aEvent ); - } - //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DocumentUndoManager::enterUndoContext( const ::rtl::OUString& i_title ) throw (RuntimeException) { - m_pImpl->enterUndoContext( i_title, false ); + SfxModelGuard aGuard( *this ); + m_pImpl->aUndoHelper.enterUndoContext( i_title, SfxModelGuardFacade( aGuard ) ); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DocumentUndoManager::enterHiddenUndoContext( ) throw (EmptyUndoStackException, RuntimeException) { - m_pImpl->enterUndoContext( ::rtl::OUString(), true ); + // SYNCHRONIZED ---> + SfxModelGuard aGuard( *this ); + m_pImpl->aUndoHelper.enterHiddenUndoContext( SfxModelGuardFacade( aGuard ) ); + // <--- SYNCHRONIZED + m_pImpl->invalidateXDo_nolck(); } //------------------------------------------------------------------------------------------------------------------ @@ -491,38 +267,9 @@ namespace sfx2 { // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - if ( !rUndoManager.IsUndoEnabled() ) - // ignore this request if the manager is locked - return; - - if ( !rUndoManager.IsInListAction() ) - throw InvalidStateException( - ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no active undo context" ) ), - static_cast< XUndoManager* >( this ) - ); - - USHORT nContextElements = 0; - bool isHiddenContext = false; - { - ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); - - isHiddenContext = m_pImpl->aContextVisibilities.top(); - m_pImpl->aContextVisibilities.pop(); - if ( isHiddenContext ) - nContextElements = rUndoManager.LeaveAndMergeListAction(); - else - nContextElements = rUndoManager.LeaveListAction(); - } - - if ( nContextElements == 0 ) - impl_notify( ::rtl::OUString(), &XUndoManagerListener::cancelledContext, aGuard ); - else if ( isHiddenContext ) - impl_notify( ::rtl::OUString(), &XUndoManagerListener::leftHiddenContext, aGuard ); - else - impl_notify( rUndoManager.GetUndoActionComment( 0, IUndoManager::CurrentLevel ), &XUndoManagerListener::leftContext, aGuard ); + m_pImpl->aUndoHelper.leaveUndoContext( SfxModelGuardFacade( aGuard ) ); // <--- SYNCHRONIZED + m_pImpl->invalidateXDo_nolck(); } //------------------------------------------------------------------------------------------------------------------ @@ -530,207 +277,73 @@ namespace sfx2 { // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - if ( !i_action.is() ) - throw IllegalArgumentException( - ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "illegal undo action object" ) ), - static_cast< XUndoManager* >( this ), - 1 - ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - if ( !rUndoManager.IsUndoEnabled() ) - // ignore the request if the manager is locked - return; - - const bool bHadRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 ); - { - ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); - rUndoManager.AddUndoAction( new UndoActionWrapper( i_action ) ); - } - const bool bHasRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 ); - - lcl_invalidateXDo( *m_pImpl ); - impl_notify( i_action->getTitle(), &XUndoManagerListener::undoActionAdded, aGuard ); - // <--- SYNCHRONIZED - - if ( bHadRedoActions && !bHasRedoActions ) - impl_notify( &XUndoManagerListener::redoActionsCleared ); - } - - //------------------------------------------------------------------------------------------------------------------ - void DocumentUndoManager::impl_do_nolck( - USHORT ( IUndoManager::*i_checkMethod )( bool const ) const, BOOL ( IUndoManager::*i_doMethod )(), - String ( IUndoManager::*i_titleRetriever )( USHORT, bool const ) const, - void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) ) - { - // SYNCHRONIZED ---> - SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - if ( rUndoManager.IsInListAction() ) - throw UndoContextNotClosedException( ::rtl::OUString(), static_cast< XUndoManager* >( this ) ); - - if ( (rUndoManager.*i_checkMethod)( IUndoManager::TopLevel ) == 0 ) - throw EmptyUndoStackException( ::rtl::OUString::createFromAscii( "stack is empty" ), static_cast< XUndoManager* >( this ) ); - - // let all views enter the standard mode - // TODO: not sure this is a good idea: This might add another action to the Undo/Redo stack, which - // will render the call somewhat meaningless - finally, the caller can't be sure that really the action - // is undone/redone which s/he intended to. - SfxObjectShell* pDocShell = m_pImpl->getObjectShell(); - OSL_ENSURE( pDocShell, "DocumentUndoManager::impl_do_nolck: do doc shell!" ); - if ( pDocShell ) - { - SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( pDocShell ); - while ( pViewFrame ) - { - SfxViewShell* pViewShell = pViewFrame->GetViewShell(); - ENSURE_OR_CONTINUE( pViewShell, "DocumentUndoManager::impl_do_nolck: no view shell in the frame!" ); - pViewShell->EnterStandardMode(); - pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDocShell ); - } - } - - const ::rtl::OUString sUndoActionTitle = (rUndoManager.*i_titleRetriever)( 0, IUndoManager::TopLevel ); - { - ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); - try - { - (rUndoManager.*i_doMethod)(); - } - catch( const RuntimeException& ) { /* allowed to leave here */ throw; } - catch( const UndoFailedException& ) { /* allowed to leave here */ throw; } - catch( const Exception& ) - { - // not allowed to leave - const Any aError( ::cppu::getCaughtException() ); - throw UndoFailedException( ::rtl::OUString(), static_cast< XUndoManager* >( this ), aError ); - } - } - - impl_notify( sUndoActionTitle, i_notificationMethod, aGuard ); + m_pImpl->aUndoHelper.addUndoAction( i_action, SfxModelGuardFacade( aGuard ) ); // <--- SYNCHRONIZED + m_pImpl->invalidateXDo_nolck(); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DocumentUndoManager::undo( ) throw (EmptyUndoStackException, UndoContextNotClosedException, UndoFailedException, RuntimeException) { - impl_do_nolck( - &IUndoManager::GetUndoActionCount, - &IUndoManager::Undo, - &IUndoManager::GetUndoActionComment, - &XUndoManagerListener::actionUndone - ); + // SYNCHRONIZED ---> + SfxModelGuard aGuard( *this ); + m_pImpl->enterViewStandardMode(); + m_pImpl->aUndoHelper.undo( SfxModelGuardFacade( aGuard ) ); + // <--- SYNCHRONIZED + m_pImpl->invalidateXDo_nolck(); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DocumentUndoManager::redo( ) throw (EmptyUndoStackException, UndoContextNotClosedException, UndoFailedException, RuntimeException) { - impl_do_nolck( - &IUndoManager::GetRedoActionCount, - &IUndoManager::Redo, - &IUndoManager::GetRedoActionComment, - &XUndoManagerListener::actionRedone - ); + // SYNCHRONIZED ---> + SfxModelGuard aGuard( *this ); + m_pImpl->enterViewStandardMode(); + m_pImpl->aUndoHelper.redo( SfxModelGuardFacade( aGuard ) ); + // <--- SYNCHRONIZED + m_pImpl->invalidateXDo_nolck(); } //------------------------------------------------------------------------------------------------------------------ ::sal_Bool SAL_CALL DocumentUndoManager::isUndoPossible( ) throw (RuntimeException) { - // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - if ( rUndoManager.IsInListAction() ) - return sal_False; - return rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) > 0; - // <--- SYNCHRONIZED + return m_pImpl->aUndoHelper.isUndoPossible(); } //------------------------------------------------------------------------------------------------------------------ ::sal_Bool SAL_CALL DocumentUndoManager::isRedoPossible( ) throw (RuntimeException) { - // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - if ( rUndoManager.IsInListAction() ) - return sal_False; - return rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0; - // <--- SYNCHRONIZED - } - - //------------------------------------------------------------------------------------------------------------------ - namespace - { - //.............................................................................................................. - ::rtl::OUString lcl_getCurrentActionTitle( DocumentUndoManager_Impl& i_impl, const bool i_undo ) - { - // SYNCHRONIZED ---> - SfxModelGuard aGuard( i_impl.rAntiImpl ); - - const IUndoManager& rUndoManager = i_impl.getUndoManager(); - const USHORT nActionCount = i_undo - ? rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) - : rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ); - if ( nActionCount == 0 ) - throw EmptyUndoStackException( - i_undo ? ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no action on the undo stack" ) ) - : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no action on the redo stack" ) ), - static_cast< XUndoManager* >( &i_impl.rAntiImpl ) - ); - return i_undo - ? rUndoManager.GetUndoActionComment( 0, IUndoManager::TopLevel ) - : rUndoManager.GetRedoActionComment( 0, IUndoManager::TopLevel ); - // <--- SYNCHRONIZED - } - - //.............................................................................................................. - Sequence< ::rtl::OUString > lcl_getAllActionTitles( DocumentUndoManager_Impl& i_impl, const bool i_undo ) - { - // SYNCHRONIZED ---> - SfxModelGuard aGuard( i_impl.rAntiImpl ); - - const IUndoManager& rUndoManager = i_impl.getUndoManager(); - const sal_Int32 nCount = i_undo - ? rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) - : rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ); - - Sequence< ::rtl::OUString > aTitles( nCount ); - for ( sal_Int32 i=0; iaUndoHelper.isRedoPossible(); } //------------------------------------------------------------------------------------------------------------------ ::rtl::OUString SAL_CALL DocumentUndoManager::getCurrentUndoActionTitle( ) throw (EmptyUndoStackException, RuntimeException) { - return lcl_getCurrentActionTitle( *m_pImpl, true ); + SfxModelGuard aGuard( *this ); + return m_pImpl->aUndoHelper.getCurrentUndoActionTitle(); } //------------------------------------------------------------------------------------------------------------------ ::rtl::OUString SAL_CALL DocumentUndoManager::getCurrentRedoActionTitle( ) throw (EmptyUndoStackException, RuntimeException) { - return lcl_getCurrentActionTitle( *m_pImpl, false ); + SfxModelGuard aGuard( *this ); + return m_pImpl->aUndoHelper.getCurrentRedoActionTitle(); } //------------------------------------------------------------------------------------------------------------------ Sequence< ::rtl::OUString > SAL_CALL DocumentUndoManager::getAllUndoActionTitles( ) throw (RuntimeException) { - return lcl_getAllActionTitles( *m_pImpl, true ); + SfxModelGuard aGuard( *this ); + return m_pImpl->aUndoHelper.getAllUndoActionTitles(); } //------------------------------------------------------------------------------------------------------------------ Sequence< ::rtl::OUString > SAL_CALL DocumentUndoManager::getAllRedoActionTitles( ) throw (RuntimeException) { - return lcl_getAllActionTitles( *m_pImpl, false ); + SfxModelGuard aGuard( *this ); + return m_pImpl->aUndoHelper.getAllRedoActionTitles(); } //------------------------------------------------------------------------------------------------------------------ @@ -738,17 +351,9 @@ namespace sfx2 { // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - if ( rUndoManager.IsInListAction() ) - throw UndoContextNotClosedException( ::rtl::OUString(), static_cast< XUndoManager* >( this ) ); - - { - ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); - rUndoManager.Clear(); - } - impl_notify( &XUndoManagerListener::allActionsCleared, aGuard ); + m_pImpl->aUndoHelper.clear( SfxModelGuardFacade( aGuard ) ); // <--- SYNCHRONIZED + m_pImpl->invalidateXDo_nolck(); } //------------------------------------------------------------------------------------------------------------------ @@ -756,17 +361,9 @@ namespace sfx2 { // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - if ( rUndoManager.IsInListAction() ) - throw UndoContextNotClosedException( ::rtl::OUString(), static_cast< XUndoManager* >( this ) ); - - { - ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); - rUndoManager.ClearRedo(); - } - impl_notify( &XUndoManagerListener::redoActionsCleared, aGuard ); + m_pImpl->aUndoHelper.clearRedo( SfxModelGuardFacade( aGuard ) ); // <--- SYNCHRONIZED + m_pImpl->invalidateXDo_nolck(); } //------------------------------------------------------------------------------------------------------------------ @@ -774,72 +371,44 @@ namespace sfx2 { // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - { - ::comphelper::FlagGuard aNotificationGuard( m_pImpl->bAPIActionRunning ); - while ( rUndoManager.IsInListAction() ) - rUndoManager.LeaveListAction(); - rUndoManager.Clear(); - } - - impl_notify( &XUndoManagerListener::resetAll, aGuard ); + m_pImpl->aUndoHelper.reset( SfxModelGuardFacade( aGuard ) ); // <--- SYNCHRONIZED + m_pImpl->invalidateXDo_nolck(); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DocumentUndoManager::lock( ) throw (RuntimeException) { - // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - rUndoManager.EnableUndo( false ); - // <--- SYNCHRONIZED + m_pImpl->aUndoHelper.lock(); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DocumentUndoManager::unlock( ) throw (RuntimeException, NotLockedException) { - // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - if ( rUndoManager.IsUndoEnabled() ) - throw NotLockedException( ::rtl::OUString::createFromAscii( "Undo manager is not locked" ), static_cast< XUndoManager* >( this ) ); - rUndoManager.EnableUndo( true ); - // <--- SYNCHRONIZED + m_pImpl->aUndoHelper.unlock(); } //------------------------------------------------------------------------------------------------------------------ ::sal_Bool SAL_CALL DocumentUndoManager::isLocked( ) throw (RuntimeException) { - // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - - IUndoManager& rUndoManager = m_pImpl->getUndoManager(); - return !rUndoManager.IsUndoEnabled(); - // <--- SYNCHRONIZED + return m_pImpl->aUndoHelper.isLocked(); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DocumentUndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) throw (RuntimeException) { - // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - if ( i_listener.is() ) - m_pImpl->aUndoListeners.addInterface( i_listener ); - // <--- SYNCHRONIZED + return m_pImpl->aUndoHelper.addUndoManagerListener( i_listener ); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DocumentUndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) throw (RuntimeException) { - // SYNCHRONIZED ---> SfxModelGuard aGuard( *this ); - if ( i_listener.is() ) - m_pImpl->aUndoListeners.removeInterface( i_listener ); - // <--- SYNCHRONIZED + return m_pImpl->aUndoHelper.removeUndoManagerListener( i_listener ); } //...................................................................................................................... diff --git a/sfx2/source/inc/docundomanager.hxx b/sfx2/source/inc/docundomanager.hxx index 7998657fbb3a..cca8d1b77fd6 100755 --- a/sfx2/source/inc/docundomanager.hxx +++ b/sfx2/source/inc/docundomanager.hxx @@ -95,34 +95,6 @@ namespace sfx2 virtual void SAL_CALL unlock( ) throw (::com::sun::star::util::NotLockedException, ::com::sun::star::uno::RuntimeException); virtual ::sal_Bool SAL_CALL isLocked( ) throw (::com::sun::star::uno::RuntimeException); - private: - void impl_notify( - ::rtl::OUString const& i_title, - void ( SAL_CALL ::com::sun::star::document::XUndoManagerListener::*i_notificationMethod )( const ::com::sun::star::document::UndoManagerEvent& ), - SfxModelGuard& i_instanceLock - ); - - void impl_notify( - void ( SAL_CALL ::com::sun::star::document::XUndoManagerListener::*i_notificationMethod )( const ::com::sun::star::lang::EventObject& ), - SfxModelGuard& i_instanceLock - ); - - void impl_notify( - ::rtl::OUString const& i_title, - void ( SAL_CALL ::com::sun::star::document::XUndoManagerListener::*i_notificationMethod )( const ::com::sun::star::document::UndoManagerEvent& ) - ); - - void impl_notify( - void ( SAL_CALL ::com::sun::star::document::XUndoManagerListener::*i_notificationMethod )( const ::com::sun::star::lang::EventObject& ) - ); - - void impl_do_nolck( - USHORT ( ::svl::IUndoManager::*i_checkMethod )( bool const ) const, - BOOL ( ::svl::IUndoManager::*i_doMethod )(), - UniString ( ::svl::IUndoManager::*i_titleRetriever )( USHORT, bool const ) const, - void ( SAL_CALL ::com::sun::star::document::XUndoManagerListener::*i_notificationMethod )( const ::com::sun::star::document::UndoManagerEvent& ) - ); - private: ::boost::scoped_ptr< DocumentUndoManager_Impl > m_pImpl; };