X

Geertjan's Blog

  • November 23, 2011

UndoRedo on Nodes (Part 1)

Geertjan Wielenga
Product Manager

When a change is made to the property in the Properties Window, below, the undo/redo functionality becomes enabled:

When undo/redo are invoked, e.g., via the buttons in the toolbar, the display name of the node changes accordingly. The only problem I have is that the buttons only become enabled when the Person Window is selected, not when the Properties Window is selected, which would be desirable.

Here's the Person object:

public class Person implements PropertyChangeListener {
    private String name;
    public static final String PROP_NAME = "name";
    public Person(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        String oldName = this.name;
        this.name = name;
        propertyChangeSupport.firePropertyChange(PROP_NAME, oldName, name);
    }
    private transient final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        propertyChangeSupport.firePropertyChange(evt);
    }
}

And here's the Node with UndoRedo enablement:

public class PersonNode extends AbstractNode implements UndoRedo.Provider, PropertyChangeListener {
    private UndoRedo.Manager manager = new UndoRedo.Manager();
    private boolean undoRedoEvent;
    public PersonNode(Person person) {
        super(Children.LEAF, Lookups.singleton(person));
        person.addPropertyChangeListener(this);
        setDisplayName(person.getName());
    }
    @Override
    protected Sheet createSheet() {
        Sheet sheet = Sheet.createDefault();
        Sheet.Set set = Sheet.createPropertiesSet();
        set.put(new NameProperty(getLookup().lookup(Person.class)));
        sheet.put(set);
        return sheet;
    }
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals(Person.PROP_NAME)) {
            firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
        }
    }
    public void fireUndoableEvent(String property, Person source, Object oldValue, Object newValue) {
        manager.addEdit(new MyAbstractUndoableEdit(source, oldValue, newValue));
    }
    @Override
    public UndoRedo getUndoRedo() {
        return manager;
    }
    @Override
    public String getDisplayName() {
        Person p = getLookup().lookup(Person.class);
        if (p != null) {
            return p.getName();
        }
        return super.getDisplayName();
    }
    private class NameProperty extends PropertySupport.ReadWrite<String> {
        private Person p;
        public NameProperty(Person p) {
            super("name", String.class, "Name", "Name of Person");
            this.p = p;
        }
        @Override
        public String getValue() throws IllegalAccessException, InvocationTargetException {
            return p.getName();
        }
        @Override
        public void setValue(String newValue) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
            String oldValue = p.getName();
            p.setName(newValue);
            if (!undoRedoEvent) {
                fireUndoableEvent("name", p, oldValue, newValue);
                fireDisplayNameChange(oldValue, newValue);
            }
        }
    }
    class MyAbstractUndoableEdit extends AbstractUndoableEdit {
        private final String oldValue;
        private final String newValue;
        private final Person source;
        private MyAbstractUndoableEdit(Person source, Object oldValue, Object newValue) {
            this.oldValue = oldValue.toString();
            this.newValue = newValue.toString();
            this.source = source;
        }
        @Override
        public boolean canRedo() {
            return true;
        }
        @Override
        public boolean canUndo() {
            return true;
        }
        @Override
        public void undo() throws CannotUndoException {
            undoRedoEvent = true;
            source.setName(oldValue.toString());
            fireDisplayNameChange(oldValue, newValue);
            undoRedoEvent = false;
        }
        @Override
        public void redo() throws CannotUndoException {
            undoRedoEvent = true;
            source.setName(newValue.toString());
            fireDisplayNameChange(oldValue, newValue);
            undoRedoEvent = false;
        }
    }
}

Does anyone out there know how to have the Undo/Redo functionality enabled when the Properties Window is selected?

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.