Commit 57cddea5 authored by Axel Howind's avatar Axel Howind

InputControl (wip)

parent 7eeea705
Pipeline #51419736 failed with stages
in 19 minutes and 10 seconds
package com.dua3.fx.util.controls;
import java.text.NumberFormat;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableStringValue;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
/**
* Interface for an input field.
......@@ -83,9 +93,15 @@ public interface InputControl<R> {
}
public State(ObservableValue<R> value, Supplier<R> dflt) {
this(value, dflt, s -> Optional.empty());
}
public State(ObservableValue<R> value, Supplier<R> dflt, Function<R,Optional<String>> validate) {
this.value.bind(value);
this.value.addListener( (v,o,n) -> updateValidState(n) );
this.dflt = Objects.requireNonNull(dflt);
this.validate = Objects.requireNonNull(validate);
updateValidState(this.value.getValue());
}
......@@ -119,4 +135,44 @@ public interface InputControl<R> {
value.setValue(dflt.get());
}
}
public static SimpleInputControl<TextField, String> stringInput(Supplier<String> dflt, Function<String, Optional<String>> validate) {
TextField control = new TextField();
ObservableStringValue value = control.textProperty();
SimpleInputControl<TextField, String> inputControl = new SimpleInputControl<>(control, value, dflt, validate);
return inputControl;
}
public static SimpleInputControl<TextField, Integer> integerInput(Supplier<Integer> dflt, Function<Integer, Optional<String>> validate) {
TextField control = new TextField();
StringProperty textProperty = control.textProperty();
IntegerProperty value = new SimpleIntegerProperty();
textProperty.bindBidirectional(value, NumberFormat.getIntegerInstance());
SimpleInputControl<TextField,Integer> inputControl = new SimpleInputControl<>(control, value.asObject(), dflt, validate);
return inputControl;
}
public static SimpleInputControl<TextField, Double> decimalInput(Supplier<Double> dflt, Function<Double, Optional<String>> validate) {
TextField control = new TextField();
StringProperty textProperty = control.textProperty();
DoubleProperty value = new SimpleDoubleProperty();
textProperty.bindBidirectional(value, NumberFormat.getInstance());
SimpleInputControl<TextField,Double> inputControl = new SimpleInputControl<>(control, value.asObject(), dflt, validate);
return inputControl;
}
public static SimpleInputControl<CheckBox, Boolean> checkBoxInput(Supplier<Boolean> dflt, String text) {
CheckBox control = new CheckBox(text);
BooleanProperty value = control.selectedProperty();
SimpleInputControl<CheckBox,Boolean> inputControl = new SimpleInputControl<>(control, value.asObject(), dflt, r -> Optional.empty());
return inputControl;
}
public static <T> SimpleInputControl<ComboBox<T>, T> comboBoxInput(Supplier<T> dflt) {
ComboBox<T> control = new ComboBox<>();
ObjectProperty<T> value = control.valueProperty();
SimpleInputControl<ComboBox<T>,T> inputControl = new SimpleInputControl<>(control, value, dflt, r -> Optional.empty());
return inputControl;
}
}
\ No newline at end of file
......@@ -14,7 +14,6 @@
package com.dua3.fx.util.controls;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
......@@ -28,18 +27,6 @@ import com.dua3.utility.lang.LangUtil;
import com.dua3.utility.options.OptionSet;
import com.dua3.utility.options.OptionValues;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableStringValue;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
/**
* Builder for Alert Dialogs.
*
......@@ -97,11 +84,7 @@ implements InputBuilder<InputPaneBuilder> {
*/
@Override
public InputPaneBuilder string(String id, String label, Supplier<String> dflt, Function<String,Optional<String>> validate) {
TextField control = new TextField();
ObservableStringValue value = control.textProperty();
return add(id, label, String.class, dflt,
new SimpleInputControl<>(control, value, dflt)
);
return add(id, label, String.class, dflt, InputControl.stringInput(dflt, validate));
}
/* (non-Javadoc)
......@@ -109,14 +92,7 @@ implements InputBuilder<InputPaneBuilder> {
*/
@Override
public InputPaneBuilder integer(String id, String label, Supplier<Integer> dflt, Function<Integer,Optional<String>> validate) {
TextField control = new TextField();
StringProperty textProperty = control.textProperty();
IntegerProperty value = new SimpleIntegerProperty();
textProperty.bindBidirectional(value, NumberFormat.getIntegerInstance());
return add(id, label, Integer.class, dflt,
new SimpleInputControl<>(control, value.asObject(), dflt)
);
return add(id, label, Integer.class, dflt, InputControl.integerInput(dflt, validate));
}
/* (non-Javadoc)
......@@ -124,14 +100,7 @@ implements InputBuilder<InputPaneBuilder> {
*/
@Override
public InputPaneBuilder decimal(String id, String label, Supplier<Double> dflt, Function<Double,Optional<String>> validate) {
TextField control = new TextField();
StringProperty textProperty = control.textProperty();
DoubleProperty value = new SimpleDoubleProperty();
textProperty.bindBidirectional(value, NumberFormat.getInstance());
return add(id, label, Double.class, dflt,
new SimpleInputControl<>(control, value.asObject(), dflt)
);
return add(id, label, Double.class, dflt, InputControl.decimalInput(dflt, validate));
}
/* (non-Javadoc)
......@@ -139,11 +108,7 @@ implements InputBuilder<InputPaneBuilder> {
*/
@Override
public InputPaneBuilder checkBox(String id, String label, Supplier<Boolean> dflt, String text) {
CheckBox control = new CheckBox(text);
BooleanProperty value = control.selectedProperty();
return add(id, label, Boolean.class, dflt,
new SimpleInputControl<>(control, value, dflt)
);
return add(id, label, Boolean.class, dflt, InputControl.checkBoxInput(dflt, text));
}
/* (non-Javadoc)
......@@ -151,11 +116,7 @@ implements InputBuilder<InputPaneBuilder> {
*/
@Override
public <T> InputPaneBuilder comboBox(String id, String label, Supplier<T> dflt, Class<T> cls, Collection<T> items) {
ComboBox<T> control = new ComboBox<T>();
ObjectProperty<T> value = control.valueProperty();
return add(id, label, cls, dflt,
new SimpleInputControl<>(control, value, dflt)
);
return add(id, label, cls, dflt, InputControl.comboBoxInput(dflt));
}
/* (non-Javadoc)
......
package com.dua3.fx.util.controls;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.logging.Logger;
......@@ -12,10 +15,13 @@ import com.dua3.utility.options.OptionSet;
import com.dua3.utility.options.OptionValues;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.ComboBox;
......@@ -35,7 +41,7 @@ public class OptionsPane extends GridPane implements InputControl<OptionValues>{
private Supplier<OptionValues> dflt;
private ObservableValue<OptionValues> value = new SimpleObjectProperty<>();
private LinkedHashMap<Option<?>, Property<?>> items = new LinkedHashMap<>();
private LinkedHashMap<Option<?>, InputControl<?>> items = new LinkedHashMap<>();
private static final Insets INSETS = new Insets(2);
......@@ -61,54 +67,74 @@ public class OptionsPane extends GridPane implements InputControl<OptionValues>{
getChildren().clear();
OptionSet optionSet = options.get();
OptionValues values = state.valueProperty().getValue();
OptionValues values = new OptionValues(dflt.get());
int row = 0;
for (Option<?> option: optionSet) {
Label label = new Label(option.getName());
Property<? extends Value<?>> valueProperty;
Control control;
Value<?> value = values.get(option);
if (option instanceof StringOption) {
TextField c = new TextField();
c.setText(value.text());
control = c;
StringProperty textProperty = c.textProperty();
Property<Value<String>> property = new SimpleObjectProperty<Value<String>>();
textProperty.addListener((v,o,n) -> {
property.setValue(Option.value(n));
});
property.addListener((v,o,n) -> textProperty.set(n.get()));
valueProperty = property;
} else if (option instanceof ChoiceOption<?>) {
var choices = FXCollections.observableList(((ChoiceOption<?>)option).getChoices());
var c = new ComboBox<>(choices);
c.getSelectionModel().select(choices.indexOf(value));
control = c;
valueProperty = c.valueProperty();
} else {
LOG.warning("unknown option type: "+option.getClass().getName());
control = null;
valueProperty = null;
}
items.put(option, valueProperty);
InputControl<?> control = createControl(values, option);
items.put(option, control);
addToGrid(label, 0, row);
addToGrid(control, 1, row);
addToGrid(control.node(), 1, row);
row++;
}
// create binding
/*
OptionValues values = new OptionValues();
for (var entry: items.entrySet()) {
Option<?> option = entry.getKey();
Property<?> property = entry.getValue();
Value<?> value = (Value<?>) property.getValue();
values.put(option, value);
}
return values;
*/
}
private void addToGrid(Control child, int c, int r) {
if (child != null) {
add(child, c, r);
setMargin(child, INSETS);
@SuppressWarnings("unchecked")
private <T> InputControl<T> createControl(OptionValues values, Option<T> option) {
InputControl<T> control;
if (option instanceof StringOption) {
var inputControl = InputControl.stringInput(() -> (String) dflt.get().get(option).get(), r -> Optional.empty());
inputControl.valueProperty().addListener( (v,o,n) -> {
values.put(option, Option.value(n));
});
values.addChangeListener( (v,o,n) -> {
inputControl.valueProperty().setValue(Objects.toString(n.get(), ""));
});
return (InputControl<T>) inputControl;
} else if (option instanceof ChoiceOption<?>) {
var choices = FXCollections.observableList(((ChoiceOption<T>)option).getChoices());
var inputControl = InputControl.comboBoxInput(() -> ((Value<T>)dflt.get().get(option)).get());
inputControl.valueProperty().addListener( (v,o,n) -> {
values.put(option, Option.value(n));
});
values.addChangeListener( (v,o,n) -> {
inputControl.valueProperty().setValue(((Value<T>) n).get());
});
return inputControl;
}
LOG.warning("unknown option type: "+option.getClass().getName());
return null;
}
private void addToGrid(Node node, int c, int r) {
if (node != null) {
add(node, c, r);
setMargin(node, INSETS);
}
}
......@@ -117,7 +143,7 @@ public class OptionsPane extends GridPane implements InputControl<OptionValues>{
OptionValues values = new OptionValues();
for (var entry: items.entrySet()) {
Option<?> option = entry.getKey();
Property<?> property = entry.getValue();
Property<?> property = entry.getValue().valueProperty();
Value<?> value = (Value<?>) property.getValue();
values.put(option, value);
}
......@@ -129,7 +155,7 @@ public class OptionsPane extends GridPane implements InputControl<OptionValues>{
public void set(OptionValues arg) {
for (var item: items.entrySet()) {
Option option = item.getKey();
Property property = item.getValue();
Property property = item.getValue().valueProperty();
Value value = arg.get(option);
property.setValue(value.get());
}
......@@ -140,4 +166,25 @@ public class OptionsPane extends GridPane implements InputControl<OptionValues>{
return this;
}
@Override
public void reset() {
// TODO Auto-generated method stub
}
@Override
public Property<OptionValues> valueProperty() {
return state.valueProperty();
}
@Override
public ReadOnlyBooleanProperty validProperty() {
return state.validProperty();
}
@Override
public ReadOnlyStringProperty errorProperty() {
return state.errorProperty();
}
}
package com.dua3.fx.util.controls;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import javafx.beans.property.Property;
......@@ -15,7 +17,7 @@ class SimpleInputControl<C extends Control,R> implements InputControl<R> {
private final State<R> state;
private final Supplier<R> dflt;
protected SimpleInputControl(C control, ObservableValue<R> value, Supplier<R> dflt) {
protected SimpleInputControl(C control, ObservableValue<R> value, Supplier<R> dflt, Function<R,Optional<String>> validate) {
this.control = Objects.requireNonNull(control);
this.state = new State<>(value);
this.dflt = dflt;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment