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