00001 /* 00002 * PROPRIETARY INFORMATION. This software is proprietary to 00003 * Side Effects Software Inc., and is not to be reproduced, 00004 * transmitted, or disclosed in any way without written permission. 00005 * 00006 * Produced by: 00007 * Ramin Kamal 00008 * Side Effects Software Inc 00009 * 477 Richmond Street West 00010 * Toronto, Ontario 00011 * Canada M5V 3E7 00012 * 416-504-9876 00013 * 00014 * NAME: UT_UndoManager.h ( Utility Library, C++) 00015 * 00016 * COMMENTS: 00017 * This is the class that manages undo and redo. 00018 * There is one global undo manager, but you can make 00019 * your own instance if you want (for example the 00020 * modeler could handle its undos separately) 00021 * 00022 * NOTE: It is not designed to be subclassed. If you 00023 * do subclass it, you're going to have to 00024 * make the destructor virtual, etc. 00025 * 00026 * Example usage: 00027 * 00028 * void f() 00029 * { 00030 * UT_AutoUndoBlock u("Some undo", ANYLEVEL); 00031 * 00032 * if (UTwillAcceptUndoAddition()) 00033 * UTaddToUndoBlock(new MY_UndoSubclass); 00034 * 00035 * // do stuff 00036 * } 00037 * 00038 * First note that we must surround the UTaddToUndoBlock() code 00039 * by creating an undoblock which is accomplished by 00040 * UT_AutoUndoBlock. This class begins an undoblock and ends when 00041 * it goes out of scope. The ANYLEVEL is additional information 00042 * saying that this undoblock can be invoked at any time. If it's 00043 * known that this should always be the topmost undoblock (eg. 00044 * action is invoked from the UI), then you should indicated this 00045 * by TOPLEVEL. 00046 * 00047 * Second, the call to UTaddToUndoBlock() must be preceded by a 00048 * check to UTwillAcceptUndoAddition(). This check ensures that 00049 * undos won't be created while performing the undo/redo action 00050 * themselves as well as when undos are explicitly disabled. 00051 * 00052 * Finally, notice that the undo object is created and ownership 00053 * is given to UTaddtoUndoBlock() so that UT_UndoManager can free 00054 * it when the undo memory limit is reached. 00055 */ 00056 00057 #ifndef __UT_UndoManager__ 00058 #define __UT_UndoManager__ 00059 00060 #include "UT_API.h" 00061 #include "UT_IntArray.h" 00062 #include "UT_PtrArray.h" 00063 #include "UT_StringArray.h" 00064 class UT_Undo; 00065 class UT_UndoBlock; 00066 struct utClearerStruct; 00067 struct utUndoInterestStruct; 00068 00069 enum UT_UndoBlockType 00070 { 00071 TOPLEVEL, 00072 ANYLEVEL 00073 }; 00074 00075 class UT_API UT_UndoManager 00076 { 00077 public: 00078 UT_UndoManager(); 00079 ~UT_UndoManager(); 00080 00081 static void disableUndoCreation(); 00082 static void enableUndoCreation(); 00083 00084 // When calling beginUndoBlock if you can determine that your code 00085 // path will only be executed from outside any other undo block (eg 00086 // on the mouse-down of a mouse-drag instantiated operation) then 00087 // pass in UT_UNDOBLOCK_TOPLEVEL as the blocktype to beginUndoBlock. 00088 // Otherwise pass in UT_UNDOBLOCK_GENERIC. 00089 int beginUndoBlock(const char *name, 00090 UT_UndoBlockType blocktype); 00091 00092 // Instead of beginning a new undo block, this will append to the previous 00093 // undo block if the given name matches. This only happens if we currently 00094 // don't have any undoblocks open. If we do, then we will just use the 00095 // current one just like beginUndoBlock(). The returned level must be 00096 // passed to a corresponding endUndoBlock() call. 00097 int beginLastUndoBlock(const char *name, 00098 UT_UndoBlockType blocktype); 00099 00100 // The level that's passed in to endUndoBlock should the level that 00101 // was returned by the matching call to beginUndoBlock. If the code 00102 // that called beginUndoBlock is too far from the call to endUndoBlock 00103 // then you can pass in -1 (ie you don't know) but that means that 00104 // some of the undo manager error detection won't be able to operate. 00105 void endUndoBlock(int level); 00106 00107 // This value should always be checked before adding to an undo block. 00108 int willAcceptUndoAddition(); 00109 // This will return a non zero value if we are performing an undo or redo. 00110 int performingUndoRedo(); 00111 00112 // This returns true if any undos are being done, zero if undos 00113 // are disabled. 00114 int isUndoEnabled(); 00115 00116 // Add an undo to the current undoblock, taken ownership of the pointer. 00117 // You *must* precede with this with a call to willAcceptUndoAddition(). 00118 // See the top of this file for how to use this. 00119 void addToUndoBlock(UT_Undo *undo); 00120 00121 // Add an undo to the undo block that last ended. Takes ownership of undo 00122 void addToLastUndoBlock(UT_Undo *undo); 00123 00124 // Suspend/Resume allowing toplevel undoblocks. All calls to suspend must 00125 // be matched with a corresponding call to resume. 00126 void suspendTopLevelUndoBlock(); 00127 void resumeTopLevelUndoBlock(); 00128 00129 // Use these functions when you want to tell the undo manager 00130 // that any undos that are being added (outside your control) 00131 // should be ignored. Just frame the code section in question 00132 // with disallowUndos() and allowUndos() in that order. 00133 void disallowUndos() { disableUndoCreation(); } 00134 void allowUndos() { enableUndoCreation(); } 00135 00136 // The strict parameter restricts the behaviour to only affect the 00137 // top undo block, rather than searching through the stack for the 00138 // first block which will have an effect. 00139 // The redoable flag determines whether or not the block about to be 00140 // undone is added to the redo stack 00141 void undo(bool strict = false, bool redoable = true); 00142 void redo(bool strict = false); 00143 00144 const char *getUndoOperationName(); 00145 const char *getRedoOperationName(); 00146 00147 /// Free all invalid undos/redos 00148 void pruneInvalidUndos(); 00149 00150 int64 getMemoryUsage(); 00151 int64 getMemoryUsageLimit() { return myMemLimit; } 00152 void setMemoryUsageLimit(int64 bytes); 00153 00154 // clearUndos will wipe away all the undo and redos 00155 void clearUndos(); 00156 00157 // clearUndoFlags is used to clear any flags that have been set 00158 // for optimization during undo blocks 00159 void clearUndoFlags(); 00160 void installUndoFlagClearer(void (*function)(void *data), 00161 void *data); 00162 void removeUndoFlagClearer(void (*function)(void *data), 00163 void *data); 00164 00165 // Install or clear a callback to be called whenever the undo/redo 00166 // stack changes. Currently this is intended for the use of the 00167 // undo manager UI, and so there can only be one interest. 00168 void setUndoInterest(void (*function)(void *data), 00169 void *data); 00170 00171 const UT_UndoBlock *getUndoStack() const { return myUndoBlockStack; } 00172 const UT_UndoBlock *getRedoStack() const { return myRedoBlockStack; } 00173 00174 private: 00175 void checkMemoryUsage(); 00176 void pruneUndoBlockStack(); 00177 void pruneRedoBlockStack(); 00178 00179 UT_UndoBlock *myUndoBlockStack; 00180 UT_UndoBlock *myRedoBlockStack; 00181 00182 int myBlockLevel; 00183 int64 myMemLimit; 00184 int64 myNetMemory; 00185 00186 UT_PtrArray<utClearerStruct *> myClearers; 00187 00188 utUndoInterestStruct *myInterest; 00189 00190 UT_IntArray myTopBlockLevelStack; 00191 UT_StringArray myTopBlockLevelNameStack; 00192 00193 char myBusyFlag; 00194 char myEnableBugNotify; 00195 }; 00196 00197 UT_API UT_UndoManager *UTgetUndoManager(); 00198 00199 // These following functions are provided for convenience. 00200 // By default they affect the global Undo manager, but you 00201 // can override that behaviour. 00202 UT_API int UTbeginUndoBlock(const char *name, 00203 UT_UndoBlockType blocktype, 00204 UT_UndoManager *man = 0); 00205 UT_API int UTwillAcceptUndoAddition(UT_UndoManager *man = 0); 00206 UT_API void UTaddToUndoBlock(UT_Undo *, UT_UndoManager *man = 0); 00207 UT_API void UTendUndoBlock(int level, UT_UndoManager *man = 0); 00208 UT_API int UTperformingUndoRedo(UT_UndoManager *man = 0); 00209 00210 // Use this name for your undo block if you want it to adopt the name 00211 // of the next undo block that gets added. 00212 #define UT_UNDOBLOCK_ADOPT_NAME "Multiple Undo Operation" 00213 00214 class UT_API UT_AutoUndoBlock 00215 { 00216 public: 00217 UT_AutoUndoBlock(const char *name, UT_UndoBlockType blocktype) 00218 { 00219 myStackLevel = UTbeginUndoBlock(name, blocktype); 00220 } 00221 ~UT_AutoUndoBlock() 00222 { 00223 UTendUndoBlock(myStackLevel); 00224 } 00225 00226 private: 00227 int myStackLevel; 00228 }; 00229 00230 // Create local instances of this class to disallow undos on construction and 00231 // allow them again when it goes out of scope. 00232 class UT_API UT_AutoDisableUndos 00233 { 00234 public: 00235 UT_AutoDisableUndos() 00236 { 00237 UT_UndoManager *undo_manager = UTgetUndoManager(); 00238 if (undo_manager) 00239 undo_manager->disallowUndos(); 00240 } 00241 00242 ~UT_AutoDisableUndos() 00243 { 00244 UT_UndoManager *undo_manager = UTgetUndoManager(); 00245 if (undo_manager) 00246 undo_manager->allowUndos(); 00247 } 00248 }; 00249 00250 #endif
1.5.9