diff options
Diffstat (limited to 'svl/source/undo/undo.cxx')
-rw-r--r-- | svl/source/undo/undo.cxx | 1502 |
1 files changed, 0 insertions, 1502 deletions
diff --git a/svl/source/undo/undo.cxx b/svl/source/undo/undo.cxx deleted file mode 100644 index 03c970a06d..0000000000 --- a/svl/source/undo/undo.cxx +++ /dev/null @@ -1,1502 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_svl.hxx" - -#include <com/sun/star/uno/Exception.hpp> - -#include <comphelper/flagguard.hxx> -#include <tools/debug.hxx> -#include <tools/diagnose_ex.h> - -#include <svl/undo.hxx> - -#include <vector> -#include <list> -#include <limits> - -using ::com::sun::star::uno::Exception; - -// STATIC DATA ----------------------------------------------------------- - -DBG_NAME(SfxUndoAction) - -//======================================================================== - -TYPEINIT0(SfxUndoAction); -TYPEINIT0(SfxListUndoAction); -TYPEINIT0(SfxLinkUndoAction); -TYPEINIT0(SfxRepeatTarget); - -//------------------------------------------------------------------------ - -SfxRepeatTarget::~SfxRepeatTarget() -{ -} - -//------------------------------------------------------------------------ - -SfxUndoContext::~SfxUndoContext() -{ -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoAction::IsLinked() -{ - return bLinked; -} - -//------------------------------------------------------------------------ - -void SfxUndoAction::SetLinked( sal_Bool bIsLinked ) -{ - bLinked = bIsLinked; -} - -//------------------------------------------------------------------------ - -SfxUndoAction::~SfxUndoAction() -{ - DBG_DTOR(SfxUndoAction, 0); - DBG_ASSERT( !IsLinked(), "Gelinkte Action geloescht" ); -} - - -SfxUndoAction::SfxUndoAction() -{ - DBG_CTOR(SfxUndoAction, 0); - SetLinked( sal_False ); -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoAction::Merge( SfxUndoAction * ) -{ - DBG_CHKTHIS(SfxUndoAction, 0); - return sal_False; -} - -//------------------------------------------------------------------------ - -XubString SfxUndoAction::GetComment() const -{ - DBG_CHKTHIS(SfxUndoAction, 0); - return XubString(); -} - -//------------------------------------------------------------------------ - - -sal_uInt16 SfxUndoAction::GetId() const -{ - DBG_CHKTHIS(SfxUndoAction, 0); - return 0; -} - -//------------------------------------------------------------------------ - -XubString SfxUndoAction::GetRepeatComment(SfxRepeatTarget&) const -{ - DBG_CHKTHIS(SfxUndoAction, 0); - return GetComment(); -} - -//------------------------------------------------------------------------ - -void SfxUndoAction::Undo() -{ - // die sind nur konzeptuell pure virtual - OSL_FAIL( "pure virtual function called: SfxUndoAction::Undo()" ); -} - -//------------------------------------------------------------------------ - -void SfxUndoAction::UndoWithContext( SfxUndoContext& i_context ) -{ - (void)i_context; - Undo(); -} - -//------------------------------------------------------------------------ - -void SfxUndoAction::Redo() -{ - // die sind nur konzeptuell pure virtual - OSL_FAIL( "pure virtual function called: SfxUndoAction::Redo()" ); -} - -//------------------------------------------------------------------------ - -void SfxUndoAction::RedoWithContext( SfxUndoContext& i_context ) -{ - (void)i_context; - Redo(); -} - -//------------------------------------------------------------------------ - -void SfxUndoAction::Repeat(SfxRepeatTarget&) -{ - // die sind nur konzeptuell pure virtual - OSL_FAIL( "pure virtual function called: SfxUndoAction::Repeat()" ); -} - -//------------------------------------------------------------------------ - - -sal_Bool SfxUndoAction::CanRepeat(SfxRepeatTarget&) const -{ - return sal_True; -} - -//======================================================================== - -typedef ::std::vector< SfxUndoListener* > UndoListeners; - -struct SVL_DLLPRIVATE SfxUndoManager_Data -{ - ::osl::Mutex aMutex; - SfxUndoArray* pUndoArray; - SfxUndoArray* pActUndoArray; - SfxUndoArray* pFatherUndoArray; - - sal_Int32 mnLockCount; - sal_Int32 mnMarks; - sal_Int32 mnEmptyMark; - bool mbDoing; - bool mbClearUntilTopLevel; - - UndoListeners aListeners; - - SfxUndoManager_Data( size_t i_nMaxUndoActionCount ) - :pUndoArray( new SfxUndoArray( i_nMaxUndoActionCount ) ) - ,pActUndoArray( NULL ) - ,pFatherUndoArray( NULL ) - ,mnLockCount( 0 ) - ,mnMarks( 0 ) - ,mnEmptyMark(MARK_INVALID) - ,mbDoing( false ) - ,mbClearUntilTopLevel( false ) - { - pActUndoArray = pUndoArray; - } - - ~SfxUndoManager_Data() - { - delete pUndoArray; - } -}; - -//======================================================================== - -namespace svl { namespace undo { namespace impl -{ - //-------------------------------------------------------------------- - class SVL_DLLPRIVATE LockGuard - { - public: - LockGuard( SfxUndoManager& i_manager ) - :m_manager( i_manager ) - { - m_manager.ImplEnableUndo_Lock( false ); - } - - ~LockGuard() - { - m_manager.ImplEnableUndo_Lock( true ); - } - - private: - SfxUndoManager& m_manager; - }; - - //-------------------------------------------------------------------- - typedef void ( SfxUndoListener::*UndoListenerVoidMethod )(); - typedef void ( SfxUndoListener::*UndoListenerStringMethod )( const String& ); - - //-------------------------------------------------------------------- - struct SVL_DLLPRIVATE NotifyUndoListener : public ::std::unary_function< SfxUndoListener*, void > - { - NotifyUndoListener() - :m_notificationMethod( NULL ) - ,m_altNotificationMethod( NULL ) - ,m_sActionComment() - { - } - - NotifyUndoListener( UndoListenerVoidMethod i_notificationMethod ) - :m_notificationMethod( i_notificationMethod ) - ,m_altNotificationMethod( NULL ) - ,m_sActionComment() - { - } - - NotifyUndoListener( UndoListenerStringMethod i_notificationMethod, const String& i_actionComment ) - :m_notificationMethod( NULL ) - ,m_altNotificationMethod( i_notificationMethod ) - ,m_sActionComment( i_actionComment ) - { - } - - bool is() const - { - return ( m_notificationMethod != NULL ) || ( m_altNotificationMethod != NULL ); - } - - void operator()( SfxUndoListener* i_listener ) const - { - OSL_PRECOND( is(), "NotifyUndoListener: this will crash!" ); - if ( m_altNotificationMethod != NULL ) - { - ( i_listener->*m_altNotificationMethod )( m_sActionComment ); - } - else - { - ( i_listener->*m_notificationMethod )(); - } - } - - private: - UndoListenerVoidMethod m_notificationMethod; - UndoListenerStringMethod m_altNotificationMethod; - String m_sActionComment; - }; - - //-------------------------------------------------------------------- - class SVL_DLLPRIVATE UndoManagerGuard - { - public: - UndoManagerGuard( SfxUndoManager_Data& i_managerData ) - :m_rManagerData( i_managerData ) - ,m_aGuard( i_managerData.aMutex ) - ,m_notifiers() - { - } - - ~UndoManagerGuard(); - - void clear() - { - m_aGuard.clear(); - } - - void reset() - { - m_aGuard.reset(); - } - - void cancelNotifications() - { - m_notifiers.clear(); - } - - /** marks the given Undo action for deletion - - The Undo action will be put into a list, whose members will be deleted from within the destructor of the - UndoManagerGuard. This deletion will happen without the UndoManager's mutex locked. - */ - void markForDeletion( SfxUndoAction* i_action ) - { - // remember - if ( i_action ) - m_aUndoActionsCleanup.push_back( i_action ); - } - - /** schedules the given SfxUndoListener method to be called for all registered listeners. - - The notification will happen after the Undo manager's mutex has been released, and after all pending - deletions of Undo actions are done. - */ - void scheduleNotification( UndoListenerVoidMethod i_notificationMethod ) - { - m_notifiers.push_back( NotifyUndoListener( i_notificationMethod ) ); - } - - void scheduleNotification( UndoListenerStringMethod i_notificationMethod, const String& i_actionComment ) - { - m_notifiers.push_back( NotifyUndoListener( i_notificationMethod, i_actionComment ) ); - } - - private: - SfxUndoManager_Data& m_rManagerData; - ::osl::ResettableMutexGuard m_aGuard; - ::std::list< SfxUndoAction* > m_aUndoActionsCleanup; - ::std::list< NotifyUndoListener > m_notifiers; - }; - - UndoManagerGuard::~UndoManagerGuard() - { - // copy members - UndoListeners aListenersCopy( m_rManagerData.aListeners ); - - // release mutex - m_aGuard.clear(); - - // delete all actions - while ( !m_aUndoActionsCleanup.empty() ) - { - SfxUndoAction* pAction = m_aUndoActionsCleanup.front(); - m_aUndoActionsCleanup.pop_front(); - try - { - delete pAction; - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION(); - } - } - - // handle scheduled notification - for ( ::std::list< NotifyUndoListener >::const_iterator notifier = m_notifiers.begin(); - notifier != m_notifiers.end(); - ++notifier - ) - { - if ( notifier->is() ) - ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(), *notifier ); - } - } -} } } - -using namespace ::svl::undo::impl; - -//======================================================================== - -SfxUndoManager::SfxUndoManager( size_t nMaxUndoActionCount ) - :m_pData( new SfxUndoManager_Data( nMaxUndoActionCount ) ) -{ -} - -//------------------------------------------------------------------------ - -SfxUndoManager::~SfxUndoManager() -{ - UndoListeners aListenersCopy; - { - UndoManagerGuard aGuard( *m_pData ); - aListenersCopy = m_pData->aListeners; - } - - ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(), - NotifyUndoListener( &SfxUndoListener::undoManagerDying ) ); -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::EnableUndo( bool i_enable ) -{ - UndoManagerGuard aGuard( *m_pData ); - ImplEnableUndo_Lock( i_enable ); - -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::ImplEnableUndo_Lock( bool const i_enable ) -{ - if ( !i_enable ) - ++m_pData->mnLockCount; - else - { - OSL_PRECOND( m_pData->mnLockCount > 0, "SfxUndoManager::ImplEnableUndo_NoNotify: not disabled, so why enabling?" ); - if ( m_pData->mnLockCount > 0 ) - --m_pData->mnLockCount; - } -} - -//------------------------------------------------------------------------ - -bool SfxUndoManager::IsUndoEnabled() const -{ - UndoManagerGuard aGuard( *m_pData ); - return ImplIsUndoEnabled_Lock(); -} - -//------------------------------------------------------------------------ - -bool SfxUndoManager::ImplIsUndoEnabled_Lock() const -{ - return m_pData->mnLockCount == 0; -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::SetMaxUndoActionCount( size_t nMaxUndoActionCount ) -{ - UndoManagerGuard aGuard( *m_pData ); - - // Remove entries from the pActUndoArray when we have to reduce - // the number of entries due to a lower nMaxUndoActionCount. - // Both redo and undo action entries will be removed until we reached the - // new nMaxUndoActionCount. - - long nNumToDelete = m_pData->pActUndoArray->aUndoActions.size() - nMaxUndoActionCount; - while ( nNumToDelete > 0 ) - { - size_t nPos = m_pData->pActUndoArray->aUndoActions.size(); - if ( nPos > m_pData->pActUndoArray->nCurUndoAction ) - { - SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[nPos-1].pAction; - if ( !pAction->IsLinked() ) - { - aGuard.markForDeletion( pAction ); - m_pData->pActUndoArray->aUndoActions.Remove( nPos-1 ); - --nNumToDelete; - } - } - - if ( nNumToDelete > 0 && m_pData->pActUndoArray->nCurUndoAction > 0 ) - { - SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[0].pAction; - if ( !pAction->IsLinked() ) - { - aGuard.markForDeletion( pAction ); - m_pData->pActUndoArray->aUndoActions.Remove(0); - --m_pData->pActUndoArray->nCurUndoAction; - --nNumToDelete; - } - } - - if ( nPos == m_pData->pActUndoArray->aUndoActions.size() ) - break; // Cannot delete more entries - } - - m_pData->pActUndoArray->nMaxUndoActions = nMaxUndoActionCount; -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::GetMaxUndoActionCount() const -{ - UndoManagerGuard aGuard( *m_pData ); - return m_pData->pActUndoArray->nMaxUndoActions; -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::ImplClearCurrentLevel_NoNotify( UndoManagerGuard& i_guard ) -{ - // clear array - while ( !m_pData->pActUndoArray->aUndoActions.empty() ) - { - size_t deletePos = m_pData->pActUndoArray->aUndoActions.size() - 1; - SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ deletePos ].pAction; - i_guard.markForDeletion( pAction ); - m_pData->pActUndoArray->aUndoActions.Remove( deletePos ); - } - - m_pData->pActUndoArray->nCurUndoAction = 0; - - m_pData->mnMarks = 0; - m_pData->mnEmptyMark = MARK_INVALID; -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::Clear() -{ - UndoManagerGuard aGuard( *m_pData ); - - OSL_ENSURE( !ImplIsInListAction_Lock(), "SfxUndoManager::Clear: suspicious call - do you really wish to clear the current level?" ); - ImplClearCurrentLevel_NoNotify( aGuard ); - - // notify listeners - aGuard.scheduleNotification( &SfxUndoListener::cleared ); -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::ClearAllLevels() -{ - UndoManagerGuard aGuard( *m_pData ); - ImplClearCurrentLevel_NoNotify( aGuard ); - - if ( ImplIsInListAction_Lock() ) - { - m_pData->mbClearUntilTopLevel = true; - } - else - { - aGuard.scheduleNotification( &SfxUndoListener::cleared ); - } -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::ImplClearRedo_NoLock( bool const i_currentLevel ) -{ - UndoManagerGuard aGuard( *m_pData ); - ImplClearRedo( aGuard, i_currentLevel ); -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::ClearRedo() -{ - OSL_ENSURE( !IsInListAction(), "SfxUndoManager::ClearRedo: suspicious call - do you really wish to clear the current level?" ); - ImplClearRedo_NoLock( CurrentLevel ); -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::Reset() -{ - UndoManagerGuard aGuard( *m_pData ); - - // clear all locks - while ( !ImplIsUndoEnabled_Lock() ) - ImplEnableUndo_Lock( true ); - - // cancel all list actions - while ( IsInListAction() ) - ImplLeaveListAction( false, aGuard ); - - // clear both stacks - ImplClearCurrentLevel_NoNotify( aGuard ); - - // cancel the notifications scheduled by ImplLeaveListAction, - // as we want to do an own, dedicated notification - aGuard.cancelNotifications(); - - // schedule notification - aGuard.scheduleNotification( &SfxUndoListener::resetAll ); -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::ImplClearUndo( UndoManagerGuard& i_guard ) -{ - while ( m_pData->pActUndoArray->nCurUndoAction > 0 ) - { - SfxUndoAction* pUndoAction = m_pData->pActUndoArray->aUndoActions[0].pAction; - m_pData->pActUndoArray->aUndoActions.Remove( 0 ); - i_guard.markForDeletion( pUndoAction ); - --m_pData->pActUndoArray->nCurUndoAction; - } - // TODO: notifications? We don't have clearedUndo, only cleared and clearedRedo at the SfxUndoListener -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::ImplClearRedo( UndoManagerGuard& i_guard, bool const i_currentLevel ) -{ - SfxUndoArray* pUndoArray = ( i_currentLevel == IUndoManager::CurrentLevel ) ? m_pData->pActUndoArray : m_pData->pUndoArray; - - // clearance - while ( pUndoArray->aUndoActions.size() > pUndoArray->nCurUndoAction ) - { - size_t deletePos = pUndoArray->aUndoActions.size() - 1; - SfxUndoAction* pAction = pUndoArray->aUndoActions[ deletePos ].pAction; - pUndoArray->aUndoActions.Remove( deletePos ); - i_guard.markForDeletion( pAction ); - } - - // notification - only if the top level's stack was cleared - if ( i_currentLevel == IUndoManager::TopLevel ) - i_guard.scheduleNotification( &SfxUndoListener::clearedRedo ); -} - -//------------------------------------------------------------------------ - -bool SfxUndoManager::ImplAddUndoAction_NoNotify( SfxUndoAction *pAction, bool bTryMerge, bool bClearRedo, UndoManagerGuard& i_guard ) -{ - if ( !ImplIsUndoEnabled_Lock() || ( m_pData->pActUndoArray->nMaxUndoActions == 0 ) ) - { - i_guard.markForDeletion( pAction ); - return false; - } - - // merge, if required - SfxUndoAction* pMergeWithAction = m_pData->pActUndoArray->nCurUndoAction ? - m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1].pAction : NULL; - if ( bTryMerge && ( !pMergeWithAction || !pMergeWithAction->Merge( pAction ) ) ) - { - i_guard.markForDeletion( pAction ); - return false; - } - - // clear redo stack, if requested - if ( bClearRedo && ( ImplGetRedoActionCount_Lock( CurrentLevel ) > 0 ) ) - ImplClearRedo( i_guard, IUndoManager::CurrentLevel ); - - // respect max number - if( m_pData->pActUndoArray == m_pData->pUndoArray ) - { - while( m_pData->pActUndoArray->aUndoActions.size() >= - m_pData->pActUndoArray->nMaxUndoActions && - !m_pData->pActUndoArray->aUndoActions[0].pAction->IsLinked() ) - { - i_guard.markForDeletion( m_pData->pActUndoArray->aUndoActions[0].pAction ); - m_pData->pActUndoArray->aUndoActions.Remove(0); - --m_pData->pActUndoArray->nCurUndoAction; - } - } - - // append new action - m_pData->pActUndoArray->aUndoActions.Insert( pAction, m_pData->pActUndoArray->nCurUndoAction++ ); - return true; -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::AddUndoAction( SfxUndoAction *pAction, sal_Bool bTryMerge ) -{ - UndoManagerGuard aGuard( *m_pData ); - - // add - if ( ImplAddUndoAction_NoNotify( pAction, bTryMerge, true, aGuard ) ) - { - // notify listeners - aGuard.scheduleNotification( &SfxUndoListener::undoActionAdded, pAction->GetComment() ); - } -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::GetUndoActionCount( bool const i_currentLevel ) const -{ - UndoManagerGuard aGuard( *m_pData ); - const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray; - return pUndoArray->nCurUndoAction; -} - -//------------------------------------------------------------------------ - -XubString SfxUndoManager::GetUndoActionComment( size_t nNo, bool const i_currentLevel ) const -{ - UndoManagerGuard aGuard( *m_pData ); - - String sComment; - const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray; - DBG_ASSERT( nNo < pUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoActionComment: illegal index!" ); - if( nNo < pUndoArray->nCurUndoAction ) - { - sComment = pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction - 1 - nNo ].pAction->GetComment(); - } - return sComment; -} - -//------------------------------------------------------------------------ - -sal_uInt16 SfxUndoManager::GetUndoActionId() const -{ - UndoManagerGuard aGuard( *m_pData ); - - DBG_ASSERT( m_pData->pActUndoArray->nCurUndoAction > 0, "svl::SfxUndoManager::GetUndoActionId(), illegal id!" ); - if ( m_pData->pActUndoArray->nCurUndoAction == 0 ) - return 0; - return m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1].pAction->GetId(); -} - -//------------------------------------------------------------------------ - -SfxUndoAction* SfxUndoManager::GetUndoAction( size_t nNo ) const -{ - UndoManagerGuard aGuard( *m_pData ); - - DBG_ASSERT( nNo < m_pData->pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoAction(), illegal id!" ); - if( nNo >= m_pData->pActUndoArray->nCurUndoAction ) - return NULL; - return m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1-nNo].pAction; -} - -//------------------------------------------------------------------------ - -/** clears the redo stack and removes the top undo action */ -void SfxUndoManager::RemoveLastUndoAction() -{ - UndoManagerGuard aGuard( *m_pData ); - - ENSURE_OR_RETURN_VOID( m_pData->pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::RemoveLastUndoAction(), no action to remove?!" ); - - m_pData->pActUndoArray->nCurUndoAction--; - - // delete redo-actions and top action - for ( size_t nPos = m_pData->pActUndoArray->aUndoActions.size(); nPos > m_pData->pActUndoArray->nCurUndoAction; --nPos ) - { - aGuard.markForDeletion( m_pData->pActUndoArray->aUndoActions[nPos-1].pAction ); - } - - m_pData->pActUndoArray->aUndoActions.Remove( - m_pData->pActUndoArray->nCurUndoAction, - m_pData->pActUndoArray->aUndoActions.size() - m_pData->pActUndoArray->nCurUndoAction ); -} - -//------------------------------------------------------------------------ - -bool SfxUndoManager::IsDoing() const -{ - UndoManagerGuard aGuard( *m_pData ); - return m_pData->mbDoing; -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoManager::Undo() -{ - return ImplUndo( NULL ); -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoManager::UndoWithContext( SfxUndoContext& i_context ) -{ - return ImplUndo( &i_context ); -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoManager::ImplUndo( SfxUndoContext* i_contextOrNull ) -{ - UndoManagerGuard aGuard( *m_pData ); - OSL_ENSURE( !IsDoing(), "SfxUndoManager::Undo: *nested* Undo/Redo actions? How this?" ); - - ::comphelper::FlagGuard aDoingGuard( m_pData->mbDoing ); - LockGuard aLockGuard( *this ); - - if ( ImplIsInListAction_Lock() ) - { - OSL_ENSURE( false, "SfxUndoManager::Undo: not possible when within a list action!" ); - return sal_False; - } - - if ( m_pData->pActUndoArray->nCurUndoAction == 0 ) - { - OSL_ENSURE( false, "SfxUndoManager::Undo: undo stack is empty!" ); - return sal_False; - } - - SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ --m_pData->pActUndoArray->nCurUndoAction ].pAction; - const String sActionComment = pAction->GetComment(); - try - { - // clear the guard/mutex before calling into the SfxUndoAction - this can be an extension-implemented UNO component - // nowadays ... - aGuard.clear(); - if ( i_contextOrNull != NULL ) - pAction->UndoWithContext( *i_contextOrNull ); - else - pAction->Undo(); - aGuard.reset(); - } - catch( ... ) - { - aGuard.reset(); - - // in theory, somebody might have tampered with all of *m_pData while the mutex was unlocked. So, see if - // we still find pAction in our current Undo array - size_t nCurAction = 0; - while ( nCurAction < m_pData->pActUndoArray->aUndoActions.size() ) - { - if ( m_pData->pActUndoArray->aUndoActions[ nCurAction++ ].pAction == pAction ) - { - // the Undo action is still there ... - // assume the error is a permanent failure, and clear the Undo stack - ImplClearUndo( aGuard ); - throw; - } - } - OSL_ENSURE( false, "SfxUndoManager::Undo: can't clear the Undo stack after the failure - some other party was faster ..." ); - throw; - } - - aGuard.scheduleNotification( &SfxUndoListener::actionUndone, sActionComment ); - - return sal_True; -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::GetRedoActionCount( bool const i_currentLevel ) const -{ - UndoManagerGuard aGuard( *m_pData ); - return ImplGetRedoActionCount_Lock( i_currentLevel ); -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::ImplGetRedoActionCount_Lock( bool const i_currentLevel ) const -{ - const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray; - return pUndoArray->aUndoActions.size() - pUndoArray->nCurUndoAction; -} - -//------------------------------------------------------------------------ - -XubString SfxUndoManager::GetRedoActionComment( size_t nNo, bool const i_currentLevel ) const -{ - UndoManagerGuard aGuard( *m_pData ); - const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray; - return pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction + nNo ].pAction->GetComment(); -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoManager::Redo() -{ - return ImplRedo( NULL ); -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoManager::RedoWithContext( SfxUndoContext& i_context ) -{ - return ImplRedo( &i_context ); -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoManager::ImplRedo( SfxUndoContext* i_contextOrNull ) -{ - UndoManagerGuard aGuard( *m_pData ); - OSL_ENSURE( !IsDoing(), "SfxUndoManager::Redo: *nested* Undo/Redo actions? How this?" ); - - ::comphelper::FlagGuard aDoingGuard( m_pData->mbDoing ); - LockGuard aLockGuard( *this ); - - if ( ImplIsInListAction_Lock() ) - { - OSL_ENSURE( false, "SfxUndoManager::Redo: not possible when within a list action!" ); - return sal_False; - } - - if ( m_pData->pActUndoArray->nCurUndoAction >= m_pData->pActUndoArray->aUndoActions.size() ) - { - OSL_ENSURE( false, "SfxUndoManager::Redo: redo stack is empty!" ); - return sal_False; - } - - SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction++ ].pAction; - const String sActionComment = pAction->GetComment(); - try - { - // clear the guard/mutex before calling into the SfxUndoAction - this can be a extension-implemented UNO component - // nowadays ... - aGuard.clear(); - if ( i_contextOrNull != NULL ) - pAction->RedoWithContext( *i_contextOrNull ); - else - pAction->Redo(); - aGuard.reset(); - } - catch( ... ) - { - aGuard.reset(); - - // in theory, somebody might have tampered with all of *m_pData while the mutex was unlocked. So, see if - // we still find pAction in our current Undo array - size_t nCurAction = 0; - while ( nCurAction < m_pData->pActUndoArray->aUndoActions.size() ) - { - if ( m_pData->pActUndoArray->aUndoActions[ nCurAction ].pAction == pAction ) - { - // the Undo action is still there ... - // assume the error is a permanent failure, and clear the Undo stack - ImplClearRedo( aGuard, IUndoManager::CurrentLevel ); - throw; - } - ++nCurAction; - } - OSL_ENSURE( false, "SfxUndoManager::Redo: can't clear the Undo stack after the failure - some other party was faster ..." ); - throw; - } - - aGuard.scheduleNotification( &SfxUndoListener::actionRedone, sActionComment ); - - return sal_True; -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::GetRepeatActionCount() const -{ - UndoManagerGuard aGuard( *m_pData ); - return m_pData->pActUndoArray->aUndoActions.size(); -} - -//------------------------------------------------------------------------ - -XubString SfxUndoManager::GetRepeatActionComment( SfxRepeatTarget &rTarget) const -{ - UndoManagerGuard aGuard( *m_pData ); - return m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->aUndoActions.size() - 1 ].pAction - ->GetRepeatComment(rTarget); -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoManager::Repeat( SfxRepeatTarget &rTarget ) -{ - UndoManagerGuard aGuard( *m_pData ); - if ( !m_pData->pActUndoArray->aUndoActions.empty() ) - { - SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->aUndoActions.size() - 1 ].pAction; - aGuard.clear(); - if ( pAction->CanRepeat( rTarget ) ) - pAction->Repeat( rTarget ); - return sal_True; - } - - return sal_False; -} - -//------------------------------------------------------------------------ - -sal_Bool SfxUndoManager::CanRepeat( SfxRepeatTarget &rTarget ) const -{ - UndoManagerGuard aGuard( *m_pData ); - if ( !m_pData->pActUndoArray->aUndoActions.empty() ) - { - size_t nActionNo = m_pData->pActUndoArray->aUndoActions.size() - 1; - return m_pData->pActUndoArray->aUndoActions[nActionNo].pAction->CanRepeat(rTarget); - } - return sal_False; -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::AddUndoListener( SfxUndoListener& i_listener ) -{ - UndoManagerGuard aGuard( *m_pData ); - m_pData->aListeners.push_back( &i_listener ); -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::RemoveUndoListener( SfxUndoListener& i_listener ) -{ - UndoManagerGuard aGuard( *m_pData ); - for ( UndoListeners::iterator lookup = m_pData->aListeners.begin(); - lookup != m_pData->aListeners.end(); - ++lookup - ) - { - if ( (*lookup) == &i_listener ) - { - m_pData->aListeners.erase( lookup ); - break; - } - } -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::EnterListAction( - const XubString& rComment, const XubString &rRepeatComment, sal_uInt16 nId ) - -/* [Beschreibung] - - Fuegt eine ListUndoAction ein und setzt dessen UndoArray als aktuelles. -*/ - -{ - UndoManagerGuard aGuard( *m_pData ); - - if( !ImplIsUndoEnabled_Lock() ) - return; - - if ( !m_pData->pUndoArray->nMaxUndoActions ) - return; - - m_pData->pFatherUndoArray = m_pData->pActUndoArray; - SfxListUndoAction* pAction = new SfxListUndoAction( rComment, rRepeatComment, nId, m_pData->pActUndoArray ); - OSL_VERIFY( ImplAddUndoAction_NoNotify( pAction, false, false, aGuard ) ); - // expected to succeed: all conditions under which it could fail should have been checked already - m_pData->pActUndoArray = pAction; - - // notification - aGuard.scheduleNotification( &SfxUndoListener::listActionEntered, rComment ); -} - -//------------------------------------------------------------------------ - -bool SfxUndoManager::IsInListAction() const -{ - UndoManagerGuard aGuard( *m_pData ); - return ImplIsInListAction_Lock(); -} - -//------------------------------------------------------------------------ - -bool SfxUndoManager::ImplIsInListAction_Lock() const -{ - return ( m_pData->pActUndoArray != m_pData->pUndoArray ); -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::GetListActionDepth() const -{ - UndoManagerGuard aGuard( *m_pData ); - size_t nDepth(0); - - SfxUndoArray* pLookup( m_pData->pActUndoArray ); - while ( pLookup != m_pData->pUndoArray ) - { - pLookup = pLookup->pFatherUndoArray; - ++nDepth; - } - - return nDepth; -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::LeaveListAction() -{ - UndoManagerGuard aGuard( *m_pData ); - size_t nCount = ImplLeaveListAction( false, aGuard ); - - if ( m_pData->mbClearUntilTopLevel ) - { - ImplClearCurrentLevel_NoNotify( aGuard ); - if ( !ImplIsInListAction_Lock() ) - { - m_pData->mbClearUntilTopLevel = false; - aGuard.scheduleNotification( &SfxUndoListener::cleared ); - } - nCount = 0; - } - - return nCount; -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::LeaveAndMergeListAction() -{ - UndoManagerGuard aGuard( *m_pData ); - return ImplLeaveListAction( true, aGuard ); -} - -//------------------------------------------------------------------------ - -size_t SfxUndoManager::ImplLeaveListAction( const bool i_merge, UndoManagerGuard& i_guard ) -{ - if ( !ImplIsUndoEnabled_Lock() ) - return 0; - - if ( !m_pData->pUndoArray->nMaxUndoActions ) - return 0; - - if( !ImplIsInListAction_Lock() ) - { - OSL_TRACE( "svl::SfxUndoManager::ImplLeaveListAction, called without calling EnterListAction()!" ); - return 0; - } - - DBG_ASSERT( m_pData->pActUndoArray->pFatherUndoArray, "SfxUndoManager::ImplLeaveListAction, no father undo array!?" ); - - // the array/level which we're about to leave - SfxUndoArray* pArrayToLeave = m_pData->pActUndoArray; - // one step up - m_pData->pActUndoArray = m_pData->pActUndoArray->pFatherUndoArray; - - // If no undo actions were added to the list, delete the list action - const size_t nListActionElements = pArrayToLeave->nCurUndoAction; - if ( nListActionElements == 0 ) - { - SfxUndoAction* pCurrentAction= m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction-1 ].pAction; - m_pData->pActUndoArray->aUndoActions.Remove( --m_pData->pActUndoArray->nCurUndoAction ); - i_guard.markForDeletion( pCurrentAction ); - - i_guard.scheduleNotification( &SfxUndoListener::listActionCancelled ); - return 0; - } - - // now that it is finally clear the list action is non-trivial, and does participate in the Undo stack, clear - // the redo stack - ImplClearRedo( i_guard, IUndoManager::CurrentLevel ); - - SfxUndoAction* pCurrentAction= m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction-1 ].pAction; - SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction * >( pCurrentAction ); - ENSURE_OR_RETURN( pListAction, "SfxUndoManager::ImplLeaveListAction: list action expected at this position!", nListActionElements ); - - if ( i_merge ) - { - // merge the list action with its predecessor on the same level - OSL_ENSURE( m_pData->pActUndoArray->nCurUndoAction > 1, - "SfxUndoManager::ImplLeaveListAction: cannot merge the list action if there's no other action on the same level - check this beforehand!" ); - if ( m_pData->pActUndoArray->nCurUndoAction > 1 ) - { - SfxUndoAction* pPreviousAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction - 2 ].pAction; - m_pData->pActUndoArray->aUndoActions.Remove( m_pData->pActUndoArray->nCurUndoAction - 2 ); - --m_pData->pActUndoArray->nCurUndoAction; - pListAction->aUndoActions.Insert( pPreviousAction, 0 ); - ++pListAction->nCurUndoAction; - - pListAction->SetComment( pPreviousAction->GetComment() ); - } - } - - // if the undo array has no comment, try to get it from its children - if ( pListAction->GetComment().Len() == 0 ) - { - for( size_t n = 0; n < pListAction->aUndoActions.size(); n++ ) - { - if( pListAction->aUndoActions[n].pAction->GetComment().Len() ) - { - pListAction->SetComment( pListAction->aUndoActions[n].pAction->GetComment() ); - break; - } - } - } - - // notify listeners - i_guard.scheduleNotification( &SfxUndoListener::listActionLeft, pListAction->GetComment() ); - - // outta here - return nListActionElements; -} - -//------------------------------------------------------------------------ -UndoStackMark SfxUndoManager::MarkTopUndoAction() -{ - UndoManagerGuard aGuard( *m_pData ); - - OSL_ENSURE( !IsInListAction(), - "SfxUndoManager::MarkTopUndoAction(): suspicious call!" ); - OSL_ENSURE((m_pData->mnMarks + 1) < (m_pData->mnEmptyMark - 1), - "SfxUndoManager::MarkTopUndoAction(): mark overflow!"); - - size_t const nActionPos = m_pData->pUndoArray->nCurUndoAction; - if (0 == nActionPos) - { - --m_pData->mnEmptyMark; - return m_pData->mnEmptyMark; - } - - m_pData->pUndoArray->aUndoActions[ nActionPos-1 ].aMarks.push_back( - ++m_pData->mnMarks ); - return m_pData->mnMarks; -} - -//------------------------------------------------------------------------ -void SfxUndoManager::RemoveMark( UndoStackMark const i_mark ) -{ - UndoManagerGuard aGuard( *m_pData ); - - if ((m_pData->mnEmptyMark < i_mark) || (MARK_INVALID == i_mark)) - { - return; // nothing to remove - } - else if (i_mark == m_pData->mnEmptyMark) - { - --m_pData->mnEmptyMark; // never returned from MarkTop => invalid - return; - } - - for ( size_t i=0; i<m_pData->pUndoArray->aUndoActions.size(); ++i ) - { - MarkedUndoAction& rAction = m_pData->pUndoArray->aUndoActions[i]; - for ( ::std::vector< UndoStackMark >::iterator markPos = rAction.aMarks.begin(); - markPos != rAction.aMarks.end(); - ++markPos - ) - { - if ( *markPos == i_mark ) - { - rAction.aMarks.erase( markPos ); - return; - } - } - } - OSL_ENSURE( false, "SfxUndoManager::RemoveMark: mark not found!" ); - // TODO: this might be too offensive. There are situations where we implicitly remove marks - // without our clients, in particular the client which created the mark, having a chance to know - // about this. -} - -//------------------------------------------------------------------------ -bool SfxUndoManager::HasTopUndoActionMark( UndoStackMark const i_mark ) -{ - UndoManagerGuard aGuard( *m_pData ); - - size_t nActionPos = m_pData->pUndoArray->nCurUndoAction; - if ( nActionPos == 0 ) - { - return (i_mark == m_pData->mnEmptyMark); - } - - const MarkedUndoAction& rAction = - m_pData->pUndoArray->aUndoActions[ nActionPos-1 ]; - for ( ::std::vector< UndoStackMark >::const_iterator markPos = rAction.aMarks.begin(); - markPos != rAction.aMarks.end(); - ++markPos - ) - { - if ( *markPos == i_mark ) - return true; - } - - return false; -} - -//------------------------------------------------------------------------ - -void SfxUndoManager::RemoveOldestUndoActions( size_t const i_count ) -{ - UndoManagerGuard aGuard( *m_pData ); - - size_t nActionsToRemove = i_count; - while ( nActionsToRemove ) - { - SfxUndoAction* pActionToRemove = m_pData->pUndoArray->aUndoActions[0].pAction; - - if ( IsInListAction() && ( m_pData->pUndoArray->nCurUndoAction == 1 ) ) - { - OSL_ENSURE( false, "SfxUndoManager::RemoveOldestUndoActions: cannot remove a not-yet-closed list action!" ); - return; - } - - aGuard.markForDeletion( pActionToRemove ); - m_pData->pUndoArray->aUndoActions.Remove( 0 ); - --m_pData->pUndoArray->nCurUndoAction; - --nActionsToRemove; - } -} - -//------------------------------------------------------------------------ - -sal_uInt16 SfxListUndoAction::GetId() const -{ - return nId; -} - -//------------------------------------------------------------------------ - -XubString SfxListUndoAction::GetComment() const -{ - return aComment; -} - -//------------------------------------------------------------------------ - -void SfxListUndoAction::SetComment( const UniString& rComment ) -{ - aComment = rComment; -} - -//------------------------------------------------------------------------ - -XubString SfxListUndoAction::GetRepeatComment(SfxRepeatTarget &) const -{ - return aRepeatComment; -} - - -//------------------------------------------------------------------------ - -SfxListUndoAction::SfxListUndoAction -( - const XubString &rComment, - const XubString rRepeatComment, - sal_uInt16 Id, - SfxUndoArray *pFather -) -: nId(Id), aComment(rComment), aRepeatComment(rRepeatComment) -{ - pFatherUndoArray = pFather; - nMaxUndoActions = USHRT_MAX; -} - -//------------------------------------------------------------------------ - -void SfxListUndoAction::Undo() -{ - for(size_t i=nCurUndoAction;i>0;) - aUndoActions[--i].pAction->Undo(); - nCurUndoAction=0; -} - -//------------------------------------------------------------------------ - -void SfxListUndoAction::UndoWithContext( SfxUndoContext& i_context ) -{ - for(size_t i=nCurUndoAction;i>0;) - aUndoActions[--i].pAction->UndoWithContext( i_context ); - nCurUndoAction=0; -} - -//------------------------------------------------------------------------ - -void SfxListUndoAction::Redo() -{ - for(size_t i=nCurUndoAction;i<aUndoActions.size();i++) - aUndoActions[i].pAction->Redo(); - nCurUndoAction = aUndoActions.size(); -} - -//------------------------------------------------------------------------ - -void SfxListUndoAction::RedoWithContext( SfxUndoContext& i_context ) -{ - for(size_t i=nCurUndoAction;i<aUndoActions.size();i++) - aUndoActions[i].pAction->RedoWithContext( i_context ); - nCurUndoAction = aUndoActions.size(); -} - -//------------------------------------------------------------------------ - -void SfxListUndoAction::Repeat(SfxRepeatTarget&rTarget) -{ - for(size_t i=0;i<nCurUndoAction;i++) - aUndoActions[i].pAction->Repeat(rTarget); -} - -//------------------------------------------------------------------------ - -sal_Bool SfxListUndoAction::CanRepeat(SfxRepeatTarget&r) const -{ - for(size_t i=0;i<nCurUndoAction;i++) - if(!aUndoActions[i].pAction->CanRepeat(r)) - return sal_False; - return sal_True; -} - -//------------------------------------------------------------------------ - -sal_Bool SfxListUndoAction::Merge( SfxUndoAction *pNextAction ) -{ - return !aUndoActions.empty() && aUndoActions[aUndoActions.size()-1].pAction->Merge( pNextAction ); -} - -//------------------------------------------------------------------------ - -SfxLinkUndoAction::SfxLinkUndoAction(::svl::IUndoManager *pManager) -/* [Beschreibung] - - Richtet eine LinkAction ein, die auf einen weiteren UndoManager zeigt. - Holt sich als zugehoerige Action des weiteren UndoManagers dessen - aktuelle Action. -*/ - -{ - pUndoManager = pManager; - SfxUndoManager* pUndoManagerImplementation = dynamic_cast< SfxUndoManager* >( pManager ); - ENSURE_OR_THROW( pUndoManagerImplementation != NULL, "unsupported undo manager implementation!" ); - // yes, this cast is dirty. But reaching into the the SfxUndoManager's implementation, - // directly accessing its internal stack, and tampering with an action on that stack - // is dirty, too. - if ( pManager->GetMaxUndoActionCount() ) - { - size_t nPos = pManager->GetUndoActionCount()-1; - pAction = pUndoManagerImplementation->m_pData->pActUndoArray->aUndoActions[nPos].pAction; - pAction->SetLinked(); - } - else - pAction = 0; -} - -//------------------------------------------------------------------------ - -void SfxLinkUndoAction::Undo() -{ - if ( pAction ) - pUndoManager->Undo(); -} - -//------------------------------------------------------------------------ - -void SfxLinkUndoAction::Redo() -{ - if ( pAction ) - pUndoManager->Redo(); -} - -//------------------------------------------------------------------------ - - -sal_Bool SfxLinkUndoAction::CanRepeat(SfxRepeatTarget& r) const -{ - return pAction && pAction->CanRepeat(r); -} - - -//------------------------------------------------------------------------ - - -void SfxLinkUndoAction::Repeat(SfxRepeatTarget&r) -{ - if ( pAction && pAction->CanRepeat( r ) ) - pAction->Repeat( r ); -} - - -//------------------------------------------------------------------------ - -XubString SfxLinkUndoAction::GetComment() const -{ - if ( pAction ) - return pAction->GetComment(); - else - return XubString(); -} - - -//------------------------------------------------------------------------ - -XubString SfxLinkUndoAction::GetRepeatComment(SfxRepeatTarget&r) const -{ - if ( pAction ) - return pAction->GetRepeatComment(r); - else - return XubString(); -} - -//------------------------------------------------------------------------ - -SfxLinkUndoAction::~SfxLinkUndoAction() -{ - if( pAction ) - pAction->SetLinked( sal_False ); -} - - -//------------------------------------------------------------------------ - -SfxUndoArray::~SfxUndoArray() -{ - while ( !aUndoActions.empty() ) - { - SfxUndoAction *pAction = aUndoActions[ aUndoActions.size() - 1 ].pAction; - aUndoActions.Remove( aUndoActions.size() - 1 ); - delete pAction; - } -} - - -sal_uInt16 SfxLinkUndoAction::GetId() const -{ - return pAction ? pAction->GetId() : 0; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |