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