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