GoUndoManager wrapper


First let me congratulate you on a great product that we recently purchased!
Ok here is what i want to do… I want to wrap the GoUndoManager. But i want to wrap it on only when a move occurs.
The insert and delete is already done trough my CommandManager…
The thing is…when moving an object (that contains multiple GoObjects), i get multiple DocumentChanged events in my GoUndoManager
wrapper class… I dont want to insert a GoCommand in my CommandManager for every sub-object that is moved…Is there a way to get the super
edit object (if it even exists) that once undone or redone moves all the GoObjects? My stuff would look something like that :
public class GoUndoManagerWrapper : GoUndoManager
public override DocumentChanged(…)
Editor.Instance.CommandManager.Do(new GoCommand(Some IGoUndoableEdit));
public class GoCommand : ICommand
public GoCommand(IGoUndoableEdit edit) { this.edit = edit; }
public Execute()
public void Undo()
Thanks…Hope i was clear enough.


Do you have to modify the standard GoUndoManager?
Would a GoView.SelectionMoved event handler suffice? You might also want to implement a SelectionCopied event handler. Of course, there are several other GoView events that might also be of interest.


The thing is…i dont want all events to be trapped by the GoUndoManager…I dont want for example the GoUndoManager to Redo and Undo the adds and removes done in a GoDocument because it is already done by my Command system… so calling undo on the GoUndoManager doesnt necessarely undo what i want… The best thing for me would be able to do SkipEvent on any event that is not a move…


Hmmm. The problem is that if there’s some code that modifies the position of an object, you can’t tell why the position changed.
Still, I wonder if you could have the GoView.SelectionMoved event handler set the GoUndoManager.CurrentEdit to null, to throw away the compound edit collection of GoChangedEventArgs that record the position changes. I haven’t tried this, so I don’t know if there might be complications.


It would be nice having a way to subclass the GoUndoManager and tell it exactly what Edits (by edits i mean a compound edit) that it is interested in…and those that arent… so whenever a move occurs i could push it in my stack (my command manager) and since its the only event recorded by the GoUndoManager …i would call Undo on the undomanager to reverse the changes…


Yes, I think you could do that by overriding EndTransaction. It would probably be easiest to just call the base method and then if the return result is true, you can decide whether or not to remove the last compound edit from the GoUndoManager.AllEdits list.


Great…that where i was heading… but i didnt think of the AllEdits list… so i remove from the list the compound edits that arent move actions…great i will try that!!!


override bool EndTransaction(bool commit, string pname)


bool ret = base.EndTransaction (commit, pname); if(ret) {
GoUndoManagerCompoundEdit edit = (AllEdits[AllEdits.Count-1] as GoUndoManagerCompoundEdit); if(edit.PresentationName != MoveSelectionName)
Editor.Instance.CommandManager.Do(new GoCommand(this));
} return ret;
} [/code] The only problem with my code...is that when i call the undomanager undo method, the object dissapears...calling redo works but undo doesnt.. so when undoing a move i get a dissapeard object and redoing the move makes it reappear at the position it was moved to...


…So any idea of what could cause this problem?

The problem is that modifying the (top-level) contents of the GoUndoManager.AllEdits list doesn't update the GoUndoManager.UndoEditIndex value, so the undo manager loses track of where it should be. If instead of your code: AllEdits.Remove(edit) you do: edit.Clear(); to leave the compound edit in place in the list, then the UndoEditIndex is still valid. Then you just need to modify [Can]Undo/Redo appropriately: public override bool CanUndo() { if (this.TransactionLevel > 0) return false; if (this.IsUndoing) return false; if (this.IsRedoing) return false; IGoUndoableEdit curr = this.EditToUndo; return curr != null; } public override void Undo() { while (true) { GoUndoManagerCompoundEdit cedit = this.EditToUndo as GoUndoManagerCompoundEdit; if (cedit != null && cedit.AllEdits.Count == 0) base.Undo(); else break; } base.Undo(); } public override bool CanRedo() { if (this.TransactionLevel > 0) return false; if (this.IsUndoing) return false; if (this.IsRedoing) return false; IGoUndoableEdit curr = this.EditToRedo; return curr != null; } public override void Redo() { while (true) { GoUndoManagerCompoundEdit cedit = this.EditToRedo as GoUndoManagerCompoundEdit; if (cedit != null && cedit.AllEdits.Count == 0) base.Redo(); else break; } base.Redo(); } (sorry for the formatting...)


I Get the same result… here is my EndTransaction method :

<B><FONT color=#c0c0c0 size=1> <FONT color=#000000>public</FONT></B></FONT><FONT color=#000000><FONT size=1> </FONT><B><FONT size=1>override</B></FONT></FONT><FONT color=#000000><FONT size=1> </FONT><B><FONT size=1>bool</B></FONT></FONT><FONT color=#000000><FONT size=1> EndTransaction(</FONT><B><FONT size=1>bool</B></FONT></FONT><FONT color=#000000><FONT size=1> commit, </FONT><B><FONT size=1>string</B></FONT></FONT><FONT size=1><FONT color=#000000> pname)</FONT> <FONT color=#000000>{</FONT> </FONT><B><FONT size=1><FONT color=#000000>bool</FONT></B></FONT><FONT color=#000000><FONT size=1> ret = </FONT><B><FONT size=1>base</B></FONT></FONT><FONT size=1><FONT color=#000000>.EndTransaction (commit, pname);</FONT> </FONT><B><FONT size=1><FONT color=#000000>if</FONT></B></FONT><FONT color=#000000><FONT size=1>(ret && (EditToUndo != </FONT><B><FONT size=1>null</B></FONT></FONT><FONT size=1><FONT color=#000000>))</FONT> <FONT color=#000000>{</FONT> </FONT><B><FONT size=1><FONT color=#000000>if</FONT></B></FONT><FONT size=1><FONT color=#000000>(EditToUndo.PresentationName != MoveSelectionName)</FONT> <FONT color=#000000>EditToUndo.Clear();</FONT> </FONT><B><FONT size=1><FONT color=#000000>else</FONT></B></FONT><FONT size=1> <FONT color=#000000>Editor.Instance.CommandManager.Do(</FONT></FONT><B><FONT size=1><FONT color=#000000>new</FONT></B></FONT><FONT color=#000000><FONT size=1> GoCommand(</FONT><B><FONT size=1>this</B></FONT></FONT><FONT size=1><FONT color=#000000>));</FONT> <FONT color=#000000>}</FONT> </FONT><B><FONT size=1><FONT color=#000000>return</FONT></B></FONT><FONT color=#ffffff size=1><FONT color=#000000> ret;</FONT> <FONT color=#000000>}</FONT> <FONT color=#000000>
I get the same thing… my node are added to the document using goView.Document.Add(node) if this can help… and when moving and undoing the move, the node dissapears and redoing makes it reappear…


Well, clearly the set of changes that are undone or redone include adding the node to the document, so that an undo makes the node disappear and a redo causes it to reappear. Did you add the node in a separate transaction?


No. Adding the node to the document and removing it is undone using my Command manager…which is not part of the GoUndoManager and upon which my Documents are updated… the only change that i want to use the GoUndoManager for is moving of selections…So are you saying that in order to have separate compound edits, i need to wrap my GoDocument.Add call and Remove in a StartTransaction EndTransaction call?


Ok wrapping Add and Remove in transactions does the trick…except that if i undo the Add… i lose the Move in the GoUndoManager…i guess it has something to do with the object being removed from the layer…


[oh-- simultaneous posts]
Yes, if you want to use the GoUndoManager, you need to make all changes inside transactions. If you don’t all the changes are lumped together into a big transaction, which typically causes more stuff to be undone than the user expected.