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

Generated by: LCOV version 1.11