I'm writing a structural modeling tool for a civil enginering application. I have one huge model class representing the entire building, which include collections of nodes, line elements, loads, etc. which are also custom classes.
I have already coded an undo engine which saves a deep-copy after each modification to the model. Now I started thinking if I could have coded differently. Instead of saving the deep-copies, I could perhaps save a list of each modifier action with a corresponding reverse modifier. So that I could apply the reverse modifiers to the current model to undo, or the modifiers to redo.
I can imagine how you would carry out simple commands that change object properties, etc. But how about complex commands? Like inserting new node objects to the model and adding some line objects which keep references to the new nodes.
How would one go about implementing that?
If I add the comment "Undo Algorthim" will that make it so I can search "Undo Algorithm" and find this? That's what I searched for and I found something closed as a duplicate.
hay,I also want to develope undo/redo in the application we are developing.We use QT4 framework and need to have many complex undo/redo actions..I was wondering , have you succeed using Command-Pattern ?
umanga: It worked but it wasn't easy. The hardest part was keeping track of references. For example, when a Frame object is deleted, its child objects: Nodes, Loads acting on it and many other user assignments needed to be kept to be reinserted when undone. But some of these child objects were shared with other objects, and undo/redo logic became quite complex. If the model wasn't that large, I would keep the memento approach; it is much easier to implement.
this is a fun problem to work on, think about how source code repos do it, like svn (they keep the diffs between commits).
This is basically how the undo engine in Cocoa, NSUndoManager, works.
If you use a database (eg sqlite) as your file format this can be almost automatic
If you augment this by tracking dependencies introduced by changes to the model, then you could potentially have an undo tree system (i.e. if I change the width of a girder, then go do some work on a separate component, I can come back and undo the girder changes without losing the other stuff). The UI for that might be a little unwieldy but it would be much more powerful than a traditional linear undo.
Can you explain this id's vs pointers idea more? Surely a pointer/memory address works just as well as id?
Not really, this addresses his initial approach. He's asking for an alternative approach. The initial being storing the full state for each step while the latter being storing only the "diffs".
I’ve never thought of paste as cut^-1.
Actually, the Paint.NET code is no longer available, but you can get the forked code.google.com/p/paint-mono
What would you put in the deque?
In my case I put the current state of the operations I wanted undo/redo functionality for. By having two deques (undo/redo) i do undo on the undo queue (pop first item) and insert it into the redo dequeue. If the number of items in the dequeues exceed the prefered size i pop an item of the tail.
What you describe actually IS a design pattern :). The problem with this approach is when your state takes a lot of memory - keeping several dozens of state version then becomes unpractical or even impossible.
Or you can store pair of closure representing normal and undo operation.
This sounds increasingly unworkable as the size of your model grows.
In what way? This approach keeps working without changes as new "things" are added to each object. Performance could be an issue as the serialized form of the objects grows in size - but this hasn't been a major problem. The system has been under continuous development for 20+ years and is in use by 1000s of users.
Please post your comments as answer only if you are confident to provide solutions! Otherwise prefer to post it as comment under the question! (if it doesn't allow to do so now! please wait till you get good reputation)