LCOV - code coverage report
Current view: top level - framework/source/fwe/helper - undomanagerhelper.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 1 439 0.2 %
Date: 2014-04-14 Functions: 2 87 2.3 %
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           0 :     UndoActionWrapper::UndoActionWrapper( Reference< XUndoAction > const& i_undoAction )
      85             :         :SfxUndoAction()
      86           0 :         ,m_xUndoAction( i_undoAction )
      87             :     {
      88           0 :         ENSURE_OR_THROW( m_xUndoAction.is(), "illegal undo action" );
      89           0 :     }
      90             : 
      91           0 :     UndoActionWrapper::~UndoActionWrapper()
      92             :     {
      93             :         try
      94             :         {
      95           0 :             Reference< XComponent > xComponent( m_xUndoAction, UNO_QUERY );
      96           0 :             if ( xComponent.is() )
      97           0 :                 xComponent->dispose();
      98             :         }
      99           0 :         catch( const Exception& )
     100             :         {
     101             :             DBG_UNHANDLED_EXCEPTION();
     102             :         }
     103           0 :     }
     104             : 
     105           0 :     OUString UndoActionWrapper::GetComment() const
     106             :     {
     107           0 :         OUString sComment;
     108             :         try
     109             :         {
     110           0 :             sComment = m_xUndoAction->getTitle();
     111             :         }
     112           0 :         catch( const Exception& )
     113             :         {
     114             :             DBG_UNHANDLED_EXCEPTION();
     115             :         }
     116           0 :         return sComment;
     117             :     }
     118             : 
     119           0 :     void UndoActionWrapper::Undo()
     120             :     {
     121           0 :         m_xUndoAction->undo();
     122           0 :     }
     123             : 
     124           0 :     void UndoActionWrapper::Redo()
     125             :     {
     126           0 :         m_xUndoAction->redo();
     127           0 :     }
     128             : 
     129           0 :     bool UndoActionWrapper::CanRepeat(SfxRepeatTarget&) const
     130             :     {
     131           0 :         return false;
     132             :     }
     133             : 
     134             :     //= UndoManagerRequest
     135             : 
     136             :     class UndoManagerRequest : public ::comphelper::AnyEvent
     137             :     {
     138             :     public:
     139           0 :         UndoManagerRequest( ::boost::function0< void > const& i_request )
     140             :             :m_request( i_request )
     141             :             ,m_caughtException()
     142           0 :             ,m_finishCondition()
     143             :         {
     144           0 :             m_finishCondition.reset();
     145           0 :         }
     146             : 
     147           0 :         void execute()
     148             :         {
     149             :             try
     150             :             {
     151           0 :                 m_request();
     152             :             }
     153           0 :             catch( const Exception& )
     154             :             {
     155           0 :                 m_caughtException = ::cppu::getCaughtException();
     156             :             }
     157           0 :             m_finishCondition.set();
     158           0 :         }
     159             : 
     160           0 :         void wait()
     161             :         {
     162           0 :             m_finishCondition.wait();
     163           0 :             if ( m_caughtException.hasValue() )
     164           0 :                 ::cppu::throwException( m_caughtException );
     165           0 :         }
     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           0 :         virtual ~UndoManagerRequest()
     178           0 :         {
     179           0 :         }
     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           0 :         ::osl::Mutex&   getMutex() { return m_aMutex; }
     210             : 
     211             :     public:
     212           0 :         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           0 :             ,m_rUndoManagerImplementation( i_undoManagerImpl )
     222             :         {
     223           0 :             getUndoManager().AddUndoListener( *this );
     224           0 :         }
     225             : 
     226           0 :         virtual ~UndoManagerHelper_Impl()
     227           0 :         {
     228           0 :         }
     229             : 
     230           0 :         IUndoManager& getUndoManager() const
     231             :         {
     232           0 :             return m_rUndoManagerImplementation.getImplUndoManager();
     233             :         }
     234             : 
     235           0 :         Reference< XUndoManager > getXUndoManager() const
     236             :         {
     237           0 :             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           0 :         void addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
     269             :         {
     270           0 :             m_aUndoListeners.addInterface( i_listener );
     271           0 :         }
     272             : 
     273           0 :         void removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
     274             :         {
     275           0 :             m_aUndoListeners.removeInterface( i_listener );
     276           0 :         }
     277             : 
     278           0 :         void addModifyListener( const Reference< XModifyListener >& i_listener )
     279             :         {
     280           0 :             m_aModifyListeners.addInterface( i_listener );
     281           0 :         }
     282             : 
     283           0 :         void removeModifyListener( const Reference< XModifyListener >& i_listener )
     284             :         {
     285           0 :             m_aModifyListeners.removeInterface( i_listener );
     286           0 :         }
     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           0 :         void notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) )
     296             :         {
     297           0 :             notify( OUString(), i_notificationMethod );
     298           0 :         }
     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           0 :     void UndoManagerHelper_Impl::disposing()
     317             :     {
     318           0 :         EventObject aEvent;
     319           0 :         aEvent.Source = getXUndoManager();
     320           0 :         m_aUndoListeners.disposeAndClear( aEvent );
     321           0 :         m_aModifyListeners.disposeAndClear( aEvent );
     322             : 
     323           0 :         ::osl::MutexGuard aGuard( m_aMutex );
     324             : 
     325           0 :         getUndoManager().RemoveUndoListener( *this );
     326             : 
     327           0 :         m_disposed = true;
     328           0 :     }
     329             : 
     330           0 :     UndoManagerEvent UndoManagerHelper_Impl::buildEvent( OUString const& i_title ) const
     331             :     {
     332           0 :         UndoManagerEvent aEvent;
     333           0 :         aEvent.Source = getXUndoManager();
     334           0 :         aEvent.UndoActionTitle = i_title;
     335           0 :         aEvent.UndoContextDepth = getUndoManager().GetListActionDepth();
     336           0 :         return aEvent;
     337             :     }
     338             : 
     339           0 :     void UndoManagerHelper_Impl::impl_notifyModified()
     340             :     {
     341           0 :         const EventObject aEvent( getXUndoManager() );
     342           0 :         m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
     343           0 :     }
     344             : 
     345           0 :     void UndoManagerHelper_Impl::notify( OUString const& i_title,
     346             :         void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const UndoManagerEvent& ) )
     347             :     {
     348           0 :         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           0 :         m_aUndoListeners.notifyEach( i_notificationMethod, aEvent );
     357           0 :         impl_notifyModified();
     358           0 :     }
     359             : 
     360           0 :     void UndoManagerHelper_Impl::notify( void ( SAL_CALL XUndoManagerListener::*i_notificationMethod )( const EventObject& ) )
     361             :     {
     362           0 :         const EventObject aEvent( getXUndoManager() );
     363             : 
     364             :         // TODO: the same comment as in the other notify, regarding SM locking applies here ...
     365             : 
     366           0 :         m_aUndoListeners.notifyEach( i_notificationMethod, aEvent );
     367           0 :         impl_notifyModified();
     368           0 :     }
     369             : 
     370           0 :     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           0 :         );
     381           0 :     }
     382             : 
     383           0 :     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           0 :         );
     392           0 :     }
     393             : 
     394           0 :     void UndoManagerHelper_Impl::addUndoAction( const Reference< XUndoAction >& i_action, IMutexGuard& i_instanceLock )
     395             :     {
     396           0 :         if ( !i_action.is() )
     397             :             throw IllegalArgumentException(
     398             :                 OUString( "illegal undo action object" ),
     399             :                 getXUndoManager(),
     400             :                 1
     401           0 :             );
     402             : 
     403             :         impl_processRequest(
     404             :             ::boost::bind(
     405             :                 &UndoManagerHelper_Impl::impl_addUndoAction,
     406             :                 this,
     407             :                 ::boost::ref( i_action )
     408             :             ),
     409             :             i_instanceLock
     410           0 :         );
     411           0 :     }
     412             : 
     413           0 :     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           0 :         );
     422           0 :     }
     423             : 
     424           0 :     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           0 :         );
     433           0 :     }
     434             : 
     435           0 :     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           0 :         );
     444           0 :     }
     445             : 
     446           0 :     void UndoManagerHelper_Impl::lock()
     447             :     {
     448             :         // SYNCHRONIZED --->
     449           0 :         ::osl::MutexGuard aGuard( getMutex() );
     450             : 
     451           0 :         if ( ++m_nLockCount == 1 )
     452             :         {
     453           0 :             IUndoManager& rUndoManager = getUndoManager();
     454           0 :             rUndoManager.EnableUndo( false );
     455           0 :         }
     456             :         // <--- SYNCHRONIZED
     457           0 :     }
     458             : 
     459           0 :     void UndoManagerHelper_Impl::unlock()
     460             :     {
     461             :         // SYNCHRONIZED --->
     462           0 :         ::osl::MutexGuard aGuard( getMutex() );
     463             : 
     464           0 :         if ( m_nLockCount == 0 )
     465           0 :             throw NotLockedException( "Undo manager is not locked", getXUndoManager() );
     466             : 
     467           0 :         if ( --m_nLockCount == 0 )
     468             :         {
     469           0 :             IUndoManager& rUndoManager = getUndoManager();
     470           0 :             rUndoManager.EnableUndo( true );
     471           0 :         }
     472             :         // <--- SYNCHRONIZED
     473           0 :     }
     474             : 
     475           0 :     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           0 :         ::rtl::Reference< UndoManagerRequest > pRequest( new UndoManagerRequest( i_request ) );
     479             :         {
     480           0 :             ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
     481           0 :             m_aEventQueue.push( pRequest );
     482             :         }
     483             : 
     484           0 :         i_instanceLock.clear();
     485             : 
     486           0 :         if ( m_bProcessingEvents )
     487             :         {
     488             :             // another thread is processing the event queue currently => it will also process the event which we just added
     489           0 :             pRequest->wait();
     490           0 :             return;
     491             :         }
     492             : 
     493           0 :         m_bProcessingEvents = true;
     494             :         do
     495             :         {
     496           0 :             pRequest.clear();
     497             :             {
     498           0 :                 ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
     499           0 :                 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           0 :                     m_bProcessingEvents = false;
     505           0 :                     return;
     506             :                 }
     507           0 :                 pRequest = m_aEventQueue.front();
     508           0 :                 m_aEventQueue.pop();
     509             :             }
     510             :             try
     511             :             {
     512           0 :                 pRequest->execute();
     513           0 :                 pRequest->wait();
     514             :             }
     515           0 :             catch( ... )
     516             :             {
     517             :                 {
     518             :                     // no chance to process further requests, if the current one failed
     519             :                     // => discard them
     520           0 :                     ::osl::MutexGuard aQueueGuard( m_aQueueMutex );
     521           0 :                     while ( !m_aEventQueue.empty() )
     522             :                     {
     523           0 :                         pRequest = m_aEventQueue.front();
     524           0 :                         m_aEventQueue.pop();
     525           0 :                         pRequest->cancel( getXUndoManager() );
     526             :                     }
     527           0 :                     m_bProcessingEvents = false;
     528             :                 }
     529             :                 // re-throw the error
     530           0 :                 throw;
     531             :             }
     532             :         }
     533           0 :         while ( true );
     534             :     }
     535             : 
     536           0 :     void UndoManagerHelper_Impl::impl_enterUndoContext( const OUString& i_title, const bool i_hidden )
     537             :     {
     538             :         // SYNCHRONIZED --->
     539           0 :         ::osl::ClearableMutexGuard aGuard( m_aMutex );
     540             : 
     541           0 :         IUndoManager& rUndoManager = getUndoManager();
     542           0 :         if ( !rUndoManager.IsUndoEnabled() )
     543             :             // ignore this request if the manager is locked
     544           0 :             return;
     545             : 
     546           0 :         if ( i_hidden && ( rUndoManager.GetUndoActionCount( IUndoManager::CurrentLevel ) == 0 ) )
     547             :             throw EmptyUndoStackException(
     548             :                 OUString( "can't enter a hidden context without a previous Undo action" ),
     549           0 :                 m_rUndoManagerImplementation.getThis()
     550           0 :             );
     551             : 
     552             :         {
     553           0 :             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
     554           0 :             rUndoManager.EnterListAction( i_title, OUString() );
     555             :         }
     556             : 
     557           0 :         m_aContextVisibilities.push( i_hidden );
     558             : 
     559           0 :         const UndoManagerEvent aEvent( buildEvent( i_title ) );
     560           0 :         aGuard.clear();
     561             :         // <--- SYNCHRONIZED
     562             : 
     563           0 :         m_aUndoListeners.notifyEach( i_hidden ? &XUndoManagerListener::enteredHiddenContext : &XUndoManagerListener::enteredContext, aEvent );
     564           0 :         impl_notifyModified();
     565             :     }
     566             : 
     567           0 :     void UndoManagerHelper_Impl::impl_leaveUndoContext()
     568             :     {
     569             :         // SYNCHRONIZED --->
     570           0 :         ::osl::ClearableMutexGuard aGuard( m_aMutex );
     571             : 
     572           0 :         IUndoManager& rUndoManager = getUndoManager();
     573           0 :         if ( !rUndoManager.IsUndoEnabled() )
     574             :             // ignore this request if the manager is locked
     575           0 :             return;
     576             : 
     577           0 :         if ( !rUndoManager.IsInListAction() )
     578             :             throw InvalidStateException(
     579             :                 OUString( "no active undo context" ),
     580             :                 getXUndoManager()
     581           0 :             );
     582             : 
     583           0 :         size_t nContextElements = 0;
     584             : 
     585           0 :         const bool isHiddenContext = m_aContextVisibilities.top();;
     586           0 :         m_aContextVisibilities.pop();
     587             : 
     588           0 :         const bool bHadRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0 );
     589             :         {
     590           0 :             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
     591           0 :             if ( isHiddenContext )
     592           0 :                 nContextElements = rUndoManager.LeaveAndMergeListAction();
     593             :             else
     594           0 :                 nContextElements = rUndoManager.LeaveListAction();
     595             :         }
     596           0 :         const bool bHasRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0 );
     597             : 
     598             :         // prepare notification
     599           0 :         void ( SAL_CALL XUndoManagerListener::*notificationMethod )( const UndoManagerEvent& ) = NULL;
     600             : 
     601           0 :         UndoManagerEvent aContextEvent( buildEvent( OUString() ) );
     602           0 :         const EventObject aClearedEvent( getXUndoManager() );
     603           0 :         if ( nContextElements == 0 )
     604             :         {
     605           0 :             notificationMethod = &XUndoManagerListener::cancelledContext;
     606             :         }
     607           0 :         else if ( isHiddenContext )
     608             :         {
     609           0 :             notificationMethod = &XUndoManagerListener::leftHiddenContext;
     610             :         }
     611             :         else
     612             :         {
     613           0 :             aContextEvent.UndoActionTitle = rUndoManager.GetUndoActionComment( 0, IUndoManager::CurrentLevel );
     614           0 :             notificationMethod = &XUndoManagerListener::leftContext;
     615             :         }
     616             : 
     617           0 :         aGuard.clear();
     618             :         // <--- SYNCHRONIZED
     619             : 
     620           0 :         if ( bHadRedoActions && !bHasRedoActions )
     621           0 :             m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aClearedEvent );
     622           0 :         m_aUndoListeners.notifyEach( notificationMethod, aContextEvent );
     623           0 :         impl_notifyModified();
     624             :     }
     625             : 
     626           0 :     void UndoManagerHelper_Impl::impl_doUndoRedo( IMutexGuard& i_externalLock, const bool i_undo )
     627             :     {
     628           0 :         ::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           0 :         ::osl::ClearableMutexGuard aGuard( m_aMutex );
     634             : 
     635           0 :         IUndoManager& rUndoManager = getUndoManager();
     636           0 :         if ( rUndoManager.IsInListAction() )
     637           0 :             throw UndoContextNotClosedException( OUString(), getXUndoManager() );
     638             : 
     639             :         const size_t nElements  =   i_undo
     640           0 :                                 ?   rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
     641           0 :                                 :   rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
     642           0 :         if ( nElements == 0 )
     643           0 :             throw EmptyUndoStackException("stack is empty", getXUndoManager() );
     644             : 
     645           0 :         aGuard.clear();
     646             :         // <--- SYNCHRONIZED
     647             : 
     648             :         try
     649             :         {
     650           0 :             if ( i_undo )
     651           0 :                 rUndoManager.Undo();
     652             :             else
     653           0 :                 rUndoManager.Redo();
     654             :         }
     655           0 :         catch( const RuntimeException& ) { /* allowed to leave here */ throw; }
     656           0 :         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           0 :         }
     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           0 :     }
     672             : 
     673           0 :     void UndoManagerHelper_Impl::impl_addUndoAction( const Reference< XUndoAction >& i_action )
     674             :     {
     675             :         // SYNCHRONIZED --->
     676           0 :         ::osl::ClearableMutexGuard aGuard( m_aMutex );
     677             : 
     678           0 :         IUndoManager& rUndoManager = getUndoManager();
     679           0 :         if ( !rUndoManager.IsUndoEnabled() )
     680             :             // ignore the request if the manager is locked
     681           0 :             return;
     682             : 
     683           0 :         const UndoManagerEvent aEventAdd( buildEvent( i_action->getTitle() ) );
     684           0 :         const EventObject aEventClear( getXUndoManager() );
     685             : 
     686           0 :         const bool bHadRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 );
     687             :         {
     688           0 :             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
     689           0 :             rUndoManager.AddUndoAction( new UndoActionWrapper( i_action ) );
     690             :         }
     691           0 :         const bool bHasRedoActions = ( rUndoManager.GetRedoActionCount( IUndoManager::CurrentLevel ) > 0 );
     692             : 
     693           0 :         aGuard.clear();
     694             :         // <--- SYNCHRONIZED
     695             : 
     696           0 :         m_aUndoListeners.notifyEach( &XUndoManagerListener::undoActionAdded, aEventAdd );
     697           0 :         if ( bHadRedoActions && !bHasRedoActions )
     698           0 :             m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aEventClear );
     699           0 :         impl_notifyModified();
     700             :     }
     701             : 
     702           0 :     void UndoManagerHelper_Impl::impl_clear()
     703             :     {
     704             :         // SYNCHRONIZED --->
     705           0 :         ::osl::ClearableMutexGuard aGuard( m_aMutex );
     706             : 
     707           0 :         IUndoManager& rUndoManager = getUndoManager();
     708           0 :         if ( rUndoManager.IsInListAction() )
     709           0 :             throw UndoContextNotClosedException( OUString(), getXUndoManager() );
     710             : 
     711             :         {
     712           0 :             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
     713           0 :             rUndoManager.Clear();
     714             :         }
     715             : 
     716           0 :         const EventObject aEvent( getXUndoManager() );
     717           0 :         aGuard.clear();
     718             :         // <--- SYNCHRONIZED
     719             : 
     720           0 :         m_aUndoListeners.notifyEach( &XUndoManagerListener::allActionsCleared, aEvent );
     721           0 :         impl_notifyModified();
     722           0 :     }
     723             : 
     724           0 :     void UndoManagerHelper_Impl::impl_clearRedo()
     725             :     {
     726             :         // SYNCHRONIZED --->
     727           0 :         ::osl::ClearableMutexGuard aGuard( m_aMutex );
     728             : 
     729           0 :         IUndoManager& rUndoManager = getUndoManager();
     730           0 :         if ( rUndoManager.IsInListAction() )
     731           0 :             throw UndoContextNotClosedException( OUString(), getXUndoManager() );
     732             : 
     733             :         {
     734           0 :             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
     735           0 :             rUndoManager.ClearRedo();
     736             :         }
     737             : 
     738           0 :         const EventObject aEvent( getXUndoManager() );
     739           0 :         aGuard.clear();
     740             :         // <--- SYNCHRONIZED
     741             : 
     742           0 :         m_aUndoListeners.notifyEach( &XUndoManagerListener::redoActionsCleared, aEvent );
     743           0 :         impl_notifyModified();
     744           0 :     }
     745             : 
     746           0 :     void UndoManagerHelper_Impl::impl_reset()
     747             :     {
     748             :         // SYNCHRONIZED --->
     749           0 :         ::osl::ClearableMutexGuard aGuard( m_aMutex );
     750             : 
     751           0 :         IUndoManager& rUndoManager = getUndoManager();
     752             :         {
     753           0 :             ::comphelper::FlagGuard aNotificationGuard( m_bAPIActionRunning );
     754           0 :             rUndoManager.Reset();
     755             :         }
     756             : 
     757           0 :         const EventObject aEvent( getXUndoManager() );
     758           0 :         aGuard.clear();
     759             :         // <--- SYNCHRONIZED
     760             : 
     761           0 :         m_aUndoListeners.notifyEach( &XUndoManagerListener::resetAll, aEvent );
     762           0 :         impl_notifyModified();
     763           0 :     }
     764             : 
     765           0 :     void UndoManagerHelper_Impl::actionUndone( const OUString& i_actionComment )
     766             :     {
     767           0 :         UndoManagerEvent aEvent;
     768           0 :         aEvent.Source = getXUndoManager();
     769           0 :         aEvent.UndoActionTitle = i_actionComment;
     770           0 :         aEvent.UndoContextDepth = 0;    // Undo can happen on level 0 only
     771           0 :         m_aUndoListeners.notifyEach( &XUndoManagerListener::actionUndone, aEvent );
     772           0 :         impl_notifyModified();
     773           0 :     }
     774             : 
     775           0 :     void UndoManagerHelper_Impl::actionRedone( const OUString& i_actionComment )
     776             :     {
     777           0 :         UndoManagerEvent aEvent;
     778           0 :         aEvent.Source = getXUndoManager();
     779           0 :         aEvent.UndoActionTitle = i_actionComment;
     780           0 :         aEvent.UndoContextDepth = 0;    // Redo can happen on level 0 only
     781           0 :         m_aUndoListeners.notifyEach( &XUndoManagerListener::actionRedone, aEvent );
     782           0 :         impl_notifyModified();
     783           0 :     }
     784             : 
     785           0 :     void UndoManagerHelper_Impl::undoActionAdded( const OUString& i_actionComment )
     786             :     {
     787           0 :         if ( m_bAPIActionRunning )
     788           0 :             return;
     789             : 
     790           0 :         notify( i_actionComment, &XUndoManagerListener::undoActionAdded );
     791             :     }
     792             : 
     793           0 :     void UndoManagerHelper_Impl::cleared()
     794             :     {
     795           0 :         if ( m_bAPIActionRunning )
     796           0 :             return;
     797             : 
     798           0 :         notify( &XUndoManagerListener::allActionsCleared );
     799             :     }
     800             : 
     801           0 :     void UndoManagerHelper_Impl::clearedRedo()
     802             :     {
     803           0 :         if ( m_bAPIActionRunning )
     804           0 :             return;
     805             : 
     806           0 :         notify( &XUndoManagerListener::redoActionsCleared );
     807             :     }
     808             : 
     809           0 :     void UndoManagerHelper_Impl::resetAll()
     810             :     {
     811           0 :         if ( m_bAPIActionRunning )
     812           0 :             return;
     813             : 
     814           0 :         notify( &XUndoManagerListener::resetAll );
     815             :     }
     816             : 
     817           0 :     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           0 :         if ( m_bAPIActionRunning )
     824           0 :             return;
     825             : 
     826           0 :         notify( i_comment, &XUndoManagerListener::enteredContext );
     827             :     }
     828             : 
     829           0 :     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           0 :         if ( m_bAPIActionRunning )
     838           0 :             return;
     839             : 
     840           0 :         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           0 :     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           0 :         if ( m_bAPIActionRunning )
     866           0 :             return;
     867             : 
     868           0 :         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           0 :     UndoManagerHelper::UndoManagerHelper( IUndoManagerImplementation& i_undoManagerImpl )
     879           0 :         :m_pImpl( new UndoManagerHelper_Impl( i_undoManagerImpl ) )
     880             :     {
     881           0 :     }
     882             : 
     883           0 :     UndoManagerHelper::~UndoManagerHelper()
     884             :     {
     885           0 :     }
     886             : 
     887           0 :     void UndoManagerHelper::disposing()
     888             :     {
     889           0 :         m_pImpl->disposing();
     890           0 :     }
     891             : 
     892           0 :     void UndoManagerHelper::enterUndoContext( const OUString& i_title, IMutexGuard& i_instanceLock )
     893             :     {
     894           0 :         m_pImpl->enterUndoContext( i_title, false, i_instanceLock );
     895           0 :     }
     896             : 
     897           0 :     void UndoManagerHelper::enterHiddenUndoContext( IMutexGuard& i_instanceLock )
     898             :     {
     899           0 :         m_pImpl->enterUndoContext( OUString(), true, i_instanceLock );
     900           0 :     }
     901             : 
     902           0 :     void UndoManagerHelper::leaveUndoContext( IMutexGuard& i_instanceLock )
     903             :     {
     904           0 :         m_pImpl->leaveUndoContext( i_instanceLock );
     905           0 :     }
     906             : 
     907           0 :     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           0 :         );
     918           0 :     }
     919             : 
     920           0 :     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           0 :         );
     931           0 :     }
     932             : 
     933           0 :     void UndoManagerHelper::addUndoAction( const Reference< XUndoAction >& i_action, IMutexGuard& i_instanceLock )
     934             :     {
     935           0 :         m_pImpl->addUndoAction( i_action, i_instanceLock );
     936           0 :     }
     937             : 
     938           0 :     void UndoManagerHelper::undo( IMutexGuard& i_instanceLock )
     939             :     {
     940           0 :         m_pImpl->undo( i_instanceLock );
     941           0 :     }
     942             : 
     943           0 :     void UndoManagerHelper::redo( IMutexGuard& i_instanceLock )
     944             :     {
     945           0 :         m_pImpl->redo( i_instanceLock );
     946           0 :     }
     947             : 
     948           0 :     bool UndoManagerHelper::isUndoPossible() const
     949             :     {
     950             :         // SYNCHRONIZED --->
     951           0 :         ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
     952           0 :         IUndoManager& rUndoManager = m_pImpl->getUndoManager();
     953           0 :         if ( rUndoManager.IsInListAction() )
     954           0 :             return false;
     955           0 :         return rUndoManager.GetUndoActionCount( IUndoManager::TopLevel ) > 0;
     956             :         // <--- SYNCHRONIZED
     957             :     }
     958             : 
     959           0 :     bool UndoManagerHelper::isRedoPossible() const
     960             :     {
     961             :         // SYNCHRONIZED --->
     962           0 :         ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
     963           0 :         const IUndoManager& rUndoManager = m_pImpl->getUndoManager();
     964           0 :         if ( rUndoManager.IsInListAction() )
     965           0 :             return false;
     966           0 :         return rUndoManager.GetRedoActionCount( IUndoManager::TopLevel ) > 0;
     967             :         // <--- SYNCHRONIZED
     968             :     }
     969             : 
     970             :     namespace
     971             :     {
     972             : 
     973           0 :         OUString lcl_getCurrentActionTitle( UndoManagerHelper_Impl& i_impl, const bool i_undo )
     974             :         {
     975             :             // SYNCHRONIZED --->
     976           0 :             ::osl::MutexGuard aGuard( i_impl.getMutex() );
     977             : 
     978           0 :             const IUndoManager& rUndoManager = i_impl.getUndoManager();
     979             :             const size_t nActionCount = i_undo
     980           0 :                                     ?   rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
     981           0 :                                     :   rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
     982           0 :             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           0 :                 );
     988             :             return  i_undo
     989           0 :                 ?   rUndoManager.GetUndoActionComment( 0, IUndoManager::TopLevel )
     990           0 :                 :   rUndoManager.GetRedoActionComment( 0, IUndoManager::TopLevel );
     991             :             // <--- SYNCHRONIZED
     992             :         }
     993             : 
     994           0 :         Sequence< OUString > lcl_getAllActionTitles( UndoManagerHelper_Impl& i_impl, const bool i_undo )
     995             :         {
     996             :             // SYNCHRONIZED --->
     997           0 :             ::osl::MutexGuard aGuard( i_impl.getMutex() );
     998             : 
     999           0 :             const IUndoManager& rUndoManager = i_impl.getUndoManager();
    1000             :             const size_t nCount =   i_undo
    1001           0 :                                 ?   rUndoManager.GetUndoActionCount( IUndoManager::TopLevel )
    1002           0 :                                 :   rUndoManager.GetRedoActionCount( IUndoManager::TopLevel );
    1003             : 
    1004           0 :             Sequence< OUString > aTitles( nCount );
    1005           0 :             for ( size_t i=0; i<nCount; ++i )
    1006             :             {
    1007           0 :                 aTitles[i] =    i_undo
    1008           0 :                             ?   rUndoManager.GetUndoActionComment( i, IUndoManager::TopLevel )
    1009           0 :                             :   rUndoManager.GetRedoActionComment( i, IUndoManager::TopLevel );
    1010             :             }
    1011           0 :             return aTitles;
    1012             :             // <--- SYNCHRONIZED
    1013             :         }
    1014             :     }
    1015             : 
    1016           0 :     OUString UndoManagerHelper::getCurrentUndoActionTitle() const
    1017             :     {
    1018           0 :         return lcl_getCurrentActionTitle( *m_pImpl, true );
    1019             :     }
    1020             : 
    1021           0 :     OUString UndoManagerHelper::getCurrentRedoActionTitle() const
    1022             :     {
    1023           0 :         return lcl_getCurrentActionTitle( *m_pImpl, false );
    1024             :     }
    1025             : 
    1026           0 :     Sequence< OUString > UndoManagerHelper::getAllUndoActionTitles() const
    1027             :     {
    1028           0 :         return lcl_getAllActionTitles( *m_pImpl, true );
    1029             :     }
    1030             : 
    1031           0 :     Sequence< OUString > UndoManagerHelper::getAllRedoActionTitles() const
    1032             :     {
    1033           0 :         return lcl_getAllActionTitles( *m_pImpl, false );
    1034             :     }
    1035             : 
    1036           0 :     void UndoManagerHelper::clear( IMutexGuard& i_instanceLock )
    1037             :     {
    1038           0 :         m_pImpl->clear( i_instanceLock );
    1039           0 :     }
    1040             : 
    1041           0 :     void UndoManagerHelper::clearRedo( IMutexGuard& i_instanceLock )
    1042             :     {
    1043           0 :         m_pImpl->clearRedo( i_instanceLock );
    1044           0 :     }
    1045             : 
    1046           0 :     void UndoManagerHelper::reset( IMutexGuard& i_instanceLock )
    1047             :     {
    1048           0 :         m_pImpl->reset( i_instanceLock );
    1049           0 :     }
    1050             : 
    1051           0 :     void UndoManagerHelper::lock()
    1052             :     {
    1053           0 :         m_pImpl->lock();
    1054           0 :     }
    1055             : 
    1056           0 :     void UndoManagerHelper::unlock()
    1057             :     {
    1058           0 :         m_pImpl->unlock();
    1059           0 :     }
    1060             : 
    1061           0 :     bool UndoManagerHelper::isLocked()
    1062             :     {
    1063             :         // SYNCHRONIZED --->
    1064           0 :         ::osl::MutexGuard aGuard( m_pImpl->getMutex() );
    1065             : 
    1066           0 :         IUndoManager& rUndoManager = m_pImpl->getUndoManager();
    1067           0 :         return !rUndoManager.IsUndoEnabled();
    1068             :         // <--- SYNCHRONIZED
    1069             :     }
    1070             : 
    1071           0 :     void UndoManagerHelper::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
    1072             :     {
    1073           0 :         if ( i_listener.is() )
    1074           0 :             m_pImpl->addUndoManagerListener( i_listener );
    1075           0 :     }
    1076             : 
    1077           0 :     void UndoManagerHelper::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener )
    1078             :     {
    1079           0 :         if ( i_listener.is() )
    1080           0 :             m_pImpl->removeUndoManagerListener( i_listener );
    1081           0 :     }
    1082             : 
    1083           0 :     void UndoManagerHelper::addModifyListener( const Reference< XModifyListener >& i_listener )
    1084             :     {
    1085           0 :         if ( i_listener.is() )
    1086           0 :             m_pImpl->addModifyListener( i_listener );
    1087           0 :     }
    1088             : 
    1089           0 :     void UndoManagerHelper::removeModifyListener( const Reference< XModifyListener >& i_listener )
    1090             :     {
    1091           0 :         if ( i_listener.is() )
    1092           0 :             m_pImpl->removeModifyListener( i_listener );
    1093           0 :     }
    1094             : 
    1095           3 : } // namespace framework
    1096             : 
    1097             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10