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