1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3*cdf0e10cSrcweir  *
4*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
5*cdf0e10cSrcweir  *
6*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
7*cdf0e10cSrcweir  *
8*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
9*cdf0e10cSrcweir  *
10*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
11*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
12*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
13*cdf0e10cSrcweir  *
14*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
15*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
18*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
19*cdf0e10cSrcweir  *
20*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
21*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
22*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
23*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
24*cdf0e10cSrcweir  *
25*cdf0e10cSrcweir  ************************************************************************/
26*cdf0e10cSrcweir 
27*cdf0e10cSrcweir #include "precompiled_framework.hxx"
28*cdf0e10cSrcweir 
29*cdf0e10cSrcweir #include "framework/undomanagerhelper.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir /** === begin UNO includes === **/
32*cdf0e10cSrcweir #include <com/sun/star/lang/XComponent.hpp>
33*cdf0e10cSrcweir /** === end UNO includes === **/
34*cdf0e10cSrcweir 
35*cdf0e10cSrcweir #include <cppuhelper/interfacecontainer.hxx>
36*cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx>
37*cdf0e10cSrcweir #include <comphelper/flagguard.hxx>
38*cdf0e10cSrcweir #include <comphelper/asyncnotification.hxx>
39*cdf0e10cSrcweir #include <svl/undo.hxx>
40*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
41*cdf0e10cSrcweir #include <osl/conditn.hxx>
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir #include <stack>
44*cdf0e10cSrcweir #include <queue>
45*cdf0e10cSrcweir #include <boost/function.hpp>
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir //......................................................................................................................
48*cdf0e10cSrcweir namespace framework
49*cdf0e10cSrcweir {
50*cdf0e10cSrcweir //......................................................................................................................
51*cdf0e10cSrcweir 
52*cdf0e10cSrcweir 	/** === begin UNO using === **/
53*cdf0e10cSrcweir 	using ::com::sun::star::uno::Reference;
54*cdf0e10cSrcweir 	using ::com::sun::star::uno::XInterface;
55*cdf0e10cSrcweir 	using ::com::sun::star::uno::UNO_QUERY;
56*cdf0e10cSrcweir 	using ::com::sun::star::uno::UNO_QUERY_THROW;
57*cdf0e10cSrcweir 	using ::com::sun::star::uno::UNO_SET_THROW;
58*cdf0e10cSrcweir 	using ::com::sun::star::uno::Exception;
59*cdf0e10cSrcweir 	using ::com::sun::star::uno::RuntimeException;
60*cdf0e10cSrcweir 	using ::com::sun::star::uno::Any;
61*cdf0e10cSrcweir 	using ::com::sun::star::uno::makeAny;
62*cdf0e10cSrcweir 	using ::com::sun::star::uno::Sequence;
63*cdf0e10cSrcweir 	using ::com::sun::star::uno::Type;
64*cdf0e10cSrcweir     using ::com::sun::star::document::XUndoManagerListener;
65*cdf0e10cSrcweir     using ::com::sun::star::document::UndoManagerEvent;
66*cdf0e10cSrcweir     using ::com::sun::star::document::EmptyUndoStackException;
67*cdf0e10cSrcweir     using ::com::sun::star::document::UndoContextNotClosedException;
68*cdf0e10cSrcweir     using ::com::sun::star::document::UndoFailedException;
69*cdf0e10cSrcweir     using ::com::sun::star::util::NotLockedException;
70*cdf0e10cSrcweir     using ::com::sun::star::lang::EventObject;
71*cdf0e10cSrcweir     using ::com::sun::star::document::XUndoAction;
72*cdf0e10cSrcweir     using ::com::sun::star::lang::XComponent;
73*cdf0e10cSrcweir     using ::com::sun::star::document::XUndoManager;
74*cdf0e10cSrcweir     using ::com::sun::star::util::InvalidStateException;
75*cdf0e10cSrcweir     using ::com::sun::star::lang::IllegalArgumentException;
76*cdf0e10cSrcweir     using ::com::sun::star::util::XModifyListener;
77*cdf0e10cSrcweir 	/** === end UNO using === **/
78*cdf0e10cSrcweir     using ::svl::IUndoManager;
79*cdf0e10cSrcweir 
80*cdf0e10cSrcweir 	//==================================================================================================================
81*cdf0e10cSrcweir 	//= UndoActionWrapper
82*cdf0e10cSrcweir 	//==================================================================================================================
83*cdf0e10cSrcweir     class UndoActionWrapper : public SfxUndoAction
84*cdf0e10cSrcweir     {
85*cdf0e10cSrcweir     public:
86*cdf0e10cSrcweir                             UndoActionWrapper(
87*cdf0e10cSrcweir                                 Reference< XUndoAction > const& i_undoAction
88*cdf0e10cSrcweir                             );
89*cdf0e10cSrcweir         virtual             ~UndoActionWrapper();
90*cdf0e10cSrcweir 
91*cdf0e10cSrcweir 	    virtual String      GetComment() const;
92*cdf0e10cSrcweir         virtual void        Undo();
93*cdf0e10cSrcweir         virtual void        Redo();
94*cdf0e10cSrcweir         virtual sal_Bool    CanRepeat(SfxRepeatTarget&) const;
95*cdf0e10cSrcweir 
96*cdf0e10cSrcweir     private:
97*cdf0e10cSrcweir         const Reference< XUndoAction >  m_xUndoAction;
98*cdf0e10cSrcweir     };
99*cdf0e10cSrcweir 
100*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
101*cdf0e10cSrcweir     UndoActionWrapper::UndoActionWrapper( Reference< XUndoAction > const& i_undoAction )
102*cdf0e10cSrcweir         :SfxUndoAction()
103*cdf0e10cSrcweir         ,m_xUndoAction( i_undoAction )
104*cdf0e10cSrcweir     {
105*cdf0e10cSrcweir         ENSURE_OR_THROW( m_xUndoAction.is(), "illegal undo action" );
106*cdf0e10cSrcweir     }
107*cdf0e10cSrcweir 
108*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
109*cdf0e10cSrcweir     UndoActionWrapper::~UndoActionWrapper()
110*cdf0e10cSrcweir     {
111*cdf0e10cSrcweir         try
112*cdf0e10cSrcweir         {
113*cdf0e10cSrcweir             Reference< XComponent > xComponent( m_xUndoAction, UNO_QUERY );
114*cdf0e10cSrcweir             if ( xComponent.is() )
115*cdf0e10cSrcweir                 xComponent->dispose();
116*cdf0e10cSrcweir         }
117*cdf0e10cSrcweir         catch( const Exception& )
118*cdf0e10cSrcweir         {
119*cdf0e10cSrcweir         	DBG_UNHANDLED_EXCEPTION();
120*cdf0e10cSrcweir         }
121*cdf0e10cSrcweir     }
122*cdf0e10cSrcweir 
123*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
124*cdf0e10cSrcweir     String UndoActionWrapper::GetComment() const
125*cdf0e10cSrcweir     {
126*cdf0e10cSrcweir         String sComment;
127*cdf0e10cSrcweir         try
128*cdf0e10cSrcweir         {
129*cdf0e10cSrcweir             sComment = m_xUndoAction->getTitle();
130*cdf0e10cSrcweir         }
131*cdf0e10cSrcweir         catch( const Exception& )
132*cdf0e10cSrcweir         {
133*cdf0e10cSrcweir         	DBG_UNHANDLED_EXCEPTION();
134*cdf0e10cSrcweir         }
135*cdf0e10cSrcweir         return sComment;
136*cdf0e10cSrcweir     }
137*cdf0e10cSrcweir 
138*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
139*cdf0e10cSrcweir     void UndoActionWrapper::Undo()
140*cdf0e10cSrcweir     {
141*cdf0e10cSrcweir         m_xUndoAction->undo();
142*cdf0e10cSrcweir     }
143*cdf0e10cSrcweir 
144*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
145*cdf0e10cSrcweir     void UndoActionWrapper::Redo()
146*cdf0e10cSrcweir     {
147*cdf0e10cSrcweir         m_xUndoAction->redo();
148*cdf0e10cSrcweir     }
149*cdf0e10cSrcweir 
150*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
151*cdf0e10cSrcweir     sal_Bool UndoActionWrapper::CanRepeat(SfxRepeatTarget&) const
152*cdf0e10cSrcweir     {
153*cdf0e10cSrcweir         return sal_False;
154*cdf0e10cSrcweir     }
155*cdf0e10cSrcweir 
156*cdf0e10cSrcweir 	//==================================================================================================================
157*cdf0e10cSrcweir 	//= UndoManagerRequest
158*cdf0e10cSrcweir 	//==================================================================================================================
159*cdf0e10cSrcweir     class UndoManagerRequest : public ::comphelper::AnyEvent
160*cdf0e10cSrcweir     {
161*cdf0e10cSrcweir     public:
162*cdf0e10cSrcweir         UndoManagerRequest( ::boost::function0< void > const& i_request )
163*cdf0e10cSrcweir             :m_request( i_request )
164*cdf0e10cSrcweir             ,m_caughtException()
165*cdf0e10cSrcweir             ,m_finishCondition()
166*cdf0e10cSrcweir         {
167*cdf0e10cSrcweir             m_finishCondition.reset();
168*cdf0e10cSrcweir         }
169*cdf0e10cSrcweir 
170*cdf0e10cSrcweir         void execute()
171*cdf0e10cSrcweir         {
172*cdf0e10cSrcweir             try
173*cdf0e10cSrcweir             {
174*cdf0e10cSrcweir                 m_request();
175*cdf0e10cSrcweir             }
176*cdf0e10cSrcweir             catch( const Exception& )
177*cdf0e10cSrcweir             {
178*cdf0e10cSrcweir                 m_caughtException = ::cppu::getCaughtException();
179*cdf0e10cSrcweir             }
180*cdf0e10cSrcweir             m_finishCondition.set();
181*cdf0e10cSrcweir         }
182*cdf0e10cSrcweir 
183*cdf0e10cSrcweir         void wait()
184*cdf0e10cSrcweir         {
185*cdf0e10cSrcweir             m_finishCondition.wait();
186*cdf0e10cSrcweir             if ( m_caughtException.hasValue() )
187*cdf0e10cSrcweir                 ::cppu::throwException( m_caughtException );
188*cdf0e10cSrcweir         }
189*cdf0e10cSrcweir 
190*cdf0e10cSrcweir         void cancel( const Reference< XInterface >& i_context )
191*cdf0e10cSrcweir         {
192*cdf0e10cSrcweir             m_caughtException <<= RuntimeException(
193*cdf0e10cSrcweir                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Concurrency error: an ealier operation on the stack failed." ) ),
194*cdf0e10cSrcweir                 i_context
195*cdf0e10cSrcweir             );
196*cdf0e10cSrcweir             m_finishCondition.set();
197*cdf0e10cSrcweir         }
198*cdf0e10cSrcweir 
199*cdf0e10cSrcweir     protected:
200*cdf0e10cSrcweir         ~UndoManagerRequest()
201*cdf0e10cSrcweir         {
202*cdf0e10cSrcweir         }
203*cdf0e10cSrcweir 
204*cdf0e10cSrcweir     private:
205*cdf0e10cSrcweir         ::boost::function0< void >  m_request;
206*cdf0e10cSrcweir         Any                         m_caughtException;
207*cdf0e10cSrcweir         ::osl::Condition            m_finishCondition;
208*cdf0e10cSrcweir     };
209*cdf0e10cSrcweir 
210*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
211*cdf0e10cSrcweir 
212*cdf0e10cSrcweir 	//==================================================================================================================
213*cdf0e10cSrcweir 	//= UndoManagerHelper_Impl
214*cdf0e10cSrcweir 	//==================================================================================================================
215*cdf0e10cSrcweir     class UndoManagerHelper_Impl : public SfxUndoListener
216*cdf0e10cSrcweir     {
217*cdf0e10cSrcweir     private:
218*cdf0e10cSrcweir         ::osl::Mutex                        m_aMutex;
219*cdf0e10cSrcweir         ::osl::Mutex                        m_aQueueMutex;
220*cdf0e10cSrcweir         bool                                m_disposed;
221*cdf0e10cSrcweir         bool                                m_bAPIActionRunning;
222*cdf0e10cSrcweir         bool                                m_bProcessingEvents;
223*cdf0e10cSrcweir         sal_Int32                           m_nLockCount;
224*cdf0e10cSrcweir         ::cppu::OInterfaceContainerHelper   m_aUndoListeners;
225*cdf0e10cSrcweir         ::cppu::OInterfaceContainerHelper   m_aModifyListeners;
226*cdf0e10cSrcweir         IUndoManagerImplementation&         m_rUndoManagerImplementation;
227*cdf0e10cSrcweir         UndoManagerHelper&                  m_rAntiImpl;
228*cdf0e10cSrcweir         ::std::stack< bool >                m_aContextVisibilities;
229*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0
230*cdf0e10cSrcweir         ::std::stack< bool >                m_aContextAPIFlags;
231*cdf0e10cSrcweir #endif
232*cdf0e10cSrcweir         ::std::queue< ::rtl::Reference< UndoManagerRequest > >
233*cdf0e10cSrcweir                                             m_aEventQueue;
234*cdf0e10cSrcweir 
235*cdf0e10cSrcweir     public:
236*cdf0e10cSrcweir         ::osl::Mutex&   getMutex() { return m_aMutex; }
237*cdf0e10cSrcweir 
238*cdf0e10cSrcweir     public:
239*cdf0e10cSrcweir         UndoManagerHelper_Impl( UndoManagerHelper& i_antiImpl, IUndoManagerImplementation& i_undoManagerImpl )
240*cdf0e10cSrcweir             :m_aMutex()
241*cdf0e10cSrcweir             ,m_aQueueMutex()
242*cdf0e10cSrcweir             ,m_disposed( false )
243*cdf0e10cSrcweir             ,m_bAPIActionRunning( false )
244*cdf0e10cSrcweir             ,m_bProcessingEvents( false )
245*cdf0e10cSrcweir             ,m_nLockCount( 0 )
246*cdf0e10cSrcweir             ,m_aUndoListeners( m_aMutex )
247*cdf0e10cSrcweir             ,m_aModifyListeners( m_aMutex )
248*cdf0e10cSrcweir             ,m_rUndoManagerImplementation( i_undoManagerImpl )
249*cdf0e10cSrcweir             ,m_rAntiImpl( i_antiImpl )
250*cdf0e10cSrcweir         {
251*cdf0e10cSrcweir             getUndoManager().AddUndoListener( *this );
252*cdf0e10cSrcweir         }
253*cdf0e10cSrcweir 
254*cdf0e10cSrcweir         virtual ~UndoManagerHelper_Impl()
255*cdf0e10cSrcweir         {
256*cdf0e10cSrcweir         }
257*cdf0e10cSrcweir 
258*cdf0e10cSrcweir         //..............................................................................................................
259*cdf0e10cSrcweir         IUndoManager& getUndoManager() const
260*cdf0e10cSrcweir         {
261*cdf0e10cSrcweir             return m_rUndoManagerImplementation.getImplUndoManager();
262*cdf0e10cSrcweir         }
263*cdf0e10cSrcweir 
264*cdf0e10cSrcweir         //..............................................................................................................
265*cdf0e10cSrcweir         Reference< XUndoManager > getXUndoManager() const
266*cdf0e10cSrcweir         {
267*cdf0e10cSrcweir             return m_rUndoManagerImplementation.getThis();
268*cdf0e10cSrcweir         }
269*cdf0e10cSrcweir 
270*cdf0e10cSrcweir         // SfxUndoListener
271*cdf0e10cSrcweir         virtual void actionUndone( const String& i_actionComment );
272*cdf0e10cSrcweir         virtual void actionRedone( const String& i_actionComment );
273*cdf0e10cSrcweir         virtual void undoActionAdded( const String& i_actionComment );
274*cdf0e10cSrcweir         virtual void cleared();
275*cdf0e10cSrcweir         virtual void clearedRedo();
276*cdf0e10cSrcweir         virtual void resetAll();
277*cdf0e10cSrcweir         virtual void listActionEntered( const String& i_comment );
278*cdf0e10cSrcweir         virtual void listActionLeft( const String& i_comment );
279*cdf0e10cSrcweir         virtual void listActionLeftAndMerged();
280*cdf0e10cSrcweir         virtual void listActionCancelled();
281*cdf0e10cSrcweir         virtual void undoManagerDying();
282*cdf0e10cSrcweir 
283*cdf0e10cSrcweir         // public operations
284*cdf0e10cSrcweir         void disposing();
285*cdf0e10cSrcweir 
286*cdf0e10cSrcweir         void enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden, IMutexGuard& i_instanceLock );
287*cdf0e10cSrcweir         void leaveUndoContext( IMutexGuard& i_instanceLock );
288*cdf0e10cSrcweir         void addUndoAction( const Reference< XUndoAction >& i_action, IMutexGuard& i_instanceLock );
289*cdf0e10cSrcweir         void undo( IMutexGuard& i_instanceLock );
290*cdf0e10cSrcweir         void redo( IMutexGuard& i_instanceLock );
291*cdf0e10cSrcweir         void clear( IMutexGuard& i_instanceLock );
292*cdf0e10cSrcweir         void clearRedo( IMutexGuard& i_instanceLock );
293*cdf0e10cSrcweir         void reset( IMutexGuard& i_instanceLock );
294*cdf0e10cSrcweir 
295*cdf0e10cSrcweir         void lock();
296*cdf0e10cSrcweir         void unlock();
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir         void addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
299*cdf0e10cSrcweir         {
300*cdf0e10cSrcweir             m_aUndoListeners.addInterface( i_listener );
301*cdf0e10cSrcweir         }
302*cdf0e10cSrcweir 
303*cdf0e10cSrcweir         void removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
304*cdf0e10cSrcweir         {
305*cdf0e10cSrcweir             m_aUndoListeners.removeInterface( i_listener );
306*cdf0e10cSrcweir         }
307*cdf0e10cSrcweir 
308*cdf0e10cSrcweir         void addModifyListener( const Reference< XModifyListener >& i_listener )
309*cdf0e10cSrcweir         {
310*cdf0e10cSrcweir             m_aModifyListeners.addInterface( i_listener );
311*cdf0e10cSrcweir         }
312*cdf0e10cSrcweir 
313*cdf0e10cSrcweir         void removeModifyListener( const Reference< XModifyListener >& i_listener )
314*cdf0e10cSrcweir         {
315*cdf0e10cSrcweir             m_aModifyListeners.removeInterface( i_listener );
316*cdf0e10cSrcweir         }
317*cdf0e10cSrcweir 
318*cdf0e10cSrcweir         UndoManagerEvent
319*cdf0e10cSrcweir             buildEvent( ::rtl::OUString const& i_title ) const;
320*cdf0e10cSrcweir 
321*cdf0e10cSrcweir         void impl_notifyModified();
322*cdf0e10cSrcweir         void notify(    ::rtl::OUString const& i_title,
323*cdf0e10cSrcweir                         void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& )
324*cdf0e10cSrcweir                     );
325*cdf0e10cSrcweir         void notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) )
326*cdf0e10cSrcweir         {
327*cdf0e10cSrcweir             notify( ::rtl::OUString(), i_notificationMethod );
328*cdf0e10cSrcweir         }
329*cdf0e10cSrcweir 
330*cdf0e10cSrcweir         void notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ) );
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir     private:
333*cdf0e10cSrcweir         /// adds a function to be called to the request processor's queue
334*cdf0e10cSrcweir         void impl_processRequest( ::boost::function0< void > const& i_request, IMutexGuard& i_instanceLock );
335*cdf0e10cSrcweir 
336*cdf0e10cSrcweir         /// impl-versions of the XUndoManager API.
337*cdf0e10cSrcweir         void impl_enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden );
338*cdf0e10cSrcweir         void impl_leaveUndoContext();
339*cdf0e10cSrcweir         void impl_addUndoAction( const Reference< XUndoAction >& i_action );
340*cdf0e10cSrcweir         void impl_doUndoRedo( IMutexGuard& i_externalLock, const bool i_undo );
341*cdf0e10cSrcweir         void impl_clear();
342*cdf0e10cSrcweir         void impl_clearRedo();
343*cdf0e10cSrcweir         void impl_reset();
344*cdf0e10cSrcweir     };
345*cdf0e10cSrcweir 
346*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
347*cdf0e10cSrcweir     void UndoManagerHelper_Impl::disposing()
348*cdf0e10cSrcweir     {
349*cdf0e10cSrcweir         EventObject aEvent;
350*cdf0e10cSrcweir         aEvent.Source = getXUndoManager();
351*cdf0e10cSrcweir         m_aUndoListeners.disposeAndClear( aEvent );
352*cdf0e10cSrcweir         m_aModifyListeners.disposeAndClear( aEvent );
353*cdf0e10cSrcweir 
354*cdf0e10cSrcweir         ::osl::MutexGuard aGuard( m_aMutex );
355*cdf0e10cSrcweir 
356*cdf0e10cSrcweir         getUndoManager().RemoveUndoListener( *this );
357*cdf0e10cSrcweir 
358*cdf0e10cSrcweir         m_disposed = true;
359*cdf0e10cSrcweir     }
360*cdf0e10cSrcweir 
361*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
362*cdf0e10cSrcweir     UndoManagerEvent UndoManagerHelper_Impl::buildEvent( ::rtl::OUString const& i_title ) const
363*cdf0e10cSrcweir     {
364*cdf0e10cSrcweir         UndoManagerEvent aEvent;
365*cdf0e10cSrcweir         aEvent.Source = getXUndoManager();
366*cdf0e10cSrcweir         aEvent.UndoActionTitle = i_title;
367*cdf0e10cSrcweir         aEvent.UndoContextDepth = getUndoManager().GetListActionDepth();
368*cdf0e10cSrcweir         return aEvent;
369*cdf0e10cSrcweir     }
370*cdf0e10cSrcweir 
371*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
372*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_notifyModified()
373*cdf0e10cSrcweir     {
374*cdf0e10cSrcweir         const EventObject aEvent( getXUndoManager() );
375*cdf0e10cSrcweir         m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
376*cdf0e10cSrcweir     }
377*cdf0e10cSrcweir 
378*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
379*cdf0e10cSrcweir     void UndoManagerHelper_Impl::notify( ::rtl::OUString const& i_title,
380*cdf0e10cSrcweir         void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) )
381*cdf0e10cSrcweir     {
382*cdf0e10cSrcweir         const UndoManagerEvent aEvent( buildEvent( i_title ) );
383*cdf0e10cSrcweir 
384*cdf0e10cSrcweir         // TODO: this notification method here is used by UndoManagerHelper_Impl, to multiplex the notifications we
385*cdf0e10cSrcweir         // receive from the IUndoManager. Those notitications are sent with a locked SolarMutex, which means
386*cdf0e10cSrcweir         // we're doing the multiplexing here with a locked SM, too. Which is Bad (TM).
387*cdf0e10cSrcweir         // Fixing this properly would require outsourcing all the notifications into an own thread - which might lead
388*cdf0e10cSrcweir         // to problems of its own, since clients might expect synchronous notifications.
389*cdf0e10cSrcweir 
390*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( i_notificationMethod, aEvent );
391*cdf0e10cSrcweir         impl_notifyModified();
392*cdf0e10cSrcweir     }
393*cdf0e10cSrcweir 
394*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
395*cdf0e10cSrcweir     void UndoManagerHelper_Impl::notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ) )
396*cdf0e10cSrcweir     {
397*cdf0e10cSrcweir         const EventObject aEvent( getXUndoManager() );
398*cdf0e10cSrcweir 
399*cdf0e10cSrcweir         // TODO: the same comment as in the other notify, regarding SM locking applies here ...
400*cdf0e10cSrcweir 
401*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( i_notificationMethod, aEvent );
402*cdf0e10cSrcweir         impl_notifyModified();
403*cdf0e10cSrcweir     }
404*cdf0e10cSrcweir 
405*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
406*cdf0e10cSrcweir     void UndoManagerHelper_Impl::enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden, IMutexGuard& i_instanceLock )
407*cdf0e10cSrcweir     {
408*cdf0e10cSrcweir         impl_processRequest(
409*cdf0e10cSrcweir             ::boost::bind(
410*cdf0e10cSrcweir                 &UndoManagerHelper_Impl::impl_enterUndoContext,
411*cdf0e10cSrcweir                 this,
412*cdf0e10cSrcweir                 ::boost::cref( i_title ),
413*cdf0e10cSrcweir                 i_hidden
414*cdf0e10cSrcweir             ),
415*cdf0e10cSrcweir             i_instanceLock
416*cdf0e10cSrcweir         );
417*cdf0e10cSrcweir     }
418*cdf0e10cSrcweir 
419*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
420*cdf0e10cSrcweir     void UndoManagerHelper_Impl::leaveUndoContext( IMutexGuard& i_instanceLock )
421*cdf0e10cSrcweir     {
422*cdf0e10cSrcweir         impl_processRequest(
423*cdf0e10cSrcweir             ::boost::bind(
424*cdf0e10cSrcweir                 &UndoManagerHelper_Impl::impl_leaveUndoContext,
425*cdf0e10cSrcweir                 this
426*cdf0e10cSrcweir             ),
427*cdf0e10cSrcweir             i_instanceLock
428*cdf0e10cSrcweir         );
429*cdf0e10cSrcweir     }
430*cdf0e10cSrcweir 
431*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
432*cdf0e10cSrcweir     void UndoManagerHelper_Impl::addUndoAction( const Reference< XUndoAction >& i_action, IMutexGuard& i_instanceLock )
433*cdf0e10cSrcweir     {
434*cdf0e10cSrcweir         if ( !i_action.is() )
435*cdf0e10cSrcweir             throw IllegalArgumentException(
436*cdf0e10cSrcweir                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "illegal undo action object" ) ),
437*cdf0e10cSrcweir                 getXUndoManager(),
438*cdf0e10cSrcweir                 1
439*cdf0e10cSrcweir             );
440*cdf0e10cSrcweir 
441*cdf0e10cSrcweir         impl_processRequest(
442*cdf0e10cSrcweir             ::boost::bind(
443*cdf0e10cSrcweir                 &UndoManagerHelper_Impl::impl_addUndoAction,
444*cdf0e10cSrcweir                 this,
445*cdf0e10cSrcweir                 ::boost::ref( i_action )
446*cdf0e10cSrcweir             ),
447*cdf0e10cSrcweir             i_instanceLock
448*cdf0e10cSrcweir         );
449*cdf0e10cSrcweir     }
450*cdf0e10cSrcweir 
451*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
452*cdf0e10cSrcweir     void UndoManagerHelper_Impl::clear( IMutexGuard& i_instanceLock )
453*cdf0e10cSrcweir     {
454*cdf0e10cSrcweir         impl_processRequest(
455*cdf0e10cSrcweir             ::boost::bind(
456*cdf0e10cSrcweir                 &UndoManagerHelper_Impl::impl_clear,
457*cdf0e10cSrcweir                 this
458*cdf0e10cSrcweir             ),
459*cdf0e10cSrcweir             i_instanceLock
460*cdf0e10cSrcweir         );
461*cdf0e10cSrcweir     }
462*cdf0e10cSrcweir 
463*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
464*cdf0e10cSrcweir     void UndoManagerHelper_Impl::clearRedo( IMutexGuard& i_instanceLock )
465*cdf0e10cSrcweir     {
466*cdf0e10cSrcweir         impl_processRequest(
467*cdf0e10cSrcweir             ::boost::bind(
468*cdf0e10cSrcweir                 &UndoManagerHelper_Impl::impl_clearRedo,
469*cdf0e10cSrcweir                 this
470*cdf0e10cSrcweir             ),
471*cdf0e10cSrcweir             i_instanceLock
472*cdf0e10cSrcweir         );
473*cdf0e10cSrcweir     }
474*cdf0e10cSrcweir 
475*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
476*cdf0e10cSrcweir     void UndoManagerHelper_Impl::reset( IMutexGuard& i_instanceLock )
477*cdf0e10cSrcweir     {
478*cdf0e10cSrcweir         impl_processRequest(
479*cdf0e10cSrcweir             ::boost::bind(
480*cdf0e10cSrcweir                 &UndoManagerHelper_Impl::impl_reset,
481*cdf0e10cSrcweir                 this
482*cdf0e10cSrcweir             ),
483*cdf0e10cSrcweir             i_instanceLock
484*cdf0e10cSrcweir         );
485*cdf0e10cSrcweir     }
486*cdf0e10cSrcweir 
487*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
488*cdf0e10cSrcweir     void UndoManagerHelper_Impl::lock()
489*cdf0e10cSrcweir     {
490*cdf0e10cSrcweir         // SYNCHRONIZED --->
491*cdf0e10cSrcweir         ::osl::MutexGuard aGuard( getMutex() );
492*cdf0e10cSrcweir 
493*cdf0e10cSrcweir         if ( ++m_nLockCount == 1 )
494*cdf0e10cSrcweir         {
495*cdf0e10cSrcweir             IUndoManager& rUndoManager = getUndoManager();
496*cdf0e10cSrcweir             rUndoManager.EnableUndo( false );
497*cdf0e10cSrcweir         }
498*cdf0e10cSrcweir         // <--- SYNCHRONIZED
499*cdf0e10cSrcweir     }
500*cdf0e10cSrcweir 
501*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
502*cdf0e10cSrcweir     void UndoManagerHelper_Impl::unlock()
503*cdf0e10cSrcweir     {
504*cdf0e10cSrcweir         // SYNCHRONIZED --->
505*cdf0e10cSrcweir         ::osl::MutexGuard aGuard( getMutex() );
506*cdf0e10cSrcweir 
507*cdf0e10cSrcweir         if ( m_nLockCount == 0 )
508*cdf0e10cSrcweir             throw NotLockedException( ::rtl::OUString::createFromAscii( "Undo manager is not locked" ), getXUndoManager() );
509*cdf0e10cSrcweir 
510*cdf0e10cSrcweir         if ( --m_nLockCount == 0 )
511*cdf0e10cSrcweir         {
512*cdf0e10cSrcweir             IUndoManager& rUndoManager = getUndoManager();
513*cdf0e10cSrcweir             rUndoManager.EnableUndo( true );
514*cdf0e10cSrcweir         }
515*cdf0e10cSrcweir         // <--- SYNCHRONIZED
516*cdf0e10cSrcweir     }
517*cdf0e10cSrcweir 
518*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
519*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_processRequest( ::boost::function0< void > const& i_request, IMutexGuard& i_instanceLock )
520*cdf0e10cSrcweir     {
521*cdf0e10cSrcweir         // create the request, and add it to our queue
522*cdf0e10cSrcweir         ::rtl::Reference< UndoManagerRequest > pRequest( new UndoManagerRequest( i_request ) );
523*cdf0e10cSrcweir         {
524*cdf0e10cSrcweir             ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
525*cdf0e10cSrcweir             m_aEventQueue.push( pRequest );
526*cdf0e10cSrcweir         }
527*cdf0e10cSrcweir 
528*cdf0e10cSrcweir         i_instanceLock.clear();
529*cdf0e10cSrcweir 
530*cdf0e10cSrcweir         if ( m_bProcessingEvents )
531*cdf0e10cSrcweir         {
532*cdf0e10cSrcweir             // another thread is processing the event queue currently => it will also process the event which we just added
533*cdf0e10cSrcweir             pRequest->wait();
534*cdf0e10cSrcweir             return;
535*cdf0e10cSrcweir         }
536*cdf0e10cSrcweir 
537*cdf0e10cSrcweir         m_bProcessingEvents = true;
538*cdf0e10cSrcweir         do
539*cdf0e10cSrcweir         {
540*cdf0e10cSrcweir             pRequest.clear();
541*cdf0e10cSrcweir             {
542*cdf0e10cSrcweir                 ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
543*cdf0e10cSrcweir                 if ( m_aEventQueue.empty() )
544*cdf0e10cSrcweir                 {
545*cdf0e10cSrcweir                     // reset the flag before releasing the queue mutex, otherwise it's possible that another thread
546*cdf0e10cSrcweir                     // could add an event after we release the mutex, but before we reset the flag. If then this other
547*cdf0e10cSrcweir                     // thread checks the flag before be reset it, this thread's event would starve.
548*cdf0e10cSrcweir                     m_bProcessingEvents = false;
549*cdf0e10cSrcweir                     return;
550*cdf0e10cSrcweir                 }
551*cdf0e10cSrcweir                 pRequest = m_aEventQueue.front();
552*cdf0e10cSrcweir                 m_aEventQueue.pop();
553*cdf0e10cSrcweir             }
554*cdf0e10cSrcweir             try
555*cdf0e10cSrcweir             {
556*cdf0e10cSrcweir                 pRequest->execute();
557*cdf0e10cSrcweir                 pRequest->wait();
558*cdf0e10cSrcweir             }
559*cdf0e10cSrcweir             catch( ... )
560*cdf0e10cSrcweir             {
561*cdf0e10cSrcweir                 {
562*cdf0e10cSrcweir                     // no chance to process further requests, if the current one failed
563*cdf0e10cSrcweir                     // => discard them
564*cdf0e10cSrcweir                     ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
565*cdf0e10cSrcweir                     while ( !m_aEventQueue.empty() )
566*cdf0e10cSrcweir                     {
567*cdf0e10cSrcweir                         pRequest = m_aEventQueue.front();
568*cdf0e10cSrcweir                         m_aEventQueue.pop();
569*cdf0e10cSrcweir                         pRequest->cancel( getXUndoManager() );
570*cdf0e10cSrcweir                     }
571*cdf0e10cSrcweir                     m_bProcessingEvents = false;
572*cdf0e10cSrcweir                 }
573*cdf0e10cSrcweir                 // re-throw the error
574*cdf0e10cSrcweir                 throw;
575*cdf0e10cSrcweir             }
576*cdf0e10cSrcweir         }
577*cdf0e10cSrcweir         while ( true );
578*cdf0e10cSrcweir     }
579*cdf0e10cSrcweir 
580*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
581*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_enterUndoContext( const ::rtl::OUString& i_title, const bool i_hidden )
582*cdf0e10cSrcweir     {
583*cdf0e10cSrcweir         // SYNCHRONIZED --->
584*cdf0e10cSrcweir         ::osl::ClearableMutexGuard aGuard( m_aMutex );
585*cdf0e10cSrcweir 
586*cdf0e10cSrcweir         IUndoManager& rUndoManager = getUndoManager();
587*cdf0e10cSrcweir         if ( !rUndoManager.IsUndoEnabled() )
588*cdf0e10cSrcweir             // ignore this request if the manager is locked
589*cdf0e10cSrcweir             return;
590*cdf0e10cSrcweir 
591*cdf0e10cSrcweir         if ( i_hidden && ( rUndoManager.GetUndoActionCount( IUndoManager::CurrentLevel ) == 0 ) )
592*cdf0e10cSrcweir             throw EmptyUndoStackException(
593*cdf0e10cSrcweir                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "can't enter a hidden context without a previous Undo action" ) ),
594*cdf0e10cSrcweir                 m_rUndoManagerImplementation.getThis()
595*cdf0e10cSrcweir             );
596*cdf0e10cSrcweir 
597*cdf0e10cSrcweir         {
598*cdf0e10cSrcweir             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
599*cdf0e10cSrcweir             rUndoManager.EnterListAction( i_title, ::rtl::OUString() );
600*cdf0e10cSrcweir         }
601*cdf0e10cSrcweir 
602*cdf0e10cSrcweir         m_aContextVisibilities.push( i_hidden );
603*cdf0e10cSrcweir 
604*cdf0e10cSrcweir         const UndoManagerEvent aEvent( buildEvent( i_title ) );
605*cdf0e10cSrcweir         aGuard.clear();
606*cdf0e10cSrcweir         // <--- SYNCHRONIZED
607*cdf0e10cSrcweir 
608*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( i_hidden ? &XUndoManagerListener::enteredHiddenContext : &XUndoManagerListener::enteredContext, aEvent );
609*cdf0e10cSrcweir         impl_notifyModified();
610*cdf0e10cSrcweir     }
611*cdf0e10cSrcweir 
612*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
613*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_leaveUndoContext()
614*cdf0e10cSrcweir     {
615*cdf0e10cSrcweir         // SYNCHRONIZED --->
616*cdf0e10cSrcweir         ::osl::ClearableMutexGuard aGuard( m_aMutex );
617*cdf0e10cSrcweir 
618*cdf0e10cSrcweir         IUndoManager& rUndoManager = getUndoManager();
619*cdf0e10cSrcweir         if ( !rUndoManager.IsUndoEnabled() )
620*cdf0e10cSrcweir             // ignore this request if the manager is locked
621*cdf0e10cSrcweir             return;
622*cdf0e10cSrcweir 
623*cdf0e10cSrcweir         if ( !rUndoManager.IsInListAction() )
624*cdf0e10cSrcweir             throw InvalidStateException(
625*cdf0e10cSrcweir                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no active undo context" ) ),
626*cdf0e10cSrcweir                 getXUndoManager()
627*cdf0e10cSrcweir             );
628*cdf0e10cSrcweir 
629*cdf0e10cSrcweir         size_t nContextElements = 0;
630*cdf0e10cSrcweir 
631*cdf0e10cSrcweir         const bool isHiddenContext = m_aContextVisibilities.top();;
632*cdf0e10cSrcweir         m_aContextVisibilities.pop();
633*cdf0e10cSrcweir 
634*cdf0e10cSrcweir         const bool bHadRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0 );
635*cdf0e10cSrcweir         {
636*cdf0e10cSrcweir             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
637*cdf0e10cSrcweir             if ( isHiddenContext )
638*cdf0e10cSrcweir                 nContextElements = rUndoManager.LeaveAndMergeListAction();
639*cdf0e10cSrcweir             else
640*cdf0e10cSrcweir                 nContextElements = rUndoManager.LeaveListAction();
641*cdf0e10cSrcweir         }
642*cdf0e10cSrcweir         const bool bHasRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0 );
643*cdf0e10cSrcweir 
644*cdf0e10cSrcweir         // prepare notification
645*cdf0e10cSrcweir         void ( SAL_CALL XUndoManagerListener::*notificationMethod )( const UndoManagerEvent& ) = NULL;
646*cdf0e10cSrcweir 
647*cdf0e10cSrcweir         UndoManagerEvent aContextEvent( buildEvent( ::rtl::OUString() ) );
648*cdf0e10cSrcweir         const EventObject aClearedEvent( getXUndoManager() );
649*cdf0e10cSrcweir         if ( nContextElements == 0 )
650*cdf0e10cSrcweir         {
651*cdf0e10cSrcweir             notificationMethod = &XUndoManagerListener::cancelledContext;
652*cdf0e10cSrcweir         }
653*cdf0e10cSrcweir         else if ( isHiddenContext )
654*cdf0e10cSrcweir         {
655*cdf0e10cSrcweir             notificationMethod = &XUndoManagerListener::leftHiddenContext;
656*cdf0e10cSrcweir         }
657*cdf0e10cSrcweir         else
658*cdf0e10cSrcweir         {
659*cdf0e10cSrcweir             aContextEvent.UndoActionTitle = rUndoManager.GetUndoActionComment( 0, IUndoManager::CurrentLevel );
660*cdf0e10cSrcweir             notificationMethod = &XUndoManagerListener::leftContext;
661*cdf0e10cSrcweir         }
662*cdf0e10cSrcweir 
663*cdf0e10cSrcweir         aGuard.clear();
664*cdf0e10cSrcweir         // <--- SYNCHRONIZED
665*cdf0e10cSrcweir 
666*cdf0e10cSrcweir         if ( bHadRedoActions && !bHasRedoActions )
667*cdf0e10cSrcweir             m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aClearedEvent );
668*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( notificationMethod, aContextEvent );
669*cdf0e10cSrcweir         impl_notifyModified();
670*cdf0e10cSrcweir     }
671*cdf0e10cSrcweir 
672*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
673*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_doUndoRedo( IMutexGuard& i_externalLock, const bool i_undo )
674*cdf0e10cSrcweir     {
675*cdf0e10cSrcweir         ::osl::Guard< ::framework::IMutex > aExternalGuard( i_externalLock.getGuardedMutex() );
676*cdf0e10cSrcweir             // note that this assumes that the mutex has been released in the thread which added the
677*cdf0e10cSrcweir             // Undo/Redo request, so we can successfully acquire it
678*cdf0e10cSrcweir 
679*cdf0e10cSrcweir         // SYNCHRONIZED --->
680*cdf0e10cSrcweir         ::osl::ClearableMutexGuard aGuard( m_aMutex );
681*cdf0e10cSrcweir 
682*cdf0e10cSrcweir         IUndoManager& rUndoManager = getUndoManager();
683*cdf0e10cSrcweir         if ( rUndoManager.IsInListAction() )
684*cdf0e10cSrcweir             throw UndoContextNotClosedException( ::rtl::OUString(), getXUndoManager() );
685*cdf0e10cSrcweir 
686*cdf0e10cSrcweir         const size_t nElements  =   i_undo
687*cdf0e10cSrcweir                                 ?   rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
688*cdf0e10cSrcweir                                 :   rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
689*cdf0e10cSrcweir         if ( nElements == 0 )
690*cdf0e10cSrcweir             throw EmptyUndoStackException( ::rtl::OUString::createFromAscii( "stack is empty" ), getXUndoManager() );
691*cdf0e10cSrcweir 
692*cdf0e10cSrcweir         aGuard.clear();
693*cdf0e10cSrcweir         // <--- SYNCHRONIZED
694*cdf0e10cSrcweir 
695*cdf0e10cSrcweir         try
696*cdf0e10cSrcweir         {
697*cdf0e10cSrcweir             if ( i_undo )
698*cdf0e10cSrcweir                 rUndoManager.Undo();
699*cdf0e10cSrcweir             else
700*cdf0e10cSrcweir                 rUndoManager.Redo();
701*cdf0e10cSrcweir         }
702*cdf0e10cSrcweir         catch( const RuntimeException& ) { /* allowed to leave here */ throw; }
703*cdf0e10cSrcweir         catch( const UndoFailedException& ) { /* allowed to leave here */ throw; }
704*cdf0e10cSrcweir         catch( const Exception& )
705*cdf0e10cSrcweir         {
706*cdf0e10cSrcweir             // not allowed to leave
707*cdf0e10cSrcweir             const Any aError( ::cppu::getCaughtException() );
708*cdf0e10cSrcweir             throw UndoFailedException( ::rtl::OUString(), getXUndoManager(), aError );
709*cdf0e10cSrcweir         }
710*cdf0e10cSrcweir 
711*cdf0e10cSrcweir         // note that in opposite to all of the other methods, we do *not* have our mutex locked when calling
712*cdf0e10cSrcweir         // into the IUndoManager implementation. This ensures that an actual XUndoAction::undo/redo is also
713*cdf0e10cSrcweir         // called without our mutex being locked.
714*cdf0e10cSrcweir         // As a consequence, we do not set m_bAPIActionRunning here. Instead, our actionUndone/actionRedone methods
715*cdf0e10cSrcweir         // *always* multiplex the event to our XUndoManagerListeners, not only when m_bAPIActionRunning is FALSE (This
716*cdf0e10cSrcweir         // again is different from all other SfxUndoListener methods).
717*cdf0e10cSrcweir         // So, we do not need to do this notification here ourself.
718*cdf0e10cSrcweir     }
719*cdf0e10cSrcweir 
720*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
721*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_addUndoAction( const Reference< XUndoAction >& i_action )
722*cdf0e10cSrcweir     {
723*cdf0e10cSrcweir         // SYNCHRONIZED --->
724*cdf0e10cSrcweir         ::osl::ClearableMutexGuard aGuard( m_aMutex );
725*cdf0e10cSrcweir 
726*cdf0e10cSrcweir         IUndoManager& rUndoManager = getUndoManager();
727*cdf0e10cSrcweir         if ( !rUndoManager.IsUndoEnabled() )
728*cdf0e10cSrcweir             // ignore the request if the manager is locked
729*cdf0e10cSrcweir             return;
730*cdf0e10cSrcweir 
731*cdf0e10cSrcweir         const UndoManagerEvent aEventAdd( buildEvent( i_action->getTitle() ) );
732*cdf0e10cSrcweir         const EventObject aEventClear( getXUndoManager() );
733*cdf0e10cSrcweir 
734*cdf0e10cSrcweir         const bool bHadRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 );
735*cdf0e10cSrcweir         {
736*cdf0e10cSrcweir             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
737*cdf0e10cSrcweir             rUndoManager.AddUndoAction( new UndoActionWrapper( i_action ) );
738*cdf0e10cSrcweir         }
739*cdf0e10cSrcweir         const bool bHasRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 );
740*cdf0e10cSrcweir 
741*cdf0e10cSrcweir         aGuard.clear();
742*cdf0e10cSrcweir         // <--- SYNCHRONIZED
743*cdf0e10cSrcweir 
744*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( &XUndoManagerListener::undoActionAdded, aEventAdd );
745*cdf0e10cSrcweir         if ( bHadRedoActions && !bHasRedoActions )
746*cdf0e10cSrcweir             m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aEventClear );
747*cdf0e10cSrcweir         impl_notifyModified();
748*cdf0e10cSrcweir     }
749*cdf0e10cSrcweir 
750*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
751*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_clear()
752*cdf0e10cSrcweir     {
753*cdf0e10cSrcweir         // SYNCHRONIZED --->
754*cdf0e10cSrcweir         ::osl::ClearableMutexGuard aGuard( m_aMutex );
755*cdf0e10cSrcweir 
756*cdf0e10cSrcweir         IUndoManager& rUndoManager = getUndoManager();
757*cdf0e10cSrcweir         if ( rUndoManager.IsInListAction() )
758*cdf0e10cSrcweir             throw UndoContextNotClosedException( ::rtl::OUString(), getXUndoManager() );
759*cdf0e10cSrcweir 
760*cdf0e10cSrcweir         {
761*cdf0e10cSrcweir             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
762*cdf0e10cSrcweir             rUndoManager.Clear();
763*cdf0e10cSrcweir         }
764*cdf0e10cSrcweir 
765*cdf0e10cSrcweir         const EventObject aEvent( getXUndoManager() );
766*cdf0e10cSrcweir         aGuard.clear();
767*cdf0e10cSrcweir         // <--- SYNCHRONIZED
768*cdf0e10cSrcweir 
769*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( &XUndoManagerListener::allActionsCleared, aEvent );
770*cdf0e10cSrcweir         impl_notifyModified();
771*cdf0e10cSrcweir     }
772*cdf0e10cSrcweir 
773*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
774*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_clearRedo()
775*cdf0e10cSrcweir     {
776*cdf0e10cSrcweir         // SYNCHRONIZED --->
777*cdf0e10cSrcweir         ::osl::ClearableMutexGuard aGuard( m_aMutex );
778*cdf0e10cSrcweir 
779*cdf0e10cSrcweir         IUndoManager& rUndoManager = getUndoManager();
780*cdf0e10cSrcweir         if ( rUndoManager.IsInListAction() )
781*cdf0e10cSrcweir             throw UndoContextNotClosedException( ::rtl::OUString(), getXUndoManager() );
782*cdf0e10cSrcweir 
783*cdf0e10cSrcweir         {
784*cdf0e10cSrcweir             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
785*cdf0e10cSrcweir             rUndoManager.ClearRedo();
786*cdf0e10cSrcweir         }
787*cdf0e10cSrcweir 
788*cdf0e10cSrcweir         const EventObject aEvent( getXUndoManager() );
789*cdf0e10cSrcweir         aGuard.clear();
790*cdf0e10cSrcweir         // <--- SYNCHRONIZED
791*cdf0e10cSrcweir 
792*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aEvent );
793*cdf0e10cSrcweir         impl_notifyModified();
794*cdf0e10cSrcweir     }
795*cdf0e10cSrcweir 
796*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
797*cdf0e10cSrcweir     void UndoManagerHelper_Impl::impl_reset()
798*cdf0e10cSrcweir     {
799*cdf0e10cSrcweir         // SYNCHRONIZED --->
800*cdf0e10cSrcweir         ::osl::ClearableMutexGuard aGuard( m_aMutex );
801*cdf0e10cSrcweir 
802*cdf0e10cSrcweir         IUndoManager& rUndoManager = getUndoManager();
803*cdf0e10cSrcweir         {
804*cdf0e10cSrcweir             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
805*cdf0e10cSrcweir             rUndoManager.Reset();
806*cdf0e10cSrcweir         }
807*cdf0e10cSrcweir 
808*cdf0e10cSrcweir         const EventObject aEvent( getXUndoManager() );
809*cdf0e10cSrcweir         aGuard.clear();
810*cdf0e10cSrcweir         // <--- SYNCHRONIZED
811*cdf0e10cSrcweir 
812*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( &XUndoManagerListener::resetAll, aEvent );
813*cdf0e10cSrcweir         impl_notifyModified();
814*cdf0e10cSrcweir     }
815*cdf0e10cSrcweir 
816*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
817*cdf0e10cSrcweir     void UndoManagerHelper_Impl::actionUndone( const String& i_actionComment )
818*cdf0e10cSrcweir     {
819*cdf0e10cSrcweir         UndoManagerEvent aEvent;
820*cdf0e10cSrcweir         aEvent.Source = getXUndoManager();
821*cdf0e10cSrcweir         aEvent.UndoActionTitle = i_actionComment;
822*cdf0e10cSrcweir         aEvent.UndoContextDepth = 0;    // Undo can happen on level 0 only
823*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( &XUndoManagerListener::actionUndone, aEvent );
824*cdf0e10cSrcweir         impl_notifyModified();
825*cdf0e10cSrcweir     }
826*cdf0e10cSrcweir 
827*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
828*cdf0e10cSrcweir     void UndoManagerHelper_Impl::actionRedone( const String& i_actionComment )
829*cdf0e10cSrcweir     {
830*cdf0e10cSrcweir         UndoManagerEvent aEvent;
831*cdf0e10cSrcweir         aEvent.Source = getXUndoManager();
832*cdf0e10cSrcweir         aEvent.UndoActionTitle = i_actionComment;
833*cdf0e10cSrcweir         aEvent.UndoContextDepth = 0;    // Redo can happen on level 0 only
834*cdf0e10cSrcweir         m_aUndoListeners.notifyEach( &XUndoManagerListener::actionRedone, aEvent );
835*cdf0e10cSrcweir         impl_notifyModified();
836*cdf0e10cSrcweir     }
837*cdf0e10cSrcweir 
838*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
839*cdf0e10cSrcweir     void UndoManagerHelper_Impl::undoActionAdded( const String& i_actionComment )
840*cdf0e10cSrcweir     {
841*cdf0e10cSrcweir         if ( m_bAPIActionRunning )
842*cdf0e10cSrcweir             return;
843*cdf0e10cSrcweir 
844*cdf0e10cSrcweir         notify( i_actionComment, &XUndoManagerListener::undoActionAdded );
845*cdf0e10cSrcweir     }
846*cdf0e10cSrcweir 
847*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
848*cdf0e10cSrcweir     void UndoManagerHelper_Impl::cleared()
849*cdf0e10cSrcweir     {
850*cdf0e10cSrcweir         if ( m_bAPIActionRunning )
851*cdf0e10cSrcweir             return;
852*cdf0e10cSrcweir 
853*cdf0e10cSrcweir         notify( &XUndoManagerListener::allActionsCleared );
854*cdf0e10cSrcweir     }
855*cdf0e10cSrcweir 
856*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
857*cdf0e10cSrcweir     void UndoManagerHelper_Impl::clearedRedo()
858*cdf0e10cSrcweir     {
859*cdf0e10cSrcweir         if ( m_bAPIActionRunning )
860*cdf0e10cSrcweir             return;
861*cdf0e10cSrcweir 
862*cdf0e10cSrcweir         notify( &XUndoManagerListener::redoActionsCleared );
863*cdf0e10cSrcweir     }
864*cdf0e10cSrcweir 
865*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
866*cdf0e10cSrcweir     void UndoManagerHelper_Impl::resetAll()
867*cdf0e10cSrcweir     {
868*cdf0e10cSrcweir         if ( m_bAPIActionRunning )
869*cdf0e10cSrcweir             return;
870*cdf0e10cSrcweir 
871*cdf0e10cSrcweir         notify( &XUndoManagerListener::resetAll );
872*cdf0e10cSrcweir     }
873*cdf0e10cSrcweir 
874*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
875*cdf0e10cSrcweir     void UndoManagerHelper_Impl::listActionEntered( const String& i_comment )
876*cdf0e10cSrcweir     {
877*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0
878*cdf0e10cSrcweir         m_aContextAPIFlags.push( m_bAPIActionRunning );
879*cdf0e10cSrcweir #endif
880*cdf0e10cSrcweir 
881*cdf0e10cSrcweir         if ( m_bAPIActionRunning )
882*cdf0e10cSrcweir             return;
883*cdf0e10cSrcweir 
884*cdf0e10cSrcweir         notify( i_comment, &XUndoManagerListener::enteredContext );
885*cdf0e10cSrcweir     }
886*cdf0e10cSrcweir 
887*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
888*cdf0e10cSrcweir     void UndoManagerHelper_Impl::listActionLeft( const String& i_comment )
889*cdf0e10cSrcweir     {
890*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0
891*cdf0e10cSrcweir         const bool bCurrentContextIsAPIContext = m_aContextAPIFlags.top();
892*cdf0e10cSrcweir         m_aContextAPIFlags.pop();
893*cdf0e10cSrcweir         OSL_ENSURE( bCurrentContextIsAPIContext == m_bAPIActionRunning, "UndoManagerHelper_Impl::listActionLeft: API and non-API contexts interwoven!" );
894*cdf0e10cSrcweir #endif
895*cdf0e10cSrcweir 
896*cdf0e10cSrcweir         if ( m_bAPIActionRunning )
897*cdf0e10cSrcweir             return;
898*cdf0e10cSrcweir 
899*cdf0e10cSrcweir         notify( i_comment, &XUndoManagerListener::leftContext );
900*cdf0e10cSrcweir     }
901*cdf0e10cSrcweir 
902*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
903*cdf0e10cSrcweir     void UndoManagerHelper_Impl::listActionLeftAndMerged()
904*cdf0e10cSrcweir     {
905*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0
906*cdf0e10cSrcweir         const bool bCurrentContextIsAPIContext = m_aContextAPIFlags.top();
907*cdf0e10cSrcweir         m_aContextAPIFlags.pop();
908*cdf0e10cSrcweir         OSL_ENSURE( bCurrentContextIsAPIContext == m_bAPIActionRunning, "UndoManagerHelper_Impl::listActionLeftAndMerged: API and non-API contexts interwoven!" );
909*cdf0e10cSrcweir #endif
910*cdf0e10cSrcweir 
911*cdf0e10cSrcweir         if ( m_bAPIActionRunning )
912*cdf0e10cSrcweir             return;
913*cdf0e10cSrcweir 
914*cdf0e10cSrcweir         notify( &XUndoManagerListener::leftHiddenContext );
915*cdf0e10cSrcweir     }
916*cdf0e10cSrcweir 
917*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
918*cdf0e10cSrcweir     void UndoManagerHelper_Impl::listActionCancelled()
919*cdf0e10cSrcweir     {
920*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 0
921*cdf0e10cSrcweir         const bool bCurrentContextIsAPIContext = m_aContextAPIFlags.top();
922*cdf0e10cSrcweir         m_aContextAPIFlags.pop();
923*cdf0e10cSrcweir         OSL_ENSURE( bCurrentContextIsAPIContext == m_bAPIActionRunning, "UndoManagerHelper_Impl::listActionCancelled: API and non-API contexts interwoven!" );
924*cdf0e10cSrcweir #endif
925*cdf0e10cSrcweir 
926*cdf0e10cSrcweir         if ( m_bAPIActionRunning )
927*cdf0e10cSrcweir             return;
928*cdf0e10cSrcweir 
929*cdf0e10cSrcweir         notify( &XUndoManagerListener::cancelledContext );
930*cdf0e10cSrcweir     }
931*cdf0e10cSrcweir 
932*cdf0e10cSrcweir  	//------------------------------------------------------------------------------------------------------------------
933*cdf0e10cSrcweir     void UndoManagerHelper_Impl::undoManagerDying()
934*cdf0e10cSrcweir     {
935*cdf0e10cSrcweir         // TODO: do we need to care? Or is this the responsibility of our owner?
936*cdf0e10cSrcweir     }
937*cdf0e10cSrcweir 
938*cdf0e10cSrcweir 	//==================================================================================================================
939*cdf0e10cSrcweir 	//= UndoManagerHelper
940*cdf0e10cSrcweir 	//==================================================================================================================
941*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
942*cdf0e10cSrcweir     UndoManagerHelper::UndoManagerHelper( IUndoManagerImplementation& i_undoManagerImpl )
943*cdf0e10cSrcweir         :m_pImpl( new UndoManagerHelper_Impl( *this, i_undoManagerImpl ) )
944*cdf0e10cSrcweir     {
945*cdf0e10cSrcweir     }
946*cdf0e10cSrcweir 
947*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
948*cdf0e10cSrcweir     UndoManagerHelper::~UndoManagerHelper()
949*cdf0e10cSrcweir     {
950*cdf0e10cSrcweir     }
951*cdf0e10cSrcweir 
952*cdf0e10cSrcweir 	//------------------------------------------------------------------------------------------------------------------
953*cdf0e10cSrcweir     void UndoManagerHelper::disposing()
954*cdf0e10cSrcweir     {
955*cdf0e10cSrcweir         m_pImpl->disposing();
956*cdf0e10cSrcweir     }
957*cdf0e10cSrcweir 
958*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
959*cdf0e10cSrcweir     void UndoManagerHelper::enterUndoContext( const ::rtl::OUString& i_title, IMutexGuard& i_instanceLock )
960*cdf0e10cSrcweir     {
961*cdf0e10cSrcweir         m_pImpl->enterUndoContext( i_title, false, i_instanceLock );
962*cdf0e10cSrcweir     }
963*cdf0e10cSrcweir 
964*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
965*cdf0e10cSrcweir     void UndoManagerHelper::enterHiddenUndoContext( IMutexGuard& i_instanceLock )
966*cdf0e10cSrcweir     {
967*cdf0e10cSrcweir         m_pImpl->enterUndoContext( ::rtl::OUString(), true, i_instanceLock );
968*cdf0e10cSrcweir     }
969*cdf0e10cSrcweir 
970*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
971*cdf0e10cSrcweir     void UndoManagerHelper::leaveUndoContext( IMutexGuard& i_instanceLock )
972*cdf0e10cSrcweir     {
973*cdf0e10cSrcweir         m_pImpl->leaveUndoContext( i_instanceLock );
974*cdf0e10cSrcweir     }
975*cdf0e10cSrcweir 
976*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
977*cdf0e10cSrcweir     void UndoManagerHelper_Impl::undo( IMutexGuard& i_instanceLock )
978*cdf0e10cSrcweir     {
979*cdf0e10cSrcweir         impl_processRequest(
980*cdf0e10cSrcweir             ::boost::bind(
981*cdf0e10cSrcweir                 &UndoManagerHelper_Impl::impl_doUndoRedo,
982*cdf0e10cSrcweir                 this,
983*cdf0e10cSrcweir                 ::boost::ref( i_instanceLock ),
984*cdf0e10cSrcweir                 true
985*cdf0e10cSrcweir             ),
986*cdf0e10cSrcweir             i_instanceLock
987*cdf0e10cSrcweir         );
988*cdf0e10cSrcweir     }
989*cdf0e10cSrcweir 
990*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
991*cdf0e10cSrcweir     void UndoManagerHelper_Impl::redo( IMutexGuard& i_instanceLock )
992*cdf0e10cSrcweir     {
993*cdf0e10cSrcweir         impl_processRequest(
994*cdf0e10cSrcweir             ::boost::bind(
995*cdf0e10cSrcweir                 &UndoManagerHelper_Impl::impl_doUndoRedo,
996*cdf0e10cSrcweir                 this,
997*cdf0e10cSrcweir                 ::boost::ref( i_instanceLock ),
998*cdf0e10cSrcweir                 false
999*cdf0e10cSrcweir             ),
1000*cdf0e10cSrcweir             i_instanceLock
1001*cdf0e10cSrcweir         );
1002*cdf0e10cSrcweir     }
1003*cdf0e10cSrcweir 
1004*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1005*cdf0e10cSrcweir     void UndoManagerHelper::addUndoAction( const Reference< XUndoAction >& i_action, IMutexGuard& i_instanceLock )
1006*cdf0e10cSrcweir     {
1007*cdf0e10cSrcweir         m_pImpl->addUndoAction( i_action, i_instanceLock );
1008*cdf0e10cSrcweir     }
1009*cdf0e10cSrcweir 
1010*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1011*cdf0e10cSrcweir     void UndoManagerHelper::undo( IMutexGuard& i_instanceLock )
1012*cdf0e10cSrcweir     {
1013*cdf0e10cSrcweir         m_pImpl->undo( i_instanceLock );
1014*cdf0e10cSrcweir     }
1015*cdf0e10cSrcweir 
1016*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1017*cdf0e10cSrcweir     void UndoManagerHelper::redo( IMutexGuard& i_instanceLock )
1018*cdf0e10cSrcweir     {
1019*cdf0e10cSrcweir         m_pImpl->redo( i_instanceLock );
1020*cdf0e10cSrcweir     }
1021*cdf0e10cSrcweir 
1022*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1023*cdf0e10cSrcweir     ::sal_Bool UndoManagerHelper::isUndoPossible() const
1024*cdf0e10cSrcweir     {
1025*cdf0e10cSrcweir         // SYNCHRONIZED --->
1026*cdf0e10cSrcweir         ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
1027*cdf0e10cSrcweir         IUndoManager& rUndoManager = m_pImpl->getUndoManager();
1028*cdf0e10cSrcweir         if ( rUndoManager.IsInListAction() )
1029*cdf0e10cSrcweir             return sal_False;
1030*cdf0e10cSrcweir         return rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) > 0;
1031*cdf0e10cSrcweir         // <--- SYNCHRONIZED
1032*cdf0e10cSrcweir     }
1033*cdf0e10cSrcweir 
1034*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1035*cdf0e10cSrcweir     ::sal_Bool UndoManagerHelper::isRedoPossible() const
1036*cdf0e10cSrcweir     {
1037*cdf0e10cSrcweir         // SYNCHRONIZED --->
1038*cdf0e10cSrcweir         ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
1039*cdf0e10cSrcweir         const IUndoManager& rUndoManager = m_pImpl->getUndoManager();
1040*cdf0e10cSrcweir         if ( rUndoManager.IsInListAction() )
1041*cdf0e10cSrcweir             return sal_False;
1042*cdf0e10cSrcweir         return rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0;
1043*cdf0e10cSrcweir         // <--- SYNCHRONIZED
1044*cdf0e10cSrcweir     }
1045*cdf0e10cSrcweir 
1046*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1047*cdf0e10cSrcweir     namespace
1048*cdf0e10cSrcweir     {
1049*cdf0e10cSrcweir         //..............................................................................................................
1050*cdf0e10cSrcweir         ::rtl::OUString lcl_getCurrentActionTitle( UndoManagerHelper_Impl& i_impl, const bool i_undo )
1051*cdf0e10cSrcweir         {
1052*cdf0e10cSrcweir             // SYNCHRONIZED --->
1053*cdf0e10cSrcweir             ::osl::MutexGuard aGuard( i_impl.getMutex() );
1054*cdf0e10cSrcweir 
1055*cdf0e10cSrcweir             const IUndoManager& rUndoManager = i_impl.getUndoManager();
1056*cdf0e10cSrcweir             const size_t nActionCount = i_undo
1057*cdf0e10cSrcweir                                     ?   rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
1058*cdf0e10cSrcweir                                     :   rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
1059*cdf0e10cSrcweir             if ( nActionCount == 0 )
1060*cdf0e10cSrcweir                 throw EmptyUndoStackException(
1061*cdf0e10cSrcweir                     i_undo ? ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no action on the undo stack" ) )
1062*cdf0e10cSrcweir                            : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no action on the redo stack" ) ),
1063*cdf0e10cSrcweir                     i_impl.getXUndoManager()
1064*cdf0e10cSrcweir                 );
1065*cdf0e10cSrcweir             return  i_undo
1066*cdf0e10cSrcweir                 ?   rUndoManager.GetUndoActionComment( 0, IUndoManager::TopLevel )
1067*cdf0e10cSrcweir                 :   rUndoManager.GetRedoActionComment( 0, IUndoManager::TopLevel );
1068*cdf0e10cSrcweir             // <--- SYNCHRONIZED
1069*cdf0e10cSrcweir         }
1070*cdf0e10cSrcweir 
1071*cdf0e10cSrcweir         //..............................................................................................................
1072*cdf0e10cSrcweir         Sequence< ::rtl::OUString > lcl_getAllActionTitles( UndoManagerHelper_Impl& i_impl, const bool i_undo )
1073*cdf0e10cSrcweir         {
1074*cdf0e10cSrcweir             // SYNCHRONIZED --->
1075*cdf0e10cSrcweir             ::osl::MutexGuard aGuard( i_impl.getMutex() );
1076*cdf0e10cSrcweir 
1077*cdf0e10cSrcweir             const IUndoManager& rUndoManager = i_impl.getUndoManager();
1078*cdf0e10cSrcweir             const size_t nCount =   i_undo
1079*cdf0e10cSrcweir                                 ?   rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
1080*cdf0e10cSrcweir                                 :   rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
1081*cdf0e10cSrcweir 
1082*cdf0e10cSrcweir             Sequence< ::rtl::OUString > aTitles( nCount );
1083*cdf0e10cSrcweir             for ( size_t i=0; i<nCount; ++i )
1084*cdf0e10cSrcweir             {
1085*cdf0e10cSrcweir                 aTitles[i] =    i_undo
1086*cdf0e10cSrcweir                             ?   rUndoManager.GetUndoActionComment( i, IUndoManager::TopLevel )
1087*cdf0e10cSrcweir                             :   rUndoManager.GetRedoActionComment( i, IUndoManager::TopLevel );
1088*cdf0e10cSrcweir             }
1089*cdf0e10cSrcweir             return aTitles;
1090*cdf0e10cSrcweir             // <--- SYNCHRONIZED
1091*cdf0e10cSrcweir         }
1092*cdf0e10cSrcweir     }
1093*cdf0e10cSrcweir 
1094*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1095*cdf0e10cSrcweir     ::rtl::OUString UndoManagerHelper::getCurrentUndoActionTitle() const
1096*cdf0e10cSrcweir     {
1097*cdf0e10cSrcweir         return lcl_getCurrentActionTitle( *m_pImpl, true );
1098*cdf0e10cSrcweir     }
1099*cdf0e10cSrcweir 
1100*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1101*cdf0e10cSrcweir     ::rtl::OUString UndoManagerHelper::getCurrentRedoActionTitle() const
1102*cdf0e10cSrcweir     {
1103*cdf0e10cSrcweir         return lcl_getCurrentActionTitle( *m_pImpl, false );
1104*cdf0e10cSrcweir     }
1105*cdf0e10cSrcweir 
1106*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1107*cdf0e10cSrcweir     Sequence< ::rtl::OUString > UndoManagerHelper::getAllUndoActionTitles() const
1108*cdf0e10cSrcweir     {
1109*cdf0e10cSrcweir         return lcl_getAllActionTitles( *m_pImpl, true );
1110*cdf0e10cSrcweir     }
1111*cdf0e10cSrcweir 
1112*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1113*cdf0e10cSrcweir     Sequence< ::rtl::OUString > UndoManagerHelper::getAllRedoActionTitles() const
1114*cdf0e10cSrcweir     {
1115*cdf0e10cSrcweir         return lcl_getAllActionTitles( *m_pImpl, false );
1116*cdf0e10cSrcweir     }
1117*cdf0e10cSrcweir 
1118*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1119*cdf0e10cSrcweir     void UndoManagerHelper::clear( IMutexGuard& i_instanceLock )
1120*cdf0e10cSrcweir     {
1121*cdf0e10cSrcweir         m_pImpl->clear( i_instanceLock );
1122*cdf0e10cSrcweir     }
1123*cdf0e10cSrcweir 
1124*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1125*cdf0e10cSrcweir     void UndoManagerHelper::clearRedo( IMutexGuard& i_instanceLock )
1126*cdf0e10cSrcweir     {
1127*cdf0e10cSrcweir         m_pImpl->clearRedo( i_instanceLock );
1128*cdf0e10cSrcweir     }
1129*cdf0e10cSrcweir 
1130*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1131*cdf0e10cSrcweir     void UndoManagerHelper::reset( IMutexGuard& i_instanceLock )
1132*cdf0e10cSrcweir     {
1133*cdf0e10cSrcweir         m_pImpl->reset( i_instanceLock );
1134*cdf0e10cSrcweir     }
1135*cdf0e10cSrcweir 
1136*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1137*cdf0e10cSrcweir     void UndoManagerHelper::lock()
1138*cdf0e10cSrcweir     {
1139*cdf0e10cSrcweir         m_pImpl->lock();
1140*cdf0e10cSrcweir     }
1141*cdf0e10cSrcweir 
1142*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1143*cdf0e10cSrcweir     void UndoManagerHelper::unlock()
1144*cdf0e10cSrcweir     {
1145*cdf0e10cSrcweir         m_pImpl->unlock();
1146*cdf0e10cSrcweir     }
1147*cdf0e10cSrcweir 
1148*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1149*cdf0e10cSrcweir     ::sal_Bool UndoManagerHelper::isLocked()
1150*cdf0e10cSrcweir     {
1151*cdf0e10cSrcweir         // SYNCHRONIZED --->
1152*cdf0e10cSrcweir         ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
1153*cdf0e10cSrcweir 
1154*cdf0e10cSrcweir         IUndoManager& rUndoManager = m_pImpl->getUndoManager();
1155*cdf0e10cSrcweir         return !rUndoManager.IsUndoEnabled();
1156*cdf0e10cSrcweir         // <--- SYNCHRONIZED
1157*cdf0e10cSrcweir     }
1158*cdf0e10cSrcweir 
1159*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1160*cdf0e10cSrcweir     void UndoManagerHelper::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
1161*cdf0e10cSrcweir     {
1162*cdf0e10cSrcweir         if ( i_listener.is() )
1163*cdf0e10cSrcweir             m_pImpl->addUndoManagerListener( i_listener );
1164*cdf0e10cSrcweir     }
1165*cdf0e10cSrcweir 
1166*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1167*cdf0e10cSrcweir     void UndoManagerHelper::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
1168*cdf0e10cSrcweir     {
1169*cdf0e10cSrcweir         if ( i_listener.is() )
1170*cdf0e10cSrcweir             m_pImpl->removeUndoManagerListener( i_listener );
1171*cdf0e10cSrcweir     }
1172*cdf0e10cSrcweir 
1173*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1174*cdf0e10cSrcweir     void UndoManagerHelper::addModifyListener( const Reference< XModifyListener >& i_listener )
1175*cdf0e10cSrcweir     {
1176*cdf0e10cSrcweir         if ( i_listener.is() )
1177*cdf0e10cSrcweir             m_pImpl->addModifyListener( i_listener );
1178*cdf0e10cSrcweir     }
1179*cdf0e10cSrcweir 
1180*cdf0e10cSrcweir     //------------------------------------------------------------------------------------------------------------------
1181*cdf0e10cSrcweir     void UndoManagerHelper::removeModifyListener( const Reference< XModifyListener >& i_listener )
1182*cdf0e10cSrcweir     {
1183*cdf0e10cSrcweir         if ( i_listener.is() )
1184*cdf0e10cSrcweir             m_pImpl->removeModifyListener( i_listener );
1185*cdf0e10cSrcweir     }
1186*cdf0e10cSrcweir 
1187*cdf0e10cSrcweir //......................................................................................................................
1188*cdf0e10cSrcweir } // namespace framework
1189*cdf0e10cSrcweir //......................................................................................................................
1190