UndoRedo on Nodes

Posted by Geertjan on Oracle Blogs See other posts from Oracle Blogs or by Geertjan
Published on Wed, 23 Nov 2011 02:51:17 -0600 Indexed on 2011/11/24 10:13 UTC
Read the original article Hit count: 460

Filed under:

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?

© Oracle Blogs or respective owner

Related posts about /NetBeans IDE