package org.phoenicis.javafx.views.mainwindow.ui;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.VBox;
import org.phoenicis.javafx.views.common.AdhocList;
import org.phoenicis.javafx.views.common.MappedList;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* This class represents a group of toggle buttons in the sidebar.
* This class must be used together with an {@link ObservableList}, containing the objects which are to be shown in this LeftToggleGroup.
* For every object inside the {@link ObservableList} a {@link ToggleButton} is created, which is then shown inside this LeftToggleGroup.
* For the creation of the {@link ToggleButton}s a converter function is used, which must be passed to the constructor of this class.
*
* @author marc
* @since 28.03.17
*/
public class LeftToggleGroup<E> extends LeftGroup {
/**
* The ToggleGroup to which all ToggleButtons in this LeftToggleGroup are added
*/
private final ToggleGroup toggleGroup;
/**
* An optional {@link ToggleButton}, which represents the selection of all categories at once.
* If this field is {@link Optional#empty()} no such button is used
*/
private final Optional<ToggleButton> allButton;
/**
* A {@link VBox} containing all shown {@link ToggleButton}s belonging to this LeftToggleGroup
*/
private final VBox toggleButtonBox;
/**
* An {@link ObservableList} containing all objects for which a {@link ToggleButton} is to be shown in this LeftToggleGroup
*/
private final ObservableList<E> elements;
/**
* An {@link ObservableList} that takes all objects in <code>elements</code> and converts them to a {@link ToggleButton}
*/
private final MappedList<? extends ToggleButton, E> mappedToggleButtons;
/**
* An {@link ObservableList} containing both the <code>allButton</code>, if it's available, and the {@link ToggleButton}s
* inside <code>mappedToggleButtons</code>
*/
private final AdhocList<? extends ToggleButton> adhocToggleButtons;
/**
* Constructor
*
* @param name The title of this LeftToggleGroup
* @param allButtonSupplier A supplier function used to create the optional "all" ToggleButton. If no such button is needed null can be used
* @param converter A converter function used to convert the source objects to ToggleButtons
*/
private LeftToggleGroup(String name, Supplier<ToggleButton> allButtonSupplier,
Function<E, ? extends ToggleButton> converter) {
super(name);
this.toggleGroup = new ToggleGroup();
this.toggleButtonBox = new VBox();
this.toggleButtonBox.getStyleClass().add("leftPaneInside");
this.elements = FXCollections.observableArrayList();
this.mappedToggleButtons = new MappedList<ToggleButton, E>(this.elements, value -> converter.apply(value));
if (allButtonSupplier != null) {
ToggleButton newAllButton = allButtonSupplier.get();
this.allButton = Optional.of(newAllButton);
this.adhocToggleButtons = new AdhocList<ToggleButton>(this.mappedToggleButtons, newAllButton);
} else {
this.allButton = Optional.empty();
this.adhocToggleButtons = new AdhocList<ToggleButton>(this.mappedToggleButtons);
}
Bindings.bindContent(this.toggleGroup.getToggles(), this.adhocToggleButtons);
Bindings.bindContent(this.toggleButtonBox.getChildren(), this.adhocToggleButtons);
this.getChildren().add(this.toggleButtonBox);
}
/**
* Constructor
*
* @param name The title of this LeftToggleGroup
* @param converter A converter function used to convert the source objects to ToggleButtons
*/
private LeftToggleGroup(String name, Function<E, ? extends ToggleButton> converter) {
this(name, null, converter);
}
/**
* This method creates a new LeftToggleGroup without an "all" categories ToggleButton using the given arguments
*
* @param name The title of the new LeftToggleGroup
* @param converter The converter function used by the new LeftToggleGroup to convert the source objects to ToggleButtons
* @param <T> The type of the source objects in the new LeftToggleGroup
* @return The newly created LeftToggleGroup with the given arguments
*/
public static <T> LeftToggleGroup<T> create(String name, Function<T, ? extends ToggleButton> converter) {
return new LeftToggleGroup<T>(name, converter);
}
/**
* This method creates a new LeftToggleGroup using the given arguments
*
* @param name The title of the new LeftToggleGroup
* @param allButtonSupplier The suppliert function used to create the "all" categories ToggleButton
* @param converter The converter function used by the new LeftToggleGroup to convert the source objects to ToggleButtons
* @param <T> The type of the source objects in the new LeftToggleGroup
* @return The newly created LeftToggleGroup with the given arguments
*/
public static <T> LeftToggleGroup<T> create(String name, Supplier<ToggleButton> allButtonSupplier,
Function<T, ? extends ToggleButton> converter) {
return new LeftToggleGroup<T>(name, allButtonSupplier, converter);
}
/**
* This method returns the {@link ObservableList} containing the source objects used to create the shown {@link ToggleButton}s.
* This {@link ObservableList} can be used to bind another {@link ObservableList} to this LeftToggleGroup
*
* @return The used {@link ObservableList}
*/
public ObservableList<E> getElements() {
return this.elements;
}
/**
* This method selects the "all" categories {@link ToggleButton} inside this LeftToggleGroup.
* If no such button exists this method does nothing
*/
public void selectAll() {
this.allButton.ifPresent(button -> button.setSelected(true));
}
/**
* This method selects the ToggleButton at a given position inside this LeftToggleGroup.
* For the position an optional "all" categories {@link ToggleButton} is ignored
*
* @param elementIndex The position of the to be selected {@link ToggleButton}
* @throws IllegalArgumentException This exception is thrown, if the given position <code>elementIndex</code>
* is outside the range of the elements contained in this LeftToggleGroup
*/
public void select(int elementIndex) {
if (elementIndex < 0 || elementIndex >= this.elements.size()) {
throw new IllegalArgumentException(String.format("Element at index %d doesn't exist", elementIndex));
} else {
mappedToggleButtons.get(elementIndex).fire();
}
}
/**
* This method selects the ToggleButton belonging to a given element contained in the <code>elements</code> {@link ObservableList}
* inside this LeftToggleGroup.
*
* @param element The element, whose corresponding {@link javafx.scene.control.ToggleButton} is to be selected
* @throws IllegalArgumentException This exception is thrown, if the given <code>element</code> doesn't exist in this LeftToggleGroup
*/
public void select(E element) {
this.select(this.elements.indexOf(element));
}
}