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 0 : class SVL_DLLPUBLIC SfxRepeatTarget
34 : {
35 : public:
36 : TYPEINFO();
37 : virtual ~SfxRepeatTarget() = 0;
38 : };
39 :
40 :
41 :
42 0 : 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 0 : struct MarkedUndoAction
89 : {
90 : SfxUndoAction* pAction;
91 : ::std::vector< UndoStackMark > aMarks;
92 :
93 0 : MarkedUndoAction( SfxUndoAction* i_action )
94 : :pAction( i_action )
95 0 : ,aMarks()
96 : {
97 0 : }
98 : };
99 :
100 0 : class SfxUndoActions
101 : {
102 : private:
103 : ::std::vector< MarkedUndoAction > m_aActions;
104 :
105 : public:
106 0 : SfxUndoActions()
107 0 : {
108 0 : }
109 :
110 0 : bool empty() const { return m_aActions.empty(); }
111 0 : size_t size() const { return m_aActions.size(); }
112 :
113 0 : const MarkedUndoAction& operator[]( size_t i ) const { return m_aActions[i]; }
114 0 : MarkedUndoAction& operator[]( size_t i ) { return m_aActions[i]; }
115 :
116 0 : void Remove( size_t i_pos )
117 : {
118 0 : m_aActions.erase( m_aActions.begin() + i_pos );
119 0 : }
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 0 : void Insert( SfxUndoAction* i_action, size_t i_pos )
127 : {
128 0 : m_aActions.insert( m_aActions.begin() + i_pos, MarkedUndoAction( i_action ) );
129 0 : }
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 0 : SfxUndoArray(size_t nMax=0):
143 : nMaxUndoActions(nMax), nCurUndoAction(0),
144 0 : 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 0 : class SVL_DLLPUBLIC SfxListUndoAction : public SfxUndoAction, public SfxUndoArray
153 :
154 : /* [Beschreibung]
155 :
156 : UndoAction zur Klammerung mehrerer Undos in einer UndoAction.
157 : Diese Actions werden vom SfxUndoManager verwendet. Dort
158 : wird mit < SfxUndoManager::EnterListAction > eine Klammerebene
159 : geoeffnet und mit <SfxUndoManager::LeaveListAction > wieder
160 : geschlossen. Redo und Undo auf SfxListUndoActions wirken
161 : Elementweise.
162 :
163 : */
164 : {
165 : public:
166 : TYPEINFO_OVERRIDE();
167 :
168 : SfxListUndoAction( const OUString &rComment,
169 : const OUString& rRepeatComment, sal_uInt16 Id, SfxUndoArray *pFather);
170 : virtual void Undo() SAL_OVERRIDE;
171 : virtual void UndoWithContext( SfxUndoContext& i_context ) SAL_OVERRIDE;
172 : virtual void Redo() SAL_OVERRIDE;
173 : virtual void RedoWithContext( SfxUndoContext& i_context ) SAL_OVERRIDE;
174 : virtual void Repeat(SfxRepeatTarget&) SAL_OVERRIDE;
175 : virtual bool CanRepeat(SfxRepeatTarget&) const SAL_OVERRIDE;
176 :
177 : virtual bool Merge( SfxUndoAction *pNextAction ) SAL_OVERRIDE;
178 :
179 : virtual OUString GetComment() const SAL_OVERRIDE;
180 : virtual OUString GetRepeatComment(SfxRepeatTarget&) const SAL_OVERRIDE;
181 : virtual sal_uInt16 GetId() const SAL_OVERRIDE;
182 :
183 : void SetComment(const OUString& rComment);
184 :
185 : private:
186 :
187 : sal_uInt16 nId;
188 : OUString aComment;
189 : OUString aRepeatComment;
190 :
191 : };
192 :
193 :
194 :
195 : /** is a callback interface for notifications about state changes of an SfxUndoManager
196 : */
197 0 : class SAL_NO_VTABLE SfxUndoListener
198 : {
199 : public:
200 : virtual void actionUndone( const OUString& i_actionComment ) = 0;
201 : virtual void actionRedone( const OUString& i_actionComment ) = 0;
202 : virtual void undoActionAdded( const OUString& i_actionComment ) = 0;
203 : virtual void cleared() = 0;
204 : virtual void clearedRedo() = 0;
205 : virtual void resetAll() = 0;
206 : virtual void listActionEntered( const OUString& i_comment ) = 0;
207 : virtual void listActionLeft( const OUString& i_comment ) = 0;
208 : virtual void listActionLeftAndMerged() = 0;
209 : virtual void listActionCancelled() = 0;
210 : virtual void undoManagerDying() = 0;
211 :
212 : protected:
213 0 : ~SfxUndoListener() {}
214 : };
215 :
216 :
217 :
218 : namespace svl
219 : {
220 0 : class SAL_NO_VTABLE IUndoManager
221 : {
222 : public:
223 : static bool const CurrentLevel = true;
224 : static bool const TopLevel = false;
225 :
226 0 : virtual ~IUndoManager() { };
227 :
228 : virtual void SetMaxUndoActionCount( size_t nMaxUndoActionCount ) = 0;
229 : virtual size_t GetMaxUndoActionCount() const = 0;
230 :
231 : virtual void AddUndoAction( SfxUndoAction *pAction, bool bTryMerg=false ) = 0;
232 :
233 : virtual size_t GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const = 0;
234 : virtual sal_uInt16 GetUndoActionId() const = 0;
235 : virtual OUString GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const = 0;
236 : virtual SfxUndoAction* GetUndoAction( size_t nNo=0 ) const = 0;
237 :
238 : virtual size_t GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const = 0;
239 : virtual OUString GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const = 0;
240 : virtual SfxUndoAction* GetRedoAction( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const = 0;
241 :
242 : virtual bool Undo() = 0;
243 : virtual bool Redo() = 0;
244 :
245 : /** clears both the Redo and the Undo stack.
246 :
247 : Will assert and bail out when called while within a list action (<member>IsInListAction</member>).
248 : */
249 : virtual void Clear() = 0;
250 :
251 : /** clears the Redo stack.
252 :
253 : Will assert and bail out when called while within a list action (<member>IsInListAction</member>).
254 : */
255 : virtual void ClearRedo() = 0;
256 :
257 : /** leaves any possible open list action (<member>IsInListAction</member>), and clears both the Undo and the
258 : Redo stack.
259 :
260 : Effectively, calling this method is equivalent to <code>while ( IsInListAction() ) LeaveListAction();</code>,
261 : followed by <code>Clear()</code>. The only difference to this calling sequence is that Reset is an
262 : atomic operation, also resulting in only one notification.
263 : */
264 : virtual void Reset() = 0;
265 :
266 : /** determines whether an Undo or Redo is currently running
267 : */
268 : virtual bool IsDoing() const = 0;
269 :
270 : virtual size_t GetRepeatActionCount() const = 0;
271 : virtual OUString GetRepeatActionComment( SfxRepeatTarget &rTarget) const = 0;
272 : virtual bool Repeat( SfxRepeatTarget &rTarget ) = 0;
273 : virtual bool CanRepeat( SfxRepeatTarget &rTarget ) const = 0;
274 :
275 : virtual void EnterListAction(const OUString &rComment, const OUString& rRepeatComment, sal_uInt16 nId=0) = 0;
276 :
277 : /** leaves the list action entered with EnterListAction
278 : @return the number of the sub actions in the list which has just been left. Note that in case no such
279 : actions exist, the list action does not contribute to the Undo stack, but is silently removed.
280 : */
281 : virtual size_t LeaveListAction() = 0;
282 :
283 : /** leaves the list action entered with EnterListAction, and forcefully merges the previous
284 : action on the stack into the newly created list action.
285 :
286 : Say you have an Undo action A on the stack, then call EnterListAction, followed by one or more calls to
287 : AddUndoAction, followed by a call to LeaveAndMergeListAction. In opposite to LeaveListAction, your Undo
288 : stack will now still contain one undo action: the newly created list action, whose first child is the
289 : original A, whose other children are those you added via AddUndoAction, and whose comment is the same as
290 : the comment of A.
291 :
292 : Effectively, this means that all actions added between EnterListAction and LeaveAndMergeListAction are
293 : hidden from the user.
294 :
295 : @return the number of the sub actions in the list which has just been left. Note that in case no such
296 : actions exist, the list action does not contribute to the Undo stack, but is silently removed.
297 : */
298 : virtual size_t LeaveAndMergeListAction() = 0;
299 :
300 : /// determines whether we're within a ListAction context, i.e. a LeaveListAction/LeaveAndMergeListAction call is pending
301 : virtual bool IsInListAction() const = 0;
302 :
303 : /// determines how many nested list actions are currently open
304 : virtual size_t GetListActionDepth() const = 0;
305 :
306 : /** clears the redo stack and removes the top undo action */
307 : virtual void RemoveLastUndoAction() = 0;
308 :
309 : /** enables (true) or disables (false) recording of undo actions
310 :
311 : If undo actions are added while undo is disabled, they are deleted.
312 : Disabling undo does not clear the current undo buffer!
313 :
314 : Multiple calls to <code>EnableUndo</code> are not cumulative. That is, calling <code>EnableUndo( false )</code>
315 : twice, and then calling <code>EnableUndo( true )</code> means that Undo is enable afterwards.
316 : */
317 : virtual void EnableUndo( bool bEnable ) = 0;
318 :
319 : // returns true if undo is currently enabled
320 : // This returns false if undo was disabled using EnableUndo( false ) and
321 : // also during the runtime of the Undo() and Redo() methods.
322 : virtual bool IsUndoEnabled() const = 0;
323 :
324 : /// adds a new listener to be notified about changes in the UndoManager's state
325 : virtual void AddUndoListener( SfxUndoListener& i_listener ) = 0;
326 : virtual void RemoveUndoListener( SfxUndoListener& i_listener ) = 0;
327 : };
328 : }
329 :
330 :
331 :
332 : namespace svl { namespace undo { namespace impl
333 : {
334 : class UndoManagerGuard;
335 : class LockGuard;
336 : } } }
337 :
338 : struct SfxUndoManager_Data;
339 : class SVL_DLLPUBLIC SfxUndoManager : public ::svl::IUndoManager
340 : {
341 : friend class SfxLinkUndoAction;
342 :
343 : ::boost::scoped_ptr< SfxUndoManager_Data >
344 : m_pData;
345 : public:
346 : SfxUndoManager( size_t nMaxUndoActionCount = 20 );
347 : virtual ~SfxUndoManager();
348 :
349 : // IUndoManager overridables
350 : virtual void SetMaxUndoActionCount( size_t nMaxUndoActionCount ) SAL_OVERRIDE;
351 : virtual size_t GetMaxUndoActionCount() const SAL_OVERRIDE;
352 : virtual void AddUndoAction( SfxUndoAction *pAction, bool bTryMerg=false ) SAL_OVERRIDE;
353 : virtual size_t GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const SAL_OVERRIDE;
354 : virtual sal_uInt16 GetUndoActionId() const SAL_OVERRIDE;
355 : virtual OUString GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const SAL_OVERRIDE;
356 : virtual SfxUndoAction* GetUndoAction( size_t nNo=0 ) const SAL_OVERRIDE;
357 : virtual size_t GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const SAL_OVERRIDE;
358 : virtual OUString GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const SAL_OVERRIDE;
359 : virtual SfxUndoAction* GetRedoAction( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const SAL_OVERRIDE;
360 : virtual bool Undo() SAL_OVERRIDE;
361 : virtual bool Redo() SAL_OVERRIDE;
362 : virtual void Clear() SAL_OVERRIDE;
363 : virtual void ClearRedo() SAL_OVERRIDE;
364 : virtual void Reset() SAL_OVERRIDE;
365 : virtual bool IsDoing() const SAL_OVERRIDE;
366 : virtual size_t GetRepeatActionCount() const SAL_OVERRIDE;
367 : virtual OUString GetRepeatActionComment( SfxRepeatTarget &rTarget) const SAL_OVERRIDE;
368 : virtual bool Repeat( SfxRepeatTarget &rTarget ) SAL_OVERRIDE;
369 : virtual bool CanRepeat( SfxRepeatTarget &rTarget ) const SAL_OVERRIDE;
370 : virtual void EnterListAction(const OUString &rComment, const OUString& rRepeatComment, sal_uInt16 nId=0) SAL_OVERRIDE;
371 : virtual size_t LeaveListAction() SAL_OVERRIDE;
372 : virtual size_t LeaveAndMergeListAction() SAL_OVERRIDE;
373 : virtual bool IsInListAction() const SAL_OVERRIDE;
374 : virtual size_t GetListActionDepth() const SAL_OVERRIDE;
375 : virtual void RemoveLastUndoAction() SAL_OVERRIDE;
376 : virtual void EnableUndo( bool bEnable ) SAL_OVERRIDE;
377 : virtual bool IsUndoEnabled() const SAL_OVERRIDE;
378 : virtual void AddUndoListener( SfxUndoListener& i_listener ) SAL_OVERRIDE;
379 : virtual void RemoveUndoListener( SfxUndoListener& i_listener ) SAL_OVERRIDE;
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 : bool UndoWithContext( SfxUndoContext& i_context );
400 : 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 : bool ImplUndo( SfxUndoContext* i_contextOrNull );
427 : 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 : private:
452 : friend class SfxUndoAction;
453 : void LinkedSfxUndoActionDestructed(const SfxUndoAction& rCandidate);
454 :
455 : public:
456 : TYPEINFO_OVERRIDE();
457 : SfxLinkUndoAction(::svl::IUndoManager *pManager);
458 : virtual ~SfxLinkUndoAction();
459 :
460 : virtual void Undo() SAL_OVERRIDE;
461 : virtual void Redo() SAL_OVERRIDE;
462 : virtual bool CanRepeat(SfxRepeatTarget& r) const SAL_OVERRIDE;
463 :
464 : virtual void Repeat(SfxRepeatTarget&r) SAL_OVERRIDE;
465 :
466 : virtual OUString GetComment() const SAL_OVERRIDE;
467 : virtual OUString GetRepeatComment(SfxRepeatTarget&r) const SAL_OVERRIDE;
468 : virtual sal_uInt16 GetId() const SAL_OVERRIDE;
469 :
470 0 : SfxUndoAction* GetAction() const { return pAction; }
471 :
472 : protected:
473 : ::svl::IUndoManager* pUndoManager;
474 : SfxUndoAction* pAction;
475 :
476 : };
477 :
478 : #endif
479 :
480 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|