The next step is to activate the undo/redo functionality... for a Node. Something I've not seen done before. I.e., when the Node is renamed via F2 on the Node, the "Undo/Redo" buttons should start working.
Here is the start of the solution, via this item in the mailing list and Timon Veenstra's BeanNode class, note especially the items in bold:
public class ShipNode extends BeanNode
implements PropertyChangeListener, UndoRedo.Provider {
private final InstanceContent ic;
private final ShipSaveCapability saveCookie;
private UndoRedo.Manager manager;
private String oldDisplayName;
private String newDisplayName;
private Ship ship;
public ShipNode(Ship bean) throws IntrospectionException {
this(bean, new InstanceContent());
}
private ShipNode(Ship bean, InstanceContent ic) throws IntrospectionException {
super(bean, Children.LEAF, new ProxyLookup(new AbstractLookup(ic), Lookups.singleton(bean)));
this.ic = ic;
setDisplayName(bean.getType());
setShortDescription(String.valueOf(bean.getYear()));
saveCookie = new ShipSaveCapability(bean);
bean.addPropertyChangeListener(WeakListeners.propertyChange(this, bean));
}
@Override
public Action[] getActions(boolean context) {
List<? extends Action> shipActions =
Utilities.actionsForPath("Actions/Ship");
return shipActions.toArray(new Action[shipActions.size()]);
}
protected void fire(boolean modified) {
if (modified) {
ic.add(saveCookie);
} else {
ic.remove(saveCookie);
}
}
@Override
public UndoRedo getUndoRedo() {
manager = Lookup.getDefault().lookup(
UndoRedo.Manager.class);
return manager;
}
private class ShipSaveCapability implements SaveCookie {
private final Ship bean;
public ShipSaveCapability(Ship bean) {
this.bean = bean;
}
@Override
public void save() throws IOException {
StatusDisplayer.getDefault().setStatusText("Saving...");
fire(false);
}
}
@Override
public boolean canRename() {
return true;
}
@Override
public void setName(String newDisplayName) {
Ship c = getLookup().lookup(Ship.class);
oldDisplayName = c.getType();
c.setType(newDisplayName);
fireNameChange(oldDisplayName, newDisplayName);
fire(true);
fireUndoableEvent("type", ship, oldDisplayName, newDisplayName);
}
public void fireUndoableEvent(String property, Ship source, Object oldValue, Object newValue) {
ReUndoableEdit reUndoableEdit = new ReUndoableEdit(
property, source, oldValue, newValue);
UndoableEditEvent undoableEditEvent = new UndoableEditEvent(
this, reUndoableEdit);
manager.undoableEditHappened(undoableEditEvent);
}
private class ReUndoableEdit extends AbstractUndoableEdit {
private Object oldValue;
private Object newValue;
private Ship source;
private String property;
public ReUndoableEdit(String property, Ship source, Object oldValue, Object newValue) {
super();
this.oldValue = oldValue;
this.newValue = newValue;
this.source = source;
this.property = property;
}
@Override
public void undo() throws CannotUndoException {
setName(oldValue.toString());
}
@Override
public void redo() throws CannotRedoException {
setName(newValue.toString());
}
}
@Override
public String getDisplayName() {
Ship c = getLookup().lookup(Ship.class);
if (null != c.getType()) {
return c.getType();
}
return super.getDisplayName();
}
@Override
public String getShortDescription() {
Ship c = getLookup().lookup(Ship.class);
if (null != String.valueOf(c.getYear())) {
return String.valueOf(c.getYear());
}
return super.getShortDescription();
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("type")) {
String oldDisplayName = evt.getOldValue().toString();
String newDisplayName = evt.getNewValue().toString();
fireDisplayNameChange(oldDisplayName, newDisplayName);
} else if (evt.getPropertyName().equals("year")) {
String oldToolTip = evt.getOldValue().toString();
String newToolTip = evt.getNewValue().toString();
fireShortDescriptionChange(oldToolTip, newToolTip);
}
fire(true);
}
}
Undo works when rename is done, but Redo never does, because Undo is constantly activated, since it is reactivated whenever there is a name change. And why must the UndoRedoManager be retrieved from the Lookup (it doesn't work otherwise)? Don't get that part of the code either. Help welcome!