I have my own implementation of ObservableList
called ObservableImmutableList
. It wraps a Guava ImmutableList
with the ObservableList
interface so I can fully utilize ImmutableList
easily with JavaFX. There is nothing mutable about it except it allows another ImmutableList
to be swapped in as the backing list using the set()
method (and notify all listeners/bindings of the change).
However, one problem I ran into is the ObservableImmutableList
cannot be sorted. I cannot extend or implement SortedList
, so how do I implement it into this class?
I tried to create a method asSorted
() which returns the ObservableImmutableList
wrapped in a SortedList
. But it also would not work. Is there some kind of simple abstract layer I can use to keep the list Immutable but allow the values to be resorted in the abstracted layer?
public final class ObservableImmutableList<T> implements ObservableList<T> {
private volatile ImmutableList<T> backingList;
private final LazyProperty<SortedList<T>> sortedList = LazyProperty.forSupplier(() -> new SortedList<>(this));
private final CopyOnWriteArrayList<ListChangeListener<? super T>> listeners = new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList<InvalidationListener> invalidationListeners = new CopyOnWriteArrayList<>();
private final ObjectProperty<ObservableList<T>> property;
private ObservableImmutableList(ImmutableList<T> immutableList) {
this.backingList = immutableList;
this.property = new SimpleObjectProperty<ObservableList<T>>(this);
}
public static <T> ObservableImmutableList<T> of(ImmutableList<T> immutableList) {
return new ObservableImmutableList<T>(immutableList);
}
public SortedList<T> asSorted() {
return sortedList.get();
}
public void set(ImmutableList<T> immutableList) {
this.property.setValue(this);
final ImmutableList<T> oldList = this.backingList;
final ImmutableList<T> newList = immutableList;
listeners.forEach(l -> l.onChanged(new Change<T>(this) {
private int changeNum = 0;
@Override
public boolean next() {
changeNum++;
return changeNum <= 2 ? true : false;
}
@Override
public boolean wasUpdated() {
return true;
}
@Override
public void reset() {
// TODO Auto-generated method stub
}
@Override
public int getFrom() {
return 0;
}
@Override
public int getTo() {
return changeNum == 1 ? oldList.size() - 1 : newList.size() - 1;
}
@Override
public List<T> getRemoved() {
return changeNum == 1 ? oldList : ImmutableList.of();
}
@Override
public List<T> getAddedSubList() {
return changeNum == 1 ? ImmutableList.of() : newList;
}
@Override
protected int[] getPermutation() {
int[] permutations = new int[changeNum == 1 ? oldList.size() : newList.size()];
for (int i = 0; i < permutations.length; i++) {
permutations[i] = i;
}
return permutations;
}
}));
this.backingList = immutableList;
invalidationListeners.forEach(l -> l.invalidated(this));
}
public ImmutableList<T> get() {
return backingList;
}
public ObjectProperty<ObservableList<T>> asProperty() {
return property;
}
@Override
public int size() {
return backingList.size();
}
@Override
public boolean isEmpty() {
return backingList.isEmpty();
}
@Override
public boolean contains(Object o) {
return backingList.contains(o);
}
@Override
public Iterator<T> iterator() {
return backingList.iterator();
}
@Override
public Object[] toArray() {
return backingList.toArray();
}
@Override
public <B> B[] toArray(B[] a) {
return backingList.toArray(a);
}
@Override @Deprecated
public boolean add(T e) {
return backingList.add(e);
}
@Override @Deprecated
public boolean remove(Object o) {
return backingList.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return backingList.containsAll(c);
}
@Override @Deprecated
public boolean addAll(Collection<? extends T> c) {
return backingList.addAll(c);
}
@Override @Deprecated
public boolean addAll(int index, Collection<? extends T> c) {
return backingList.addAll(index, c);
}
@Override @Deprecated
public boolean removeAll(Collection<?> c) {
return backingList.removeAll(c);
}
@Override @Deprecated
public boolean retainAll(Collection<?> c) {
return backingList.retainAll(c);
}
@Override @Deprecated
public void clear() {
backingList.clear();
}
@Override
public T get(int index) {
return backingList.get(index);
}
@Override @Deprecated
public T set(int index, T element) {
return backingList.set(index, element);
}
@Override @Deprecated
public void add(int index, T element) {
backingList.add(index, element);
}
@Override @Deprecated
public T remove(int index) {
return backingList.remove(index);
}
@Override
public int indexOf(Object o) {
return backingList.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return backingList.lastIndexOf(o);
}
@Override
public ListIterator<T> listIterator() {
return backingList.listIterator();
}
@Override
public ListIterator<T> listIterator(int index) {
return backingList.listIterator(index);
}
@Override
public ImmutableList<T> subList(int fromIndex, int toIndex) {
return backingList.subList(fromIndex, toIndex);
}
@Override
public void addListener(InvalidationListener listener) {
invalidationListeners.add(listener);
}
@Override
public void removeListener(InvalidationListener listener) {
invalidationListeners.remove(listener);
}
@Override
public void addListener(ListChangeListener<? super T> listener) {
listeners.add(listener);
}
@Override
public void removeListener(ListChangeListener<? super T> listener) {
listeners.remove(listener);
}
@Override @Deprecated
public boolean addAll(T... elements) {
return backingList.addAll(ImmutableList.copyOf(elements));
}
@Override @Deprecated
public boolean setAll(T... elements) {
return false;
}
@Override @Deprecated
public boolean setAll(Collection<? extends T> col) {
return false;
}
@Override @Deprecated
public boolean removeAll(T... elements) {
return backingList.removeAll(ImmutableList.copyOf(elements));
}
@Override @Deprecated
public boolean retainAll(T... elements) {
return false;
}
@Override @Deprecated
public void remove(int from, int to) {
}
@Override
public String toString() {
return backingList.toString();
}
}