If I have two separate ObservableLists, and both are put in a single ObservableList for a TableView... is there a way to create a binding between those two ObservableLists and the aggregated one? I tried to mess around and override the calculate() method for the ObjectBinding, but I don't think this is what I want. Any thoughts on how to tackle this?
UPDATE: Going on a related tangent to show an implication discussed below. This is my ObservableImmutableList implementation that is struggling to work with the checked solution.
package com.nield.utilities.fx;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;
import javafx.beans.InvalidationListener;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import com.google.common.collect.ImmutableList;
public final class ObservableImmutableList<T> implements ObservableList<T> {
private volatile ImmutableList<T> backingList;
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 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();
}
}
And here is the static factory to merge two ObservableLists together so far. It works for standard implementations of ObservableList, but it is not working with my ObservableImmutableList implementation.
package com.nield.finance;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import com.google.common.collect.ImmutableList;
import com.nield.utilities.fx.ObservableImmutableList;
public class ObservableMerge {
static ObservableImmutableList<String> a = ObservableImmutableList.of(ImmutableList.of("ABQ","DAL"));
static ObservableImmutableList<String> b = ObservableImmutableList.of(ImmutableList.of("HOU","PHX"));
static ObservableList<String> aandb = FXCollections.observableArrayList();
static ObservableList<String> merge(ObservableList<String> into, ObservableList<String>... lists) {
final ObservableList<String> list = into;
for (ObservableList<String> l : lists) {
list.addAll(l);
l.addListener((javafx.collections.ListChangeListener.Change<? extends String> c) -> {
while (c.next()) {
if (c.wasAdded()) {
list.addAll(c.getAddedSubList());
}
if (c.wasRemoved()) {
list.removeAll(c.getRemoved());
}
if (c.wasUpdated()) {
list.removeAll(c.getRemoved());
list.addAll(c.getAddedSubList());
}
}
});
}
return list;
}
public static void main(String...args) {
merge(aandb, a, b);
System.out.println(""+aandb);
a.set(ImmutableList.of("LAX", "BUR"));
System.out.println(""+aandb);
}
}
And here is the static factory to merge two ObservableLists (it should work with the ObservableImmutableList too, but its not.
package com.nield.finance;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import com.google.common.collect.ImmutableList;
import com.nield.utilities.fx.ObservableImmutableList;
public class ObservableMerge {
static ObservableImmutableList<String> a = ObservableImmutableList.of(ImmutableList.of("ABQ","DAL"));
static ObservableImmutableList<String> b = ObservableImmutableList.of(ImmutableList.of("HOU","PHX"));
static ObservableList<String> aandb = FXCollections.observableArrayList();
static ObservableList<String> merge(ObservableList<String> into, ObservableList<String>... lists) {
final ObservableList<String> list = into;
for (ObservableList<String> l : lists) {
list.addAll(l);
l.addListener((javafx.collections.ListChangeListener.Change<? extends String> c) -> {
while (c.next()) {
if (c.wasAdded()) {
list.addAll(c.getAddedSubList());
}
if (c.wasRemoved()) {
list.removeAll(c.getRemoved());
}
if (c.wasUpdated()) {
list.removeAll(c.getRemoved());
list.addAll(c.getAddedSubList());
}
}
});
}
return list;
}
public static void main(String...args) {
merge(aandb, a, b);
System.out.println(""+aandb);
a.set(ImmutableList.of("LAX", "BUR"));
System.out.println(""+aandb);
}
}
This might be a starting point:
public class ObservableMerge {
static ObservableList<String> a = FXCollections.observableArrayList();
static ObservableList<String> b = FXCollections.observableArrayList();
static ObservableList<String> aandb = FXCollections.observableArrayList();
static ObservableList<String> merge(ObservableList<String> into, ObservableList<String>... lists) {
final ObservableList<String> list = into;
for (ObservableList<String> l : lists) {
list.addAll(l);
l.addListener((javafx.collections.ListChangeListener.Change<? extends String> c) -> {
while (c.next()) {
if (c.wasAdded()) {
list.addAll(c.getAddedSubList());
}
if (c.wasRemoved()) {
list.removeAll(c.getRemoved());
}
}
});
}
return list;
}
public static void main(String...args) {
merge(aandb, a, b);
System.out.println(""+aandb);
a.add("Hello");
b.add("Peter");
System.out.println(""+aandb);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With