xref: /trunk/main/svl/inc/svl/undo.hxx (revision 89358e0f)
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 
MarkedUndoActionMarkedUndoAction98     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:
SfxUndoActions()111     SfxUndoActions()
112     {
113     }
114 
empty() const115     bool    empty() const { return m_aActions.empty(); }
size() const116     size_t  size() const { return m_aActions.size(); }
117 
operator [](size_t i) const118     const MarkedUndoAction& operator[]( size_t i ) const { return m_aActions[i]; }
operator [](size_t i)119           MarkedUndoAction& operator[]( size_t i )       { return m_aActions[i]; }
120 
Remove(size_t i_pos)121     void    Remove( size_t i_pos )
122     {
123         m_aActions.erase( m_aActions.begin() + i_pos );
124     }
125 
Remove(size_t i_pos,size_t i_count)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 
Insert(SfxUndoAction * i_action,size_t i_pos)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;
SfxUndoArraySfxUndoArray147 							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 
~IUndoManager()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         virtual SfxUndoAction*  GetRedoAction( 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 SfxUndoAction*  GetRedoAction( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const;
365     virtual sal_Bool        Undo();
366     virtual sal_Bool        Redo();
367     virtual void            Clear();
368     virtual void            ClearRedo();
369     virtual void            Reset();
370     virtual bool            IsDoing() const;
371     virtual size_t          GetRepeatActionCount() const;
372     virtual UniString       GetRepeatActionComment( SfxRepeatTarget &rTarget) const;
373     virtual sal_Bool        Repeat( SfxRepeatTarget &rTarget );
374     virtual sal_Bool        CanRepeat( SfxRepeatTarget &rTarget ) const;
375     virtual void            EnterListAction(const UniString &rComment, const UniString& rRepeatComment, sal_uInt16 nId=0);
376     virtual size_t          LeaveListAction();
377     virtual size_t          LeaveAndMergeListAction();
378     virtual bool            IsInListAction() const;
379     virtual size_t          GetListActionDepth() const;
380     virtual void            RemoveLastUndoAction();
381     virtual void            EnableUndo( bool bEnable );
382     virtual bool            IsUndoEnabled() const;
383     virtual void            AddUndoListener( SfxUndoListener& i_listener );
384     virtual void            RemoveUndoListener( SfxUndoListener& i_listener );
385 
386     /** marks the current top-level element of the Undo stack, and returns a unique ID for it
387     */
388     UndoStackMark   MarkTopUndoAction();
389 
390     /** removes a mark given by its ID.
391         After the call, the mark ID is invalid.
392     */
393     void            RemoveMark( UndoStackMark const i_mark );
394 
395     /** determines whether the top action on the Undo stack has a given mark
396     */
397     bool            HasTopUndoActionMark( UndoStackMark const i_mark );
398 
399     /** removes the oldest Undo actions from the stack
400     */
401     void            RemoveOldestUndoActions( size_t const i_count );
402 
403 protected:
404     sal_Bool UndoWithContext( SfxUndoContext& i_context );
405     sal_Bool RedoWithContext( SfxUndoContext& i_context );
406 
407     void    ImplClearRedo_NoLock( bool const i_currentLevel );
408 
409     /** clears all undo actions on the current level, plus all undo actions on superordinate levels,
410         as soon as those levels are reached.
411 
412         If no list action is active currently, i.e. we're on the top level already, this method is equivalent to
413         ->Clear.
414 
415         Otherwise, the Undo actions on the current level are removed. Upon leaving the current list action, all
416         undo actions on the then-current level are removed, too. This is continued until the top level is reached.
417     */
418     void    ClearAllLevels();
419 
420 private:
421     size_t  ImplLeaveListAction( const bool i_merge, ::svl::undo::impl::UndoManagerGuard& i_guard );
422     bool    ImplAddUndoAction_NoNotify( SfxUndoAction* pAction, bool bTryMerge, bool bClearRedo, ::svl::undo::impl::UndoManagerGuard& i_guard );
423     void    ImplClearRedo( ::svl::undo::impl::UndoManagerGuard& i_guard, bool const i_currentLevel );
424     void    ImplClearUndo( ::svl::undo::impl::UndoManagerGuard& i_guard );
425     void    ImplClearCurrentLevel_NoNotify( ::svl::undo::impl::UndoManagerGuard& i_guard );
426     size_t  ImplGetRedoActionCount_Lock( bool const i_currentLevel = CurrentLevel ) const;
427     bool    ImplIsUndoEnabled_Lock() const;
428     bool    ImplIsInListAction_Lock() const;
429     void    ImplEnableUndo_Lock( bool const i_enable );
430 
431     sal_Bool ImplUndo( SfxUndoContext* i_contextOrNull );
432     sal_Bool ImplRedo( SfxUndoContext* i_contextOrNull );
433 
434     friend class ::svl::undo::impl::LockGuard;
435 };
436 
437 //=========================================================================
438 
439 class SVL_DLLPUBLIC SfxLinkUndoAction : public SfxUndoAction
440 
441 /*	[Beschreibung]
442 
443 	Die SfxLinkUndoAction dient zur Verbindung zweier SfxUndoManager. Die
444 	im ersten SfxUndoManager eingefuegten SfxUndoAction leiten ihr Undo und Redo
445 	an den zweiten weiter, so dass ein Undo und Redo am ersten
446 	SfxUndoManager wie eine am zweiten wirkt.
447 
448 	Die SfxLinkUndoAction ist nach dem Einfuegen der SfxUndoAction am
449 	zweiten SfxUndoManager einzufuegen. Waehrend der zweite SfxUndoManager
450 	vom ersten ferngesteuert wird, duerfen an ihm weder Actions eingefuegt werden,
451 	noch darf Undo/Redo aufgerufen werden.
452 
453 */
454 
455 {
456 private:
457     friend class SfxUndoAction;
458     void LinkedSfxUndoActionDestructed(const SfxUndoAction& rCandidate);
459 
460 public:
461 							TYPEINFO();
462                             SfxLinkUndoAction(::svl::IUndoManager *pManager);
463 							~SfxLinkUndoAction();
464 
465 	virtual void			Undo();
466 	virtual void			Redo();
467 	virtual sal_Bool			CanRepeat(SfxRepeatTarget& r) const;
468 
469 	virtual void			Repeat(SfxRepeatTarget&r);
470 
471 	virtual UniString       GetComment() const;
472 	virtual UniString       GetRepeatComment(SfxRepeatTarget&r) const;
473 	virtual sal_uInt16	GetId() const;
474 
GetAction() const475 	SfxUndoAction*			GetAction() const { return pAction; }
476 
477 protected:
478 	::svl::IUndoManager     *pUndoManager;
479 	SfxUndoAction			*pAction;
480 
481 };
482 
483 #endif
484