LCOV - code coverage report
Current view: top level - libreoffice/svl/source/undo - undo.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 285 581 49.1 %
Date: 2012-12-27 Functions: 59 133 44.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             : 
      21             : #include <com/sun/star/uno/Exception.hpp>
      22             : 
      23             : #include <comphelper/flagguard.hxx>
      24             : #include <tools/debug.hxx>
      25             : #include <tools/diagnose_ex.h>
      26             : 
      27             : #include <svl/undo.hxx>
      28             : 
      29             : #include <vector>
      30             : #include <list>
      31             : #include <limits>
      32             : 
      33             : using ::com::sun::star::uno::Exception;
      34             : 
      35             : // STATIC DATA -----------------------------------------------------------
      36             : 
      37             : DBG_NAME(SfxUndoAction)
      38             : 
      39             : //========================================================================
      40             : 
      41           0 : TYPEINIT0(SfxUndoAction);
      42           0 : TYPEINIT0(SfxListUndoAction);
      43           0 : TYPEINIT0(SfxLinkUndoAction);
      44           0 : TYPEINIT0(SfxRepeatTarget);
      45             : 
      46             : //------------------------------------------------------------------------
      47             : 
      48         286 : SfxRepeatTarget::~SfxRepeatTarget()
      49             : {
      50         286 : }
      51             : 
      52             : //------------------------------------------------------------------------
      53             : 
      54           0 : SfxUndoContext::~SfxUndoContext()
      55             : {
      56           0 : }
      57             : 
      58             : //------------------------------------------------------------------------
      59             : 
      60         911 : sal_Bool SfxUndoAction::IsLinked()
      61             : {
      62         911 :     return bLinked;
      63             : }
      64             : 
      65             : //------------------------------------------------------------------------
      66             : 
      67       67636 : void SfxUndoAction::SetLinked( sal_Bool bIsLinked )
      68             : {
      69       67636 :     bLinked = bIsLinked;
      70       67636 : }
      71             : 
      72             : //------------------------------------------------------------------------
      73             : 
      74       67548 : SfxUndoAction::~SfxUndoAction()
      75             : {
      76             :     DBG_DTOR(SfxUndoAction, 0);
      77             :     DBG_ASSERT( !IsLinked(), "Gelinkte Action geloescht" );
      78       67548 : }
      79             : 
      80             : 
      81       67636 : SfxUndoAction::SfxUndoAction()
      82             : {
      83             :     DBG_CTOR(SfxUndoAction, 0);
      84       67636 :     SetLinked( sal_False );
      85       67636 : }
      86             : 
      87             : //------------------------------------------------------------------------
      88             : 
      89           0 : sal_Bool SfxUndoAction::Merge( SfxUndoAction * )
      90             : {
      91             :     DBG_CHKTHIS(SfxUndoAction, 0);
      92           0 :     return sal_False;
      93             : }
      94             : 
      95             : //------------------------------------------------------------------------
      96             : 
      97           0 : OUString SfxUndoAction::GetComment() const
      98             : {
      99             :     DBG_CHKTHIS(SfxUndoAction, 0);
     100           0 :     return OUString();
     101             : }
     102             : 
     103             : //------------------------------------------------------------------------
     104             : 
     105             : 
     106           0 : sal_uInt16 SfxUndoAction::GetId() const
     107             : {
     108             :     DBG_CHKTHIS(SfxUndoAction, 0);
     109           0 :     return 0;
     110             : }
     111             : 
     112             : //------------------------------------------------------------------------
     113             : 
     114           0 : OUString SfxUndoAction::GetRepeatComment(SfxRepeatTarget&) const
     115             : {
     116             :     DBG_CHKTHIS(SfxUndoAction, 0);
     117           0 :     return GetComment();
     118             : }
     119             : 
     120             : //------------------------------------------------------------------------
     121             : 
     122           0 : void SfxUndoAction::Undo()
     123             : {
     124             :     // die sind nur konzeptuell pure virtual
     125             :     OSL_FAIL( "pure virtual function called: SfxUndoAction::Undo()" );
     126           0 : }
     127             : 
     128             : //------------------------------------------------------------------------
     129             : 
     130           0 : void SfxUndoAction::UndoWithContext( SfxUndoContext& i_context )
     131             : {
     132             :     (void)i_context;
     133           0 :     Undo();
     134           0 : }
     135             : 
     136             : //------------------------------------------------------------------------
     137             : 
     138           0 : void SfxUndoAction::Redo()
     139             : {
     140             :     // die sind nur konzeptuell pure virtual
     141             :     OSL_FAIL( "pure virtual function called: SfxUndoAction::Redo()" );
     142           0 : }
     143             : 
     144             : //------------------------------------------------------------------------
     145             : 
     146           0 : void SfxUndoAction::RedoWithContext( SfxUndoContext& i_context )
     147             : {
     148             :     (void)i_context;
     149           0 :     Redo();
     150           0 : }
     151             : 
     152             : //------------------------------------------------------------------------
     153             : 
     154           0 : void SfxUndoAction::Repeat(SfxRepeatTarget&)
     155             : {
     156             :     // die sind nur konzeptuell pure virtual
     157             :     OSL_FAIL( "pure virtual function called: SfxUndoAction::Repeat()" );
     158           0 : }
     159             : 
     160             : //------------------------------------------------------------------------
     161             : 
     162             : 
     163           0 : sal_Bool SfxUndoAction::CanRepeat(SfxRepeatTarget&) const
     164             : {
     165           0 :     return sal_True;
     166             : }
     167             : 
     168             : //========================================================================
     169             : 
     170             : typedef ::std::vector< SfxUndoListener* >   UndoListeners;
     171             : 
     172             : struct SVL_DLLPRIVATE SfxUndoManager_Data
     173             : {
     174             :     ::osl::Mutex    aMutex;
     175             :     SfxUndoArray*   pUndoArray;
     176             :     SfxUndoArray*   pActUndoArray;
     177             :     SfxUndoArray*   pFatherUndoArray;
     178             : 
     179             :     sal_Int32       mnMarks;
     180             :     sal_Int32       mnEmptyMark;
     181             :     bool            mbUndoEnabled;
     182             :     bool            mbDoing;
     183             :     bool            mbClearUntilTopLevel;
     184             : 
     185             :     UndoListeners   aListeners;
     186             : 
     187        3692 :     SfxUndoManager_Data( size_t i_nMaxUndoActionCount )
     188        3692 :         :pUndoArray( new SfxUndoArray( i_nMaxUndoActionCount ) )
     189             :         ,pActUndoArray( NULL )
     190             :         ,pFatherUndoArray( NULL )
     191             :         ,mnMarks( 0 )
     192        3692 :         ,mnEmptyMark(MARK_INVALID)
     193             :         ,mbUndoEnabled( true )
     194             :         ,mbDoing( false )
     195       11076 :         ,mbClearUntilTopLevel( false )
     196             :     {
     197        3692 :         pActUndoArray = pUndoArray;
     198        3692 :     }
     199             : 
     200        3108 :     ~SfxUndoManager_Data()
     201        3108 :     {
     202        3108 :         delete pUndoArray;
     203        3108 :     }
     204             : };
     205             : 
     206             : //========================================================================
     207             : 
     208             : namespace svl { namespace undo { namespace impl
     209             : {
     210             :     //--------------------------------------------------------------------
     211             :     class SVL_DLLPRIVATE LockGuard
     212             :     {
     213             :     public:
     214           3 :         LockGuard( SfxUndoManager& i_manager )
     215           3 :             :m_manager( i_manager )
     216             :         {
     217           3 :             m_manager.ImplEnableUndo_Lock( false );
     218           3 :         }
     219             : 
     220           3 :         ~LockGuard()
     221             :         {
     222           3 :             m_manager.ImplEnableUndo_Lock( true );
     223           3 :         }
     224             : 
     225             :     private:
     226             :         SfxUndoManager& m_manager;
     227             :     };
     228             : 
     229             :     //--------------------------------------------------------------------
     230             :     typedef void ( SfxUndoListener::*UndoListenerVoidMethod )();
     231             :     typedef void ( SfxUndoListener::*UndoListenerStringMethod )( const String& );
     232             : 
     233             :     //--------------------------------------------------------------------
     234     1523228 :     struct SVL_DLLPRIVATE NotifyUndoListener : public ::std::unary_function< SfxUndoListener*, void >
     235             :     {
     236             :         NotifyUndoListener()
     237             :             :m_notificationMethod( NULL )
     238             :             ,m_altNotificationMethod( NULL )
     239             :             ,m_sActionComment()
     240             :         {
     241             :         }
     242             : 
     243      130934 :         NotifyUndoListener( UndoListenerVoidMethod i_notificationMethod )
     244             :             :m_notificationMethod( i_notificationMethod )
     245             :             ,m_altNotificationMethod( NULL )
     246      130934 :             ,m_sActionComment()
     247             :         {
     248      130934 :         }
     249             : 
     250       88446 :         NotifyUndoListener( UndoListenerStringMethod i_notificationMethod, const String& i_actionComment )
     251             :             :m_notificationMethod( NULL )
     252             :             ,m_altNotificationMethod( i_notificationMethod )
     253       88446 :             ,m_sActionComment( i_actionComment )
     254             :         {
     255       88446 :         }
     256             : 
     257      216272 :         bool is() const
     258             :         {
     259      216272 :             return ( m_notificationMethod != 0 ) || ( m_altNotificationMethod != 0 );
     260             :         }
     261             : 
     262           0 :         void operator()( SfxUndoListener* i_listener ) const
     263             :         {
     264             :             OSL_PRECOND( is(), "NotifyUndoListener: this will crash!" );
     265           0 :             if ( m_altNotificationMethod != 0 )
     266             :             {
     267           0 :                 ( i_listener->*m_altNotificationMethod )( m_sActionComment );
     268             :             }
     269             :             else
     270             :             {
     271           0 :                 ( i_listener->*m_notificationMethod )();
     272             :             }
     273           0 :         }
     274             : 
     275             :     private:
     276             :         UndoListenerVoidMethod      m_notificationMethod;
     277             :         UndoListenerStringMethod    m_altNotificationMethod;
     278             :         String                      m_sActionComment;
     279             :     };
     280             : 
     281             :     //--------------------------------------------------------------------
     282             :     class SVL_DLLPRIVATE UndoManagerGuard
     283             :     {
     284             :     public:
     285      345507 :         UndoManagerGuard( SfxUndoManager_Data& i_managerData )
     286             :             :m_rManagerData( i_managerData )
     287             :             ,m_aGuard( i_managerData.aMutex )
     288      345507 :             ,m_notifiers()
     289             :         {
     290      345507 :         }
     291             : 
     292             :         ~UndoManagerGuard();
     293             : 
     294           3 :         void clear()
     295             :         {
     296           3 :             m_aGuard.clear();
     297           3 :         }
     298             : 
     299           3 :         void reset()
     300             :         {
     301           3 :             m_aGuard.reset();
     302           3 :         }
     303             : 
     304           0 :         void cancelNotifications()
     305             :         {
     306           0 :             m_notifiers.clear();
     307           0 :         }
     308             : 
     309             :         /** marks the given Undo action for deletion
     310             : 
     311             :             The Undo action will be put into a list, whose members will be deleted from within the destructor of the
     312             :             UndoManagerGuard. This deletion will happen without the UndoManager's mutex locked.
     313             :         */
     314       45586 :         void    markForDeletion( SfxUndoAction* i_action )
     315             :         {
     316             :             // remember
     317       45586 :             if ( i_action )
     318       45586 :                 m_aUndoActionsCleanup.push_back( i_action );
     319       45586 :         }
     320             : 
     321             :         /** schedules the given SfxUndoListener method to be called for all registered listeners.
     322             : 
     323             :             The notification will happen after the Undo manager's mutex has been released, and after all pending
     324             :             deletions of Undo actions are done.
     325             :         */
     326      127826 :         void    scheduleNotification( UndoListenerVoidMethod i_notificationMethod )
     327             :         {
     328      127826 :             m_notifiers.push_back( NotifyUndoListener( i_notificationMethod ) );
     329      127826 :         }
     330             : 
     331       88446 :         void    scheduleNotification( UndoListenerStringMethod i_notificationMethod, const String& i_actionComment )
     332             :         {
     333       88446 :             m_notifiers.push_back( NotifyUndoListener( i_notificationMethod, i_actionComment ) );
     334       88446 :         }
     335             : 
     336             :     private:
     337             :         SfxUndoManager_Data&                m_rManagerData;
     338             :         ::osl::ResettableMutexGuard         m_aGuard;
     339             :         ::std::list< SfxUndoAction* >       m_aUndoActionsCleanup;
     340             :         ::std::list< NotifyUndoListener >   m_notifiers;
     341             :     };
     342             : 
     343      691014 :     UndoManagerGuard::~UndoManagerGuard()
     344             :     {
     345             :         // copy members
     346      345507 :         UndoListeners aListenersCopy( m_rManagerData.aListeners );
     347             : 
     348             :         // release mutex
     349      345507 :         m_aGuard.clear();
     350             : 
     351             :         // delete all actions
     352      736600 :         while ( !m_aUndoActionsCleanup.empty() )
     353             :         {
     354       45586 :             SfxUndoAction* pAction = m_aUndoActionsCleanup.front();
     355       45586 :             m_aUndoActionsCleanup.pop_front();
     356             :             try
     357             :             {
     358       45586 :                 delete pAction;
     359             :             }
     360           0 :             catch( const Exception& )
     361             :             {
     362             :                 DBG_UNHANDLED_EXCEPTION();
     363             :             }
     364             :         }
     365             : 
     366             :         // handle scheduled notification
     367     1685337 :         for (   ::std::list< NotifyUndoListener >::const_iterator notifier = m_notifiers.begin();
     368     1123558 :                 notifier != m_notifiers.end();
     369             :                 ++notifier
     370             :              )
     371             :         {
     372      216272 :             if ( notifier->is() )
     373      216272 :                 ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(), *notifier );
     374      345507 :         }
     375      345507 :     }
     376             : } } }
     377             : 
     378             : using namespace ::svl::undo::impl;
     379             : 
     380             : //========================================================================
     381             : 
     382        3692 : SfxUndoManager::SfxUndoManager( size_t nMaxUndoActionCount )
     383        3692 :     :m_pData( new SfxUndoManager_Data( nMaxUndoActionCount ) )
     384             : {
     385        3692 : }
     386             : 
     387             : //------------------------------------------------------------------------
     388             : 
     389        6275 : SfxUndoManager::~SfxUndoManager()
     390             : {
     391        3108 :     UndoListeners aListenersCopy;
     392             :     {
     393        3108 :         UndoManagerGuard aGuard( *m_pData );
     394        3108 :         aListenersCopy = m_pData->aListeners;
     395             :     }
     396             : 
     397             :     ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(),
     398        3108 :         NotifyUndoListener( &SfxUndoListener::undoManagerDying ) );
     399        3167 : }
     400             : 
     401             : //------------------------------------------------------------------------
     402             : 
     403        6188 : void SfxUndoManager::EnableUndo( bool i_enable )
     404             : {
     405        6188 :     UndoManagerGuard aGuard( *m_pData );
     406        6188 :     ImplEnableUndo_Lock( i_enable );
     407             : 
     408        6188 : }
     409             : 
     410             : //------------------------------------------------------------------------
     411             : 
     412        6194 : void SfxUndoManager::ImplEnableUndo_Lock( bool const i_enable )
     413             : {
     414        6194 :     if ( m_pData->mbUndoEnabled == i_enable )
     415       11705 :         return;
     416         683 :     m_pData->mbUndoEnabled = i_enable;
     417             : }
     418             : 
     419             : //------------------------------------------------------------------------
     420             : 
     421      115832 : bool SfxUndoManager::IsUndoEnabled() const
     422             : {
     423      115832 :     UndoManagerGuard aGuard( *m_pData );
     424      115832 :     return ImplIsUndoEnabled_Lock();
     425             : }
     426             : 
     427             : //------------------------------------------------------------------------
     428             : 
     429      268823 : bool SfxUndoManager::ImplIsUndoEnabled_Lock() const
     430             : {
     431      268823 :     return m_pData->mbUndoEnabled;
     432             : }
     433             : 
     434             : //------------------------------------------------------------------------
     435             : 
     436         353 : void SfxUndoManager::SetMaxUndoActionCount( size_t nMaxUndoActionCount )
     437             : {
     438         353 :     UndoManagerGuard aGuard( *m_pData );
     439             : 
     440             :     // Remove entries from the pActUndoArray when we have to reduce
     441             :     // the number of entries due to a lower nMaxUndoActionCount.
     442             :     // Both redo and undo action entries will be removed until we reached the
     443             :     // new nMaxUndoActionCount.
     444             : 
     445         353 :     long nNumToDelete = m_pData->pActUndoArray->aUndoActions.size() - nMaxUndoActionCount;
     446         706 :     while ( nNumToDelete > 0 )
     447             :     {
     448           0 :         size_t nPos = m_pData->pActUndoArray->aUndoActions.size();
     449           0 :         if ( nPos > m_pData->pActUndoArray->nCurUndoAction )
     450             :         {
     451           0 :             SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[nPos-1].pAction;
     452           0 :             if ( !pAction->IsLinked() )
     453             :             {
     454           0 :                 aGuard.markForDeletion( pAction );
     455           0 :                 m_pData->pActUndoArray->aUndoActions.Remove( nPos-1 );
     456           0 :                 --nNumToDelete;
     457             :             }
     458             :         }
     459             : 
     460           0 :         if ( nNumToDelete > 0 && m_pData->pActUndoArray->nCurUndoAction > 0 )
     461             :         {
     462           0 :             SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[0].pAction;
     463           0 :             if ( !pAction->IsLinked() )
     464             :             {
     465           0 :                 aGuard.markForDeletion( pAction );
     466           0 :                 m_pData->pActUndoArray->aUndoActions.Remove(0);
     467           0 :                 --m_pData->pActUndoArray->nCurUndoAction;
     468           0 :                 --nNumToDelete;
     469             :             }
     470             :         }
     471             : 
     472           0 :         if ( nPos == m_pData->pActUndoArray->aUndoActions.size() )
     473           0 :             break; // Cannot delete more entries
     474             :     }
     475             : 
     476         353 :     m_pData->pActUndoArray->nMaxUndoActions = nMaxUndoActionCount;
     477         353 : }
     478             : 
     479             : //------------------------------------------------------------------------
     480             : 
     481           0 : size_t SfxUndoManager::GetMaxUndoActionCount() const
     482             : {
     483           0 :     UndoManagerGuard aGuard( *m_pData );
     484           0 :     return m_pData->pActUndoArray->nMaxUndoActions;
     485             : }
     486             : 
     487             : //------------------------------------------------------------------------
     488             : 
     489      106003 : void SfxUndoManager::ImplClearCurrentLevel_NoNotify( UndoManagerGuard& i_guard )
     490             : {
     491             :     // clear array
     492      234857 :     while ( !m_pData->pActUndoArray->aUndoActions.empty() )
     493             :     {
     494       22851 :         size_t deletePos = m_pData->pActUndoArray->aUndoActions.size() - 1;
     495       22851 :         SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ deletePos ].pAction;
     496       22851 :         i_guard.markForDeletion( pAction );
     497       22851 :         m_pData->pActUndoArray->aUndoActions.Remove( deletePos );
     498             :     }
     499             : 
     500      106003 :     m_pData->pActUndoArray->nCurUndoAction = 0;
     501             : 
     502      106003 :     m_pData->mnMarks = 0;
     503      106003 :     m_pData->mnEmptyMark = MARK_INVALID;
     504      106003 : }
     505             : 
     506             : //------------------------------------------------------------------------
     507             : 
     508      105892 : void SfxUndoManager::Clear()
     509             : {
     510      105892 :     UndoManagerGuard aGuard( *m_pData );
     511             : 
     512             :     OSL_ENSURE( !ImplIsInListAction_Lock(), "SfxUndoManager::Clear: suspicious call - do you really wish to clear the current level?" );
     513      105892 :     ImplClearCurrentLevel_NoNotify( aGuard );
     514             : 
     515             :     // notify listeners
     516      105892 :     aGuard.scheduleNotification( &SfxUndoListener::cleared );
     517      105892 : }
     518             : 
     519             : //------------------------------------------------------------------------
     520             : 
     521         111 : void SfxUndoManager::ClearAllLevels()
     522             : {
     523         111 :     UndoManagerGuard aGuard( *m_pData );
     524         111 :     ImplClearCurrentLevel_NoNotify( aGuard );
     525             : 
     526         111 :     if ( ImplIsInListAction_Lock() )
     527             :     {
     528           0 :         m_pData->mbClearUntilTopLevel = true;
     529             :     }
     530             :     else
     531             :     {
     532         111 :         aGuard.scheduleNotification( &SfxUndoListener::cleared );
     533         111 :     }
     534         111 : }
     535             : 
     536             : //------------------------------------------------------------------------
     537             : 
     538           0 : void SfxUndoManager::ImplClearRedo_NoLock( bool const i_currentLevel )
     539             : {
     540           0 :     UndoManagerGuard aGuard( *m_pData );
     541           0 :     ImplClearRedo( aGuard, i_currentLevel );
     542           0 : }
     543             : 
     544             : //------------------------------------------------------------------------
     545             : 
     546           0 : void SfxUndoManager::ClearRedo()
     547             : {
     548             :     OSL_ENSURE( !IsInListAction(), "SfxUndoManager::ClearRedo: suspicious call - do you really wish to clear the current level?" );
     549           0 :     ImplClearRedo_NoLock( CurrentLevel );
     550           0 : }
     551             : 
     552             : //------------------------------------------------------------------------
     553             : 
     554           0 : void SfxUndoManager::Reset()
     555             : {
     556           0 :     UndoManagerGuard aGuard( *m_pData );
     557             : 
     558             :     // clear all locks
     559           0 :     while ( !ImplIsUndoEnabled_Lock() )
     560           0 :         ImplEnableUndo_Lock( true );
     561             : 
     562             :     // cancel all list actions
     563           0 :     while ( IsInListAction() )
     564           0 :         ImplLeaveListAction( false, aGuard );
     565             : 
     566             :     // clear both stacks
     567           0 :     ImplClearCurrentLevel_NoNotify( aGuard );
     568             : 
     569             :     // cancel the notifications scheduled by ImplLeaveListAction,
     570             :     // as we want to do an own, dedicated notification
     571           0 :     aGuard.cancelNotifications();
     572             : 
     573             :     // schedule notification
     574           0 :     aGuard.scheduleNotification( &SfxUndoListener::resetAll );
     575           0 : }
     576             : 
     577             : //------------------------------------------------------------------------
     578             : 
     579           0 : void SfxUndoManager::ImplClearUndo( UndoManagerGuard& i_guard )
     580             : {
     581           0 :     while ( m_pData->pActUndoArray->nCurUndoAction > 0 )
     582             :     {
     583           0 :         SfxUndoAction* pUndoAction = m_pData->pActUndoArray->aUndoActions[0].pAction;
     584           0 :         m_pData->pActUndoArray->aUndoActions.Remove( 0 );
     585           0 :         i_guard.markForDeletion( pUndoAction );
     586           0 :         --m_pData->pActUndoArray->nCurUndoAction;
     587             :     }
     588             :     // TODO: notifications? We don't have clearedUndo, only cleared and clearedRedo at the SfxUndoListener
     589           0 : }
     590             : 
     591             : //------------------------------------------------------------------------
     592             : 
     593       20902 : void SfxUndoManager::ImplClearRedo( UndoManagerGuard& i_guard, bool const i_currentLevel )
     594             : {
     595       20902 :     SfxUndoArray* pUndoArray = ( i_currentLevel == IUndoManager::CurrentLevel ) ? m_pData->pActUndoArray : m_pData->pUndoArray;
     596             : 
     597             :     // clearance
     598       41805 :     while ( pUndoArray->aUndoActions.size() > pUndoArray->nCurUndoAction )
     599             :     {
     600           1 :         size_t deletePos = pUndoArray->aUndoActions.size() - 1;
     601           1 :         SfxUndoAction* pAction = pUndoArray->aUndoActions[ deletePos ].pAction;
     602           1 :         pUndoArray->aUndoActions.Remove( deletePos );
     603           1 :         i_guard.markForDeletion( pAction );
     604             :     }
     605             : 
     606             :     // notification - only if the top level's stack was cleared
     607       20902 :     if ( i_currentLevel == IUndoManager::TopLevel )
     608           0 :         i_guard.scheduleNotification( &SfxUndoListener::clearedRedo );
     609       20902 : }
     610             : 
     611             : //------------------------------------------------------------------------
     612             : 
     613       67541 : bool SfxUndoManager::ImplAddUndoAction_NoNotify( SfxUndoAction *pAction, bool bTryMerge, bool bClearRedo, UndoManagerGuard& i_guard )
     614             : {
     615       67541 :     if ( !ImplIsUndoEnabled_Lock() || ( m_pData->pActUndoArray->nMaxUndoActions == 0 ) )
     616             :     {
     617           0 :         i_guard.markForDeletion( pAction );
     618           0 :         return false;
     619             :     }
     620             : 
     621             :     // merge, if required
     622       67541 :     SfxUndoAction* pMergeWithAction = m_pData->pActUndoArray->nCurUndoAction ?
     623       67541 :         m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1].pAction : NULL;
     624       67541 :     if ( bTryMerge && pMergeWithAction )
     625             :     {
     626           0 :         bool bMerged = pMergeWithAction->Merge( pAction );
     627           0 :         if ( bMerged )
     628             :         {
     629           0 :             i_guard.markForDeletion( pAction );
     630           0 :             return false;
     631             :         }
     632             :     }
     633             : 
     634             :     // clear redo stack, if requested
     635       67541 :     if ( bClearRedo && ( ImplGetRedoActionCount_Lock( CurrentLevel ) > 0 ) )
     636           0 :         ImplClearRedo( i_guard, IUndoManager::CurrentLevel );
     637             : 
     638             :     // respect max number
     639       67541 :     if( m_pData->pActUndoArray == m_pData->pUndoArray )
     640             :     {
     641      137148 :         while( m_pData->pActUndoArray->aUndoActions.size() >=
     642       45716 :                m_pData->pActUndoArray->nMaxUndoActions &&
     643         911 :                !m_pData->pActUndoArray->aUndoActions[0].pAction->IsLinked() )
     644             :         {
     645         911 :             i_guard.markForDeletion( m_pData->pActUndoArray->aUndoActions[0].pAction );
     646         911 :             m_pData->pActUndoArray->aUndoActions.Remove(0);
     647         911 :             if (m_pData->pActUndoArray->nCurUndoAction > 0)
     648             :             {
     649         911 :                 --m_pData->pActUndoArray->nCurUndoAction;
     650             :             }
     651             :         }
     652             :     }
     653             : 
     654             :     // append new action
     655       67541 :     m_pData->pActUndoArray->aUndoActions.Insert( pAction, m_pData->pActUndoArray->nCurUndoAction++ );
     656       67541 :     return true;
     657             : }
     658             : 
     659             : //------------------------------------------------------------------------
     660             : 
     661       24816 : void SfxUndoManager::AddUndoAction( SfxUndoAction *pAction, sal_Bool bTryMerge )
     662             : {
     663       24816 :     UndoManagerGuard aGuard( *m_pData );
     664             : 
     665             :     // add
     666       24816 :     if ( ImplAddUndoAction_NoNotify( pAction, bTryMerge, true, aGuard ) )
     667             :     {
     668             :         // notify listeners
     669       24816 :         aGuard.scheduleNotification( &SfxUndoListener::undoActionAdded, pAction->GetComment() );
     670       24816 :     }
     671       24816 : }
     672             : 
     673             : //------------------------------------------------------------------------
     674             : 
     675          27 : size_t SfxUndoManager::GetUndoActionCount( bool const i_currentLevel ) const
     676             : {
     677          27 :     UndoManagerGuard aGuard( *m_pData );
     678          27 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     679          27 :     return pUndoArray->nCurUndoAction;
     680             : }
     681             : 
     682             : //------------------------------------------------------------------------
     683             : 
     684           0 : OUString SfxUndoManager::GetUndoActionComment( size_t nNo, bool const i_currentLevel ) const
     685             : {
     686           0 :     UndoManagerGuard aGuard( *m_pData );
     687             : 
     688           0 :     OUString sComment;
     689           0 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     690             :     DBG_ASSERT( nNo < pUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoActionComment: illegal index!" );
     691           0 :     if( nNo < pUndoArray->nCurUndoAction )
     692           0 :         sComment = pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction - 1 - nNo ].pAction->GetComment();
     693           0 :     return sComment;
     694             : }
     695             : 
     696             : //------------------------------------------------------------------------
     697             : 
     698           0 : sal_uInt16 SfxUndoManager::GetUndoActionId() const
     699             : {
     700           0 :     UndoManagerGuard aGuard( *m_pData );
     701             : 
     702             :     DBG_ASSERT( m_pData->pActUndoArray->nCurUndoAction > 0, "svl::SfxUndoManager::GetUndoActionId(), illegal id!" );
     703           0 :     if ( m_pData->pActUndoArray->nCurUndoAction == 0 )
     704           0 :         return 0;
     705           0 :     return m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1].pAction->GetId();
     706             : }
     707             : 
     708             : //------------------------------------------------------------------------
     709             : 
     710           0 : SfxUndoAction* SfxUndoManager::GetUndoAction( size_t nNo ) const
     711             : {
     712           0 :     UndoManagerGuard aGuard( *m_pData );
     713             : 
     714             :     DBG_ASSERT( nNo < m_pData->pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoAction(), illegal id!" );
     715           0 :     if( nNo >= m_pData->pActUndoArray->nCurUndoAction )
     716           0 :         return NULL;
     717           0 :     return m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1-nNo].pAction;
     718             : }
     719             : 
     720             : //------------------------------------------------------------------------
     721             : 
     722             : /** clears the redo stack and removes the top undo action */
     723           0 : void SfxUndoManager::RemoveLastUndoAction()
     724             : {
     725           0 :     UndoManagerGuard aGuard( *m_pData );
     726             : 
     727           0 :     ENSURE_OR_RETURN_VOID( m_pData->pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::RemoveLastUndoAction(), no action to remove?!" );
     728             : 
     729           0 :     m_pData->pActUndoArray->nCurUndoAction--;
     730             : 
     731             :     // delete redo-actions and top action
     732           0 :     for ( size_t nPos = m_pData->pActUndoArray->aUndoActions.size(); nPos > m_pData->pActUndoArray->nCurUndoAction; --nPos )
     733             :     {
     734           0 :         aGuard.markForDeletion( m_pData->pActUndoArray->aUndoActions[nPos-1].pAction );
     735             :     }
     736             : 
     737           0 :     m_pData->pActUndoArray->aUndoActions.Remove(
     738           0 :         m_pData->pActUndoArray->nCurUndoAction,
     739           0 :         m_pData->pActUndoArray->aUndoActions.size() - m_pData->pActUndoArray->nCurUndoAction );
     740             : }
     741             : 
     742             : //------------------------------------------------------------------------
     743             : 
     744          46 : bool SfxUndoManager::IsDoing() const
     745             : {
     746          46 :     UndoManagerGuard aGuard( *m_pData );
     747          46 :     return m_pData->mbDoing;
     748             : }
     749             : 
     750             : //------------------------------------------------------------------------
     751             : 
     752           2 : sal_Bool SfxUndoManager::Undo()
     753             : {
     754           2 :     return ImplUndo( NULL );
     755             : }
     756             : 
     757             : //------------------------------------------------------------------------
     758             : 
     759           0 : sal_Bool SfxUndoManager::UndoWithContext( SfxUndoContext& i_context )
     760             : {
     761           0 :     return ImplUndo( &i_context );
     762             : }
     763             : 
     764             : //------------------------------------------------------------------------
     765             : 
     766           2 : sal_Bool SfxUndoManager::ImplUndo( SfxUndoContext* i_contextOrNull )
     767             : {
     768           2 :     UndoManagerGuard aGuard( *m_pData );
     769             :     OSL_ENSURE( !IsDoing(), "SfxUndoManager::Undo: *nested* Undo/Redo actions? How this?" );
     770             : 
     771           2 :     ::comphelper::FlagGuard aDoingGuard( m_pData->mbDoing );
     772           2 :     LockGuard aLockGuard( *this );
     773             : 
     774           2 :     if ( ImplIsInListAction_Lock() )
     775             :     {
     776             :         OSL_ENSURE( false, "SfxUndoManager::Undo: not possible when within a list action!" );
     777           0 :         return sal_False;
     778             :     }
     779             : 
     780           2 :     if ( m_pData->pActUndoArray->nCurUndoAction == 0 )
     781             :     {
     782             :         OSL_ENSURE( false, "SfxUndoManager::Undo: undo stack is empty!" );
     783           0 :         return sal_False;
     784             :     }
     785             : 
     786           2 :     SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ --m_pData->pActUndoArray->nCurUndoAction ].pAction;
     787           2 :     const String sActionComment = pAction->GetComment();
     788             :     try
     789             :     {
     790             :         // clear the guard/mutex before calling into the SfxUndoAction - this can be an extension-implemented UNO component
     791             :         // nowadays ...
     792           2 :         aGuard.clear();
     793           2 :         if ( i_contextOrNull != NULL )
     794           0 :             pAction->UndoWithContext( *i_contextOrNull );
     795             :         else
     796           2 :             pAction->Undo();
     797           2 :         aGuard.reset();
     798             :     }
     799           0 :     catch( ... )
     800             :     {
     801           0 :         aGuard.reset();
     802             : 
     803             :         // in theory, somebody might have tampered with all of *m_pData while the mutex was unlocked. So, see if
     804             :         // we still find pAction in our current Undo array
     805           0 :         size_t nCurAction = 0;
     806           0 :         while ( nCurAction < m_pData->pActUndoArray->aUndoActions.size() )
     807             :         {
     808           0 :             if ( m_pData->pActUndoArray->aUndoActions[ nCurAction++ ].pAction == pAction )
     809             :             {
     810             :                 // the Undo action is still there ...
     811             :                 // assume the error is a permanent failure, and clear the Undo stack
     812           0 :                 ImplClearUndo( aGuard );
     813           0 :                 throw;
     814             :             }
     815             :         }
     816             :         OSL_ENSURE( false, "SfxUndoManager::Undo: can't clear the Undo stack after the failure - some other party was faster ..." );
     817           0 :         throw;
     818             :     }
     819             : 
     820           2 :     aGuard.scheduleNotification( &SfxUndoListener::actionUndone, sActionComment );
     821             : 
     822           2 :     return sal_True;
     823             : }
     824             : 
     825             : //------------------------------------------------------------------------
     826             : 
     827           2 : size_t SfxUndoManager::GetRedoActionCount( bool const i_currentLevel ) const
     828             : {
     829           2 :     UndoManagerGuard aGuard( *m_pData );
     830           2 :     return ImplGetRedoActionCount_Lock( i_currentLevel );
     831             : }
     832             : 
     833             : //------------------------------------------------------------------------
     834             : 
     835       24818 : size_t SfxUndoManager::ImplGetRedoActionCount_Lock( bool const i_currentLevel ) const
     836             : {
     837       24818 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     838       24818 :     return pUndoArray->aUndoActions.size() - pUndoArray->nCurUndoAction;
     839             : }
     840             : 
     841             : //------------------------------------------------------------------------
     842             : 
     843           0 : OUString SfxUndoManager::GetRedoActionComment( size_t nNo, bool const i_currentLevel ) const
     844             : {
     845           0 :     UndoManagerGuard aGuard( *m_pData );
     846           0 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     847           0 :     return pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction + nNo ].pAction->GetComment();
     848             : }
     849             : 
     850             : //------------------------------------------------------------------------
     851             : 
     852           1 : sal_Bool SfxUndoManager::Redo()
     853             : {
     854           1 :     return ImplRedo( NULL );
     855             : }
     856             : 
     857             : //------------------------------------------------------------------------
     858             : 
     859           0 : sal_Bool SfxUndoManager::RedoWithContext( SfxUndoContext& i_context )
     860             : {
     861           0 :     return ImplRedo( &i_context );
     862             : }
     863             : 
     864             : //------------------------------------------------------------------------
     865             : 
     866           1 : sal_Bool SfxUndoManager::ImplRedo( SfxUndoContext* i_contextOrNull )
     867             : {
     868           1 :     UndoManagerGuard aGuard( *m_pData );
     869             :     OSL_ENSURE( !IsDoing(), "SfxUndoManager::Redo: *nested* Undo/Redo actions? How this?" );
     870             : 
     871           1 :     ::comphelper::FlagGuard aDoingGuard( m_pData->mbDoing );
     872           1 :     LockGuard aLockGuard( *this );
     873             : 
     874           1 :     if ( ImplIsInListAction_Lock() )
     875             :     {
     876             :         OSL_ENSURE( false, "SfxUndoManager::Redo: not possible when within a list action!" );
     877           0 :         return sal_False;
     878             :     }
     879             : 
     880           1 :     if ( m_pData->pActUndoArray->nCurUndoAction >= m_pData->pActUndoArray->aUndoActions.size() )
     881             :     {
     882             :         OSL_ENSURE( false, "SfxUndoManager::Redo: redo stack is empty!" );
     883           0 :         return sal_False;
     884             :     }
     885             : 
     886           1 :     SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction++ ].pAction;
     887           1 :     const String sActionComment = pAction->GetComment();
     888             :     try
     889             :     {
     890             :         // clear the guard/mutex before calling into the SfxUndoAction - this can be a extension-implemented UNO component
     891             :         // nowadays ...
     892           1 :         aGuard.clear();
     893           1 :         if ( i_contextOrNull != NULL )
     894           0 :             pAction->RedoWithContext( *i_contextOrNull );
     895             :         else
     896           1 :             pAction->Redo();
     897           1 :         aGuard.reset();
     898             :     }
     899           0 :     catch( ... )
     900             :     {
     901           0 :         aGuard.reset();
     902             : 
     903             :         // in theory, somebody might have tampered with all of *m_pData while the mutex was unlocked. So, see if
     904             :         // we still find pAction in our current Undo array
     905           0 :         size_t nCurAction = 0;
     906           0 :         while ( nCurAction < m_pData->pActUndoArray->aUndoActions.size() )
     907             :         {
     908           0 :             if ( m_pData->pActUndoArray->aUndoActions[ nCurAction ].pAction == pAction )
     909             :             {
     910             :                 // the Undo action is still there ...
     911             :                 // assume the error is a permanent failure, and clear the Undo stack
     912           0 :                 ImplClearRedo( aGuard, IUndoManager::CurrentLevel );
     913           0 :                 throw;
     914             :             }
     915           0 :             ++nCurAction;
     916             :         }
     917             :         OSL_ENSURE( false, "SfxUndoManager::Redo: can't clear the Undo stack after the failure - some other party was faster ..." );
     918           0 :         throw;
     919             :     }
     920             : 
     921           1 :     aGuard.scheduleNotification( &SfxUndoListener::actionRedone, sActionComment );
     922             : 
     923           1 :     return sal_True;
     924             : }
     925             : 
     926             : //------------------------------------------------------------------------
     927             : 
     928           0 : size_t SfxUndoManager::GetRepeatActionCount() const
     929             : {
     930           0 :     UndoManagerGuard aGuard( *m_pData );
     931           0 :     return m_pData->pActUndoArray->aUndoActions.size();
     932             : }
     933             : 
     934             : //------------------------------------------------------------------------
     935             : 
     936           0 : OUString SfxUndoManager::GetRepeatActionComment(SfxRepeatTarget &rTarget) const
     937             : {
     938           0 :     UndoManagerGuard aGuard( *m_pData );
     939           0 :     return m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->aUndoActions.size() - 1 ].pAction
     940           0 :         ->GetRepeatComment(rTarget);
     941             : }
     942             : 
     943             : //------------------------------------------------------------------------
     944             : 
     945           0 : sal_Bool SfxUndoManager::Repeat( SfxRepeatTarget &rTarget )
     946             : {
     947           0 :     UndoManagerGuard aGuard( *m_pData );
     948           0 :     if ( !m_pData->pActUndoArray->aUndoActions.empty() )
     949             :     {
     950           0 :         SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->aUndoActions.size() - 1 ].pAction;
     951           0 :         aGuard.clear();
     952           0 :         if ( pAction->CanRepeat( rTarget ) )
     953           0 :             pAction->Repeat( rTarget );
     954           0 :         return sal_True;
     955             :     }
     956             : 
     957           0 :     return sal_False;
     958             : }
     959             : 
     960             : //------------------------------------------------------------------------
     961             : 
     962           0 : sal_Bool SfxUndoManager::CanRepeat( SfxRepeatTarget &rTarget ) const
     963             : {
     964           0 :     UndoManagerGuard aGuard( *m_pData );
     965           0 :     if ( !m_pData->pActUndoArray->aUndoActions.empty() )
     966             :     {
     967           0 :         size_t nActionNo = m_pData->pActUndoArray->aUndoActions.size() - 1;
     968           0 :         return m_pData->pActUndoArray->aUndoActions[nActionNo].pAction->CanRepeat(rTarget);
     969             :     }
     970           0 :     return sal_False;
     971             : }
     972             : 
     973             : //------------------------------------------------------------------------
     974             : 
     975           1 : void SfxUndoManager::AddUndoListener( SfxUndoListener& i_listener )
     976             : {
     977           1 :     UndoManagerGuard aGuard( *m_pData );
     978           1 :     m_pData->aListeners.push_back( &i_listener );
     979           1 : }
     980             : 
     981             : //------------------------------------------------------------------------
     982             : 
     983           1 : void SfxUndoManager::RemoveUndoListener( SfxUndoListener& i_listener )
     984             : {
     985           1 :     UndoManagerGuard aGuard( *m_pData );
     986           3 :     for (   UndoListeners::iterator lookup = m_pData->aListeners.begin();
     987           2 :             lookup != m_pData->aListeners.end();
     988             :             ++lookup
     989             :         )
     990             :     {
     991           1 :         if ( (*lookup) == &i_listener )
     992             :         {
     993           1 :             m_pData->aListeners.erase( lookup );
     994           1 :             break;
     995             :         }
     996           1 :     }
     997           1 : }
     998             : 
     999             : //------------------------------------------------------------------------
    1000             : 
    1001       42725 : void SfxUndoManager::EnterListAction(
    1002             :     const OUString& rComment, const OUString &rRepeatComment, sal_uInt16 nId )
    1003             : 
    1004             : /*  [Beschreibung]
    1005             : 
    1006             :     Fuegt eine ListUndoAction ein und setzt dessen UndoArray als aktuelles.
    1007             : */
    1008             : 
    1009             : {
    1010       42725 :     UndoManagerGuard aGuard( *m_pData );
    1011             : 
    1012       42725 :     if( !ImplIsUndoEnabled_Lock() )
    1013             :         return;
    1014             : 
    1015       42725 :     if ( !m_pData->pUndoArray->nMaxUndoActions )
    1016             :         return;
    1017             : 
    1018       42725 :     m_pData->pFatherUndoArray = m_pData->pActUndoArray;
    1019       42725 :     SfxListUndoAction* pAction = new SfxListUndoAction( rComment, rRepeatComment, nId, m_pData->pActUndoArray );
    1020       42725 :     OSL_VERIFY( ImplAddUndoAction_NoNotify( pAction, false, false, aGuard ) );
    1021             :         // expected to succeed: all conditions under which it could fail should have been checked already
    1022       42725 :     m_pData->pActUndoArray = pAction;
    1023             : 
    1024             :     // notification
    1025       42725 :     aGuard.scheduleNotification( &SfxUndoListener::listActionEntered, rComment );
    1026             : }
    1027             : 
    1028             : //------------------------------------------------------------------------
    1029             : 
    1030         758 : bool SfxUndoManager::IsInListAction() const
    1031             : {
    1032         758 :     UndoManagerGuard aGuard( *m_pData );
    1033         758 :     return ImplIsInListAction_Lock();
    1034             : }
    1035             : 
    1036             : //------------------------------------------------------------------------
    1037             : 
    1038       43597 : bool SfxUndoManager::ImplIsInListAction_Lock() const
    1039             : {
    1040       43597 :     return ( m_pData->pActUndoArray != m_pData->pUndoArray );
    1041             : }
    1042             : 
    1043             : //------------------------------------------------------------------------
    1044             : 
    1045           0 : size_t SfxUndoManager::GetListActionDepth() const
    1046             : {
    1047           0 :     UndoManagerGuard aGuard( *m_pData );
    1048           0 :     size_t nDepth(0);
    1049             : 
    1050           0 :     SfxUndoArray* pLookup( m_pData->pActUndoArray );
    1051           0 :     while ( pLookup != m_pData->pUndoArray )
    1052             :     {
    1053           0 :         pLookup = pLookup->pFatherUndoArray;
    1054           0 :         ++nDepth;
    1055             :     }
    1056             : 
    1057           0 :     return nDepth;
    1058             : }
    1059             : 
    1060             : //------------------------------------------------------------------------
    1061             : 
    1062       42725 : size_t SfxUndoManager::LeaveListAction()
    1063             : {
    1064       42725 :     UndoManagerGuard aGuard( *m_pData );
    1065       42725 :     size_t nCount = ImplLeaveListAction( false, aGuard );
    1066             : 
    1067       42725 :     if ( m_pData->mbClearUntilTopLevel )
    1068             :     {
    1069           0 :         ImplClearCurrentLevel_NoNotify( aGuard );
    1070           0 :         if ( !ImplIsInListAction_Lock() )
    1071             :         {
    1072           0 :             m_pData->mbClearUntilTopLevel = false;
    1073           0 :             aGuard.scheduleNotification( &SfxUndoListener::cleared );
    1074             :         }
    1075           0 :         nCount = 0;
    1076             :     }
    1077             : 
    1078       42725 :     return nCount;
    1079             : }
    1080             : 
    1081             : //------------------------------------------------------------------------
    1082             : 
    1083           0 : size_t SfxUndoManager::LeaveAndMergeListAction()
    1084             : {
    1085           0 :     UndoManagerGuard aGuard( *m_pData );
    1086           0 :     return ImplLeaveListAction( true, aGuard );
    1087             : }
    1088             : 
    1089             : //------------------------------------------------------------------------
    1090             : 
    1091       42725 : size_t SfxUndoManager::ImplLeaveListAction( const bool i_merge, UndoManagerGuard& i_guard )
    1092             : {
    1093       42725 :     if ( !ImplIsUndoEnabled_Lock() )
    1094           0 :         return 0;
    1095             : 
    1096       42725 :     if ( !m_pData->pUndoArray->nMaxUndoActions )
    1097           0 :         return 0;
    1098             : 
    1099       42725 :     if( !ImplIsInListAction_Lock() )
    1100             :     {
    1101             :         OSL_TRACE( "svl::SfxUndoManager::ImplLeaveListAction, called without calling EnterListAction()!" );
    1102           0 :         return 0;
    1103             :     }
    1104             : 
    1105             :     DBG_ASSERT( m_pData->pActUndoArray->pFatherUndoArray, "SfxUndoManager::ImplLeaveListAction, no father undo array!?" );
    1106             : 
    1107             :     // the array/level which we're about to leave
    1108       42725 :     SfxUndoArray* pArrayToLeave = m_pData->pActUndoArray;
    1109             :     // one step up
    1110       42725 :     m_pData->pActUndoArray = m_pData->pActUndoArray->pFatherUndoArray;
    1111             : 
    1112             :     // If no undo actions were added to the list, delete the list action
    1113       42725 :     const size_t nListActionElements = pArrayToLeave->nCurUndoAction;
    1114       42725 :     if ( nListActionElements == 0 )
    1115             :     {
    1116       21823 :         SfxUndoAction* pCurrentAction= m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction-1 ].pAction;
    1117       21823 :         m_pData->pActUndoArray->aUndoActions.Remove( --m_pData->pActUndoArray->nCurUndoAction );
    1118       21823 :         i_guard.markForDeletion( pCurrentAction );
    1119             : 
    1120       21823 :         i_guard.scheduleNotification( &SfxUndoListener::listActionCancelled );
    1121       21823 :         return 0;
    1122             :     }
    1123             : 
    1124             :     // now that it is finally clear the list action is non-trivial, and does participate in the Undo stack, clear
    1125             :     // the redo stack
    1126       20902 :     ImplClearRedo( i_guard, IUndoManager::CurrentLevel );
    1127             : 
    1128       20902 :     SfxUndoAction* pCurrentAction= m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction-1 ].pAction;
    1129       20902 :     SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction * >( pCurrentAction );
    1130       20902 :     ENSURE_OR_RETURN( pListAction, "SfxUndoManager::ImplLeaveListAction: list action expected at this position!", nListActionElements );
    1131             : 
    1132       20902 :     if ( i_merge )
    1133             :     {
    1134             :         // merge the list action with its predecessor on the same level
    1135             :         OSL_ENSURE( m_pData->pActUndoArray->nCurUndoAction > 1,
    1136             :             "SfxUndoManager::ImplLeaveListAction: cannot merge the list action if there's no other action on the same level - check this beforehand!" );
    1137           0 :         if ( m_pData->pActUndoArray->nCurUndoAction > 1 )
    1138             :         {
    1139           0 :             SfxUndoAction* pPreviousAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction - 2 ].pAction;
    1140           0 :             m_pData->pActUndoArray->aUndoActions.Remove( m_pData->pActUndoArray->nCurUndoAction - 2 );
    1141           0 :             --m_pData->pActUndoArray->nCurUndoAction;
    1142           0 :             pListAction->aUndoActions.Insert( pPreviousAction, 0 );
    1143           0 :             ++pListAction->nCurUndoAction;
    1144             : 
    1145           0 :             pListAction->SetComment( pPreviousAction->GetComment() );
    1146             :         }
    1147             :     }
    1148             : 
    1149             :     // if the undo array has no comment, try to get it from its children
    1150       20902 :     if ( pListAction->GetComment().isEmpty() )
    1151             :     {
    1152           0 :         for( size_t n = 0; n < pListAction->aUndoActions.size(); n++ )
    1153             :         {
    1154           0 :             if (!pListAction->aUndoActions[n].pAction->GetComment().isEmpty())
    1155             :             {
    1156           0 :                 pListAction->SetComment( pListAction->aUndoActions[n].pAction->GetComment() );
    1157           0 :                 break;
    1158             :             }
    1159             :         }
    1160             :     }
    1161             : 
    1162             :     // notify listeners
    1163       20902 :     i_guard.scheduleNotification( &SfxUndoListener::listActionLeft, pListAction->GetComment() );
    1164             : 
    1165             :     // outta here
    1166       20902 :     return nListActionElements;
    1167             : }
    1168             : 
    1169             : //------------------------------------------------------------------------
    1170        2908 : UndoStackMark SfxUndoManager::MarkTopUndoAction()
    1171             : {
    1172        2908 :     UndoManagerGuard aGuard( *m_pData );
    1173             : 
    1174             :     OSL_ENSURE( !IsInListAction(),
    1175             :             "SfxUndoManager::MarkTopUndoAction(): suspicious call!" );
    1176             :     OSL_ENSURE((m_pData->mnMarks + 1) < (m_pData->mnEmptyMark - 1),
    1177             :             "SfxUndoManager::MarkTopUndoAction(): mark overflow!");
    1178             : 
    1179        2908 :     size_t const nActionPos = m_pData->pUndoArray->nCurUndoAction;
    1180        2908 :     if (0 == nActionPos)
    1181             :     {
    1182        2908 :         --m_pData->mnEmptyMark;
    1183        2908 :         return m_pData->mnEmptyMark;
    1184             :     }
    1185             : 
    1186           0 :     m_pData->pUndoArray->aUndoActions[ nActionPos-1 ].aMarks.push_back(
    1187           0 :             ++m_pData->mnMarks );
    1188           0 :     return m_pData->mnMarks;
    1189             : }
    1190             : 
    1191             : //------------------------------------------------------------------------
    1192          11 : void SfxUndoManager::RemoveMark( UndoStackMark const i_mark )
    1193             : {
    1194          11 :     UndoManagerGuard aGuard( *m_pData );
    1195             : 
    1196          11 :     if ((m_pData->mnEmptyMark < i_mark) || (MARK_INVALID == i_mark))
    1197             :     {
    1198             :         return; // nothing to remove
    1199             :     }
    1200          11 :     else if (i_mark == m_pData->mnEmptyMark)
    1201             :     {
    1202          11 :         --m_pData->mnEmptyMark; // never returned from MarkTop => invalid
    1203             :         return;
    1204             :     }
    1205             : 
    1206           0 :     for ( size_t i=0; i<m_pData->pUndoArray->aUndoActions.size(); ++i )
    1207             :     {
    1208           0 :         MarkedUndoAction& rAction = m_pData->pUndoArray->aUndoActions[i];
    1209           0 :         for (   ::std::vector< UndoStackMark >::iterator markPos = rAction.aMarks.begin();
    1210           0 :                 markPos != rAction.aMarks.end();
    1211             :                 ++markPos
    1212             :             )
    1213             :         {
    1214           0 :             if ( *markPos == i_mark )
    1215             :             {
    1216           0 :                 rAction.aMarks.erase( markPos );
    1217             :                 return;
    1218             :             }
    1219             :         }
    1220             :     }
    1221          11 :     OSL_ENSURE( false, "SfxUndoManager::RemoveMark: mark not found!" );
    1222             :         // TODO: this might be too offensive. There are situations where we implicitly remove marks
    1223             :         // without our clients, in particular the client which created the mark, having a chance to know
    1224             :         // about this.
    1225             : }
    1226             : 
    1227             : //------------------------------------------------------------------------
    1228           0 : bool SfxUndoManager::HasTopUndoActionMark( UndoStackMark const i_mark )
    1229             : {
    1230           0 :     UndoManagerGuard aGuard( *m_pData );
    1231             : 
    1232           0 :     size_t nActionPos = m_pData->pUndoArray->nCurUndoAction;
    1233           0 :     if ( nActionPos == 0 )
    1234             :     {
    1235           0 :         return (i_mark == m_pData->mnEmptyMark);
    1236             :     }
    1237             : 
    1238             :     const MarkedUndoAction& rAction =
    1239           0 :             m_pData->pUndoArray->aUndoActions[ nActionPos-1 ];
    1240           0 :     for (   ::std::vector< UndoStackMark >::const_iterator markPos = rAction.aMarks.begin();
    1241           0 :             markPos != rAction.aMarks.end();
    1242             :             ++markPos
    1243             :         )
    1244             :     {
    1245           0 :         if ( *markPos == i_mark )
    1246           0 :             return true;
    1247             :     }
    1248             : 
    1249           0 :     return false;
    1250             : }
    1251             : 
    1252             : //------------------------------------------------------------------------
    1253             : 
    1254           0 : void SfxUndoManager::RemoveOldestUndoActions( size_t const i_count )
    1255             : {
    1256           0 :     UndoManagerGuard aGuard( *m_pData );
    1257             : 
    1258           0 :     size_t nActionsToRemove = i_count;
    1259           0 :     while ( nActionsToRemove )
    1260             :     {
    1261           0 :         SfxUndoAction* pActionToRemove = m_pData->pUndoArray->aUndoActions[0].pAction;
    1262             : 
    1263           0 :         if ( IsInListAction() && ( m_pData->pUndoArray->nCurUndoAction == 1 ) )
    1264             :         {
    1265             :             OSL_ENSURE( false, "SfxUndoManager::RemoveOldestUndoActions: cannot remove a not-yet-closed list action!" );
    1266           0 :             return;
    1267             :         }
    1268             : 
    1269           0 :         aGuard.markForDeletion( pActionToRemove );
    1270           0 :         m_pData->pUndoArray->aUndoActions.Remove( 0 );
    1271           0 :         --m_pData->pUndoArray->nCurUndoAction;
    1272           0 :         --nActionsToRemove;
    1273           0 :     }
    1274             : }
    1275             : 
    1276             : //------------------------------------------------------------------------
    1277             : 
    1278           0 : sal_uInt16 SfxListUndoAction::GetId() const
    1279             : {
    1280           0 :     return nId;
    1281             : }
    1282             : 
    1283             : //------------------------------------------------------------------------
    1284             : 
    1285       41807 : OUString SfxListUndoAction::GetComment() const
    1286             : {
    1287       41807 :     return aComment;
    1288             : }
    1289             : 
    1290             : //------------------------------------------------------------------------
    1291             : 
    1292           0 : void SfxListUndoAction::SetComment(const OUString& rComment)
    1293             : {
    1294           0 :     aComment = rComment;
    1295           0 : }
    1296             : 
    1297             : //------------------------------------------------------------------------
    1298             : 
    1299           0 : OUString SfxListUndoAction::GetRepeatComment(SfxRepeatTarget &) const
    1300             : {
    1301           0 :     return aRepeatComment;
    1302             : }
    1303             : 
    1304             : 
    1305             : //------------------------------------------------------------------------
    1306             : 
    1307       42725 : SfxListUndoAction::SfxListUndoAction
    1308             : (
    1309             :     const OUString &rComment,
    1310             :     const OUString rRepeatComment,
    1311             :     sal_uInt16 Id,
    1312             :     SfxUndoArray *pFather
    1313             : )
    1314       42725 : : nId(Id), aComment(rComment), aRepeatComment(rRepeatComment)
    1315             : {
    1316       42725 :     pFatherUndoArray = pFather;
    1317       42725 :     nMaxUndoActions = USHRT_MAX;
    1318       42725 : }
    1319             : 
    1320             : //------------------------------------------------------------------------
    1321             : 
    1322           4 : void SfxListUndoAction::Undo()
    1323             : {
    1324          13 :     for(size_t i=nCurUndoAction;i>0;)
    1325           5 :         aUndoActions[--i].pAction->Undo();
    1326           4 :     nCurUndoAction=0;
    1327           4 : }
    1328             : 
    1329             : //------------------------------------------------------------------------
    1330             : 
    1331           0 : void SfxListUndoAction::UndoWithContext( SfxUndoContext& i_context )
    1332             : {
    1333           0 :     for(size_t i=nCurUndoAction;i>0;)
    1334           0 :         aUndoActions[--i].pAction->UndoWithContext( i_context );
    1335           0 :     nCurUndoAction=0;
    1336           0 : }
    1337             : 
    1338             : //------------------------------------------------------------------------
    1339             : 
    1340           2 : void SfxListUndoAction::Redo()
    1341             : {
    1342           4 :     for(size_t i=nCurUndoAction;i<aUndoActions.size();i++)
    1343           2 :         aUndoActions[i].pAction->Redo();
    1344           2 :     nCurUndoAction = aUndoActions.size();
    1345           2 : }
    1346             : 
    1347             : //------------------------------------------------------------------------
    1348             : 
    1349           0 : void SfxListUndoAction::RedoWithContext( SfxUndoContext& i_context )
    1350             : {
    1351           0 :     for(size_t i=nCurUndoAction;i<aUndoActions.size();i++)
    1352           0 :         aUndoActions[i].pAction->RedoWithContext( i_context );
    1353           0 :     nCurUndoAction = aUndoActions.size();
    1354           0 : }
    1355             : 
    1356             : //------------------------------------------------------------------------
    1357             : 
    1358           0 : void SfxListUndoAction::Repeat(SfxRepeatTarget&rTarget)
    1359             : {
    1360           0 :     for(size_t i=0;i<nCurUndoAction;i++)
    1361           0 :         aUndoActions[i].pAction->Repeat(rTarget);
    1362           0 : }
    1363             : 
    1364             : //------------------------------------------------------------------------
    1365             : 
    1366           0 : sal_Bool SfxListUndoAction::CanRepeat(SfxRepeatTarget&r)  const
    1367             : {
    1368           0 :     for(size_t i=0;i<nCurUndoAction;i++)
    1369           0 :         if(!aUndoActions[i].pAction->CanRepeat(r))
    1370           0 :             return sal_False;
    1371           0 :     return sal_True;
    1372             : }
    1373             : 
    1374             : //------------------------------------------------------------------------
    1375             : 
    1376           0 : sal_Bool SfxListUndoAction::Merge( SfxUndoAction *pNextAction )
    1377             : {
    1378           0 :     return !aUndoActions.empty() && aUndoActions[aUndoActions.size()-1].pAction->Merge( pNextAction );
    1379             : }
    1380             : 
    1381             : //------------------------------------------------------------------------
    1382             : 
    1383           0 : SfxLinkUndoAction::SfxLinkUndoAction(::svl::IUndoManager *pManager)
    1384             : /*  [Beschreibung]
    1385             : 
    1386             :     Richtet eine LinkAction ein, die auf einen weiteren UndoManager zeigt.
    1387             :     Holt sich als zugehoerige Action des weiteren UndoManagers dessen
    1388             :     aktuelle Action.
    1389             : */
    1390             : 
    1391             : {
    1392           0 :     pUndoManager = pManager;
    1393           0 :     SfxUndoManager* pUndoManagerImplementation = dynamic_cast< SfxUndoManager* >( pManager );
    1394           0 :     ENSURE_OR_THROW( pUndoManagerImplementation != NULL, "unsupported undo manager implementation!" );
    1395             :         // yes, this cast is dirty. But reaching into the the SfxUndoManager's implementation,
    1396             :         // directly accessing its internal stack, and tampering with an action on that stack
    1397             :         // is dirty, too.
    1398           0 :     if ( pManager->GetMaxUndoActionCount() )
    1399             :     {
    1400           0 :         size_t nPos = pManager->GetUndoActionCount()-1;
    1401           0 :         pAction = pUndoManagerImplementation->m_pData->pActUndoArray->aUndoActions[nPos].pAction;
    1402           0 :         pAction->SetLinked();
    1403             :     }
    1404             :     else
    1405           0 :         pAction = 0;
    1406           0 : }
    1407             : 
    1408             : //------------------------------------------------------------------------
    1409             : 
    1410           0 : void SfxLinkUndoAction::Undo()
    1411             : {
    1412           0 :     if ( pAction )
    1413           0 :         pUndoManager->Undo();
    1414           0 : }
    1415             : 
    1416             : //------------------------------------------------------------------------
    1417             : 
    1418           0 : void SfxLinkUndoAction::Redo()
    1419             : {
    1420           0 :     if ( pAction )
    1421           0 :         pUndoManager->Redo();
    1422           0 : }
    1423             : 
    1424             : //------------------------------------------------------------------------
    1425             : 
    1426             : 
    1427           0 : sal_Bool SfxLinkUndoAction::CanRepeat(SfxRepeatTarget& r) const
    1428             : {
    1429           0 :     return pAction && pAction->CanRepeat(r);
    1430             : }
    1431             : 
    1432             : 
    1433             : //------------------------------------------------------------------------
    1434             : 
    1435             : 
    1436           0 : void SfxLinkUndoAction::Repeat(SfxRepeatTarget&r)
    1437             : {
    1438           0 :     if ( pAction && pAction->CanRepeat( r ) )
    1439           0 :         pAction->Repeat( r );
    1440           0 : }
    1441             : 
    1442             : 
    1443             : //------------------------------------------------------------------------
    1444             : 
    1445           0 : OUString SfxLinkUndoAction::GetComment() const
    1446             : {
    1447           0 :     if ( pAction )
    1448           0 :         return pAction->GetComment();
    1449           0 :     return OUString();
    1450             : }
    1451             : 
    1452             : 
    1453             : //------------------------------------------------------------------------
    1454             : 
    1455           0 : OUString SfxLinkUndoAction::GetRepeatComment(SfxRepeatTarget&r) const
    1456             : {
    1457           0 :     if ( pAction )
    1458           0 :         return pAction->GetRepeatComment(r);
    1459           0 :     return OUString();
    1460             : }
    1461             : 
    1462             : //------------------------------------------------------------------------
    1463             : 
    1464           0 : SfxLinkUndoAction::~SfxLinkUndoAction()
    1465             : {
    1466           0 :     if( pAction )
    1467           0 :         pAction->SetLinked( sal_False );
    1468           0 : }
    1469             : 
    1470             : 
    1471             : //------------------------------------------------------------------------
    1472             : 
    1473       91596 : SfxUndoArray::~SfxUndoArray()
    1474             : {
    1475      113466 :     while ( !aUndoActions.empty() )
    1476             :     {
    1477       21870 :         SfxUndoAction *pAction = aUndoActions[ aUndoActions.size() - 1 ].pAction;
    1478       21870 :         aUndoActions.Remove( aUndoActions.size() - 1 );
    1479       21870 :         delete pAction;
    1480             :     }
    1481       45798 : }
    1482             : 
    1483             : 
    1484           0 : sal_uInt16 SfxLinkUndoAction::GetId() const
    1485             : {
    1486           0 :       return pAction ? pAction->GetId() : 0;
    1487         111 : }
    1488             : 
    1489             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10