00001 /* 00002 * Copyright 2007 Martin von Gagern 00003 * 00004 * 00005 * This file is part of bande. 00006 * 00007 * bande is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 3 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * bande is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 00022 /** 00023 * @file 00024 * Interface of class bande::UndoManager. 00025 */ 00026 00027 namespace bande { 00028 00029 00030 00031 /** 00032 * Abstract base class for any undoable modification. 00033 */ 00034 class UndoBase { 00035 public: 00036 00037 /** 00038 * Destructor. 00039 * This cirtual destructor allows clean destruction of derived 00040 * classes even in the presence of polymorphism. 00041 */ 00042 virtual ~UndoBase() {} 00043 00044 /** 00045 * Undo one operation. 00046 * This is a pure virtual function that must be overridden by any 00047 * concrete derived class. 00048 */ 00049 virtual void undo() = 0; 00050 }; 00051 00052 00053 00054 class UndoManager; 00055 00056 00057 00058 /** 00059 * Stack pointer for the UndoManager. 00060 * This encapsulates the current state of the UndoManager. It 00061 * represents a snapshot of its action stack and allows undoing all 00062 * actions that were added later in order to restore the state 00063 * corresponding to this snapshot. 00064 */ 00065 class UndoState { 00066 public: 00067 00068 /** 00069 * Undo all modifications added after this state was saved. 00070 */ 00071 void restore(); 00072 00073 protected: 00074 00075 /** 00076 * Constructor. 00077 * Access to this constructor is only allowed from within the 00078 * UndoManager. Other code must ask UndoManager::save() to get an 00079 * UndoState object. 00080 * @param um the undo manager associated with this state. 00081 * @param pos the current stack pointer of this undo manager. 00082 */ 00083 UndoState(UndoManager& um, unsigned pos) : um(um), pos(pos) { } 00084 00085 /** 00086 * The UndoManager may create objects of this class. 00087 */ 00088 friend class UndoManager; 00089 00090 private: 00091 00092 /** 00093 * The associated undo manager. 00094 */ 00095 UndoManager& um; 00096 00097 /** 00098 * Stack pointer for the associated undo manager. 00099 */ 00100 const unsigned pos; 00101 }; 00102 00103 00104 00105 /** 00106 * Stack of undoable modifications. 00107 * 00108 * Whenever a class performs some local modification that needs to 00109 * be unwound when the current branch is left, this modification can 00110 * be registered with the UndoManager. In this way, no class has to 00111 * care for properly cleaning up all modifications in all possible 00112 * cases. It registers the undo event when it performs the 00113 * modification in the first place, and after that it can forget 00114 * about it. The branching code will ask the undo manager to rewind 00115 * modifications in reverse order at appropriate times. 00116 */ 00117 class UndoManager { 00118 public: 00119 00120 virtual ~UndoManager(); 00121 00122 /** 00123 * Save current state. 00124 * 00125 * The returned object can be used to rewind all modifications 00126 * added after its creation. 00127 * 00128 * @return an object encapsulating the current state of the stack 00129 * of modifications. 00130 */ 00131 UndoState save() { return UndoState(*this, events.size()); } 00132 00133 /** 00134 * Record a modification for later rewinding. 00135 * The undo manager will ensure the objects will get deleted 00136 * eventually. 00137 * 00138 * @param event an undoable object describing the modification. 00139 */ 00140 void record(UndoBase* event) { events.push_back(event); } 00141 00142 protected: 00143 00144 void restore(unsigned pos); 00145 00146 /** 00147 * The UndoState may initiate rewinding of modifications. 00148 */ 00149 friend void UndoState::restore(); 00150 00151 private: 00152 00153 /** 00154 * A stack of undoable events. 00155 */ 00156 std::vector<UndoBase*> events; 00157 }; 00158 00159 00160 00161 inline void UndoState::restore() { um.restore(pos); } 00162 00163 00164 00165 /** 00166 * Undo information for modification of one int variable. 00167 */ 00168 class UndoInt : public UndoBase { 00169 public: 00170 00171 /** 00172 * Record undo information given pointer and previous value. 00173 * @param p the pointer of the variable about to be modified. 00174 * @param v the old value of the variable to be restored upon 00175 * undo. 00176 */ 00177 UndoInt(int* p, int v) : ptr(p), val(v) { } 00178 00179 /** 00180 * Record undo information using a reference to the variable. 00181 * The supplied reference will be used to record both the 00182 * variable's address and its current (old) value. 00183 * @param i the variable that is about to be modified. 00184 */ 00185 UndoInt(int& i) : ptr(&i), val(i) { } 00186 00187 /** 00188 * Undo the modification. 00189 * The recorded old value is written to the recoded address. 00190 */ 00191 void undo() { *ptr = val; } 00192 00193 protected: 00194 00195 /** 00196 * Address of the modified variable. 00197 */ 00198 int *ptr; 00199 00200 /** 00201 * Old value of the modified variable. 00202 */ 00203 int val; 00204 }; 00205 00206 }
1.6.0