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/datetime.hxx> 25 #include <o3tl/strong_int.hxx> 26 27 #include <memory> 28 #include <vector> 29 30 typedef o3tl::strong_int<sal_Int32, struct ViewShellIdTag> ViewShellId; 31 typedef o3tl::strong_int<int, struct ViewShellDocIdTag> ViewShellDocId; 32 33 typedef struct _xmlTextWriter* xmlTextWriterPtr; 34 35 class SVL_DLLPUBLIC SfxRepeatTarget 36 { 37 public: 38 virtual ~SfxRepeatTarget() = 0; 39 }; 40 41 42 class SVL_DLLPUBLIC SfxUndoContext 43 { 44 public: 45 virtual ~SfxUndoContext() = 0; 46 }; 47 48 49 class SVL_DLLPUBLIC SfxUndoAction 50 { 51 public: 52 SfxUndoAction(); 53 virtual ~SfxUndoAction() COVERITY_NOEXCEPT_FALSE; 54 55 virtual void Undo(); 56 virtual void UndoWithContext( SfxUndoContext& i_context ); 57 virtual void Redo(); 58 virtual void RedoWithContext( SfxUndoContext& i_context ); 59 virtual void Repeat(SfxRepeatTarget&); 60 virtual bool CanRepeat(SfxRepeatTarget&) const; 61 62 virtual bool Merge( SfxUndoAction *pNextAction ); 63 64 virtual OUString GetComment() const; 65 virtual OUString GetRepeatComment(SfxRepeatTarget&) const; 66 /// ID of the view shell that created this undo action. 67 virtual ViewShellId GetViewShellId() const; 68 /// Timestamp when this undo item was created. 69 const DateTime& GetDateTime() const; 70 virtual void dumpAsXml(xmlTextWriterPtr pWriter) const; 71 72 private: 73 SfxUndoAction( const SfxUndoAction& ) = delete; 74 SfxUndoAction& operator=( const SfxUndoAction& ) = delete; 75 76 DateTime m_aDateTime; 77 }; 78 79 80 /// is a mark on the Undo stack 81 typedef sal_Int32 UndoStackMark; 82 #define MARK_INVALID ::std::numeric_limits< UndoStackMark >::max() 83 84 struct MarkedUndoAction 85 { 86 std::unique_ptr<SfxUndoAction> pAction; 87 ::std::vector< UndoStackMark > aMarks; 88 MarkedUndoActionMarkedUndoAction89 MarkedUndoAction(std::unique_ptr<SfxUndoAction> p) : pAction(std::move(p)) {} 90 }; 91 92 /** do not make use of these implementation details, unless you 93 really really have to! */ 94 struct SVL_DLLPUBLIC SfxUndoArray 95 { 96 std::vector<MarkedUndoAction> maUndoActions; 97 size_t nMaxUndoActions; 98 size_t nCurUndoAction; 99 SfxUndoArray *pFatherUndoArray; 100 SfxUndoArraySfxUndoArray101 SfxUndoArray(size_t nMax=0) : 102 nMaxUndoActions(nMax), nCurUndoAction(0), pFatherUndoArray(nullptr) {} 103 virtual ~SfxUndoArray(); 104 105 SfxUndoArray& operator=( SfxUndoArray const & ) = delete; // MSVC2017 workaround 106 SfxUndoArray( SfxUndoArray const & ) = delete; // MSVC2017 workaround 107 GetUndoActionSfxUndoArray108 SfxUndoAction* GetUndoAction(size_t idx) { return maUndoActions[idx].pAction.get(); } 109 std::unique_ptr<SfxUndoAction> Remove(int idx); 110 void Remove( size_t i_pos, size_t i_count ); 111 void Insert( std::unique_ptr<SfxUndoAction> i_action, size_t i_pos ); 112 }; 113 114 115 /** do not make use of these implementation details, unless you 116 really really have to! */ 117 class SVL_DLLPUBLIC SfxListUndoAction final : public SfxUndoAction, public SfxUndoArray 118 119 /* [Explanation] 120 121 UndoAction to composite multiple Undos in one UndoAction. 122 These actions are used by SfxUndomanager. With < SfxUndoManager::EnterListAction > 123 you can go one composite level down and with < SfxUndoManager::LeaveListAction > up again. 124 Redo and Undo work element wise on SfxListUndoActions. 125 */ 126 { 127 struct Impl; 128 std::unique_ptr<Impl> mpImpl; 129 130 public: 131 132 SfxListUndoAction( 133 const OUString &rComment, const OUString& rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId, SfxUndoArray *pFather ); 134 virtual ~SfxListUndoAction() override; 135 136 virtual void Undo() override; 137 virtual void UndoWithContext( SfxUndoContext& i_context ) override; 138 virtual void Redo() override; 139 virtual void RedoWithContext( SfxUndoContext& i_context ) override; 140 virtual void Repeat(SfxRepeatTarget&) override; 141 virtual bool CanRepeat(SfxRepeatTarget&) const override; 142 143 virtual bool Merge( SfxUndoAction *pNextAction ) override; 144 145 virtual OUString GetComment() const override; 146 /// See SfxUndoAction::GetViewShellId(). 147 ViewShellId GetViewShellId() const override; 148 virtual OUString GetRepeatComment(SfxRepeatTarget&) const override; 149 sal_uInt16 GetId() const; 150 151 void SetComment(const OUString& rComment); 152 void dumpAsXml(xmlTextWriterPtr pWriter) const override; 153 }; 154 155 156 /** is a callback interface for notifications about state changes of an SfxUndoManager 157 */ 158 class SAL_NO_VTABLE SfxUndoListener 159 { 160 public: 161 virtual void actionUndone( const OUString& i_actionComment ) = 0; 162 virtual void actionRedone( const OUString& i_actionComment ) = 0; 163 virtual void undoActionAdded( const OUString& i_actionComment ) = 0; 164 virtual void cleared() = 0; 165 virtual void clearedRedo() = 0; 166 virtual void resetAll() = 0; 167 virtual void listActionEntered( const OUString& i_comment ) = 0; 168 virtual void listActionLeft( const OUString& i_comment ) = 0; 169 virtual void listActionCancelled() = 0; 170 171 protected: ~SfxUndoListener()172 ~SfxUndoListener() {} 173 }; 174 175 176 namespace svl::undo::impl 177 { 178 class UndoManagerGuard; 179 class LockGuard; 180 } 181 182 struct SfxUndoManager_Data; 183 class SVL_DLLPUBLIC SfxUndoManager 184 { 185 std::unique_ptr< SfxUndoManager_Data > 186 m_xData; 187 public: 188 static bool const CurrentLevel = true; 189 static bool const TopLevel = false; 190 191 SfxUndoManager( size_t nMaxUndoActionCount = 20 ); 192 virtual ~SfxUndoManager(); 193 194 void SetMaxUndoActionCount( size_t nMaxUndoActionCount ); 195 virtual void AddUndoAction( std::unique_ptr<SfxUndoAction> pAction, bool bTryMerg=false ); 196 virtual size_t GetUndoActionCount( bool const i_currentLevel = CurrentLevel ) const; 197 OUString GetUndoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const; 198 SfxUndoAction* GetUndoAction( size_t nNo=0 ) const; 199 /// Get info about all undo actions (comment, view shell id, etc.) 200 OUString GetUndoActionsInfo() const; 201 virtual size_t GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const; 202 OUString GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const; 203 SfxUndoAction* GetRedoAction() const; 204 /// Get info about all redo actions (comment, view shell id, etc.) 205 OUString GetRedoActionsInfo() const; 206 virtual bool Undo(); 207 virtual bool Redo(); 208 /** Clears both the Redo and the Undo stack. 209 Will assert and bail out when called while within a list action (<member>IsInListAction</member>). 210 */ 211 virtual void Clear(); 212 /** Clears the Redo stack. 213 Will assert and bail out when called while within a list action (<member>IsInListAction</member>). 214 */ 215 virtual void ClearRedo(); 216 /** leaves any possible open list action (<member>IsInListAction</member>), and clears both the Undo and the 217 Redo stack. 218 219 Effectively, calling this method is equivalent to <code>while ( IsInListAction() ) LeaveListAction();</code>, 220 followed by <code>Clear()</code>. The only difference to this calling sequence is that Reset is an 221 atomic operation, also resulting in only one notification. 222 */ 223 void Reset(); 224 /** determines whether an Undo or Redo is currently running 225 */ 226 bool IsDoing() const; 227 size_t GetRepeatActionCount() const; 228 OUString GetRepeatActionComment( SfxRepeatTarget &rTarget) const; 229 bool Repeat( SfxRepeatTarget &rTarget ); 230 bool CanRepeat( SfxRepeatTarget &rTarget ) const; 231 virtual void EnterListAction(const OUString &rComment, const OUString& rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId); 232 /** Leaves the list action entered with EnterListAction 233 @return the number of the sub actions in the list which has just been left. Note that in case no such 234 actions exist, the list action does not contribute to the Undo stack, but is silently removed. 235 */ 236 size_t LeaveListAction(); 237 238 /** Leaves the list action entered with EnterListAction, and forcefully merges the previous 239 action on the stack into the newly created list action. 240 241 Say you have an Undo action A on the stack, then call EnterListAction, followed by one or more calls to 242 AddUndoAction, followed by a call to LeaveAndMergeListAction. In opposite to LeaveListAction, your Undo 243 stack will now still contain one undo action: the newly created list action, whose first child is the 244 original A, whose other children are those you added via AddUndoAction, and whose comment is the same as 245 the comment of A. 246 247 Effectively, this means that all actions added between EnterListAction and LeaveAndMergeListAction are 248 hidden from the user. 249 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 size_t LeaveAndMergeListAction(); 254 /// determines whether we're within a ListAction context, i.e. a LeaveListAction/LeaveAndMergeListAction call is pending 255 bool IsInListAction() const; 256 /// Determines how many nested list actions are currently open 257 size_t GetListActionDepth() const; 258 /** Clears the redo stack and removes the top undo action */ 259 void RemoveLastUndoAction(); 260 /** enables (true) or disables (false) recording of undo actions 261 262 If undo actions are added while undo is disabled, they are deleted. 263 Disabling undo does not clear the current undo buffer! 264 265 Multiple calls to <code>EnableUndo</code> are not cumulative. That is, calling <code>EnableUndo( false )</code> 266 twice, and then calling <code>EnableUndo( true )</code> means that Undo is enable afterwards. 267 */ 268 void EnableUndo( bool bEnable ); 269 /// returns true if undo is currently enabled. 270 /// This returns false if undo was disabled using EnableUndo( false ) and 271 /// also during the runtime of the Undo() and Redo() methods. 272 bool IsUndoEnabled() const; 273 /// Adds a new listener to be notified about changes in the UndoManager's state 274 void AddUndoListener( SfxUndoListener& i_listener ); 275 void RemoveUndoListener( SfxUndoListener& i_listener ); 276 bool IsEmptyActions() const; 277 278 279 /** marks the current top-level element of the Undo stack, and returns a unique ID for it 280 */ 281 UndoStackMark MarkTopUndoAction(); 282 283 /** removes a mark given by its ID. 284 After the call, the mark ID is invalid. 285 */ 286 void RemoveMark( UndoStackMark const i_mark ); 287 288 /** determines whether the top action on the Undo stack has a given mark 289 */ 290 bool HasTopUndoActionMark( UndoStackMark const i_mark ); 291 292 /** removes the oldest Undo actions from the stack 293 */ 294 void RemoveOldestUndoAction(); 295 296 void dumpAsXml(xmlTextWriterPtr pWriter) const; 297 298 protected: 299 bool UndoWithContext( SfxUndoContext& i_context ); 300 bool RedoWithContext( SfxUndoContext& i_context ); 301 302 void ImplClearRedo_NoLock( bool const i_currentLevel ); 303 304 /** clears all undo actions on the current level, plus all undo actions on superordinate levels, 305 as soon as those levels are reached. 306 307 If no list action is active currently, i.e. we're on the top level already, this method is equivalent to 308 ->Clear. 309 310 Otherwise, the Undo actions on the current level are removed. Upon leaving the current list action, all 311 undo actions on the then-current level are removed, too. This is continued until the top level is reached. 312 */ 313 void ClearAllLevels(); 314 virtual void EmptyActionsChanged(); 315 316 private: 317 size_t ImplLeaveListAction( const bool i_merge, ::svl::undo::impl::UndoManagerGuard& i_guard ); 318 bool ImplAddUndoAction_NoNotify( std::unique_ptr<SfxUndoAction> pAction, bool bTryMerge, bool bClearRedo, ::svl::undo::impl::UndoManagerGuard& i_guard ); 319 void ImplClearRedo( ::svl::undo::impl::UndoManagerGuard& i_guard, bool const i_currentLevel ); 320 void ImplClearUndo( ::svl::undo::impl::UndoManagerGuard& i_guard ); 321 void ImplClearCurrentLevel_NoNotify( ::svl::undo::impl::UndoManagerGuard& i_guard ); 322 size_t ImplGetRedoActionCount_Lock( bool const i_currentLevel = CurrentLevel ) const; 323 bool ImplIsUndoEnabled_Lock() const; 324 bool ImplIsInListAction_Lock() const; 325 void ImplEnableUndo_Lock( bool const i_enable ); 326 327 bool ImplUndo( SfxUndoContext* i_contextOrNull ); 328 bool ImplRedo( SfxUndoContext* i_contextOrNull ); 329 void ImplCheckEmptyActions(); 330 inline bool ImplIsEmptyActions() const; 331 332 friend class ::svl::undo::impl::LockGuard; 333 }; 334 335 #endif 336 337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 338