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