package org.codefx.libfx.nesting;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.Property;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import org.codefx.libfx.nesting.listener.NestedChangeListenerHandle;
import org.codefx.libfx.nesting.listener.NestedInvalidationListenerHandle;
import org.codefx.libfx.nesting.property.NestedDoubleProperty;
import org.codefx.libfx.nesting.property.NestedProperty;
/**
* <p>
* This class provides static functions to obtain builders for nested classes like {@link Nesting} or
* {@link NestedProperty}.
* <h2>Builders</h2> Calling {@code on} will return a builder whose type depends on the type of the specified
* observable. Similarly a call to one of the builders' {@code nest...}-methods returns a (new) builder whose type
* depends on the type of observable the nesting step will return. Each type of builder allows only those functions
* which are supported by that observable.
* <h3>Examples on Builder Types</h3> If the last nesting step provides a {@link javafx.beans.property.DoubleProperty
* DoubleProperty}, a {@link DoublePropertyNestingBuilder} will be returned. Because a {@code Double} cannot contain
* another observable no further nesting is possible and hence no {@code nest...}-methods are available. But it can be
* used to build a {@link NestedDoubleProperty} which in turn is not possible e.g. on an {@link ObservableValue} and is
* hence not provided by an {@link ObservableValueNestingBuilder}.
* <p>
* Likewise a {@link ChangeListener} cannot be added if the last step provides an {@link Observable} because it only
* accepts {@link InvalidationListener InvalidationListeners}.
* <h2>Examples</h2> More examples and explanations can be found online.
* <h3>Change Listener</h3>
*
* <pre>
* {@code
* Nestings.on(currentEmployee)
* .nestProperty(employee -> employee.addressProperty())
* .nestProperty(address -> address.streetNameProperty())
* .addListener((observable, oldValue, newValue) -> ... );
* }
* </pre>
* <h3>Nested Property</h3>
*
* <pre>
* {@code
* NestedStringProperty asNestedStringProperty = Nestings.on(currentEmployee)
* .nestProperty(employee -> employee.addressProperty())
* .nestStringProperty(address -> address.streetNameProperty())
* .buildProperty();
* }
* </pre>
*
* @see Nesting
* @see NestedProperty
* @see NestedChangeListenerHandle
* @see NestedInvalidationListenerHandle
*/
public class Nestings {
/**
* Starts a nesting with the specified outer observable.
*
* @param outerObservable
* the outer {@link Observable} on which the nesting begins
* @return an instance of {@link ObservableNestingBuilder} which depends on the specified outer observable
*/
public static ObservableNestingBuilder on(Observable outerObservable) {
return new ObservableNestingBuilder(outerObservable);
}
/**
* Starts a nesting with the specified outer observable.
*
* @param <T>
* the type the outer observable wraps
* @param outerObservable
* the outer {@link ObservableValue} on which the nesting begins
* @return an instance of {@link ObservableValueNestingBuilder} which depends on the specified outer observable
*/
public static <T> ObservableValueNestingBuilder<T> on(ObservableValue<T> outerObservable) {
return new ObservableValueNestingBuilder<T>(outerObservable);
}
/**
* Starts a nesting with the specified outer property.
*
* @param <T>
* the type the outer property wraps
* @param outerProperty
* the outer {@link Property} on which the nesting begins
* @return an instance of {@link ObjectPropertyNestingBuilder} which depends on the specified outer observable value
*/
public static <T> ObjectPropertyNestingBuilder<T> on(Property<T> outerProperty) {
return new ObjectPropertyNestingBuilder<T>(outerProperty);
}
}