Commit 7b34f11f authored by Axel Howind's avatar Axel Howind

result handling (in progress)

parent 7fde8135
......@@ -14,25 +14,24 @@
package com.dua3.fx.util.controls;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import javafx.scene.control.Dialog;
/**
* Abstract base class for Dialog builders.
* Provides a fluent interface to create Dialogs.
*/
public abstract class AbstractDialogBuilder<T, B extends AbstractDialogBuilder<T, B>>
extends AbstractDialogPaneBuilder<T, B> {
public abstract class AbstractDialogBuilder<D extends Dialog<R>, B extends AbstractDialogBuilder<D, B,R>,R>
extends AbstractDialogPaneBuilder<D, B, R> {
private final BiConsumer<T, String> titleSetter;
private final BiConsumer<D,String> titleSetter;
AbstractDialogBuilder(
Supplier<T> supplier,
BiConsumer<T, String> titleSetter,
BiConsumer<T, String> headerSetter,
BiConsumer<T, String> textSetter) {
super(supplier, headerSetter, textSetter);
this.titleSetter = titleSetter;
protected AbstractDialogBuilder(Supplier<D> supplier) {
super(supplier, Dialog::setHeaderText, Dialog::setContentText);
this.titleSetter = Dialog::setTitle;
}
private String title = null;
......@@ -43,8 +42,8 @@ public abstract class AbstractDialogBuilder<T, B extends AbstractDialogBuilder<T
* @return Dialog instance
*/
@Override
public T build() {
T dlg = super.build();
public D build() {
D dlg = super.build();
applyIfNotNull(titleSetter, dlg, title);
......@@ -67,4 +66,15 @@ public abstract class AbstractDialogBuilder<T, B extends AbstractDialogBuilder<T
return (B) this;
}
/**
* Build and show the dialog.
*
* This is equivalent to calling build().showAndWait().
*
* @return
* Optinal containing the result as defined by the dialog
*/
public Optional<R> showAndWait() {
return build().showAndWait();
}
}
......@@ -25,45 +25,46 @@ import javafx.scene.control.ButtonType;
*
* Provides a fluent interface to create Dialog panes.
*
* @param <T> the type of the dialog or pane to build
* @param <D> the type of the dialog or pane to build
* @param <B> the type of the builder
* @param <R> the result type
*/
public abstract class AbstractDialogPaneBuilder<T, B extends AbstractDialogPaneBuilder<T, B>> {
public abstract class AbstractDialogPaneBuilder<D, B extends AbstractDialogPaneBuilder<D, B, R>, R> {
public static interface ResultHandler<T> {
boolean handleResult(T source, ButtonType btn);
public static interface ResultHandler<R> {
boolean handleResult(ButtonType btn, R result);
}
final BiConsumer<T, String> headerSetter;
final BiConsumer<T, String> textSetter;
final BiConsumer<D, String> headerSetter;
final BiConsumer<D, String> textSetter;
AbstractDialogPaneBuilder(
Supplier<T> supplier,
BiConsumer<T, String> headerSetter,
BiConsumer<T, String> textSetter
Supplier<D> supplier,
BiConsumer<D, String> headerSetter,
BiConsumer<D, String> textSetter
) {
this.supplier = supplier;
this.headerSetter=headerSetter;
this.textSetter=textSetter;
}
private Supplier<T> supplier;
private Supplier<D> supplier;
private String header = null;
private String text = null;
private ResultHandler<T> resultHandler = (p,b) -> true;
private ResultHandler<R> resultHandler = (b,r) -> true;
protected void setSupplier(Supplier<T> supplier) {
protected void setSupplier(Supplier<D> supplier) {
this.supplier = Objects.requireNonNull(supplier);
}
protected <C,D> void applyIfNotNull(BiConsumer<C,D> consumer, C a, D b) {
protected static <C,D> void applyIfNotNull(BiConsumer<C,D> consumer, C a, D b) {
if (a!=null && b!=null) {
consumer.accept(a,b);
}
}
protected String format(String fmt, Object... args) {
protected static String format(String fmt, Object... args) {
return String.format(fmt, args);
}
......@@ -71,8 +72,8 @@ public abstract class AbstractDialogPaneBuilder<T, B extends AbstractDialogPaneB
* Create Alert instance.
* @return Alert instance
*/
public T build() {
T dlg = supplier.get();
public D build() {
D dlg = supplier.get();
applyIfNotNull(headerSetter, dlg, header);
applyIfNotNull(textSetter, dlg, text);
......@@ -111,12 +112,12 @@ public abstract class AbstractDialogPaneBuilder<T, B extends AbstractDialogPaneB
}
@SuppressWarnings("unchecked")
public B resultHandler(ResultHandler<T> resultHandler) {
public B resultHandler(ResultHandler<R> resultHandler) {
this.resultHandler = Objects.requireNonNull(resultHandler);
return (B) this;
}
public ResultHandler<T> getResultHandler() {
public ResultHandler<R> getResultHandler() {
return resultHandler;
}
......
......@@ -28,7 +28,7 @@ import javafx.scene.control.DialogPane;
* Provides a fluent interface to create Alerts.
*/
public class AlertBuilder
extends StandardDialogBuilder<Alert, AlertBuilder, ButtonType> {
extends AbstractDialogBuilder<Alert, AlertBuilder, ButtonType> {
public AlertBuilder(AlertType type) {
super(() -> new Alert(type));
}
......
......@@ -15,6 +15,7 @@
package com.dua3.fx.util.controls;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.DialogPane;
/**
......@@ -23,7 +24,7 @@ import javafx.scene.control.DialogPane;
* Provides a fluent interface to create Alerts.
*/
public class AlertPaneBuilder
extends StandardDialogPaneBuilder<DialogPane, AlertPaneBuilder> {
extends StandardDialogPaneBuilder<DialogPane, AlertPaneBuilder, ButtonType> {
public AlertPaneBuilder(AlertType type) {
super(() -> createPane(type));
}
......
......@@ -8,7 +8,6 @@ import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import com.dua3.fx.util.controls.InputDialogPane.InputControl;
import com.dua3.utility.options.OptionSet;
import com.dua3.utility.options.OptionValues;
......
package com.dua3.fx.util.controls;
import java.util.Optional;
import javafx.scene.Node;
/**
* Interface for an input field.
*
* @param <R> the input result type
*/
public interface InputControl<R> {
/**
* Get the Node for this input element.
*
* @return the node
*/
Node node();
/**
* Get value.
*
* @return the current value
*/
R get();
/**
* Set value.
*
* @param arg the value to set
*/
void set(R arg);
/**
* Validate user input.
*
* @return if not valid, an Optional containing the error; otherwise an empty
* Optional
*/
default Optional<String> validate() {
return Optional.empty();
}
}
\ No newline at end of file
......@@ -22,7 +22,6 @@ import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import com.dua3.fx.util.controls.InputDialogPane.InputControl;
import com.dua3.utility.options.OptionSet;
import com.dua3.utility.options.OptionValues;
......@@ -32,7 +31,7 @@ import com.dua3.utility.options.OptionValues;
* Provides a fluent interface to create Alerts.
*/
public class InputDialogBuilder
extends StandardDialogBuilder<InputDialog, InputDialogBuilder, Map<String, Object>>
extends AbstractDialogBuilder<InputDialog, InputDialogBuilder, Map<String, Object>>
implements InputBuilder<InputDialogBuilder> {
private final InputDialogPaneBuilder pb = new InputDialogPaneBuilder();
......
......@@ -29,44 +29,6 @@ public class InputDialogPane extends DialogPane {
private static final String MARKER_ERROR = "\u26A0";
private static final String MARKER_OK = "";
/**
* Interface for an input field.
*
* @param <T> the input value's type
*/
public interface InputControl<T> {
/**
* Get the Node for this input element.
*
* @return the node
*/
Node node();
/**
* Get value.
*
* @return the current value
*/
T get();
/**
* Set value.
*
* @param arg the value to set
*/
void set(T arg);
/**
* Validate user input.
*
* @return if not valid, an Optional containing the error; otherwise an empty
* Optional
*/
default Optional<String> validate() {
return Optional.empty();
}
}
/**
* Meta data for a single input field consisting of ID, label text, default value etc.
*
......
......@@ -16,6 +16,7 @@ package com.dua3.fx.util.controls;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.DoubleFunction;
......@@ -23,7 +24,6 @@ import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import com.dua3.fx.util.controls.InputDialogPane.InputControl;
import com.dua3.fx.util.controls.InputDialogPane.Meta;
import com.dua3.utility.lang.LangUtil;
import com.dua3.utility.options.OptionSet;
......@@ -41,7 +41,7 @@ import javafx.scene.control.TextField;
* Provides a fluent interface to create Alerts.
*/
public class InputDialogPaneBuilder
extends StandardDialogPaneBuilder<InputDialogPane, InputDialogPaneBuilder>
extends StandardDialogPaneBuilder<InputDialogPane, InputDialogPaneBuilder, Map<String, Object>>
implements InputBuilder<InputDialogPaneBuilder> {
public InputDialogPaneBuilder() {
......
......@@ -24,7 +24,7 @@ import com.dua3.utility.options.OptionValues;
*
* Provides a fluent interface to create Alerts.
*/
public class OptionsDialogBuilder extends StandardDialogBuilder<OptionsDialog, OptionsDialogBuilder, OptionValues> {
public class OptionsDialogBuilder extends AbstractDialogBuilder<OptionsDialog, OptionsDialogBuilder, OptionValues> {
public OptionsDialogBuilder() {
super(OptionsDialog::new);
......
......@@ -4,7 +4,6 @@ import java.util.LinkedHashMap;
import java.util.function.Supplier;
import java.util.logging.Logger;
import com.dua3.fx.util.controls.InputDialogPane.InputControl;
import com.dua3.utility.options.Option;
import com.dua3.utility.options.Option.ChoiceOption;
import com.dua3.utility.options.Option.StringOption;
......
......@@ -21,7 +21,7 @@ import javafx.scene.control.TextInputDialog;
*
* Provides a fluent interface to create Alerts.
*/
public class PromptBuilder extends StandardDialogBuilder<TextInputDialog, PromptBuilder, String> {
public class PromptBuilder extends AbstractDialogBuilder<TextInputDialog, PromptBuilder, String> {
public PromptBuilder() {
super(TextInputDialog::new);
}
......
......@@ -4,8 +4,6 @@ import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.logging.Logger;
import com.dua3.fx.util.controls.InputDialogPane.InputControl;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.control.RadioButton;
......@@ -19,7 +17,6 @@ public class RadioPane<T> extends VBox implements InputControl<T> {
private final LinkedHashMap<T, RadioButton> items = new LinkedHashMap<>();
private final ToggleGroup group;
private final T currentValue;
private static final double SPACING = 4;
......@@ -31,7 +28,6 @@ public class RadioPane<T> extends VBox implements InputControl<T> {
* the current value
*/
public RadioPane(Collection<T> items, T currentValue) {
this.currentValue = currentValue;
this.group = new ToggleGroup();
this.setSpacing(SPACING);
......
package com.dua3.fx.util.controls;
import java.util.Optional;
import java.util.function.Supplier;
import javafx.scene.control.Dialog;
public class StandardDialogBuilder<T extends Dialog<R>, B extends StandardDialogBuilder<T,B,R>, R>
extends AbstractDialogBuilder<T, B> {
protected StandardDialogBuilder(Supplier<T> supplier) {
super(supplier, Dialog::setTitle, Dialog::setHeaderText, Dialog::setContentText);
}
/**
* Build and show the dialog.
*
* This is equivalent to calling build().showAndWait().
*
* @return
* Optinal containing the result as defined by the dialog
*/
public Optional<R> showAndWait() {
return build().showAndWait();
}
}
......@@ -4,9 +4,16 @@ import java.util.function.Supplier;
import javafx.scene.control.DialogPane;
public class StandardDialogPaneBuilder<T extends DialogPane, B extends StandardDialogPaneBuilder<T,B>>
extends AbstractDialogPaneBuilder<T, B> {
protected StandardDialogPaneBuilder(Supplier<T> supplier) {
/**
* Abstract base for DialogPane builders.
*
* @param <D> the type of the dialog or pane to build
* @param <B> the type of the builder
* @param <R> the result type
*/
public class StandardDialogPaneBuilder<D extends DialogPane, B extends StandardDialogPaneBuilder<D,B,R>,R>
extends AbstractDialogPaneBuilder<D, B,R> {
protected StandardDialogPaneBuilder(Supplier<D> supplier) {
super(supplier, DialogPane::setHeaderText, DialogPane::setContentText);
}
......
......@@ -63,11 +63,11 @@ public class WizardDialog extends Dialog<ButtonType> {
/**
* Wizard page information class.
*/
public static class Page {
private DialogPane pane;
public static class Page<D extends DialogPane,R> {
private D pane;
private String previous;
private String next;
private Consumer<? super DialogPane> resultHandler;
private ResultHandler<R> resultHandler;
public String getPrevious() {
return previous;
......@@ -85,29 +85,28 @@ public class WizardDialog extends Dialog<ButtonType> {
this.next = next;
}
public DialogPane getPane() {
public D getPane() {
return pane;
}
@SuppressWarnings("unchecked")
public <P extends DialogPane> void setPane(P pane, ResultHandler<P> resultHandler) {
public void setPane(D pane, ResultHandler<R> resultHandler) {
this.pane = pane;
this.resultHandler = (Consumer<? super DialogPane>) resultHandler;
this.resultHandler = resultHandler;
}
public void apply() {
resultHandler.accept(pane);
// FIXME
}
}
/** Map {@code <page-name> |-> <page-information>}. */
private Map<String, Page> pages;
private Map<String, Page<?,?>> pages;
/** The currently displayed page. */
private Page currentPage;
private Page<?,?> currentPage;
/** Stack of displayed pages (for navigating back). */
private ObservableList<String> pageStack = FXCollections.observableArrayList();
public void setPages(Map<String,Page> pages, String startPage) {
public void setPages(Map<String,Page<?,?>> pages, String startPage) {
this.pages = pages;
checkPages();
......@@ -117,9 +116,9 @@ public class WizardDialog extends Dialog<ButtonType> {
private void checkPages() {
Set<String> pageNames = pages.keySet();
for (Entry<String, Page> entry: pages.entrySet()) {
for (Entry<String, Page<?,?>> entry: pages.entrySet()) {
String name = entry.getKey();
Page page = entry.getValue();
Page<?,?> page = entry.getValue();
DialogPane pane = page.getPane();
// check page names
......@@ -171,7 +170,7 @@ public class WizardDialog extends Dialog<ButtonType> {
LOG.log(Level.FINE, () -> "current page: "+pageName);
}
public Page getCurrentPage() {
public Page<?,?> getCurrentPage() {
return currentPage;
}
......
......@@ -19,13 +19,13 @@ public class WizardDialogBuilder {
return this;
}
LinkedHashMap<String, Page> pages = new LinkedHashMap<>();
LinkedHashMap<String, Page<?,?>> pages = new LinkedHashMap<>();
public <T extends DialogPane,B extends StandardDialogPaneBuilder<T,B>> WizardDialogBuilder page(String name, B builder) {
Page page = new Page();
public <D extends DialogPane,B extends StandardDialogPaneBuilder<D,B,R>,R> WizardDialogBuilder page(String name, B builder) {
Page<D,R> page = new Page<>();
page.setNext(builder.next);
T pane = builder.build();
ResultHandler<T> resultHandler = builder.getResultHandler();
D pane = builder.build();
ResultHandler<R> resultHandler = builder.getResultHandler();
page.setPane(pane, resultHandler);
pages.put(name, page);
......@@ -51,10 +51,10 @@ public class WizardDialogBuilder {
public WizardDialog build() {
WizardDialog dlg = new WizardDialog();
Page prev = null;
Page<?,?> prev = null;
for (var entry:pages.entrySet()) {
String name = entry.getKey();
Page page = entry.getValue();
Page<?,?> page = entry.getValue();
if (prev!= null && prev.getNext()==null) {
prev.setNext(name);
......
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