package org.fxmisc.easybind; import java.util.function.Function; import java.util.stream.Stream; import javafx.beans.InvalidationListener; import javafx.beans.WeakInvalidationListener; import javafx.beans.binding.ObjectBinding; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener.Change; import javafx.collections.ObservableList; import javafx.collections.WeakListChangeListener; import org.fxmisc.easybind.monadic.MonadicBinding; class ListCombinationBinding<T, U> extends ObjectBinding<U> implements MonadicBinding<U> { private final ListChangeListener<ObservableValue<? extends T>> listListener = ch -> sourceChanged(ch); private final InvalidationListener elemListener = obs -> elementInvalidated(); private final WeakListChangeListener<ObservableValue<? extends T>> weakListListener = new WeakListChangeListener<>(listListener); private final WeakInvalidationListener weakElemListener = new WeakInvalidationListener(elemListener); private final ObservableList<? extends ObservableValue<? extends T>> source; private final Function<? super Stream<T>, ? extends U> combiner; public ListCombinationBinding( ObservableList<? extends ObservableValue<? extends T>> list, Function<? super Stream<T>, ? extends U> f) { source = list; combiner = f; source.addListener(weakListListener); source.forEach(elem -> elem.addListener(weakElemListener)); } @Override protected U computeValue() { return combiner.apply(source.stream().map(obs -> obs.getValue())); } @Override public void dispose() { source.forEach(elem -> elem.removeListener(weakElemListener)); source.removeListener(weakListListener); } private void sourceChanged( Change<? extends ObservableValue<? extends T>> ch) { while(ch.next()) { ch.getRemoved().forEach(elem -> elem.removeListener(weakElemListener)); ch.getAddedSubList().forEach(elem -> elem.addListener(weakElemListener)); invalidate(); } } private void elementInvalidated() { invalidate(); } }