/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "docundomanager.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace sfx2 { using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::XInterface; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::com::sun::star::uno::UNO_SET_THROW; using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::RuntimeException; using ::com::sun::star::uno::Any; using ::com::sun::star::uno::makeAny; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Type; using ::com::sun::star::util::InvalidStateException; using ::com::sun::star::document::EmptyUndoStackException; using ::com::sun::star::util::NotLockedException; using ::com::sun::star::document::UndoContextNotClosedException; using ::com::sun::star::document::XUndoAction; using ::com::sun::star::document::XUndoManagerSupplier; using ::com::sun::star::lang::XComponent; using ::com::sun::star::lang::IllegalArgumentException; using ::com::sun::star::lang::NotInitializedException; using ::com::sun::star::lang::EventObject; using ::com::sun::star::document::UndoManagerEvent; using ::com::sun::star::document::XUndoManagerListener; using ::com::sun::star::document::UndoFailedException; using ::com::sun::star::document::XUndoManager; using ::com::sun::star::lang::NoSupportException; using ::com::sun::star::frame::XModel; using ::svl::IUndoManager; //= DocumentUndoManager_Impl struct DocumentUndoManager_Impl : public ::framework::IUndoManagerImplementation { DocumentUndoManager& rAntiImpl; IUndoManager* pUndoManager; ::framework::UndoManagerHelper aUndoHelper; DocumentUndoManager_Impl( DocumentUndoManager& i_antiImpl ) :rAntiImpl( i_antiImpl ) ,pUndoManager( impl_retrieveUndoManager( i_antiImpl.getBaseModel() ) ) // do this *before* the construction of aUndoHelper (which actually means: put pUndoManager before // aUndoHelper in the member list)! ,aUndoHelper( *this ) { } virtual ~DocumentUndoManager_Impl() { }; SfxObjectShell* getObjectShell() { return rAntiImpl.getBaseModel().GetObjectShell(); } // IUndoManagerImplementation virtual ::svl::IUndoManager& getImplUndoManager() SAL_OVERRIDE; virtual Reference< XUndoManager > getThis() SAL_OVERRIDE; void disposing() { aUndoHelper.disposing(); ENSURE_OR_RETURN_VOID( pUndoManager, "DocumentUndoManager_Impl::disposing: already disposed!" ); pUndoManager = NULL; } void invalidateXDo_nolck(); private: static IUndoManager* impl_retrieveUndoManager( SfxBaseModel& i_baseModel ) { IUndoManager* pUndoManager( NULL ); SfxObjectShell* pObjectShell = i_baseModel.GetObjectShell(); if ( pObjectShell != NULL ) pUndoManager = pObjectShell->GetUndoManager(); if ( !pUndoManager ) throw NotInitializedException( OUString(), *&i_baseModel ); return pUndoManager; } }; ::svl::IUndoManager& DocumentUndoManager_Impl::getImplUndoManager() { ENSURE_OR_THROW( pUndoManager != NULL, "DocumentUndoManager_Impl::getImplUndoManager: no access to the doc's UndoManager implementation!" ); #if OSL_DEBUG_LEVEL > 0 // in a non-product build, assert if the current UndoManager at the shell is not the same we obtained // (and cached) at construction time SfxObjectShell* pObjectShell = rAntiImpl.getBaseModel().GetObjectShell(); OSL_ENSURE( ( pObjectShell != NULL ) && ( pUndoManager == pObjectShell->GetUndoManager() ), "DocumentUndoManager_Impl::getImplUndoManager: the UndoManager changed meanwhile - what about our listener?" ); #endif return *pUndoManager; } Reference< XUndoManager > DocumentUndoManager_Impl::getThis() { return static_cast< XUndoManager* >( &rAntiImpl ); } void DocumentUndoManager_Impl::invalidateXDo_nolck() { SfxModelGuard aGuard( rAntiImpl ); const SfxObjectShell* pDocShell = getObjectShell(); ENSURE_OR_THROW( pDocShell != NULL, "lcl_invalidateUndo: no access to the doc shell!" ); SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst( pDocShell ); while ( pViewFrame ) { pViewFrame->GetBindings().Invalidate( SID_UNDO ); pViewFrame->GetBindings().Invalidate( SID_REDO ); pViewFrame = SfxViewFrame::GetNext( *pViewFrame, pDocShell ); } } //= SolarMutexFacade /** a facade for the SolarMutex, implementing ::framework::IMutex */ class SolarMutexFacade : public ::framework::IMutex { public: SolarMutexFacade() { } virtual ~SolarMutexFacade() {} virtual void acquire() SAL_OVERRIDE { Application::GetSolarMutex().acquire(); } virtual void release() SAL_OVERRIDE { Application::GetSolarMutex().release(); } }; //= UndoManagerGuard class UndoManagerGuard :public ::framework::IMutexGuard ,public ::boost::noncopyable { public: UndoManagerGuard( DocumentUndoManager& i_undoManager ) :m_guard( i_undoManager ) ,m_solarMutexFacade() { } virtual ~UndoManagerGuard() { } virtual void clear() SAL_OVERRIDE { m_guard.clear(); } virtual ::framework::IMutex& getGuardedMutex() SAL_OVERRIDE { // note that this means that we *know* that SfxModelGuard also locks the SolarMutex (nothing more, nothing less). // If this ever changes, we need to adjust this code here, too. return m_solarMutexFacade; } private: SfxModelGuard m_guard; SolarMutexFacade m_solarMutexFacade; }; //= DocumentUndoManager DocumentUndoManager::DocumentUndoManager( SfxBaseModel& i_document ) :SfxModelSubComponent( i_document ) ,m_pImpl( new DocumentUndoManager_Impl( *this ) ) { } DocumentUndoManager::~DocumentUndoManager() { } void DocumentUndoManager::disposing() { m_pImpl->disposing(); } bool DocumentUndoManager::isInContext() const { // No mutex locking within this method, no disposal check - this is the responsibility of the owner. return m_pImpl->getImplUndoManager().IsInListAction(); } void SAL_CALL DocumentUndoManager::acquire() throw() { OWeakObject::acquire(); SfxModelSubComponent::acquireModel(); } void SAL_CALL DocumentUndoManager::release() throw() { SfxModelSubComponent::releaseModel(); OWeakObject::release(); } void SAL_CALL DocumentUndoManager::enterUndoContext( const OUString& i_title ) throw (RuntimeException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.enterUndoContext( i_title, aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } void SAL_CALL DocumentUndoManager::enterHiddenUndoContext( ) throw (EmptyUndoStackException, RuntimeException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.enterHiddenUndoContext( aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } void SAL_CALL DocumentUndoManager::leaveUndoContext( ) throw (InvalidStateException, RuntimeException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.leaveUndoContext( aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } void SAL_CALL DocumentUndoManager::addUndoAction( const Reference< XUndoAction >& i_action ) throw (RuntimeException, IllegalArgumentException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.addUndoAction( i_action, aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } void SAL_CALL DocumentUndoManager::undo( ) throw (EmptyUndoStackException, UndoContextNotClosedException, UndoFailedException, RuntimeException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.undo( aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } void SAL_CALL DocumentUndoManager::redo( ) throw (EmptyUndoStackException, UndoContextNotClosedException, UndoFailedException, RuntimeException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.redo( aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } sal_Bool SAL_CALL DocumentUndoManager::isUndoPossible( ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.isUndoPossible(); } sal_Bool SAL_CALL DocumentUndoManager::isRedoPossible( ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.isRedoPossible(); } OUString SAL_CALL DocumentUndoManager::getCurrentUndoActionTitle( ) throw (EmptyUndoStackException, RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.getCurrentUndoActionTitle(); } OUString SAL_CALL DocumentUndoManager::getCurrentRedoActionTitle( ) throw (EmptyUndoStackException, RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.getCurrentRedoActionTitle(); } Sequence< OUString > SAL_CALL DocumentUndoManager::getAllUndoActionTitles( ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.getAllUndoActionTitles(); } Sequence< OUString > SAL_CALL DocumentUndoManager::getAllRedoActionTitles( ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.getAllRedoActionTitles(); } void SAL_CALL DocumentUndoManager::clear( ) throw (UndoContextNotClosedException, RuntimeException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.clear( aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } void SAL_CALL DocumentUndoManager::clearRedo( ) throw (UndoContextNotClosedException, RuntimeException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.clearRedo( aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } void SAL_CALL DocumentUndoManager::reset() throw (RuntimeException, std::exception) { // SYNCHRONIZED ---> UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.reset( aGuard ); // <--- SYNCHRONIZED m_pImpl->invalidateXDo_nolck(); } void SAL_CALL DocumentUndoManager::lock( ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.lock(); } void SAL_CALL DocumentUndoManager::unlock( ) throw (RuntimeException, NotLockedException, std::exception) { UndoManagerGuard aGuard( *this ); m_pImpl->aUndoHelper.unlock(); } sal_Bool SAL_CALL DocumentUndoManager::isLocked( ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.isLocked(); } void SAL_CALL DocumentUndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.addUndoManagerListener( i_listener ); } void SAL_CALL DocumentUndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return m_pImpl->aUndoHelper.removeUndoManagerListener( i_listener ); } Reference< XInterface > SAL_CALL DocumentUndoManager::getParent( ) throw (RuntimeException, std::exception) { UndoManagerGuard aGuard( *this ); return static_cast< XModel* >( &getBaseModel() ); } void SAL_CALL DocumentUndoManager::setParent( const Reference< XInterface >& i_parent ) throw (NoSupportException, RuntimeException, std::exception) { (void)i_parent; throw NoSupportException( OUString(), m_pImpl->getThis() ); } } // namespace sfx2 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */