package org.fxmisc.easybind.select; import java.util.function.Function; import javafx.beans.InvalidationListener; import javafx.beans.value.ObservableValue; class IntermediateSelectionElement<T, U, V> implements NestedSelectionElement<T, V> { private final InvalidationListener observableInvalidationListener = obs -> observableInvalidated(); private final Function<? super T, ObservableValue<U>> selector; private final NestedSelectionElement<U, V> nested; private final Runnable onInvalidation; private ObservableValue<U> observable = null; public IntermediateSelectionElement( Runnable onInvalidation, Function<? super T, ObservableValue<U>> selector, NestedSelectionElementFactory<U, V> nestedSelectionFactory) { this.onInvalidation = onInvalidation; this.selector = selector; this.nested = nestedSelectionFactory.create(this::nestedInvalidated); } @Override public void connect(T baseVal) { if(isConnected()) { throw new IllegalStateException("Already connected"); } observable = selector.apply(baseVal); observable.addListener(observableInvalidationListener); } @Override public void disconnect() { if(isConnected()) { nested.disconnect(); observable.removeListener(observableInvalidationListener); observable = null; } } @Override public final boolean isConnected() { return observable != null; } @Override public V getValue() { if(!isConnected()) { throw new IllegalStateException("Not connected"); } if(!nested.isConnected()) { U observableVal = observable.getValue(); if(observableVal == null) { return null; } nested.connect(observableVal); } return nested.getValue(); } private void nestedInvalidated() { onInvalidation.run(); } private void observableInvalidated() { nested.disconnect(); onInvalidation.run(); } }