xref: /aoo41x/main/svl/inc/svl/undo.hxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #ifndef _UNDO_HXX
28 #define _UNDO_HXX
29 
30 #include "svl/svldllapi.h"
31 #include <tools/rtti.hxx>
32 #include <tools/string.hxx>
33 #include <svl/svarray.hxx>
34 
35 #include <boost/scoped_ptr.hpp>
36 
37 #include <vector>
38 #include <limits>
39 
40 //====================================================================
41 
42 class SVL_DLLPUBLIC SfxRepeatTarget
43 {
44 public:
45 						TYPEINFO();
46 	virtual 			~SfxRepeatTarget() = 0;
47 };
48 
49 //====================================================================
50 
51 class SVL_DLLPUBLIC SfxUndoContext
52 {
53 public:
54     virtual             ~SfxUndoContext() = 0;
55 };
56 
57 //====================================================================
58 
59 class SVL_DLLPUBLIC SfxUndoAction
60 {
61 	sal_Bool bLinked;
62 public:
63 							TYPEINFO();
64 							SfxUndoAction();
65 	virtual 				~SfxUndoAction();
66 
67 	virtual sal_Bool            IsLinked();
68 	virtual void            SetLinked( sal_Bool bIsLinked = sal_True );
69 	virtual void			Undo();
70     virtual void            UndoWithContext( SfxUndoContext& i_context );
71 	virtual void			Redo();
72     virtual void            RedoWithContext( SfxUndoContext& i_context );
73 	virtual void			Repeat(SfxRepeatTarget&);
74 	virtual sal_Bool			CanRepeat(SfxRepeatTarget&) const;
75 
76 	virtual sal_Bool			Merge( SfxUndoAction *pNextAction );
77 
78 	virtual UniString       GetComment() const;
79 	virtual UniString       GetRepeatComment(SfxRepeatTarget&) const;
80 	virtual sal_uInt16	GetId() const;
81 
82 private:
83 	SfxUndoAction&			operator=( const SfxUndoAction& );	  // n.i.!!
84 };
85 
86 //========================================================================
87 
88 /// is a mark on the Undo stack
89 typedef sal_Int32 UndoStackMark;
90 #define MARK_INVALID    ::std::numeric_limits< UndoStackMark >::max()
91 
92 //========================================================================
93 
94 struct MarkedUndoAction
95 {
96     SfxUndoAction*                  pAction;
97     ::std::vector< UndoStackMark >  aMarks;
98 
99     MarkedUndoAction( SfxUndoAction* i_action )
100         :pAction( i_action )
101         ,aMarks()
102     {
103     }
104 };
105 
106 class SfxUndoActions
107 {
108 private:
109     ::std::vector< MarkedUndoAction > m_aActions;
110 
111 public:
112     SfxUndoActions()
113     {
114     }
115 
116     bool    empty() const { return m_aActions.empty(); }
117     size_t  size() const { return m_aActions.size(); }
118 
119     const MarkedUndoAction& operator[]( size_t i ) const { return m_aActions[i]; }
120           MarkedUndoAction& operator[]( size_t i )       { return m_aActions[i]; }
121 
122     void    Remove( size_t i_pos )
123     {
124         m_aActions.erase( m_aActions.begin() + i_pos );
125     }
126 
127     void    Remove( size_t i_pos, size_t i_count )
128     {
129         m_aActions.erase( m_aActions.begin() + i_pos, m_aActions.begin() + i_pos + i_count );
130     }
131 
132     void    Insert( SfxUndoAction* i_action, size_t i_pos )
133     {
134         m_aActions.insert( m_aActions.begin() + i_pos, MarkedUndoAction( i_action ) );
135     }
136 };
137 
138 //====================================================================
139 
140 /** do not make use of these implementation details, unless you
141 	really really have to! */
142 struct SVL_DLLPUBLIC SfxUndoArray
143 {
144 	SfxUndoActions          aUndoActions;
145 	size_t					nMaxUndoActions;
146 	size_t					nCurUndoAction;
147 	SfxUndoArray 			*pFatherUndoArray;
148 							SfxUndoArray(size_t nMax=0):
149                                 nMaxUndoActions(nMax), nCurUndoAction(0),
150                                 pFatherUndoArray(0) {}
151 						   ~SfxUndoArray();
152 };
153 
154 //=========================================================================
155 
156 /** do not make use of these implementation details, unless you
157 	really really have to! */
158 class SVL_DLLPUBLIC SfxListUndoAction : public SfxUndoAction, public SfxUndoArray
159 
160 /*	[Beschreibung]
161 
162 	UndoAction zur Klammerung mehrerer Undos in einer UndoAction.
163 	Diese Actions werden vom SfxUndoManager verwendet. Dort
164 	wird mit < SfxUndoManager::EnterListAction > eine Klammerebene
165 	geoeffnet und mit <SfxUndoManager::LeaveListAction > wieder
166 	geschlossen. Redo und Undo auf SfxListUndoActions wirken
167 	Elementweise.
168 
169 */
170 {
171 	public:
172 							TYPEINFO();
173 
174 							SfxListUndoAction( const UniString &rComment,
175 								const UniString rRepeatComment, sal_uInt16 Id, SfxUndoArray *pFather);
176 	virtual void			Undo();
177     virtual void            UndoWithContext( SfxUndoContext& i_context );
178 	virtual void			Redo();
179     virtual void            RedoWithContext( SfxUndoContext& i_context );
180 	virtual void			Repeat(SfxRepeatTarget&);
181 	virtual sal_Bool			CanRepeat(SfxRepeatTarget&) const;
182 
183 	virtual sal_Bool			Merge( SfxUndoAction *pNextAction );
184 
185     virtual UniString       GetComment() const;
186     virtual UniString       GetRepeatComment(SfxRepeatTarget&) const;
187 	virtual sal_uInt16  GetId() const;
188 
189 	void SetComment( const UniString& rComment );
190 
191 	private:
192 
193     sal_uInt16		    nId;
194     UniString               aComment;
195     UniString               aRepeatComment;
196 
197 };
198 
199 //=========================================================================
200 
201 /**  is a callback interface for notifications about state changes of an SfxUndoManager
202 */
203 class SAL_NO_VTABLE SfxUndoListener
204 {
205 public:
206     virtual void actionUndone( const String& i_actionComment ) = 0;
207     virtual void actionRedone( const String& i_actionComment ) = 0;
208     virtual void undoActionAdded( const String& i_actionComment ) = 0;
209     virtual void cleared() = 0;
210     virtual void clearedRedo() = 0;
211     virtual void resetAll() = 0;
212     virtual void listActionEntered( const String& i_comment ) = 0;
213     virtual void listActionLeft( const String& i_comment ) = 0;
214     virtual void listActionLeftAndMerged() = 0;
215     virtual void listActionCancelled() = 0;
216     virtual void undoManagerDying() = 0;
217 };
218 
219 //=========================================================================
220 
221 namespace svl
222 {
223     class SAL_NO_VTABLE IUndoManager
224     {
225     public:
226         enum
227         {
228             CurrentLevel = true,
229             TopLevel = false
230         };
231 
232         virtual                 ~IUndoManager() { };
233 
234         virtual void            SetMaxUndoActionCount( size_t nMaxUndoActionCount ) = 0;
235         virtual size_t          GetMaxUndoActionCount() const = 0;
236 
237         virtual void            AddUndoAction( SfxUndoAction *pAction, sal_Bool bTryMerg=sal_False ) = 0;
238 
239         virtual size_t          GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const = 0;
240         virtual sal_uInt16      GetUndoActionId() const = 0;
241         virtual UniString       GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const = 0;
242         virtual SfxUndoAction*  GetUndoAction( size_t nNo=0 ) const = 0;
243 
244         virtual size_t          GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const = 0;
245         virtual UniString       GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const = 0;
246 
247         virtual sal_Bool        Undo() = 0;
248         virtual sal_Bool        Redo() = 0;
249 
250         /** clears both the Redo and the Undo stack.
251 
252             Will assert and bail out when called while within a list action (<member>IsInListAction</member>).
253         */
254         virtual void            Clear() = 0;
255 
256         /** clears the Redo stack.
257 
258             Will assert and bail out when called while within a list action (<member>IsInListAction</member>).
259         */
260         virtual void            ClearRedo() = 0;
261 
262         /** leaves any possible open list action (<member>IsInListAction</member>), and clears both the Undo and the
263             Redo stack.
264 
265             Effectively, calling this method is equivalent to <code>while ( IsInListAction() ) LeaveListAction();</code>,
266             followed by <code>Clear()</code>. The only difference to this calling sequence is that Reset is an
267             atomar operation, also resulting in only one notification.
268         */
269         virtual void            Reset() = 0;
270 
271         /** determines whether an Undo or Redo is currently running
272         */
273         virtual bool            IsDoing() const = 0;
274 
275         virtual size_t          GetRepeatActionCount() const = 0;
276         virtual UniString       GetRepeatActionComment( SfxRepeatTarget &rTarget) const = 0;
277         virtual sal_Bool        Repeat( SfxRepeatTarget &rTarget ) = 0;
278         virtual sal_Bool        CanRepeat( SfxRepeatTarget &rTarget ) const = 0;
279 
280         virtual void            EnterListAction(const UniString &rComment, const UniString& rRepeatComment, sal_uInt16 nId=0) = 0;
281 
282         /** leaves the list action entered with EnterListAction
283             @return the number of the sub actions in the list which has just been left. Note that in case no such
284                 actions exist, the list action does not contribute to the Undo stack, but is silently removed.
285         */
286         virtual size_t          LeaveListAction() = 0;
287 
288         /** leaves the list action entered with EnterListAction, and forcefully merges the previous
289             action on the stack into the newly created list action.
290 
291             Say you have an Undo action A on the stack, then call EnterListAction, followed by one or more calls to
292             AddUndoAction, followed by a call to LeaveAndMergeListAction. In opposite to LeaveListAction, your Undo
293             stack will now still contain one undo action: the newly created list action, whose first child is the
294             original A, whose other children are those you added via AddUndoAction, and whose comment is the same as
295             the comment of A.
296 
297             Effectively, this means that all actions added between EnterListAction and LeaveAndMergeListAction are
298             hidden from the user.
299 
300             @return the number of the sub actions in the list which has just been left. Note that in case no such
301                 actions exist, the list action does not contribute to the Undo stack, but is silently removed.
302         */
303         virtual size_t          LeaveAndMergeListAction() = 0;
304 
305         /// determines whether we're within a ListAction context, i.e. a LeaveListAction/LeaveAndMergeListAction call is pending
306         virtual bool            IsInListAction() const = 0;
307 
308         /// determines how many nested list actions are currently open
309         virtual size_t          GetListActionDepth() const = 0;
310 
311         /** clears the redo stack and removes the top undo action */
312         virtual void            RemoveLastUndoAction() = 0;
313 
314         /** enables (true) or disables (false) recording of undo actions
315 
316             If undo actions are added while undo is disabled, they are deleted.
317             Disabling undo does not clear the current undo buffer!
318 
319             Multiple calls to <code>EnableUndo</code> are not cumulative. That is, calling <code>EnableUndo( false )</code>
320             twice, and then calling <code>EnableUndo( true )</code> means that Undo is enable afterwards.
321         */
322         virtual void            EnableUndo( bool bEnable ) = 0;
323 
324         // returns true if undo is currently enabled
325         // This returns false if undo was disabled using EnableUndo( false ) and
326         // also during the runtime of the Undo() and Redo() methods.
327         virtual bool            IsUndoEnabled() const = 0;
328 
329         /// adds a new listener to be notified about changes in the UndoManager's state
330         virtual void            AddUndoListener( SfxUndoListener& i_listener ) = 0;
331         virtual void            RemoveUndoListener( SfxUndoListener& i_listener ) = 0;
332    };
333 }
334 
335 //=========================================================================
336 
337 namespace svl { namespace undo { namespace impl
338 {
339     class UndoManagerGuard;
340     class LockGuard;
341 } } }
342 
343 struct SfxUndoManager_Data;
344 class SVL_DLLPUBLIC SfxUndoManager : public ::svl::IUndoManager
345 {
346 	friend class SfxLinkUndoAction;
347 
348     ::boost::scoped_ptr< SfxUndoManager_Data >
349                             m_pData;
350 public:
351 							SfxUndoManager( size_t nMaxUndoActionCount = 20 );
352 	virtual 				~SfxUndoManager();
353 
354     // IUndoManager overridables
355     virtual void            SetMaxUndoActionCount( size_t nMaxUndoActionCount );
356     virtual size_t          GetMaxUndoActionCount() const;
357     virtual void            AddUndoAction( SfxUndoAction *pAction, sal_Bool bTryMerg=sal_False );
358     virtual size_t          GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const;
359     virtual sal_uInt16      GetUndoActionId() const;
360     virtual UniString       GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const;
361     virtual SfxUndoAction*  GetUndoAction( size_t nNo=0 ) const;
362     virtual size_t          GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const;
363     virtual UniString       GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const;
364     virtual sal_Bool        Undo();
365     virtual sal_Bool        Redo();
366     virtual void            Clear();
367     virtual void            ClearRedo();
368     virtual void            Reset();
369     virtual bool            IsDoing() const;
370     virtual size_t          GetRepeatActionCount() const;
371     virtual UniString       GetRepeatActionComment( SfxRepeatTarget &rTarget) const;
372     virtual sal_Bool        Repeat( SfxRepeatTarget &rTarget );
373     virtual sal_Bool        CanRepeat( SfxRepeatTarget &rTarget ) const;
374     virtual void            EnterListAction(const UniString &rComment, const UniString& rRepeatComment, sal_uInt16 nId=0);
375     virtual size_t          LeaveListAction();
376     virtual size_t          LeaveAndMergeListAction();
377     virtual bool            IsInListAction() const;
378     virtual size_t          GetListActionDepth() const;
379     virtual void            RemoveLastUndoAction();
380     virtual void            EnableUndo( bool bEnable );
381     virtual bool            IsUndoEnabled() const;
382     virtual void            AddUndoListener( SfxUndoListener& i_listener );
383     virtual void            RemoveUndoListener( SfxUndoListener& i_listener );
384 
385     /** marks the current top-level element of the Undo stack, and returns a unique ID for it
386     */
387     UndoStackMark   MarkTopUndoAction();
388 
389     /** removes a mark given by its ID.
390         After the call, the mark ID is invalid.
391     */
392     void            RemoveMark( UndoStackMark const i_mark );
393 
394     /** determines whether the top action on the Undo stack has a given mark
395     */
396     bool            HasTopUndoActionMark( UndoStackMark const i_mark );
397 
398     /** removes the oldest Undo actions from the stack
399     */
400     void            RemoveOldestUndoActions( size_t const i_count );
401 
402 protected:
403     sal_Bool UndoWithContext( SfxUndoContext& i_context );
404     sal_Bool RedoWithContext( SfxUndoContext& i_context );
405 
406     void    ImplClearRedo_NoLock( bool const i_currentLevel );
407 
408     /** clears all undo actions on the current level, plus all undo actions on superordinate levels,
409         as soon as those levels are reached.
410 
411         If no list action is active currently, i.e. we're on the top level already, this method is equivalent to
412         ->Clear.
413 
414         Otherwise, the Undo actions on the current level are removed. Upon leaving the current list action, all
415         undo actions on the then-current level are removed, too. This is continued until the top level is reached.
416     */
417     void    ClearAllLevels();
418 
419 private:
420     size_t  ImplLeaveListAction( const bool i_merge, ::svl::undo::impl::UndoManagerGuard& i_guard );
421     bool    ImplAddUndoAction_NoNotify( SfxUndoAction* pAction, bool bTryMerge, bool bClearRedo, ::svl::undo::impl::UndoManagerGuard& i_guard );
422     void    ImplClearRedo( ::svl::undo::impl::UndoManagerGuard& i_guard, bool const i_currentLevel );
423     void    ImplClearUndo( ::svl::undo::impl::UndoManagerGuard& i_guard );
424     void    ImplClearCurrentLevel_NoNotify( ::svl::undo::impl::UndoManagerGuard& i_guard );
425     size_t  ImplGetRedoActionCount_Lock( bool const i_currentLevel = CurrentLevel ) const;
426     bool    ImplIsUndoEnabled_Lock() const;
427     bool    ImplIsInListAction_Lock() const;
428     void    ImplEnableUndo_Lock( bool const i_enable );
429 
430     sal_Bool ImplUndo( SfxUndoContext* i_contextOrNull );
431     sal_Bool ImplRedo( SfxUndoContext* i_contextOrNull );
432 
433     friend class ::svl::undo::impl::LockGuard;
434 };
435 
436 //=========================================================================
437 
438 class SVL_DLLPUBLIC SfxLinkUndoAction : public SfxUndoAction
439 
440 /*	[Beschreibung]
441 
442 	Die SfxLinkUndoAction dient zur Verbindung zweier SfxUndoManager. Die
443 	im ersten SfxUndoManager eingefuegten SfxUndoAction leiten ihr Undo und Redo
444 	an den zweiten weiter, so dass ein Undo und Redo am ersten
445 	SfxUndoManager wie eine am zweiten wirkt.
446 
447 	Die SfxLinkUndoAction ist nach dem Einfuegen der SfxUndoAction am
448 	zweiten SfxUndoManager einzufuegen. Waehrend der zweite SfxUndoManager
449 	vom ersten ferngesteuert wird, duerfen an ihm weder Actions eingefuegt werden,
450 	noch darf Undo/Redo aufgerufen werden.
451 
452 */
453 
454 {
455 public:
456 							TYPEINFO();
457                             SfxLinkUndoAction(::svl::IUndoManager *pManager);
458 							~SfxLinkUndoAction();
459 
460 	virtual void			Undo();
461 	virtual void			Redo();
462 	virtual sal_Bool			CanRepeat(SfxRepeatTarget& r) const;
463 
464 	virtual void			Repeat(SfxRepeatTarget&r);
465 
466 	virtual UniString       GetComment() const;
467 	virtual UniString       GetRepeatComment(SfxRepeatTarget&r) const;
468 	virtual sal_uInt16	GetId() const;
469 
470 	SfxUndoAction*			GetAction() const { return pAction; }
471 
472 protected:
473 	::svl::IUndoManager     *pUndoManager;
474 	SfxUndoAction			*pAction;
475 
476 };
477 
478 #endif
479