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