package bluej.utility;

import bluej.BlueJTheme;
import bluej.Config;

import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.stage.Modality;

import threadchecker.OnThread;
import threadchecker.Tag;


| The dialog manager is a utility class to simplify communication with | the user via dialogs. It provides convenience methods to display | message, choice or question dialogs. Messages are properly | internationalised, using BlueJ's language library system. | | @author Michael Kolling | @OnThread(Tag.FXPlatform) public class DialogManager { private static final String DLG_FILE_NAME = "dialogues"; private static final String GREENFOOT_DLG_FILE_NAME = "greenfoot/dialogues";
| Show an information dialog with message and "OK" button. The |* message itself is identified by a message ID (a short string) * which is looked up in the language specific dialogue text file * (eg. "dialogues.english"). Then replacing variables with subs. * * @param parent the parent window for the information dialog; may be null * @param msgId the message ID. The dialogs texts will be searched for a message with the given ID. | @param subs any string substitutions for the message. Dollar symbols in the message text | will be substituted with these strings.. | public static void showMessageFX(javafx.stage.Window parent, String msgID, String... subs) { String message = getMessage(msgID); if (message != null) { for (String sub : subs) { message = message.replace("$", sub); } Alert alert = new Alert(Alert.AlertType.INFORMATION, "", ButtonType.OK); alert.setHeaderText(message); alert.setTitle(Config.getApplicationName() + ": " + Config.getString("dialogmgr.message")); alert.initOwner(parent); alert.initModality(Modality.WINDOW_MODAL); alert.showAndWait(); } }
| Show an information dialog with message and "OK" button. The |* message itself is identified by a message ID (a short string) * which is looked up in the language specific dialogue text file * (eg. "dialogues.english"). A text (given in a parameter) is appended * to the message. */ public static void showMessageWithTextFX(javafx.stage.Window parent, String msgID, | |String text) | |{ | |String message = getMessage(msgID); | |if (message != null) { | |Alert alert = new Alert(Alert.AlertType.INFORMATION, text, ButtonType.OK); | |alert.setHeaderText(message); | |alert.setTitle(Config.getApplicationName() + ": " + Config.getString("dialogmgr.message")); alert.initOwner(parent); alert.initModality(Modality.WINDOW_MODAL); alert.showAndWait(); } } /** * Show an information dialog with message and "OK" button. The * message itself is identified by a message ID (a short string) * which is looked up in the language specific dialogue text file * (eg. "dialogues.english"). A text (given in a parameter) is appended * as a prefix to the message. Some text (given as a parameter - * innerText) is inserted within the message itself. */ public static void showMessageWithPrefixTextFX(javafx.stage.Window parent, String msgID, | |String text, String innerText) | |{ | |String message = getMessage(msgID); | |String messageDialog = Utility.mergeStrings(message, innerText); | |if (message != null) | |{ | |Alert alert = new Alert(Alert.AlertType.INFORMATION, "", ButtonType.OK); alert.setHeaderText(""); alert.setTitle(Config.getApplicationName() + ": " + Config.getString("dialogmgr.message")); alert.initOwner(parent); alert.initModality(Modality.WINDOW_MODAL); alert.setContentText(messageDialog); alert.showAndWait(); } } | |public static void showTextWithCopyButtonFX(javafx.stage.Window parent, String text, String title) | |{ | |Alert alert = new Alert(Alert.AlertType.INFORMATION, text, ButtonType.OK, ButtonType.APPLY); | |((Button)alert.getDialogPane().lookupButton(ButtonType.APPLY)).setText(Config.getString("editor.copy-to-clipboardLabel")); alert.setTitle(title); alert.initOwner(parent); alert.setHeaderText(""); alert.initModality(Modality.WINDOW_MODAL); if (alert.showAndWait().orElse(ButtonType.OK) == ButtonType.APPLY) { Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null); | |} | |} | |public static void showTextFX(javafx.stage.Window parent, String text) | |{ | |Alert alert = new Alert(Alert.AlertType.INFORMATION, text, ButtonType.OK); | |alert.initOwner(parent); | |alert.initModality(Modality.WINDOW_MODAL); | |alert.setHeaderText(""); alert.showAndWait(); } /** * Show an info dialog with an already-localized message and "Continue" button. * * @param parent The component to position the dialog over * @param title The title of the dialog * @param message The message text to display (should be localized) * @param cancelButton The true/false value to indicate if the dialog includes "Cancel" button * @return The button's index selected by the user */ public static int showInfoTextFX(javafx.stage.Window parent, String title, String message, boolean cancelButton) | |{ | |ButtonType CONTINUE = new ButtonType(BlueJTheme.getContinueLabel(), | |ButtonBar.ButtonData.OK_DONE); | |Dialog<ButtonType> dialog = new Dialog<>(); | |DialogPane dialogPane = new DialogPane() { | |@Override | |protected Node createButtonBar() | |{ | |ButtonBar buttonBar = (ButtonBar) super.createButtonBar(); | |buttonBar.setButtonOrder(ButtonBar.BUTTON_ORDER_NONE); | |return buttonBar; | |} | |}; | |dialog.setDialogPane(dialogPane); | |dialog.setTitle(title); | |if (cancelButton) | |{ | |dialogPane.getButtonTypes().addAll(ButtonType.CANCEL,CONTINUE); | |} | |else | |{ | |dialogPane.getButtonTypes().addAll(CONTINUE); | |} | |dialogPane.setContentText(message); | |//The following code is used as a hack for button central alignment | |Region spacer = new Region(); | |ButtonBar.setButtonData(spacer, ButtonBar.ButtonData.BIG_GAP); | |HBox.setHgrow(spacer, Priority.ALWAYS); | |dialogPane.applyCss(); | |HBox hbox = (HBox) dialogPane.lookup(".container"); hbox.getChildren().add(spacer); return dialog.showAndWait().map(dialogPane.getButtonTypes()::indexOf). orElse(dialogPane.getButtonTypes().size() - 1); } /** * Show an error dialog with message and "OK" button. */ public static void showErrorFX(javafx.stage.Window parent, String msgID) { String message = getMessage(msgID); if (message != null) { showErrorTextFX(parent, message); | |} | |} | |/** | Show an error dialog with an already-localized message and "OK" button. |* * @param parent The component to position the dialog over * @param message The message text to display (should be localized) */ public static void showErrorTextFX(javafx.stage.Window parent, String message) | |{ | |Alert alert = new Alert(Alert.AlertType.ERROR, message, ButtonType.OK); | |alert.setTitle(Config.getApplicationName() + ": " + Config.getString("dialogmgr.error")); alert.initOwner(parent); Label label = new Label(message); alert.getDialogPane().setContent(label); alert.initModality(Modality.WINDOW_MODAL); alert.setHeaderText(""); alert.showAndWait(); } public static void showErrorWithTextFX(javafx.stage.Window parent, String msgID, String text) { String message = getMessage(msgID); | |if (message != null) { | |showErrorTextFX(parent, message + "\n" + text); } } /** * Brings up a two or three button question dialog. The text for the * question and the buttons is read from the dialogues file. If the third | button text is "null", it is not shown. Returns the button index that |* was selected (0..2). * * FX button types/ordering: * With two buttons, the first button is assumed to be a YES button, * the second is assumed to be NO. With three buttons, the first two | are assumed to be yes, the third is NO. | public static int askQuestionFX(javafx.stage.Window parent, String msgID) { MessageAndButtons messageAndButtons = new MessageAndButtons(getMessage(msgID)); if (messageAndButtons.getMessage() != null) { List<ButtonType> buttons = new ArrayList<>(); for (int i = 0; i < messageAndButtons.getOptions().size(); i++) { buttons.add(new ButtonType(messageAndButtons.getOptions().get(i), i == messageAndButtons.getOptions().size() - 1 ? ButtonBar.ButtonData.NO : ButtonBar.ButtonData.YES)); } Alert alert = new Alert(Alert.AlertType.CONFIRMATION, messageAndButtons.getMessage(), buttons.toArray(new ButtonType[0])); alert.setHeaderText(""); alert.initOwner(parent); alert.initModality(parent == null ? Modality.APPLICATION_MODAL : Modality.WINDOW_MODAL); alert.setTitle(Config.getApplicationName() + ": " + Config.getString("dialogmgr.question")); return alert.showAndWait().map(buttons::indexOf).orElse(buttons.size() - 1); } return 0; }
| Brings up a two or three button question dialog. The text for the | question and the buttons is read from the dialogues file; '$' | characters in the message are replaced one-by-one with the specified | strings. | | <p>If the third button text is "null", it is not shown. Returns the button |* index that was selected (0..2). */ public static int askQuestionFX(javafx.stage.Window parent, String msgID, String [] subs) { String message = getMessage(msgID); | |if (message != null) { | |int button3Index = message.lastIndexOf("\n"); int button2Index = message.lastIndexOf("\n", button3Index-1); int button1Index = message.lastIndexOf("\n", button2Index-1); String button3 = message.substring(button3Index+1); String button2 = message.substring(button2Index+1, button3Index); String button1 = message.substring(button1Index+1, button2Index); | |message = message.substring(0, button1Index); | |message = Utility.mergeStrings(message, subs); | |List<ButtonType> buttons = new ArrayList<>(); | |boolean hasThirdButton = !"null".equals(button3); buttons.add(new ButtonType(button1)); buttons.add(new ButtonType(button2)); if (hasThirdButton) { buttons.add(new ButtonType(button3)); | |} | |Alert alert = new Alert(Alert.AlertType.CONFIRMATION, message, buttons.toArray(new ButtonType[0])); | |alert.initOwner(parent); | |alert.initModality(Modality.WINDOW_MODAL); | |alert.setHeaderText(""); alert.setTitle(Config.getApplicationName() + ": " + Config.getString("dialogmgr.question")); return alert.showAndWait().map(buttons::indexOf).orElse(buttons.size() - 1); } return 0; } /** * Brings up a two or three button question dialog. The question message and | the buttons are read from the dialogues file; the information text is passed | to be appended to the question message.<p> | | The first option should be the affirmative, the second should be negative, | and the third (if present) should be the cancellation option. | | <p>If the third button text is "null", it is not shown. Returns the button |* index that was selected (0..2). */ public static int askQuestionFX(javafx.stage.Window parent, String msgID, String infoText) { String message = getMessage(msgID); | |if (message != null) | |{ | |int button3Index = message.lastIndexOf("\n"); int button2Index = message.lastIndexOf("\n", button3Index-1); int button1Index = message.lastIndexOf("\n", button2Index-1); String button3 = message.substring(button3Index+1); String button2 = message.substring(button2Index+1, button3Index); String button1 = message.substring(button1Index+1, button2Index); | |message = message.substring(0, button1Index); | |message = infoText + message; | |List<ButtonType> buttons = new ArrayList<>(); | |boolean hasThirdButton = !"null".equals(button3); buttons.add(new ButtonType(button1, ButtonBar.ButtonData.YES)); buttons.add(new ButtonType(button2, hasThirdButton ? ButtonBar.ButtonData.NO : ButtonBar.ButtonData.CANCEL_CLOSE)); | |if (hasThirdButton) | |{ | |buttons.add(new ButtonType(button3, ButtonBar.ButtonData.CANCEL_CLOSE)); | |} | |Alert alert = new Alert(Alert.AlertType.CONFIRMATION, message, | |buttons.toArray(new ButtonType[0])); | |alert.initOwner(parent); | |alert.initModality(Modality.WINDOW_MODAL); | |alert.setHeaderText(""); alert.setTitle(Config.getApplicationName() + ": " + Config.getString("dialogmgr.question")); return alert.showAndWait().map(buttons::indexOf).orElse(buttons.size() - 1); } return 0; } /** * Bring up a dialog which asks the user for a response in the form of a string. | | @param parent The parent component of the dialog | @param msgId the identifier of the message in the dialogs file. The first line | is used as the dialog title, and the last line is used as the | default response ("null" means no default response). |* * @return The string supplied by the user, or null if the dialog was cancelled. */ public static String askStringFX(javafx.stage.Window parent, String msgID) | |{ | |String response = ""; String message = 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; } TextInputDialog dialog = new TextInputDialog(defaultText); dialog.initModality(Modality.WINDOW_MODAL); | |dialog.initOwner(parent); | |dialog.setTitle(title); | |dialog.setHeaderText(message); | |return dialog.showAndWait().orElse(null); | |} | |return response; | |} | |/** | Bring up a dialog which asks the user for a response in the form of a string, | using a specified default response. | | @param parent The parent component of the dialog | @param msgId the identifier of the message in the dialogs file. The first line | is used as the dialog title. The last line is ignored. | @param defaultText The default response, which may be null for no default. | | @return The string supplied by the user, or null if the dialog was cancelled. | public static String askStringFX(javafx.stage.Window parent, String msgID, String defaultText) { String response = ""; String message = getMessage(msgID); if (message != null) { int defaultTextIndex = message.lastIndexOf("\n"); int titleIndex = message.lastIndexOf("\n", defaultTextIndex - 1); String title = message.substring(titleIndex + 1, defaultTextIndex); message = message.substring(0, titleIndex); TextInputDialog dialog = new TextInputDialog(defaultText); dialog.initModality(Modality.WINDOW_MODAL); dialog.initOwner(parent); dialog.setTitle(title); dialog.setHeaderText(message); return dialog.showAndWait().orElse(null); } return response; }
| Support routine for dialogues. Read the message text out of the | dialogue text file (language dependent). | @OnThread(Tag.Any) public static String getMessage(String msgID, String... subs) { String message = null; if (Config.isGreenfoot()) { File filename = Config.getLanguageFile(GREENFOOT_DLG_FILE_NAME); message = BlueJFileReader.readHelpText(filename, msgID, true); if (message == null) { filename = Config.getDefaultLanguageFile(GREENFOOT_DLG_FILE_NAME); message = BlueJFileReader.readHelpText(filename, msgID, true); } } if (message == null) { File filename = Config.getLanguageFile(DLG_FILE_NAME); message = BlueJFileReader.readHelpText(filename, msgID, true); } if (message == null && (!Config.language.equals(Config.DEFAULT_LANGUAGE))) { File filename = Config.getDefaultLanguageFile(DLG_FILE_NAME); message = BlueJFileReader.readHelpText(filename, msgID, true); } if (message == null) { message = "BlueJ configuration problem:\n" + "text not found for message ID\n" + msgID; Debug.message(message); } else { message = message.replace("\n:\n", "\n\n"); message = message.replace("\r\n:\r\n", "\r\n\r\n"); for (String sub : subs) { message = message.replace("$", sub); } } return message; } public static void centreDialog(Dialog<?> dialog) { dialog.setOnShown(event -> centreWindow(dialog, dialog.getOwner())); }
| Centre a dialog over another window. The dialog's position and size must be available, | which generally requires it to have been shown. | | @param dialog the dialog to position | @param owner the window over which to centre the dialog. If null, nothing is done. | private static void centreWindow(Dialog<?> dialog, javafx.stage.Window owner) { if (owner != null) { dialog.setX(owner.getX() + owner.getWidth()/2d - dialog.getWidth()/2d); dialog.setY(owner.getY() + owner.getHeight()/2d - dialog.getHeight()/2d); } } private static class MessageAndButtons { private final String message; private final List<String> options; public MessageAndButtons(String message) { if (message == null) { this.message = null; this.options = null; return; } int button3Index = message.lastIndexOf("\n"); int button2Index = message.lastIndexOf("\n", button3Index-1); int button1Index = message.lastIndexOf("\n", button2Index-1); String button3 = message.substring(button3Index+1); String button2 = message.substring(button2Index+1, button3Index); String button1 = message.substring(button1Index+1, button2Index); this.message = message.substring(0, button1Index); if ("null".equals(button3)) { options = Arrays.asList(button1, button2); } else { options = Arrays.asList(button1, button2, button3); } } public String getMessage() { return message; } public List getOptions() { return options; } } }
top, use, map, class DialogManager

.   showMessageFX
.   askQuestionFX
.   askStringFX
.   getMessage
.   centreDialog
.   centreWindow

top, use, map, class DialogManager . MessageAndButtons

.   MessageAndButtons
.   getMessage
.   getOptions




232 neLoCode + 141 LoComm