LCOV - code coverage report
Current view: top level - framework/source/fwe/helper - undomanagerhelper.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 418 439 95.2 %
Date: 2014-11-03 Functions: 84 87 96.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10