diff --git a/core/ui/src/main/java/org/phoebus/ui/application/Messages.java b/core/ui/src/main/java/org/phoebus/ui/application/Messages.java index e9a8cdb981..22bb252a91 100644 --- a/core/ui/src/main/java/org/phoebus/ui/application/Messages.java +++ b/core/ui/src/main/java/org/phoebus/ui/application/Messages.java @@ -40,11 +40,14 @@ public class Messages public static String DockSplitH; public static String DockSplitV; public static String Enjoy; + public static String ErrorDuringEvalutationOfTheFlagSelectSettings; + public static String ErrorLoadingPhoebusConfiguration; public static String Exit; public static String ExitContent; public static String ExitHdr; public static String ExitTitle; public static String File; + public static String FileDoesNotExist; public static String FileExists; public static String FixedTitle; public static String Help; @@ -90,10 +93,12 @@ public class Messages public static String MonitorTaskUi; public static String NamePane; public static String NamePaneHdr; + public static String OK; public static String Open; public static String OpenHdr; public static String OpenTitle; public static String OpenWith; + public static String PhoebusWillQuit; public static String ProgressTitle; public static String PVListAppName; public static String PVListJobName; @@ -129,9 +134,12 @@ public class Messages public static String SavingHdr; public static String ScreenshotErrHdr; public static String ScreenshotErrMsg; + public static String SelectPhoebusConfiguration; public static String SelectTab; public static String ShowStatusbar; public static String ShowToolbar; + public static String TheArgumentIsNotADirectory; + public static String TheDirectoryDoesNotContainConfigurationFiles; public static String Time12h; public static String Time1d; public static String Time3d; diff --git a/core/ui/src/main/java/org/phoebus/ui/application/PhoebusApplication.java b/core/ui/src/main/java/org/phoebus/ui/application/PhoebusApplication.java index e2ca5467b4..cdbd71a08c 100644 --- a/core/ui/src/main/java/org/phoebus/ui/application/PhoebusApplication.java +++ b/core/ui/src/main/java/org/phoebus/ui/application/PhoebusApplication.java @@ -5,6 +5,7 @@ import java.io.FileNotFoundException; import java.lang.ref.WeakReference; import java.net.URI; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -28,6 +29,8 @@ import java.util.logging.Logger; import java.util.stream.Collectors; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.scene.control.Alert; import javafx.scene.control.Button; @@ -36,6 +39,7 @@ import javafx.scene.control.CheckBox; import javafx.scene.control.CheckMenuItem; import javafx.scene.control.Dialog; +import javafx.scene.control.ListView; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuButton; @@ -44,14 +48,27 @@ import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.ToolBar; import javafx.scene.control.Tooltip; -import javafx.scene.layout.*; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyCodeCombination; +import javafx.scene.input.KeyCombination; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Text; +import javafx.stage.Stage; +import javafx.stage.Window; +import javafx.util.Pair; import org.phoebus.framework.jobs.JobManager; import org.phoebus.framework.jobs.JobMonitor; import org.phoebus.framework.jobs.SubJobMonitor; import org.phoebus.framework.persistence.MementoTree; import org.phoebus.framework.persistence.XMLMementoTree; +import org.phoebus.framework.preferences.PropertyPreferenceLoader; import org.phoebus.framework.spi.AppDescriptor; import org.phoebus.framework.spi.AppResourceDescriptor; import org.phoebus.framework.util.ResourceParser; @@ -85,12 +102,6 @@ import javafx.scene.control.Alert.AlertType; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyCodeCombination; -import javafx.scene.input.KeyCombination; -import javafx.scene.input.MouseEvent; -import javafx.stage.Stage; -import javafx.stage.Window; /** * Primary UI for a phoebus application @@ -286,6 +297,9 @@ public void start(final Stage initial_stage) throws Exception { // Save original application parameters application_parameters.addAll(getParameters().getRaw()); + Platform.setImplicitExit(false); // Avoids shutdown of Phoebus when the '-select_settings' option is used after the dialog to select configuration file has been closed. Platform.setImplicitExit(true) is called below to restore the option again. + possiblySelectIniFile(application_parameters); // possiblySelectIniFile() must be called before preferences are initialized, to ensure that the selected configuration options are applied before old configuration options are loaded. + // Show splash screen as soon as possible.. final Splash splash = Preferences.splash ? new Splash(initial_stage) : null; @@ -294,9 +308,131 @@ public void start(final Stage initial_stage) throws Exception { { final JobMonitor splash_monitor = new SplashJobMonitor(monitor, splash); backgroundStartup(splash_monitor, splash); + Platform.setImplicitExit(true); }); } + private void possiblySelectIniFile(CopyOnWriteArrayList application_parameters) { + + Consumer> displayErrorMessageAndQuit = errorTitleAndErrorMessage -> { + + String errorTitle = errorTitleAndErrorMessage.getKey(); + String errorMessage = errorTitleAndErrorMessage.getValue(); + + logger.log(Level.SEVERE, errorMessage); + + Dialog errorDialog = new Alert(AlertType.ERROR); + errorDialog.setTitle(errorTitle); + errorDialog.setHeaderText(errorTitle); + errorDialog.setContentText(errorMessage + "\n\n" + Messages.PhoebusWillQuit); + errorDialog.showAndWait(); + + stop(); + }; + + if (application_parameters.contains("-select_settings")) { + int indexOfFlag = application_parameters.indexOf("-select_settings", 0); + if (indexOfFlag < 0) { + throw new RuntimeException("Error, this should never happen!"); + } + if (application_parameters.size() > indexOfFlag) { + String iniFilesLocation_String = application_parameters.get(indexOfFlag + 1); + File iniFilesLocation_File = new File(iniFilesLocation_String); + if (iniFilesLocation_File.isDirectory()) { + List iniFilesInDirectory_List = Arrays.stream(iniFilesLocation_File.listFiles()).filter(file -> file.getAbsolutePath().endsWith(".ini") || file.getAbsolutePath().endsWith(".xml")).collect(Collectors.toList()); + ObservableList iniFilesInDirectory_ObservableList = FXCollections.observableArrayList(iniFilesInDirectory_List); + + if (iniFilesInDirectory_List.size() > 0) { + Dialog iniFileSelectionDialog = new Dialog(); + iniFileSelectionDialog.setTitle(Messages.SelectPhoebusConfiguration); + iniFileSelectionDialog.setHeaderText(Messages.SelectPhoebusConfiguration); + iniFileSelectionDialog.setGraphic(null); + + iniFileSelectionDialog.setWidth(500); + iniFileSelectionDialog.setHeight(400); + iniFileSelectionDialog.setResizable(false); + + ListView listView = new ListView(iniFilesInDirectory_ObservableList); + listView.getSelectionModel().select(0); + + Runnable setReturnValueAndCloseDialog = () -> { + File selectedFile = (File) listView.getSelectionModel().getSelectedItem(); + if (selectedFile == null) { + selectedFile = (File) listView.getItems().get(0); + } + iniFileSelectionDialog.setResult(selectedFile); + iniFileSelectionDialog.close(); + }; + listView.setOnMouseClicked(mouseEvent -> { + if (mouseEvent.getClickCount() == 2) { + setReturnValueAndCloseDialog.run(); + } + }); + listView.setOnKeyPressed(keyEvent -> { + if (keyEvent.getCode() == KeyCode.ENTER) { + setReturnValueAndCloseDialog.run(); + } + }); + + iniFileSelectionDialog.getDialogPane().getButtonTypes().add(ButtonType.CLOSE); + Button closeButton = (Button) iniFileSelectionDialog.getDialogPane().lookupButton(ButtonType.CLOSE); + closeButton.setVisible(false); // In JavaFX, a button of type ButtonType.CLOSE must exist so that the "X"-button closes the window. + + Button okButton = new Button(Messages.OK); + okButton.setOnAction(actionEvent -> setReturnValueAndCloseDialog.run()); + okButton.setPrefWidth(500); + + VBox vBox = new VBox(listView, okButton); + iniFileSelectionDialog.getDialogPane().setContent(vBox); + listView.requestFocus(); + + iniFileSelectionDialog.getDialogPane().addEventFilter(KeyEvent.KEY_PRESSED, keyEvent -> { + if (keyEvent.getCode() == KeyCode.ESCAPE) { + iniFileSelectionDialog.close(); + keyEvent.consume(); + } + }); + + iniFileSelectionDialog.setOnCloseRequest(dialogEvent -> { + Object currentResult = iniFileSelectionDialog.getResult(); + if (currentResult == null || !(currentResult instanceof File)) { + // Return null when closing the dialog by clicking the "X"-button or the ESC-key. + iniFileSelectionDialog.setResult(null); + } + }); + + Optional maybeSelectedFile = iniFileSelectionDialog.showAndWait(); + if (maybeSelectedFile.isPresent()) { + File selectedFile = maybeSelectedFile.get(); + try { + FileInputStream selectedFile_FileInputStream = new FileInputStream(selectedFile); + try { + if (selectedFile.getAbsolutePath().endsWith(".xml")) { + java.util.prefs.Preferences.importPreferences(selectedFile_FileInputStream); + } + else { + PropertyPreferenceLoader.load(selectedFile_FileInputStream); + } + } catch (Exception exception) { + displayErrorMessageAndQuit.accept(new Pair(Messages.ErrorLoadingPhoebusConfiguration, Messages.ErrorLoadingPhoebusConfiguration + " '" + selectedFile.getAbsolutePath() + "': " + exception.getMessage())); + } + } catch (FileNotFoundException e) { + displayErrorMessageAndQuit.accept(new Pair(Messages.ErrorLoadingPhoebusConfiguration, Messages.ErrorLoadingPhoebusConfiguration + " '" + selectedFile.getAbsolutePath() + "': " + Messages.FileDoesNotExist)); + } + } else { + // Selecting a configuration was cancelled either by pressing the "X"-button or by pressing the ESC-key. + stop(); + } + } else { + displayErrorMessageAndQuit.accept(new Pair(Messages.ErrorDuringEvalutationOfTheFlagSelectSettings, Messages.ErrorDuringEvalutationOfTheFlagSelectSettings + ": " + MessageFormat.format(Messages.TheDirectoryDoesNotContainConfigurationFiles, iniFilesLocation_String))); + } + } else { + displayErrorMessageAndQuit.accept(new Pair(Messages.ErrorDuringEvalutationOfTheFlagSelectSettings, Messages.ErrorDuringEvalutationOfTheFlagSelectSettings + ": " + MessageFormat.format(Messages.TheArgumentIsNotADirectory, iniFilesLocation_String))); + } + } + } + } + /** * Perform potentially slow startup task off the UI thread * diff --git a/core/ui/src/main/resources/org/phoebus/ui/application/messages.properties b/core/ui/src/main/resources/org/phoebus/ui/application/messages.properties index 2c9a3c4882..3f4b29c0c2 100644 --- a/core/ui/src/main/resources/org/phoebus/ui/application/messages.properties +++ b/core/ui/src/main/resources/org/phoebus/ui/application/messages.properties @@ -26,11 +26,14 @@ DockNotSaved= DockSplitH=Split Left/Right DockSplitV=Split Top/Bottom Enjoy=Enjoy CS-Studio! +ErrorDuringEvalutationOfTheFlagSelectSettings=Error during evaluation of the flag '-select_settings' +ErrorLoadingPhoebusConfiguration=Error loading Phoebus configuration Exit=Exit ExitContent=Closing this window exits the application,\nclosing all other windows.\n ExitHdr=Close main window ExitTitle=Exit File=File +FileDoesNotExist=File does not exist! FileExists=File \"{0}\" already exists. Do you want to overwrite it? FixedTitle=CS-Studio Help=Help @@ -76,10 +79,12 @@ MonitorTaskTabs=Restore tabs MonitorTaskUi=Start UI NamePane=Name Pane NamePaneHdr=Assign a name to this pane.\nSome displays can be configured\nto appear in a named pane. +OK=OK Open=Open... OpenHdr=Select application for opening\n OpenTitle=Open OpenWith=Open With... +PhoebusWillQuit=Phoebus will quit. ProgressTitle=CS-Studio PVListAppName=PV List PVListJobName=List PVs @@ -115,9 +120,12 @@ SavingErr=Error saving SavingHdr=Save error ScreenshotErrHdr=Screenshot error ScreenshotErrMsg=Cannot write screenshot +SelectPhoebusConfiguration=Select Phoebus configuration SelectTab=Select Tab ShowStatusbar=Show Status bar ShowToolbar=Show Toolbar +TheArgumentIsNotADirectory=the argument ''{0}'' is not a directory! +TheDirectoryDoesNotContainConfigurationFiles=the directory ''{0}'' does not contain any .ini or .xml file(s)! Time12h=12 h Time1d=1 day Time3d=3 days