LCOV - code coverage report
Current view: top level - svl/source/undo - undo.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 451 595 75.8 %
Date: 2014-04-11 Functions: 90 136 66.2 %
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          24 : TYPEINIT0(SfxRepeatTarget);
      39             : 
      40             : 
      41        5803 : SfxRepeatTarget::~SfxRepeatTarget()
      42             : {
      43        5803 : }
      44             : 
      45             : 
      46          30 : SfxUndoContext::~SfxUndoContext()
      47             : {
      48          30 : }
      49             : 
      50             : 
      51           0 : void SfxUndoAction::SetLinkToSfxLinkUndoAction(SfxLinkUndoAction* pSfxLinkUndoAction)
      52             : {
      53           0 :     mpSfxLinkUndoAction = pSfxLinkUndoAction;
      54           0 : }
      55             : 
      56             : 
      57      210404 : SfxUndoAction::~SfxUndoAction()
      58             : {
      59      210404 :     if(mpSfxLinkUndoAction)
      60             :     {
      61           0 :         mpSfxLinkUndoAction->LinkedSfxUndoActionDestructed(*this);
      62           0 :         mpSfxLinkUndoAction = 0;
      63             :     }
      64      210404 : }
      65             : 
      66             : 
      67      213567 : SfxUndoAction::SfxUndoAction()
      68      213567 : :   mpSfxLinkUndoAction(0)
      69             : {
      70      213567 : }
      71             : 
      72             : 
      73           0 : bool SfxUndoAction::Merge( SfxUndoAction * )
      74             : {
      75           0 :     return false;
      76             : }
      77             : 
      78             : 
      79          94 : OUString SfxUndoAction::GetComment() const
      80             : {
      81          94 :     return OUString();
      82             : }
      83             : 
      84             : 
      85             : 
      86           3 : sal_uInt16 SfxUndoAction::GetId() const
      87             : {
      88           3 :     return 0;
      89             : }
      90             : 
      91             : 
      92          36 : OUString SfxUndoAction::GetRepeatComment(SfxRepeatTarget&) const
      93             : {
      94          36 :     return GetComment();
      95             : }
      96             : 
      97             : 
      98           0 : void SfxUndoAction::Undo()
      99             : {
     100             :     // die sind nur konzeptuell pure virtual
     101             :     OSL_FAIL( "pure virtual function called: SfxUndoAction::Undo()" );
     102           0 : }
     103             : 
     104             : 
     105          25 : void SfxUndoAction::UndoWithContext( SfxUndoContext& i_context )
     106             : {
     107             :     (void)i_context;
     108          25 :     Undo();
     109          23 : }
     110             : 
     111             : 
     112           0 : void SfxUndoAction::Redo()
     113             : {
     114             :     // die sind nur konzeptuell pure virtual
     115             :     OSL_FAIL( "pure virtual function called: SfxUndoAction::Redo()" );
     116           0 : }
     117             : 
     118             : 
     119           2 : void SfxUndoAction::RedoWithContext( SfxUndoContext& i_context )
     120             : {
     121             :     (void)i_context;
     122           2 :     Redo();
     123           0 : }
     124             : 
     125             : 
     126           0 : void SfxUndoAction::Repeat(SfxRepeatTarget&)
     127             : {
     128             :     // die sind nur konzeptuell pure virtual
     129             :     OSL_FAIL( "pure virtual function called: SfxUndoAction::Repeat()" );
     130           0 : }
     131             : 
     132             : 
     133             : 
     134           0 : bool SfxUndoAction::CanRepeat(SfxRepeatTarget&) const
     135             : {
     136           0 :     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       21870 :     SfxUndoManager_Data( size_t i_nMaxUndoActionCount )
     158       21870 :         :pUndoArray( new SfxUndoArray( i_nMaxUndoActionCount ) )
     159             :         ,pActUndoArray( NULL )
     160             :         ,pFatherUndoArray( NULL )
     161             :         ,mnMarks( 0 )
     162       21870 :         ,mnEmptyMark(MARK_INVALID)
     163             :         ,mbUndoEnabled( true )
     164             :         ,mbDoing( false )
     165       65610 :         ,mbClearUntilTopLevel( false )
     166             :     {
     167       21870 :         pActUndoArray = pUndoArray;
     168       21870 :     }
     169             : 
     170       20088 :     ~SfxUndoManager_Data()
     171       20088 :     {
     172       20088 :         delete pUndoArray;
     173       20088 :     }
     174             : };
     175             : 
     176             : 
     177             : namespace svl { namespace undo { namespace impl
     178             : {
     179             :     class SVL_DLLPRIVATE LockGuard
     180             :     {
     181             :     public:
     182         230 :         LockGuard( SfxUndoManager& i_manager )
     183         230 :             :m_manager( i_manager )
     184             :         {
     185         230 :             m_manager.ImplEnableUndo_Lock( false );
     186         230 :         }
     187             : 
     188         230 :         ~LockGuard()
     189             :         {
     190         230 :             m_manager.ImplEnableUndo_Lock( true );
     191         230 :         }
     192             : 
     193             :     private:
     194             :         SfxUndoManager& m_manager;
     195             :     };
     196             : 
     197             :     typedef void ( SfxUndoListener::*UndoListenerVoidMethod )();
     198             :     typedef void ( SfxUndoListener::*UndoListenerStringMethod )( const OUString& );
     199             : 
     200    16495943 :     struct SVL_DLLPRIVATE NotifyUndoListener : public ::std::unary_function< SfxUndoListener*, void >
     201             :     {
     202     2116106 :         NotifyUndoListener( UndoListenerVoidMethod i_notificationMethod )
     203             :             :m_notificationMethod( i_notificationMethod )
     204             :             ,m_altNotificationMethod( NULL )
     205     2116106 :             ,m_sActionComment()
     206             :         {
     207     2116106 :         }
     208             : 
     209      251943 :         NotifyUndoListener( UndoListenerStringMethod i_notificationMethod, const OUString& i_actionComment )
     210             :             :m_notificationMethod( NULL )
     211             :             ,m_altNotificationMethod( i_notificationMethod )
     212      251943 :             ,m_sActionComment( i_actionComment )
     213             :         {
     214      251943 :         }
     215             : 
     216     2347949 :         bool is() const
     217             :         {
     218     2347949 :             return ( m_notificationMethod != 0 ) || ( m_altNotificationMethod != 0 );
     219             :         }
     220             : 
     221        4902 :         void operator()( SfxUndoListener* i_listener ) const
     222             :         {
     223             :             OSL_PRECOND( is(), "NotifyUndoListener: this will crash!" );
     224        4902 :             if ( m_altNotificationMethod != 0 )
     225             :             {
     226        4792 :                 ( i_listener->*m_altNotificationMethod )( m_sActionComment );
     227             :             }
     228             :             else
     229             :             {
     230         110 :                 ( i_listener->*m_notificationMethod )();
     231             :             }
     232        4902 :         }
     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     4031284 :         UndoManagerGuard( SfxUndoManager_Data& i_managerData )
     244             :             :m_rManagerData( i_managerData )
     245             :             ,m_aGuard( i_managerData.aMutex )
     246     4031284 :             ,m_notifiers()
     247             :         {
     248     4031284 :         }
     249             : 
     250             :         ~UndoManagerGuard();
     251             : 
     252         230 :         void clear()
     253             :         {
     254         230 :             m_aGuard.clear();
     255         230 :         }
     256             : 
     257         230 :         void reset()
     258             :         {
     259         230 :             m_aGuard.reset();
     260         230 :         }
     261             : 
     262          64 :         void cancelNotifications()
     263             :         {
     264          64 :             m_notifiers.clear();
     265          64 :         }
     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      144336 :         void    markForDeletion( SfxUndoAction* i_action )
     273             :         {
     274             :             // remember
     275      144336 :             if ( i_action )
     276      144336 :                 m_aUndoActionsCleanup.push_back( i_action );
     277      144336 :         }
     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     2096018 :         void    scheduleNotification( UndoListenerVoidMethod i_notificationMethod )
     285             :         {
     286     2096018 :             m_notifiers.push_back( NotifyUndoListener( i_notificationMethod ) );
     287     2096018 :         }
     288             : 
     289      251943 :         void    scheduleNotification( UndoListenerStringMethod i_notificationMethod, const OUString& i_actionComment )
     290             :         {
     291      251943 :             m_notifiers.push_back( NotifyUndoListener( i_notificationMethod, i_actionComment ) );
     292      251943 :         }
     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     8062568 :     UndoManagerGuard::~UndoManagerGuard()
     302             :     {
     303             :         // copy members
     304     4031284 :         UndoListeners aListenersCopy( m_rManagerData.aListeners );
     305             : 
     306             :         // release mutex
     307     4031284 :         m_aGuard.clear();
     308             : 
     309             :         // delete all actions
     310     8206904 :         while ( !m_aUndoActionsCleanup.empty() )
     311             :         {
     312      144336 :             SfxUndoAction* pAction = m_aUndoActionsCleanup.front();
     313      144336 :             m_aUndoActionsCleanup.pop_front();
     314             :             try
     315             :             {
     316      144336 :                 delete pAction;
     317             :             }
     318             :             catch( const Exception& )
     319             :             {
     320             :                 DBG_UNHANDLED_EXCEPTION();
     321             :             }
     322             :         }
     323             : 
     324             :         // handle scheduled notification
     325    19137699 :         for (   ::std::list< NotifyUndoListener >::const_iterator notifier = m_notifiers.begin();
     326    12758466 :                 notifier != m_notifiers.end();
     327             :                 ++notifier
     328             :              )
     329             :         {
     330     2347949 :             if ( notifier->is() )
     331     2347949 :                 ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(), *notifier );
     332     4031284 :         }
     333     4031284 :     }
     334             : } } }
     335             : 
     336             : using namespace ::svl::undo::impl;
     337             : 
     338             : 
     339       21870 : SfxUndoManager::SfxUndoManager( size_t nMaxUndoActionCount )
     340       21870 :     :m_pData( new SfxUndoManager_Data( nMaxUndoActionCount ) )
     341             : {
     342       21870 : }
     343             : 
     344             : 
     345       40176 : SfxUndoManager::~SfxUndoManager()
     346             : {
     347       20088 :     UndoListeners aListenersCopy;
     348             :     {
     349       20088 :         UndoManagerGuard aGuard( *m_pData );
     350       20088 :         aListenersCopy = m_pData->aListeners;
     351             :     }
     352             : 
     353             :     ::std::for_each( aListenersCopy.begin(), aListenersCopy.end(),
     354       20088 :         NotifyUndoListener( &SfxUndoListener::undoManagerDying ) );
     355       20088 : }
     356             : 
     357             : 
     358       66173 : void SfxUndoManager::EnableUndo( bool i_enable )
     359             : {
     360       66173 :     UndoManagerGuard aGuard( *m_pData );
     361       66173 :     ImplEnableUndo_Lock( i_enable );
     362             : 
     363       66173 : }
     364             : 
     365             : 
     366       66633 : void SfxUndoManager::ImplEnableUndo_Lock( bool const i_enable )
     367             : {
     368       66633 :     if ( m_pData->mbUndoEnabled == i_enable )
     369      108351 :         return;
     370       24915 :     m_pData->mbUndoEnabled = i_enable;
     371             : }
     372             : 
     373             : 
     374     1524248 : bool SfxUndoManager::IsUndoEnabled() const
     375             : {
     376     1524248 :     UndoManagerGuard aGuard( *m_pData );
     377     1524248 :     return ImplIsUndoEnabled_Lock();
     378             : }
     379             : 
     380             : 
     381     1967169 : bool SfxUndoManager::ImplIsUndoEnabled_Lock() const
     382             : {
     383     1967169 :     return m_pData->mbUndoEnabled;
     384             : }
     385             : 
     386             : 
     387        4436 : void SfxUndoManager::SetMaxUndoActionCount( size_t nMaxUndoActionCount )
     388             : {
     389        4436 :     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        4436 :     long nNumToDelete = m_pData->pActUndoArray->aUndoActions.size() - nMaxUndoActionCount;
     397        8880 :     while ( nNumToDelete > 0 )
     398             :     {
     399           8 :         size_t nPos = m_pData->pActUndoArray->aUndoActions.size();
     400           8 :         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           8 :         if ( nNumToDelete > 0 && m_pData->pActUndoArray->nCurUndoAction > 0 )
     409             :         {
     410           8 :             SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[0].pAction;
     411           8 :             aGuard.markForDeletion( pAction );
     412           8 :             m_pData->pActUndoArray->aUndoActions.Remove(0);
     413           8 :             --m_pData->pActUndoArray->nCurUndoAction;
     414           8 :             --nNumToDelete;
     415             :         }
     416             : 
     417           8 :         if ( nPos == m_pData->pActUndoArray->aUndoActions.size() )
     418           0 :             break; // Cannot delete more entries
     419             :     }
     420             : 
     421        4436 :     m_pData->pActUndoArray->nMaxUndoActions = nMaxUndoActionCount;
     422        4436 : }
     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     2005149 : void SfxUndoManager::ImplClearCurrentLevel_NoNotify( UndoManagerGuard& i_guard )
     433             : {
     434             :     // clear array
     435     4057797 :     while ( !m_pData->pActUndoArray->aUndoActions.empty() )
     436             :     {
     437       47499 :         size_t deletePos = m_pData->pActUndoArray->aUndoActions.size() - 1;
     438       47499 :         SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ deletePos ].pAction;
     439       47499 :         i_guard.markForDeletion( pAction );
     440       47499 :         m_pData->pActUndoArray->aUndoActions.Remove( deletePos );
     441             :     }
     442             : 
     443     2005149 :     m_pData->pActUndoArray->nCurUndoAction = 0;
     444             : 
     445     2005149 :     m_pData->mnMarks = 0;
     446     2005149 :     m_pData->mnEmptyMark = MARK_INVALID;
     447     2005149 : }
     448             : 
     449             : 
     450     2003079 : void SfxUndoManager::Clear()
     451             : {
     452     2003079 :     UndoManagerGuard aGuard( *m_pData );
     453             : 
     454             :     OSL_ENSURE( !ImplIsInListAction_Lock(), "SfxUndoManager::Clear: suspicious call - do you really wish to clear the current level?" );
     455     2003079 :     ImplClearCurrentLevel_NoNotify( aGuard );
     456             : 
     457             :     // notify listeners
     458     2003079 :     aGuard.scheduleNotification( &SfxUndoListener::cleared );
     459     2003079 : }
     460             : 
     461             : 
     462        2006 : void SfxUndoManager::ClearAllLevels()
     463             : {
     464        2006 :     UndoManagerGuard aGuard( *m_pData );
     465        2006 :     ImplClearCurrentLevel_NoNotify( aGuard );
     466             : 
     467        2006 :     if ( ImplIsInListAction_Lock() )
     468             :     {
     469           0 :         m_pData->mbClearUntilTopLevel = true;
     470             :     }
     471             :     else
     472             :     {
     473        2006 :         aGuard.scheduleNotification( &SfxUndoListener::cleared );
     474        2006 :     }
     475        2006 : }
     476             : 
     477             : 
     478       17549 : void SfxUndoManager::ImplClearRedo_NoLock( bool const i_currentLevel )
     479             : {
     480       17549 :     UndoManagerGuard aGuard( *m_pData );
     481       17549 :     ImplClearRedo( aGuard, i_currentLevel );
     482       17549 : }
     483             : 
     484             : 
     485           3 : void SfxUndoManager::ClearRedo()
     486             : {
     487             :     OSL_ENSURE( !IsInListAction(), "SfxUndoManager::ClearRedo: suspicious call - do you really wish to clear the current level?" );
     488           3 :     ImplClearRedo_NoLock( CurrentLevel );
     489           3 : }
     490             : 
     491             : 
     492          64 : void SfxUndoManager::Reset()
     493             : {
     494          64 :     UndoManagerGuard aGuard( *m_pData );
     495             : 
     496             :     // clear all locks
     497         128 :     while ( !ImplIsUndoEnabled_Lock() )
     498           0 :         ImplEnableUndo_Lock( true );
     499             : 
     500             :     // cancel all list actions
     501         140 :     while ( IsInListAction() )
     502          12 :         ImplLeaveListAction( false, aGuard );
     503             : 
     504             :     // clear both stacks
     505          64 :     ImplClearCurrentLevel_NoNotify( aGuard );
     506             : 
     507             :     // cancel the notifications scheduled by ImplLeaveListAction,
     508             :     // as we want to do an own, dedicated notification
     509          64 :     aGuard.cancelNotifications();
     510             : 
     511             :     // schedule notification
     512          64 :     aGuard.scheduleNotification( &SfxUndoListener::resetAll );
     513          64 : }
     514             : 
     515             : 
     516           8 : void SfxUndoManager::ImplClearUndo( UndoManagerGuard& i_guard )
     517             : {
     518          24 :     while ( m_pData->pActUndoArray->nCurUndoAction > 0 )
     519             :     {
     520           8 :         SfxUndoAction* pUndoAction = m_pData->pActUndoArray->aUndoActions[0].pAction;
     521           8 :         m_pData->pActUndoArray->aUndoActions.Remove( 0 );
     522           8 :         i_guard.markForDeletion( pUndoAction );
     523           8 :         --m_pData->pActUndoArray->nCurUndoAction;
     524             :     }
     525             :     // TODO: notifications? We don't have clearedUndo, only cleared and clearedRedo at the SfxUndoListener
     526           8 : }
     527             : 
     528             : 
     529       62049 : void SfxUndoManager::ImplClearRedo( UndoManagerGuard& i_guard, bool const i_currentLevel )
     530             : {
     531       62049 :     SfxUndoArray* pUndoArray = ( i_currentLevel == IUndoManager::CurrentLevel ) ? m_pData->pActUndoArray : m_pData->pUndoArray;
     532             : 
     533             :     // clearance
     534      124133 :     while ( pUndoArray->aUndoActions.size() > pUndoArray->nCurUndoAction )
     535             :     {
     536          35 :         size_t deletePos = pUndoArray->aUndoActions.size() - 1;
     537          35 :         SfxUndoAction* pAction = pUndoArray->aUndoActions[ deletePos ].pAction;
     538          35 :         pUndoArray->aUndoActions.Remove( deletePos );
     539          35 :         i_guard.markForDeletion( pAction );
     540             :     }
     541             : 
     542             :     // notification - only if the top level's stack was cleared
     543       62049 :     if ( i_currentLevel == IUndoManager::TopLevel )
     544       17546 :         i_guard.scheduleNotification( &SfxUndoListener::clearedRedo );
     545       62049 : }
     546             : 
     547             : 
     548      207254 : bool SfxUndoManager::ImplAddUndoAction_NoNotify( SfxUndoAction *pAction, bool bTryMerge, bool bClearRedo, UndoManagerGuard& i_guard )
     549             : {
     550      207254 :     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      207254 :     SfxUndoAction* pMergeWithAction = m_pData->pActUndoArray->nCurUndoAction ?
     558      207254 :         m_pData->pActUndoArray->aUndoActions[m_pData->pActUndoArray->nCurUndoAction-1].pAction : NULL;
     559      207254 :     if ( bTryMerge && pMergeWithAction )
     560             :     {
     561           3 :         bool bMerged = pMergeWithAction->Merge( pAction );
     562           3 :         if ( bMerged )
     563             :         {
     564           3 :             i_guard.markForDeletion( pAction );
     565           3 :             return false;
     566             :         }
     567             :     }
     568             : 
     569             :     // clear redo stack, if requested
     570      207251 :     if ( bClearRedo && ( ImplGetRedoActionCount_Lock( CurrentLevel ) > 0 ) )
     571          14 :         ImplClearRedo( i_guard, IUndoManager::CurrentLevel );
     572             : 
     573             :     // respect max number
     574      207251 :     if( m_pData->pActUndoArray == m_pData->pUndoArray )
     575             :     {
     576      312236 :         while(m_pData->pActUndoArray->aUndoActions.size() >= m_pData->pActUndoArray->nMaxUndoActions)
     577             :         {
     578       23460 :             i_guard.markForDeletion( m_pData->pActUndoArray->aUndoActions[0].pAction );
     579       23460 :             m_pData->pActUndoArray->aUndoActions.Remove(0);
     580       23460 :             if (m_pData->pActUndoArray->nCurUndoAction > 0)
     581             :             {
     582       23460 :                 --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       23460 :             --m_pData->mnEmptyMark;
     590             :         }
     591             :     }
     592             : 
     593             :     // append new action
     594      207251 :     m_pData->pActUndoArray->aUndoActions.Insert( pAction, m_pData->pActUndoArray->nCurUndoAction++ );
     595      207251 :     return true;
     596             : }
     597             : 
     598             : 
     599       89452 : void SfxUndoManager::AddUndoAction( SfxUndoAction *pAction, bool bTryMerge )
     600             : {
     601       89452 :     UndoManagerGuard aGuard( *m_pData );
     602             : 
     603             :     // add
     604       89452 :     if ( ImplAddUndoAction_NoNotify( pAction, bTryMerge, true, aGuard ) )
     605             :     {
     606             :         // notify listeners
     607       89449 :         aGuard.scheduleNotification( &SfxUndoListener::undoActionAdded, pAction->GetComment() );
     608       89452 :     }
     609       89452 : }
     610             : 
     611             : 
     612       10102 : size_t SfxUndoManager::GetUndoActionCount( bool const i_currentLevel ) const
     613             : {
     614       10102 :     UndoManagerGuard aGuard( *m_pData );
     615       10102 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     616       10102 :     return pUndoArray->nCurUndoAction;
     617             : }
     618             : 
     619             : 
     620         237 : OUString SfxUndoManager::GetUndoActionComment( size_t nNo, bool const i_currentLevel ) const
     621             : {
     622         237 :     UndoManagerGuard aGuard( *m_pData );
     623             : 
     624         237 :     OUString sComment;
     625         237 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     626             :     DBG_ASSERT( nNo < pUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoActionComment: illegal index!" );
     627         237 :     if( nNo < pUndoArray->nCurUndoAction )
     628         237 :         sComment = pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction - 1 - nNo ].pAction->GetComment();
     629         237 :     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       13228 : SfxUndoAction* SfxUndoManager::GetUndoAction( size_t nNo ) const
     645             : {
     646       13228 :     UndoManagerGuard aGuard( *m_pData );
     647             : 
     648             :     DBG_ASSERT( nNo < m_pData->pActUndoArray->nCurUndoAction, "svl::SfxUndoManager::GetUndoAction(), illegal id!" );
     649       13228 :     if( nNo >= m_pData->pActUndoArray->nCurUndoAction )
     650           0 :         return NULL;
     651       13228 :     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        1268 : bool SfxUndoManager::IsDoing() const
     677             : {
     678        1268 :     UndoManagerGuard aGuard( *m_pData );
     679        1268 :     return m_pData->mbDoing;
     680             : }
     681             : 
     682             : 
     683         185 : bool SfxUndoManager::Undo()
     684             : {
     685         185 :     return ImplUndo( NULL );
     686             : }
     687             : 
     688             : 
     689          26 : bool SfxUndoManager::UndoWithContext( SfxUndoContext& i_context )
     690             : {
     691          26 :     return ImplUndo( &i_context );
     692             : }
     693             : 
     694             : 
     695         211 : bool SfxUndoManager::ImplUndo( SfxUndoContext* i_contextOrNull )
     696             : {
     697         211 :     UndoManagerGuard aGuard( *m_pData );
     698             :     OSL_ENSURE( !IsDoing(), "SfxUndoManager::Undo: *nested* Undo/Redo actions? How this?" );
     699             : 
     700         422 :     ::comphelper::FlagGuard aDoingGuard( m_pData->mbDoing );
     701         422 :     LockGuard aLockGuard( *this );
     702             : 
     703         211 :     if ( ImplIsInListAction_Lock() )
     704             :     {
     705             :         OSL_ENSURE( false, "SfxUndoManager::Undo: not possible when within a list action!" );
     706           0 :         return false;
     707             :     }
     708             : 
     709         211 :     if ( m_pData->pActUndoArray->nCurUndoAction == 0 )
     710             :     {
     711             :         OSL_ENSURE( false, "SfxUndoManager::Undo: undo stack is empty!" );
     712           0 :         return false;
     713             :     }
     714             : 
     715         211 :     SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ --m_pData->pActUndoArray->nCurUndoAction ].pAction;
     716         422 :     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         211 :         aGuard.clear();
     722         211 :         if ( i_contextOrNull != NULL )
     723          26 :             pAction->UndoWithContext( *i_contextOrNull );
     724             :         else
     725         185 :             pAction->Undo();
     726         203 :         aGuard.reset();
     727             :     }
     728           8 :     catch( ... )
     729             :     {
     730           8 :         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           8 :         size_t nCurAction = 0;
     735          24 :         while ( nCurAction < m_pData->pActUndoArray->aUndoActions.size() )
     736             :         {
     737          16 :             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           8 :                 ImplClearUndo( aGuard );
     742           8 :                 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         203 :     aGuard.scheduleNotification( &SfxUndoListener::actionUndone, sActionComment );
     750             : 
     751         414 :     return true;
     752             : }
     753             : 
     754             : 
     755        2674 : size_t SfxUndoManager::GetRedoActionCount( bool const i_currentLevel ) const
     756             : {
     757        2674 :     UndoManagerGuard aGuard( *m_pData );
     758        2674 :     return ImplGetRedoActionCount_Lock( i_currentLevel );
     759             : }
     760             : 
     761             : 
     762       92123 : size_t SfxUndoManager::ImplGetRedoActionCount_Lock( bool const i_currentLevel ) const
     763             : {
     764       92123 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     765       92123 :     return pUndoArray->aUndoActions.size() - pUndoArray->nCurUndoAction;
     766             : }
     767             : 
     768             : 
     769           3 : SfxUndoAction* SfxUndoManager::GetRedoAction( size_t nNo, bool const i_currentLevel ) const
     770             : {
     771           3 :     UndoManagerGuard aGuard( *m_pData );
     772             : 
     773           3 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     774           3 :     if ( (pUndoArray->nCurUndoAction + nNo) > pUndoArray->aUndoActions.size() )
     775             :     {
     776           0 :         return NULL;
     777             :     }
     778           3 :     return pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction + nNo ].pAction;
     779             : }
     780             : 
     781             : 
     782          56 : OUString SfxUndoManager::GetRedoActionComment( size_t nNo, bool const i_currentLevel ) const
     783             : {
     784          56 :     OUString sComment;
     785         112 :     UndoManagerGuard aGuard( *m_pData );
     786          56 :     const SfxUndoArray* pUndoArray = i_currentLevel ? m_pData->pActUndoArray : m_pData->pUndoArray;
     787          56 :     if ( (pUndoArray->nCurUndoAction + nNo) < pUndoArray->aUndoActions.size() )
     788             :     {
     789          56 :         sComment = pUndoArray->aUndoActions[ pUndoArray->nCurUndoAction + nNo ].pAction->GetComment();
     790             :     }
     791         112 :     return sComment;
     792             : }
     793             : 
     794             : 
     795          16 : bool SfxUndoManager::Redo()
     796             : {
     797          16 :     return ImplRedo( NULL );
     798             : }
     799             : 
     800             : 
     801           3 : bool SfxUndoManager::RedoWithContext( SfxUndoContext& i_context )
     802             : {
     803           3 :     return ImplRedo( &i_context );
     804             : }
     805             : 
     806             : 
     807          19 : bool SfxUndoManager::ImplRedo( SfxUndoContext* i_contextOrNull )
     808             : {
     809          19 :     UndoManagerGuard aGuard( *m_pData );
     810             :     OSL_ENSURE( !IsDoing(), "SfxUndoManager::Redo: *nested* Undo/Redo actions? How this?" );
     811             : 
     812          38 :     ::comphelper::FlagGuard aDoingGuard( m_pData->mbDoing );
     813          38 :     LockGuard aLockGuard( *this );
     814             : 
     815          19 :     if ( ImplIsInListAction_Lock() )
     816             :     {
     817             :         OSL_ENSURE( false, "SfxUndoManager::Redo: not possible when within a list action!" );
     818           0 :         return false;
     819             :     }
     820             : 
     821          19 :     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          19 :     SfxUndoAction* pAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction++ ].pAction;
     828          38 :     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          19 :         aGuard.clear();
     834          19 :         if ( i_contextOrNull != NULL )
     835           3 :             pAction->RedoWithContext( *i_contextOrNull );
     836             :         else
     837          16 :             pAction->Redo();
     838          11 :         aGuard.reset();
     839             :     }
     840           8 :     catch( ... )
     841             :     {
     842           8 :         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           8 :         size_t nCurAction = 0;
     847          24 :         while ( nCurAction < m_pData->pActUndoArray->aUndoActions.size() )
     848             :         {
     849          16 :             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           8 :                 ImplClearRedo( aGuard, IUndoManager::CurrentLevel );
     854           8 :                 throw;
     855             :             }
     856           8 :             ++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          11 :     aGuard.scheduleNotification( &SfxUndoListener::actionRedone, sActionComment );
     863             : 
     864          30 :     return true;
     865             : }
     866             : 
     867             : 
     868         754 : size_t SfxUndoManager::GetRepeatActionCount() const
     869             : {
     870         754 :     UndoManagerGuard aGuard( *m_pData );
     871         754 :     return m_pData->pActUndoArray->aUndoActions.size();
     872             : }
     873             : 
     874             : 
     875          38 : OUString SfxUndoManager::GetRepeatActionComment(SfxRepeatTarget &rTarget) const
     876             : {
     877          38 :     UndoManagerGuard aGuard( *m_pData );
     878          38 :     return m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->aUndoActions.size() - 1 ].pAction
     879          38 :         ->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         100 : bool SfxUndoManager::CanRepeat( SfxRepeatTarget &rTarget ) const
     900             : {
     901         100 :     UndoManagerGuard aGuard( *m_pData );
     902         100 :     if ( !m_pData->pActUndoArray->aUndoActions.empty() )
     903             :     {
     904         100 :         size_t nActionNo = m_pData->pActUndoArray->aUndoActions.size() - 1;
     905         100 :         return m_pData->pActUndoArray->aUndoActions[nActionNo].pAction->CanRepeat(rTarget);
     906             :     }
     907           0 :     return false;
     908             : }
     909             : 
     910             : 
     911          51 : void SfxUndoManager::AddUndoListener( SfxUndoListener& i_listener )
     912             : {
     913          51 :     UndoManagerGuard aGuard( *m_pData );
     914          51 :     m_pData->aListeners.push_back( &i_listener );
     915          51 : }
     916             : 
     917             : 
     918          50 : void SfxUndoManager::RemoveUndoListener( SfxUndoListener& i_listener )
     919             : {
     920          50 :     UndoManagerGuard aGuard( *m_pData );
     921         150 :     for (   UndoListeners::iterator lookup = m_pData->aListeners.begin();
     922         100 :             lookup != m_pData->aListeners.end();
     923             :             ++lookup
     924             :         )
     925             :     {
     926          50 :         if ( (*lookup) == &i_listener )
     927             :         {
     928          50 :             m_pData->aListeners.erase( lookup );
     929          50 :             break;
     930             :         }
     931          50 :     }
     932          50 : }
     933             : 
     934             : 
     935      117802 : void SfxUndoManager::EnterListAction( const OUString& rComment,
     936             :                                       const OUString &rRepeatComment, sal_uInt16 nId )
     937             : 
     938             : /*  [Beschreibung]
     939             : 
     940             :     Fuegt eine ListUndoAction ein und setzt dessen UndoArray als aktuelles.
     941             : */
     942             : 
     943             : {
     944      117802 :     UndoManagerGuard aGuard( *m_pData );
     945             : 
     946      117802 :     if( !ImplIsUndoEnabled_Lock() )
     947           0 :         return;
     948             : 
     949      117802 :     if ( !m_pData->pUndoArray->nMaxUndoActions )
     950           0 :         return;
     951             : 
     952      117802 :     m_pData->pFatherUndoArray = m_pData->pActUndoArray;
     953      117802 :     SfxListUndoAction* pAction = new SfxListUndoAction( rComment, rRepeatComment, nId, m_pData->pActUndoArray );
     954      117802 :     OSL_VERIFY( ImplAddUndoAction_NoNotify( pAction, false, false, aGuard ) );
     955             :         // expected to succeed: all conditions under which it could fail should have been checked already
     956      117802 :     m_pData->pActUndoArray = pAction;
     957             : 
     958             :     // notification
     959      117802 :     aGuard.scheduleNotification( &SfxUndoListener::listActionEntered, rComment );
     960             : }
     961             : 
     962             : 
     963        5826 : bool SfxUndoManager::IsInListAction() const
     964             : {
     965        5826 :     UndoManagerGuard aGuard( *m_pData );
     966        5826 :     return ImplIsInListAction_Lock();
     967             : }
     968             : 
     969             : 
     970      125863 : bool SfxUndoManager::ImplIsInListAction_Lock() const
     971             : {
     972      125863 :     return ( m_pData->pActUndoArray != m_pData->pUndoArray );
     973             : }
     974             : 
     975             : 
     976        4627 : size_t SfxUndoManager::GetListActionDepth() const
     977             : {
     978        4627 :     UndoManagerGuard aGuard( *m_pData );
     979        4627 :     size_t nDepth(0);
     980             : 
     981        4627 :     SfxUndoArray* pLookup( m_pData->pActUndoArray );
     982        9509 :     while ( pLookup != m_pData->pUndoArray )
     983             :     {
     984         255 :         pLookup = pLookup->pFatherUndoArray;
     985         255 :         ++nDepth;
     986             :     }
     987             : 
     988        4627 :     return nDepth;
     989             : }
     990             : 
     991             : 
     992      117773 : size_t SfxUndoManager::LeaveListAction()
     993             : {
     994      117773 :     UndoManagerGuard aGuard( *m_pData );
     995      117773 :     size_t nCount = ImplLeaveListAction( false, aGuard );
     996             : 
     997      117773 :     if ( m_pData->mbClearUntilTopLevel )
     998             :     {
     999           0 :         ImplClearCurrentLevel_NoNotify( aGuard );
    1000           0 :         if ( !ImplIsInListAction_Lock() )
    1001             :         {
    1002           0 :             m_pData->mbClearUntilTopLevel = false;
    1003           0 :             aGuard.scheduleNotification( &SfxUndoListener::cleared );
    1004             :         }
    1005           0 :         nCount = 0;
    1006             :     }
    1007             : 
    1008      117773 :     return nCount;
    1009             : }
    1010             : 
    1011             : 
    1012          16 : size_t SfxUndoManager::LeaveAndMergeListAction()
    1013             : {
    1014          16 :     UndoManagerGuard aGuard( *m_pData );
    1015          16 :     return ImplLeaveListAction( true, aGuard );
    1016             : }
    1017             : 
    1018             : 
    1019      117801 : size_t SfxUndoManager::ImplLeaveListAction( const bool i_merge, UndoManagerGuard& i_guard )
    1020             : {
    1021      117801 :     if ( !ImplIsUndoEnabled_Lock() )
    1022           0 :         return 0;
    1023             : 
    1024      117801 :     if ( !m_pData->pUndoArray->nMaxUndoActions )
    1025           0 :         return 0;
    1026             : 
    1027      117801 :     if( !ImplIsInListAction_Lock() )
    1028             :     {
    1029             :         OSL_TRACE( "svl::SfxUndoManager::ImplLeaveListAction, called without calling EnterListAction()!" );
    1030           0 :         return 0;
    1031             :     }
    1032             : 
    1033             :     DBG_ASSERT( m_pData->pActUndoArray->pFatherUndoArray, "SfxUndoManager::ImplLeaveListAction, no father undo array!?" );
    1034             : 
    1035             :     // the array/level which we're about to leave
    1036      117801 :     SfxUndoArray* pArrayToLeave = m_pData->pActUndoArray;
    1037             :     // one step up
    1038      117801 :     m_pData->pActUndoArray = m_pData->pActUndoArray->pFatherUndoArray;
    1039             : 
    1040             :     // If no undo actions were added to the list, delete the list action
    1041      117801 :     const size_t nListActionElements = pArrayToLeave->nCurUndoAction;
    1042      117801 :     if ( nListActionElements == 0 )
    1043             :     {
    1044       73323 :         SfxUndoAction* pCurrentAction= m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction-1 ].pAction;
    1045       73323 :         m_pData->pActUndoArray->aUndoActions.Remove( --m_pData->pActUndoArray->nCurUndoAction );
    1046       73323 :         i_guard.markForDeletion( pCurrentAction );
    1047             : 
    1048       73323 :         i_guard.scheduleNotification( &SfxUndoListener::listActionCancelled );
    1049       73323 :         return 0;
    1050             :     }
    1051             : 
    1052             :     // now that it is finally clear the list action is non-trivial, and does participate in the Undo stack, clear
    1053             :     // the redo stack
    1054       44478 :     ImplClearRedo( i_guard, IUndoManager::CurrentLevel );
    1055             : 
    1056       44478 :     SfxUndoAction* pCurrentAction= m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction-1 ].pAction;
    1057       44478 :     SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction * >( pCurrentAction );
    1058       44478 :     ENSURE_OR_RETURN( pListAction, "SfxUndoManager::ImplLeaveListAction: list action expected at this position!", nListActionElements );
    1059             : 
    1060       44478 :     if ( i_merge )
    1061             :     {
    1062             :         // merge the list action with its predecessor on the same level
    1063             :         OSL_ENSURE( m_pData->pActUndoArray->nCurUndoAction > 1,
    1064             :             "SfxUndoManager::ImplLeaveListAction: cannot merge the list action if there's no other action on the same level - check this beforehand!" );
    1065           8 :         if ( m_pData->pActUndoArray->nCurUndoAction > 1 )
    1066             :         {
    1067           8 :             SfxUndoAction* pPreviousAction = m_pData->pActUndoArray->aUndoActions[ m_pData->pActUndoArray->nCurUndoAction - 2 ].pAction;
    1068           8 :             m_pData->pActUndoArray->aUndoActions.Remove( m_pData->pActUndoArray->nCurUndoAction - 2 );
    1069           8 :             --m_pData->pActUndoArray->nCurUndoAction;
    1070           8 :             pListAction->aUndoActions.Insert( pPreviousAction, 0 );
    1071           8 :             ++pListAction->nCurUndoAction;
    1072             : 
    1073           8 :             pListAction->SetComment( pPreviousAction->GetComment() );
    1074             :         }
    1075             :     }
    1076             : 
    1077             :     // if the undo array has no comment, try to get it from its children
    1078       44478 :     if ( pListAction->GetComment().isEmpty() )
    1079             :     {
    1080          41 :         for( size_t n = 0; n < pListAction->aUndoActions.size(); n++ )
    1081             :         {
    1082          41 :             if (!pListAction->aUndoActions[n].pAction->GetComment().isEmpty())
    1083             :             {
    1084          21 :                 pListAction->SetComment( pListAction->aUndoActions[n].pAction->GetComment() );
    1085          21 :                 break;
    1086             :             }
    1087             :         }
    1088             :     }
    1089             : 
    1090             :     // notify listeners
    1091       44478 :     i_guard.scheduleNotification( &SfxUndoListener::listActionLeft, pListAction->GetComment() );
    1092             : 
    1093             :     // outta here
    1094       44478 :     return nListActionElements;
    1095             : }
    1096             : 
    1097       29313 : UndoStackMark SfxUndoManager::MarkTopUndoAction()
    1098             : {
    1099       29313 :     UndoManagerGuard aGuard( *m_pData );
    1100             : 
    1101             :     OSL_ENSURE( !IsInListAction(),
    1102             :             "SfxUndoManager::MarkTopUndoAction(): suspicious call!" );
    1103             :     OSL_ENSURE((m_pData->mnMarks + 1) < (m_pData->mnEmptyMark - 1),
    1104             :             "SfxUndoManager::MarkTopUndoAction(): mark overflow!");
    1105             : 
    1106       29313 :     size_t const nActionPos = m_pData->pUndoArray->nCurUndoAction;
    1107       29313 :     if (0 == nActionPos)
    1108             :     {
    1109       29115 :         --m_pData->mnEmptyMark;
    1110       29115 :         return m_pData->mnEmptyMark;
    1111             :     }
    1112             : 
    1113         198 :     m_pData->pUndoArray->aUndoActions[ nActionPos-1 ].aMarks.push_back(
    1114         396 :             ++m_pData->mnMarks );
    1115         198 :     return m_pData->mnMarks;
    1116             : }
    1117             : 
    1118          16 : void SfxUndoManager::RemoveMark( UndoStackMark const i_mark )
    1119             : {
    1120          16 :     UndoManagerGuard aGuard( *m_pData );
    1121             : 
    1122          16 :     if ((m_pData->mnEmptyMark < i_mark) || (MARK_INVALID == i_mark))
    1123             :     {
    1124           0 :         return; // nothing to remove
    1125             :     }
    1126          16 :     else if (i_mark == m_pData->mnEmptyMark)
    1127             :     {
    1128          16 :         --m_pData->mnEmptyMark; // never returned from MarkTop => invalid
    1129          16 :         return;
    1130             :     }
    1131             : 
    1132           0 :     for ( size_t i=0; i<m_pData->pUndoArray->aUndoActions.size(); ++i )
    1133             :     {
    1134           0 :         MarkedUndoAction& rAction = m_pData->pUndoArray->aUndoActions[i];
    1135           0 :         for (   ::std::vector< UndoStackMark >::iterator markPos = rAction.aMarks.begin();
    1136           0 :                 markPos != rAction.aMarks.end();
    1137             :                 ++markPos
    1138             :             )
    1139             :         {
    1140           0 :             if ( *markPos == i_mark )
    1141             :             {
    1142           0 :                 rAction.aMarks.erase( markPos );
    1143           0 :                 return;
    1144             :             }
    1145             :         }
    1146             :     }
    1147           0 :     OSL_ENSURE( false, "SfxUndoManager::RemoveMark: mark not found!" );
    1148             :         // TODO: this might be too offensive. There are situations where we implicitly remove marks
    1149             :         // without our clients, in particular the client which created the mark, having a chance to know
    1150             :         // about this.
    1151             : }
    1152             : 
    1153          25 : bool SfxUndoManager::HasTopUndoActionMark( UndoStackMark const i_mark )
    1154             : {
    1155          25 :     UndoManagerGuard aGuard( *m_pData );
    1156             : 
    1157          25 :     size_t nActionPos = m_pData->pUndoArray->nCurUndoAction;
    1158          25 :     if ( nActionPos == 0 )
    1159             :     {
    1160           7 :         return (i_mark == m_pData->mnEmptyMark);
    1161             :     }
    1162             : 
    1163             :     const MarkedUndoAction& rAction =
    1164          18 :             m_pData->pUndoArray->aUndoActions[ nActionPos-1 ];
    1165          54 :     for (   ::std::vector< UndoStackMark >::const_iterator markPos = rAction.aMarks.begin();
    1166          36 :             markPos != rAction.aMarks.end();
    1167             :             ++markPos
    1168             :         )
    1169             :     {
    1170           0 :         if ( *markPos == i_mark )
    1171           0 :             return true;
    1172             :     }
    1173             : 
    1174          18 :     return false;
    1175             : }
    1176             : 
    1177             : 
    1178           0 : void SfxUndoManager::RemoveOldestUndoActions( size_t const i_count )
    1179             : {
    1180           0 :     UndoManagerGuard aGuard( *m_pData );
    1181             : 
    1182           0 :     size_t nActionsToRemove = i_count;
    1183           0 :     while ( nActionsToRemove )
    1184             :     {
    1185           0 :         SfxUndoAction* pActionToRemove = m_pData->pUndoArray->aUndoActions[0].pAction;
    1186             : 
    1187           0 :         if ( IsInListAction() && ( m_pData->pUndoArray->nCurUndoAction == 1 ) )
    1188             :         {
    1189             :             OSL_ENSURE( false, "SfxUndoManager::RemoveOldestUndoActions: cannot remove a not-yet-closed list action!" );
    1190           0 :             return;
    1191             :         }
    1192             : 
    1193           0 :         aGuard.markForDeletion( pActionToRemove );
    1194           0 :         m_pData->pUndoArray->aUndoActions.Remove( 0 );
    1195           0 :         --m_pData->pUndoArray->nCurUndoAction;
    1196           0 :         --nActionsToRemove;
    1197           0 :     }
    1198             : }
    1199             : 
    1200             : 
    1201        2854 : sal_uInt16 SfxListUndoAction::GetId() const
    1202             : {
    1203        2854 :     return nId;
    1204             : }
    1205             : 
    1206             : 
    1207       89223 : OUString SfxListUndoAction::GetComment() const
    1208             : {
    1209       89223 :     return aComment;
    1210             : }
    1211             : 
    1212             : 
    1213        5281 : void SfxListUndoAction::SetComment(const OUString& rComment)
    1214             : {
    1215        5281 :     aComment = rComment;
    1216        5281 : }
    1217             : 
    1218             : 
    1219           2 : OUString SfxListUndoAction::GetRepeatComment(SfxRepeatTarget &) const
    1220             : {
    1221           2 :     return aRepeatComment;
    1222             : }
    1223             : 
    1224             : 
    1225             : 
    1226      117802 : SfxListUndoAction::SfxListUndoAction
    1227             : (
    1228             :     const OUString &rComment,
    1229             :     const OUString &rRepeatComment,
    1230             :     sal_uInt16 Id,
    1231             :     SfxUndoArray *pFather
    1232             : )
    1233      117802 : : nId(Id), aComment(rComment), aRepeatComment(rRepeatComment)
    1234             : {
    1235      117802 :     pFatherUndoArray = pFather;
    1236      117802 :     nMaxUndoActions = USHRT_MAX;
    1237      117802 : }
    1238             : 
    1239             : 
    1240          31 : void SfxListUndoAction::Undo()
    1241             : {
    1242         116 :     for(size_t i=nCurUndoAction;i>0;)
    1243          54 :         aUndoActions[--i].pAction->Undo();
    1244          31 :     nCurUndoAction=0;
    1245          31 : }
    1246             : 
    1247             : 
    1248          16 : void SfxListUndoAction::UndoWithContext( SfxUndoContext& i_context )
    1249             : {
    1250          56 :     for(size_t i=nCurUndoAction;i>0;)
    1251          24 :         aUndoActions[--i].pAction->UndoWithContext( i_context );
    1252          16 :     nCurUndoAction=0;
    1253          16 : }
    1254             : 
    1255             : 
    1256           2 : void SfxListUndoAction::Redo()
    1257             : {
    1258           4 :     for(size_t i=nCurUndoAction;i<aUndoActions.size();i++)
    1259           2 :         aUndoActions[i].pAction->Redo();
    1260           2 :     nCurUndoAction = aUndoActions.size();
    1261           2 : }
    1262             : 
    1263             : 
    1264           2 : void SfxListUndoAction::RedoWithContext( SfxUndoContext& i_context )
    1265             : {
    1266           4 :     for(size_t i=nCurUndoAction;i<aUndoActions.size();i++)
    1267           2 :         aUndoActions[i].pAction->RedoWithContext( i_context );
    1268           2 :     nCurUndoAction = aUndoActions.size();
    1269           2 : }
    1270             : 
    1271             : 
    1272           0 : void SfxListUndoAction::Repeat(SfxRepeatTarget&rTarget)
    1273             : {
    1274           0 :     for(size_t i=0;i<nCurUndoAction;i++)
    1275           0 :         aUndoActions[i].pAction->Repeat(rTarget);
    1276           0 : }
    1277             : 
    1278             : 
    1279           4 : bool SfxListUndoAction::CanRepeat(SfxRepeatTarget&r)  const
    1280             : {
    1281          10 :     for(size_t i=0;i<nCurUndoAction;i++)
    1282             :     {
    1283           6 :         if(!aUndoActions[i].pAction->CanRepeat(r))
    1284           0 :             return false;
    1285             :     }
    1286           4 :     return true;
    1287             : }
    1288             : 
    1289             : 
    1290           0 : bool SfxListUndoAction::Merge( SfxUndoAction *pNextAction )
    1291             : {
    1292           0 :     return !aUndoActions.empty() && aUndoActions[aUndoActions.size()-1].pAction->Merge( pNextAction );
    1293             : }
    1294             : 
    1295             : 
    1296           0 : SfxLinkUndoAction::SfxLinkUndoAction(::svl::IUndoManager *pManager)
    1297             : /*  [Beschreibung]
    1298             : 
    1299             :     Richtet eine LinkAction ein, die auf einen weiteren UndoManager zeigt.
    1300             :     Holt sich als zugehoerige Action des weiteren UndoManagers dessen
    1301             :     aktuelle Action.
    1302             : */
    1303             : 
    1304             : {
    1305           0 :     pUndoManager = pManager;
    1306           0 :     SfxUndoManager* pUndoManagerImplementation = dynamic_cast< SfxUndoManager* >( pManager );
    1307           0 :     ENSURE_OR_THROW( pUndoManagerImplementation != NULL, "unsupported undo manager implementation!" );
    1308             :         // yes, this cast is dirty. But reaching into the SfxUndoManager's implementation,
    1309             :         // directly accessing its internal stack, and tampering with an action on that stack
    1310             :         // is dirty, too.
    1311           0 :     if ( pManager->GetMaxUndoActionCount() )
    1312             :     {
    1313           0 :         size_t nPos = pManager->GetUndoActionCount()-1;
    1314           0 :         pAction = pUndoManagerImplementation->m_pData->pActUndoArray->aUndoActions[nPos].pAction;
    1315           0 :         pAction->SetLinkToSfxLinkUndoAction(this);
    1316             :     }
    1317             :     else
    1318           0 :         pAction = 0;
    1319           0 : }
    1320             : 
    1321             : 
    1322           0 : void SfxLinkUndoAction::Undo()
    1323             : {
    1324           0 :     if ( pAction )
    1325           0 :         pUndoManager->Undo();
    1326           0 : }
    1327             : 
    1328             : 
    1329           0 : void SfxLinkUndoAction::Redo()
    1330             : {
    1331           0 :     if ( pAction )
    1332           0 :         pUndoManager->Redo();
    1333           0 : }
    1334             : 
    1335             : 
    1336             : 
    1337           0 : bool SfxLinkUndoAction::CanRepeat(SfxRepeatTarget& r) const
    1338             : {
    1339           0 :     return pAction && pAction->CanRepeat(r);
    1340             : }
    1341             : 
    1342             : 
    1343             : 
    1344             : 
    1345           0 : void SfxLinkUndoAction::Repeat(SfxRepeatTarget&r)
    1346             : {
    1347           0 :     if ( pAction && pAction->CanRepeat( r ) )
    1348           0 :         pAction->Repeat( r );
    1349           0 : }
    1350             : 
    1351             : 
    1352             : 
    1353           0 : OUString SfxLinkUndoAction::GetComment() const
    1354             : {
    1355           0 :     if ( pAction )
    1356           0 :         return pAction->GetComment();
    1357           0 :     return OUString();
    1358             : }
    1359             : 
    1360             : 
    1361             : 
    1362           0 : OUString SfxLinkUndoAction::GetRepeatComment(SfxRepeatTarget&r) const
    1363             : {
    1364           0 :     if ( pAction )
    1365           0 :         return pAction->GetRepeatComment(r);
    1366           0 :     return OUString();
    1367             : }
    1368             : 
    1369             : 
    1370           0 : SfxLinkUndoAction::~SfxLinkUndoAction()
    1371             : {
    1372           0 :     if( pAction )
    1373           0 :         pAction->SetLinkToSfxLinkUndoAction(0);
    1374           0 : }
    1375             : 
    1376             : 
    1377           0 : void SfxLinkUndoAction::LinkedSfxUndoActionDestructed(const SfxUndoAction& rCandidate)
    1378             : {
    1379             :     OSL_ENSURE(0 != pAction, "OOps, we have no linked SfxUndoAction (!)");
    1380             :     OSL_ENSURE(pAction == &rCandidate, "OOps, the destroyed and linked UndoActions differ (!)");
    1381             :     (void)rCandidate;
    1382           0 :     pAction = 0;
    1383           0 : }
    1384             : 
    1385             : 
    1386      292740 : SfxUndoArray::~SfxUndoArray()
    1387             : {
    1388      332411 :     while ( !aUndoActions.empty() )
    1389             :     {
    1390       59759 :         SfxUndoAction *pAction = aUndoActions[ aUndoActions.size() - 1 ].pAction;
    1391       59759 :         aUndoActions.Remove( aUndoActions.size() - 1 );
    1392       59759 :         delete pAction;
    1393             :     }
    1394      156414 : }
    1395             : 
    1396             : 
    1397           0 : sal_uInt16 SfxLinkUndoAction::GetId() const
    1398             : {
    1399           0 :       return pAction ? pAction->GetId() : 0;
    1400         531 : }
    1401             : 
    1402             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10