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 MarkedUndoActionMarkedUndoAction98 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: SfxUndoActions()111 SfxUndoActions() 112 { 113 } 114 empty() const115 bool empty() const { return m_aActions.empty(); } size() const116 size_t size() const { return m_aActions.size(); } 117 operator [](size_t i) const118 const MarkedUndoAction& operator[]( size_t i ) const { return m_aActions[i]; } operator [](size_t i)119 MarkedUndoAction& operator[]( size_t i ) { return m_aActions[i]; } 120 Remove(size_t i_pos)121 void Remove( size_t i_pos ) 122 { 123 m_aActions.erase( m_aActions.begin() + i_pos ); 124 } 125 Remove(size_t i_pos,size_t i_count)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 Insert(SfxUndoAction * i_action,size_t i_pos)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; SfxUndoArraySfxUndoArray147 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 ~IUndoManager()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 virtual SfxUndoAction* GetRedoAction( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const = 0; 246 247 virtual sal_Bool Undo() = 0; 248 virtual sal_Bool Redo() = 0; 249 250 /** clears both the Redo and the Undo stack. 251 252 Will assert and bail out when called while within a list action (<member>IsInListAction</member>). 253 */ 254 virtual void Clear() = 0; 255 256 /** clears the Redo stack. 257 258 Will assert and bail out when called while within a list action (<member>IsInListAction</member>). 259 */ 260 virtual void ClearRedo() = 0; 261 262 /** leaves any possible open list action (<member>IsInListAction</member>), and clears both the Undo and the 263 Redo stack. 264 265 Effectively, calling this method is equivalent to <code>while ( IsInListAction() ) LeaveListAction();</code>, 266 followed by <code>Clear()</code>. The only difference to this calling sequence is that Reset is an 267 atomar operation, also resulting in only one notification. 268 */ 269 virtual void Reset() = 0; 270 271 /** determines whether an Undo or Redo is currently running 272 */ 273 virtual bool IsDoing() const = 0; 274 275 virtual size_t GetRepeatActionCount() const = 0; 276 virtual UniString GetRepeatActionComment( SfxRepeatTarget &rTarget) const = 0; 277 virtual sal_Bool Repeat( SfxRepeatTarget &rTarget ) = 0; 278 virtual sal_Bool CanRepeat( SfxRepeatTarget &rTarget ) const = 0; 279 280 virtual void EnterListAction(const UniString &rComment, const UniString& rRepeatComment, sal_uInt16 nId=0) = 0; 281 282 /** leaves the list action entered with EnterListAction 283 @return the number of the sub actions in the list which has just been left. Note that in case no such 284 actions exist, the list action does not contribute to the Undo stack, but is silently removed. 285 */ 286 virtual size_t LeaveListAction() = 0; 287 288 /** leaves the list action entered with EnterListAction, and forcefully merges the previous 289 action on the stack into the newly created list action. 290 291 Say you have an Undo action A on the stack, then call EnterListAction, followed by one or more calls to 292 AddUndoAction, followed by a call to LeaveAndMergeListAction. In opposite to LeaveListAction, your Undo 293 stack will now still contain one undo action: the newly created list action, whose first child is the 294 original A, whose other children are those you added via AddUndoAction, and whose comment is the same as 295 the comment of A. 296 297 Effectively, this means that all actions added between EnterListAction and LeaveAndMergeListAction are 298 hidden from the user. 299 300 @return the number of the sub actions in the list which has just been left. Note that in case no such 301 actions exist, the list action does not contribute to the Undo stack, but is silently removed. 302 */ 303 virtual size_t LeaveAndMergeListAction() = 0; 304 305 /// determines whether we're within a ListAction context, i.e. a LeaveListAction/LeaveAndMergeListAction call is pending 306 virtual bool IsInListAction() const = 0; 307 308 /// determines how many nested list actions are currently open 309 virtual size_t GetListActionDepth() const = 0; 310 311 /** clears the redo stack and removes the top undo action */ 312 virtual void RemoveLastUndoAction() = 0; 313 314 /** enables (true) or disables (false) recording of undo actions 315 316 If undo actions are added while undo is disabled, they are deleted. 317 Disabling undo does not clear the current undo buffer! 318 319 Multiple calls to <code>EnableUndo</code> are not cumulative. That is, calling <code>EnableUndo( false )</code> 320 twice, and then calling <code>EnableUndo( true )</code> means that Undo is enable afterwards. 321 */ 322 virtual void EnableUndo( bool bEnable ) = 0; 323 324 // returns true if undo is currently enabled 325 // This returns false if undo was disabled using EnableUndo( false ) and 326 // also during the runtime of the Undo() and Redo() methods. 327 virtual bool IsUndoEnabled() const = 0; 328 329 /// adds a new listener to be notified about changes in the UndoManager's state 330 virtual void AddUndoListener( SfxUndoListener& i_listener ) = 0; 331 virtual void RemoveUndoListener( SfxUndoListener& i_listener ) = 0; 332 }; 333 } 334 335 //========================================================================= 336 337 namespace svl { namespace undo { namespace impl 338 { 339 class UndoManagerGuard; 340 class LockGuard; 341 } } } 342 343 struct SfxUndoManager_Data; 344 class SVL_DLLPUBLIC SfxUndoManager : public ::svl::IUndoManager 345 { 346 friend class SfxLinkUndoAction; 347 348 ::boost::scoped_ptr< SfxUndoManager_Data > 349 m_pData; 350 public: 351 SfxUndoManager( size_t nMaxUndoActionCount = 20 ); 352 virtual ~SfxUndoManager(); 353 354 // IUndoManager overridables 355 virtual void SetMaxUndoActionCount( size_t nMaxUndoActionCount ); 356 virtual size_t GetMaxUndoActionCount() const; 357 virtual void AddUndoAction( SfxUndoAction *pAction, sal_Bool bTryMerg=sal_False ); 358 virtual size_t GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const; 359 virtual sal_uInt16 GetUndoActionId() const; 360 virtual UniString GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const; 361 virtual SfxUndoAction* GetUndoAction( size_t nNo=0 ) const; 362 virtual size_t GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const; 363 virtual UniString GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const; 364 virtual SfxUndoAction* GetRedoAction( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const; 365 virtual sal_Bool Undo(); 366 virtual sal_Bool Redo(); 367 virtual void Clear(); 368 virtual void ClearRedo(); 369 virtual void Reset(); 370 virtual bool IsDoing() const; 371 virtual size_t GetRepeatActionCount() const; 372 virtual UniString GetRepeatActionComment( SfxRepeatTarget &rTarget) const; 373 virtual sal_Bool Repeat( SfxRepeatTarget &rTarget ); 374 virtual sal_Bool CanRepeat( SfxRepeatTarget &rTarget ) const; 375 virtual void EnterListAction(const UniString &rComment, const UniString& rRepeatComment, sal_uInt16 nId=0); 376 virtual size_t LeaveListAction(); 377 virtual size_t LeaveAndMergeListAction(); 378 virtual bool IsInListAction() const; 379 virtual size_t GetListActionDepth() const; 380 virtual void RemoveLastUndoAction(); 381 virtual void EnableUndo( bool bEnable ); 382 virtual bool IsUndoEnabled() const; 383 virtual void AddUndoListener( SfxUndoListener& i_listener ); 384 virtual void RemoveUndoListener( SfxUndoListener& i_listener ); 385 386 /** marks the current top-level element of the Undo stack, and returns a unique ID for it 387 */ 388 UndoStackMark MarkTopUndoAction(); 389 390 /** removes a mark given by its ID. 391 After the call, the mark ID is invalid. 392 */ 393 void RemoveMark( UndoStackMark const i_mark ); 394 395 /** determines whether the top action on the Undo stack has a given mark 396 */ 397 bool HasTopUndoActionMark( UndoStackMark const i_mark ); 398 399 /** removes the oldest Undo actions from the stack 400 */ 401 void RemoveOldestUndoActions( size_t const i_count ); 402 403 protected: 404 sal_Bool UndoWithContext( SfxUndoContext& i_context ); 405 sal_Bool RedoWithContext( SfxUndoContext& i_context ); 406 407 void ImplClearRedo_NoLock( bool const i_currentLevel ); 408 409 /** clears all undo actions on the current level, plus all undo actions on superordinate levels, 410 as soon as those levels are reached. 411 412 If no list action is active currently, i.e. we're on the top level already, this method is equivalent to 413 ->Clear. 414 415 Otherwise, the Undo actions on the current level are removed. Upon leaving the current list action, all 416 undo actions on the then-current level are removed, too. This is continued until the top level is reached. 417 */ 418 void ClearAllLevels(); 419 420 private: 421 size_t ImplLeaveListAction( const bool i_merge, ::svl::undo::impl::UndoManagerGuard& i_guard ); 422 bool ImplAddUndoAction_NoNotify( SfxUndoAction* pAction, bool bTryMerge, bool bClearRedo, ::svl::undo::impl::UndoManagerGuard& i_guard ); 423 void ImplClearRedo( ::svl::undo::impl::UndoManagerGuard& i_guard, bool const i_currentLevel ); 424 void ImplClearUndo( ::svl::undo::impl::UndoManagerGuard& i_guard ); 425 void ImplClearCurrentLevel_NoNotify( ::svl::undo::impl::UndoManagerGuard& i_guard ); 426 size_t ImplGetRedoActionCount_Lock( bool const i_currentLevel = CurrentLevel ) const; 427 bool ImplIsUndoEnabled_Lock() const; 428 bool ImplIsInListAction_Lock() const; 429 void ImplEnableUndo_Lock( bool const i_enable ); 430 431 sal_Bool ImplUndo( SfxUndoContext* i_contextOrNull ); 432 sal_Bool ImplRedo( SfxUndoContext* i_contextOrNull ); 433 434 friend class ::svl::undo::impl::LockGuard; 435 }; 436 437 //========================================================================= 438 439 class SVL_DLLPUBLIC SfxLinkUndoAction : public SfxUndoAction 440 441 /* [Beschreibung] 442 443 Die SfxLinkUndoAction dient zur Verbindung zweier SfxUndoManager. Die 444 im ersten SfxUndoManager eingefuegten SfxUndoAction leiten ihr Undo und Redo 445 an den zweiten weiter, so dass ein Undo und Redo am ersten 446 SfxUndoManager wie eine am zweiten wirkt. 447 448 Die SfxLinkUndoAction ist nach dem Einfuegen der SfxUndoAction am 449 zweiten SfxUndoManager einzufuegen. Waehrend der zweite SfxUndoManager 450 vom ersten ferngesteuert wird, duerfen an ihm weder Actions eingefuegt werden, 451 noch darf Undo/Redo aufgerufen werden. 452 453 */ 454 455 { 456 private: 457 friend class SfxUndoAction; 458 void LinkedSfxUndoActionDestructed(const SfxUndoAction& rCandidate); 459 460 public: 461 TYPEINFO(); 462 SfxLinkUndoAction(::svl::IUndoManager *pManager); 463 ~SfxLinkUndoAction(); 464 465 virtual void Undo(); 466 virtual void Redo(); 467 virtual sal_Bool CanRepeat(SfxRepeatTarget& r) const; 468 469 virtual void Repeat(SfxRepeatTarget&r); 470 471 virtual UniString GetComment() const; 472 virtual UniString GetRepeatComment(SfxRepeatTarget&r) const; 473 virtual sal_uInt16 GetId() const; 474 GetAction() const475 SfxUndoAction* GetAction() const { return pAction; } 476 477 protected: 478 ::svl::IUndoManager *pUndoManager; 479 SfxUndoAction *pAction; 480 481 }; 482 483 #endif 484