In the recent training in Stellenbosch, we managed to include the NetBeans Platform UndoRedo support in an application we worked on, as described in this tutorial. However, when we looked at the Visual Library, the question was raised: "How would UndoRedo work in a Visual Library scene?"
As you can see below, I managed to get it working. I.e., when a widget is moved, the Undo action is enabled. When the Undo action is invoked, the widget is returned to where it was prior to the move. (And then the Redo action is enabled, with corresponding code.)

For this scenario, the widget needs its own MoveStrategy, which has been discussed elsewhere in this blog: //widget.createActions(ACTION_MOVE).addAction(Action Factory.createMoveAction()); MyMoveStrategyProvider provider = new MyMoveStrategyProvider(scene); widget.createActions(ACTION_MOVE).addAction(Action Factory.createMoveAction(provider, provider));
Within the TopComponent, as always when working with UndoRedo, you need to return the UndoRedo.Manager from the getUndoRedo method, which is one of the methods defined in the TopComponent: private UndoRedo.Manager manager = new UndoRedo.Manager(); @Override public UndoRedo getUndoRedo() { return manager; }
Now that we have an UndoRedo.Manager, we can use it within our MoveStrategy: public final class MyMoveStrategyProvider implements MoveStrategy, MoveProvider { private HashMap originalLocations = new HashMap(); private final ObjectScene scene; private Point originalLoc; private Point suggestedLoc; public MyMoveStrategyProvider(ObjectScene scene) { this.scene = scene; } @Override public Point locationSuggested(Widget widget, Point originalLocation, Point suggestedLocation) { this.originalLoc = originalLocation; this.suggestedLoc = suggestedLocation; return suggestedLocation; } @Override public void movementStarted(Widget widget) { manager.addEdit(new MyAbstractUndoableEdit(widget)); } @Override public void movementFinished(Widget widget) { MyAbstractUndoableEdit myAbstractUndoableEdit = new MyAbstractUndoableEdit(widget); manager.undoableEditHappened(new UndoableEditEvent(scene, myAbstractUndoableEdit)); } class MyAbstractUndoableEdit extends AbstractUndoableEdit { private final Widget widget; private MyAbstractUndoableEdit(Widget widget) { this.widget = widget; } @Override public boolean canRedo() { return true; } @Override public boolean canUndo() { return true; } @Override public void undo() throws CannotUndoException { widget.setPreferredLocation(originalLoc); originalLocations.clear(); scene.validate(); } @Override public void redo() throws CannotUndoException { widget.setPreferredLocation(suggestedLoc); scene.validate(); } @Override public boolean isSignificant() { return true; } } @Override public Point getOriginalLocation(Widget widget) { return ActionFactory.createDefaultMoveProvider().getOrigi nalLocation(widget); } @Override public void setNewLocation(Widget widget, Point location) { ActionFactory.createDefaultMoveProvider().setNewLo cation(widget, location); } }
That's all you need. However, you might want to store each moved widget, with each moved position, so that you can create an UndoRedo feature that supports each widget separately. You could also store many moves per widget, rather than one, so that the user will be able to undo/redo many times, instead of just once per scene, as is currently the case.


Read More about [UndoRedo in Visual Library Scenes...