Basic "undo/redo" on the entire document is implemented but getting it actually working is tricky.
Consider input methods. Each input has a set of input methods, only one of which is active. Opening a method creates a dialog containing four widgets, one of which is visible depending on which is the active method - and the widgets link to the methods. Of course, if you reload the entire document (which is essentially what you do when you undo/redo) you're creating a completely new set of methods, and the widget doesn't have links to those!
This is going to be even worse with nodes. You might have a tab open which has a link to its node. Undo, and you now have a tab linked to a dead node.
OK, for inputs it is no longer failing because I'm deserialising each method into its original data structure. That seems to be OK, but invalidation now isn't working (called from onInputChanged).
Undo appears to work OK on treeview inputs (rgb, envi) but not so well on Multifile. I'm tempted to leave it; I'm not happy with multifile and I don't think it will often be used.
Now for nodes. Urgh.
When an undo is performed, replaceData is called on the document. This will deserialise the data into the document which will replace the entire graph. For all windows with this document, replaceDocument will be called. This will replace the graph (and the document although at the moment it will always be the same), reconstruct the scene, and update all tabs to use the new node. The nodes to set the tabs to are identified by name from the old node used by that tab.
next up: adding mark() calls to the UI and redo/undo calls to the main window (or tab).
This all got very complicated:
node tabs have to call mark() before writing any widget changes to the node. This only calls node.mark (which itself calls mark on the document) when the updatingTabs flag is false.
when a tab has to set itself up from the node we call nodeChanged - we used to call onNodeChanged. This new method will just call onNodeChanged in the tab, but will set updatingTabs to true. This will stop inadvertent double-marking when we change a widget: sometimes we change a widget, state gets copied into the node, then onNodeChange would be called writing to the widget again.
Canvas setup (setMapping, setGraph, setPersister, setROINode) was done in tab init, and now is done in onNodeChanged. This is because the current undo model replaces the document contents, and remaps tabs to different nodes. This needs to be done for the underlying canvas too, and is best done in onNodeChanged.
Now for nodes. Urgh.