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

Generated by: LCOV version 1.10