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