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