package bluej.utility.javafx.dialog;
import bluej.Config;
import bluej.utility.DialogManager;
import bluej.utility.javafx.JavaFXUtil;
import javafx.application.Platform;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Window;
import java.util.Optional;
| A base-class for dialogs which ask for a single text-field input from the user.
|
| You will need to subclass this class and implement convert, which converts
| the user's String input into R, the type returned. (If you just want the user's
| raw input, just implement convert as returning the passed parameter.)
|
| You may also want to override validate to either prevent invalid inputs
| being allowed in the field, or to disable/enable the OK button (see setOKEnabled).
|
public abstract class InputDialog<R>{
private final Dialog<R> dialog;
protected final TextField field;
private final Label prompt;
private final Label error;
private final DialogPaneAnimateError dialogPane;
| Creates an InputDialog.
| @param title The title of the dialog (shown in window title bar)
| @param label The text shown in the label above the text field.
| @param prompt The prompt shown in the text field
| @param styleClass The style-class to apply to the dialog.
| @param labelAfterField The label (null if none) to show after the text field (e.g. a file extension suffix)
|
protected InputDialog(String title, String label, String prompt, String styleClass, String labelAfterField)
{
dialog = new Dialog<>();
dialog.initModality(Modality.WINDOW_MODAL);
dialog.setTitle(title);
VBox content = new VBox();
this.prompt = new Label(label);
field = new TextField();
field.setPromptText(prompt);
field.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ESCAPE && dialog.getDialogPane().getButtonTypes().contains(ButtonType.CANCEL))
{
dialog.hide();
e.consume();
}
});
error = new Label();
if (labelAfterField == null)
{
content.getChildren().addAll(this.prompt, field, error);
}
else
{
HBox hbox = new HBox(field, new Label(labelAfterField));
content.getChildren().addAll(this.prompt, hbox, error);
}
dialogPane = new DialogPaneAnimateError(error, () -> validate(field.getText(), field.getText()));
dialog.setDialogPane(dialogPane);
dialog.getDialogPane().setContent(content);
dialog.getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL);
Config.addDialogStylesheets(dialog.getDialogPane());
if (styleClass != null)
JavaFXUtil.addStyleClass(content, styleClass);
JavaFXUtil.addStyleClass(content, "input-dialog-content");
JavaFXUtil.addStyleClass(this.prompt, "input-dialog-prompt");
JavaFXUtil.addStyleClass(field, "input-dialog-field");
JavaFXUtil.addStyleClass(error, "dialog-error-label");
| Scenic view:
|
|dialog.initModality(Modality.NONE);
|
|dialog.setOnShown(e -> org.scenicview.ScenicView.show(dialogPane));
field.setTextFormatter(new TextFormatter<Object>((TextFormatter.Change change) -> {
if (!change.getControlText().equals(change.getControlNewText()) && !validate(change.getControlText(), change.getControlNewText()))
{
change.setRange(0, change.getControlText().length());
change.setText(change.getControlText());
}
return change;
}));
dialog.setResultConverter(buttonType -> {
if (buttonType == ButtonType.OK)
return convert(field.getText());
else{ return null;
}
});
}
| Gets either the title (pass true) or message (pass false) for a dialog
| from the DialogManager.
|
private static String getDetail(String msgID, boolean getTitle)
{
String message = DialogManager.getMessage(msgID);
if (message != null)
{
int defaultTextIndex = message.lastIndexOf("\n");
int titleIndex = message.lastIndexOf("\n", defaultTextIndex - 1);
String defaultText = message.substring(defaultTextIndex + 1);
String title = message.substring(titleIndex + 1, defaultTextIndex);
message = message.substring(0, titleIndex);
if ("null".equals(defaultText))
{
defaultText = null;
}
return getTitle ? title : message;
}
return "";
}
protected InputDialog(String title, String label, String prompt, String styleClass)
{
this(title, label, prompt, styleClass, null);
}
protected InputDialog(String dialogMsgID, String prompt, String styleClass)
{
this(getDetail(dialogMsgID, true), getDetail(dialogMsgID, false).replace("\n", " "), prompt, styleClass);
}
| Sets the owner of the dialog. Should be called before dialog is shown.
|
public void initOwner(Window parent)
{
dialog.initOwner(parent);
}
| Sets the prompt text. Can be called any time, including while the dialog
| is showing. Although if the text changes length a lot, the layout may be disturbed.
|
protected void setPrompt(String s)
{
prompt.setText(s);
}
| Shows the dialog and waits for it to be dismissed (e.g. by closing
| the window, pressing escape, clicking OK or Cancel). The returned
| value is Optional.of(X) if OK was pressed, and convert(..) returned
| X, where X != null. In any other case (window closed by cancelled or
| closing, or convert returns null), Optional.empty will be returned.
|
| If you want null to be an acceptable return from convert, and treated
| differently to cancelled, consider wrapping it an Optional, so that
| R itself is Optional, and you get back an Optional<Optional<..>> from this method.
|
public Optional showAndWait()
{
Platform.runLater(field::requestFocus);
return dialog.showAndWait();
}
| Sets the error text in the dialog. Will only be visible if you have previously
| called addErrorTextLabel.
|
protected void setErrorText(String errorText)
{
error.setText(errorText);
JavaFXUtil.setPseudoclass("bj-dialog-error", !errorText.equals(""), field);
}
| Sets the OK button of the dialog to be enabled (pass true) or not (pass false)
|
protected void setOKEnabled(boolean okEnabled)
{
dialogPane.getOKButton().setDisable(!okEnabled);
}
| Convert the user's text input into a return value of the desired type,
| e.g. Integer or perhaps String.
| @param input The user text to convert. Will not be null.
| @return The converted value. See showAndWait for details of the consequences
| of returning null here.
|
protected abstract R convert(String input);
| Given a new input, checks whether to allow it as text in the text field
| (disallowing pressing OK is another matter, which should be handled by setOKEnabled).
| Note that you should always allow blank input, and new input which is identical to old output,
| so make sure to return true when newInput is the empty String.
|
| You may also want to call setErrorText or setOKEnabled during your implementation of this method,
| to show an error or disable the OK button if the input is invalid. (But if you do, make
| sure to blank the error and enable the OK button when the input becomes valid again.)
|
| This method gets called with the current content for oldInput and newInput if the user hovers over
| the OK button while the field is blank, to allow you to set the error text (which
| will then be animated).
|
| @param oldInput The previous text
| @param newInput The potential new input
| @return Whether to allow the new input (true) or revert to previous (false)
|
protected boolean validate(String oldInput, String newInput)
{
return true;
}
}
. InputDialog
. getDetail
. InputDialog
. InputDialog
. initOwner
. setPrompt
. showAndWait
. setErrorText
. setOKEnabled
. convert
. validate
208 neLoCode
+ 49 LoComm