4
using System.Collections;
8
public class UndoQueue: MarshalByRefObject
10
ArrayList changeList = new ArrayList ();
11
int undoListCount = 0;
12
static UndoQueue empty = new UndoQueue ();
14
public void AddChange (UndoRedoChange change)
16
if (undoListCount < changeList.Count) {
17
// Destroy all undone changes
18
changeList.RemoveRange (undoListCount, changeList.Count - undoListCount);
20
changeList.Add (change);
21
undoListCount = changeList.Count;
24
public static UndoQueue Empty {
29
get { return undoListCount > 0; }
33
get { return undoListCount < changeList.Count; }
38
if (undoListCount == 0)
41
UndoRedoChange change = (UndoRedoChange) changeList [--undoListCount];
42
if (change.CheckValid ()) {
43
object res = change.ApplyChange ();
45
changeList [undoListCount] = res;
48
changeList.RemoveAt (undoListCount);
50
changeList.RemoveAt (undoListCount);
57
if (undoListCount == changeList.Count)
60
UndoRedoChange change = (UndoRedoChange) changeList [undoListCount++];
61
if (change.CheckValid ()) {
62
object res = change.ApplyChange ();
64
changeList [undoListCount - 1] = res;
68
changeList.RemoveAt (undoListCount);
72
changeList.RemoveAt (--undoListCount);
79
for (int n=0; n<changeList.Count; n++) {
80
UndoRedoChange change = (UndoRedoChange) changeList [n];
81
if (!change.CheckValid()) {
82
changeList.RemoveAt (n);
83
if (n < undoListCount)
90
public abstract class UndoRedoChange: MarshalByRefObject
92
public abstract UndoRedoChange ApplyChange ();
94
public virtual bool CheckValid ()
101
class ObjectWrapperUndoRedoChange: UndoRedoChange
103
UndoRedoManager manager;
104
public string TargetObject;
106
public ObjectWrapperUndoRedoChange Next;
108
public ObjectWrapperUndoRedoChange (UndoRedoManager manager, string targetObject, object diff)
110
this.manager = manager;
111
this.TargetObject = targetObject;
115
public override UndoRedoChange ApplyChange ()
117
return manager.ApplyChange (this);
120
public override bool CheckValid ()
122
return manager.CheckValid ();
126
class UndoRedoManager: IDisposable
129
ObjectWrapper rootObject;
131
UndoManager undoManager = new UndoManager ();
133
public UndoRedoManager ()
135
undoManager.UndoCheckpoint += OnUndoCheckpoint;
138
public ObjectWrapper RootObject {
139
get { return rootObject; }
142
undoManager.SetRoot (rootObject);
146
public UndoQueue UndoQueue {
147
get { return queue; }
148
set { queue = value; }
151
internal UndoManager UndoManager {
152
get { return undoManager; }
155
void OnUndoCheckpoint (object sender, UndoCheckpointEventArgs args)
157
AddChange (args.ModifiedObjects);
160
void AddChange (ObjectWrapper[] obs)
162
if (updating || queue == null)
165
ObjectWrapperUndoRedoChange firstChange = null;
166
ObjectWrapperUndoRedoChange lastChange = null;
168
// Console.WriteLine ("** UNDO CHECKPOINT: {0} objects", obs.Length);
170
foreach (ObjectWrapper ob in obs) {
172
// Get the diff for going from the new status to the old status
173
object diff = GetDiff (ob);
175
if (diff == null) // No differences
178
// Console.WriteLine ("ADDCHANGE " + ob + " uid:" + ob.UndoId);
179
// PrintPatch (diff);
181
if (ob.UndoId == null || ob.UndoId.Length == 0)
182
throw new InvalidOperationException ("Object of type '" + ob.GetType () + "' does not have an undo id.");
184
ObjectWrapperUndoRedoChange change = new ObjectWrapperUndoRedoChange (this, ob.UndoId, diff);
185
if (lastChange == null)
186
lastChange = firstChange = change;
188
lastChange.Next = change;
192
if (firstChange != null)
193
queue.AddChange (firstChange);
196
protected virtual object GetDiff (ObjectWrapper w)
198
return w.GetUndoDiff ();
201
public UndoRedoChange ApplyChange (ObjectWrapperUndoRedoChange first)
206
ObjectWrapperUndoRedoChange change = first;
207
ObjectWrapperUndoRedoChange lastRedo = null;
208
while (change != null) {
209
ObjectWrapperUndoRedoChange redo = ApplyDiff (change.TargetObject, change.Diff);
211
redo.Next = lastRedo;
214
change = change.Next;
217
} catch (Exception ex) {
218
Console.WriteLine (ex);
225
ObjectWrapperUndoRedoChange ApplyDiff (string id, object diff)
227
// Console.WriteLine ("** APPLYING DIFF: uid:" + id);
228
// PrintPatch (diff);
230
ObjectWrapper ww = rootObject.FindObjectByUndoId (id);
232
Console.WriteLine ("Object with undo id '{0}' not found", id);
236
object reverseDiff = ww.ApplyUndoRedoDiff (diff);
238
if (reverseDiff != null) {
239
// Console.WriteLine ("** REVERSE DIFF:");
240
// PrintPatch (reverseDiff);
242
ObjectWrapperUndoRedoChange change = new ObjectWrapperUndoRedoChange (this, id, reverseDiff);
248
internal bool CheckValid ()
250
return rootObject != null;
253
public void Dispose ()
260
internal void PrintPatch (object diff)
263
foreach (object ob in (Array)diff)
264
if (ob != null) PrintPatch (ob);
265
} else if (diff is XmlElement)
266
Console.WriteLine (((XmlElement)diff).OuterXml);
268
Console.WriteLine (diff.ToString ());