Closed dlemmermann closed 7 years ago
Currently my change object for list changes looks like this, but I keep getting "IllegalArgumentException: Unexpected change received".
` public static abstract class MyChange {
public abstract void redo();
public abstract PathwayChange invert();
public Optional<PathwayChange> mergeWith(PathwayChange other) {
// don't merge changes by default
return Optional.empty();
}
}
// list changes (elements added or removed)
public static class ListChange extends MyChange {
private ListChangeListener.Change change;
private ObservableList list;
private boolean added;
private List elements;
private int hashCode;
public ListChange(ListChangeListener.Change change) {
this.change = change;
list = change.getList();
change.next(); // not optimal, there could be several changes!
if (change.wasAdded()) {
added = true;
elements = change.getAddedSubList();
} else if (change.wasRemoved()) {
added = false;
elements = change.getRemoved();
}
hashCode = Objects.hash(change, list, elements, added);
}
// private constructor, only used internally be invert() method
private ListChange(ListChangeListener.Change change, ObservableList list, List elements, boolean added) {
this.change = change;
this.list = list;
this.elements = elements;
this.added = added;
this.hashCode = Objects.hash(change, list, elements, added);
}
@Override
public void redo() {
if (added) {
list.addAll(elements);
} else {
list.removeAll(elements);
}
}
@Override
public ListChange invert() {
return new ListChange(change, list, elements, !added);
}
@Override
public boolean equals(Object other) {
if (other instanceof ListChange) {
ListChange that = (ListChange) other;
return Objects.equals(this.change, that.change)
&& Objects.equals(this.list, that.list)
&& Objects.equals(this.elements, that.elements)
&& Objects.equals(this.added, that.added);
}
return false;
}
@Override
public int hashCode() {
return hashCode;
}
}
`
Based on the error message I am currently assuming it has something to do with the equals() and hashCode() methods.
It has to be the case that when you apply a change c
, a change c1
arrives in the change stream such that c.equals(c1)
. This is probably not the case because of comparing the original ListChangeListener.Change
objects. You probably don't need to store these objects at all.
I made it work by only basing the hash code and equals methods on the added / removed elements list. Additionally I had to create a new element list to avoid concurrent modification exceptions.
` public static class ListChange extends PathwayChange {
private ObservableList collection;
private boolean added;
private List elements;
public ListChange(ListChangeListener.Change change) {
collection = change.getList();
change.next();
if (change.wasAdded()) {
added = true;
elements = new ArrayList(change.getAddedSubList());
} else if (change.wasRemoved()) {
added = false;
elements = new ArrayList(change.getRemoved());
}
}
// private constructor, only used internally be invert() method
private ListChange(ObservableList collection, List elements, boolean added) {
this.collection = collection;
this.elements = elements;
this.added = added;
}
@Override
public void redo() {
if (added) {
collection.addAll(elements);
} else {
collection.removeAll(elements);
}
}
@Override
public ListChange invert() {
return new ListChange(collection, elements, !added);
}
@Override
public boolean equals(Object other) {
if (other instanceof ListChange) {
ListChange that = (ListChange) other;
return Objects.equals(this.elements, that.elements);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(elements);
}
}`
Thank you. This works for me too, but I wonder how to undo/redo items in a tableview feeded by an observable list. I have an ObservableList<MyObject>
where MyObject contains different variables of type BooleanProperty, StringProperty and DoubleProperty. How can I undo/redo changes of theses using "c.wasUpdated()" of the ListChangeListener? Is it possible or do I have to try a different approach?
could you share PathwayChange class implementation...please...
It would be great if you could also show an example on how to undo / redo changes on collections.