From 934676f784e0d9a21f73a2e17986cb79ee5ae269 Mon Sep 17 00:00:00 2001 From: Abraham Wolk Date: Fri, 11 Aug 2023 10:25:13 +0200 Subject: [PATCH 1/6] CSSTUDIO-2007 Prevent saving to a file that is already opened. --- .../phoebus/ui/docking/DockItemWithInput.java | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java index 2b8c7d05a5..421b90daa8 100644 --- a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java +++ b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java @@ -24,7 +24,9 @@ import java.util.stream.Collectors; import javafx.scene.Scene; +import javafx.scene.layout.Region; import javafx.stage.Window; +import org.apache.commons.io.FilenameUtils; import org.phoebus.framework.jobs.JobManager; import org.phoebus.framework.jobs.JobMonitor; import org.phoebus.framework.jobs.JobRunnable; @@ -425,10 +427,36 @@ else if (response == ButtonType.NO) return false; } - // Update input - setInput(ResourceParser.getURI(actual_file.get())); - // Save in that file - return save(monitor); + URI newInput = ResourceParser.getURI(actual_file.get()); + DockItemWithInput existingInstanceWithInput = DockStage.getDockItemWithInput(getApplication().getAppDescriptor().getName(), newInput); + if (existingInstanceWithInput == null || (input != null && newInput.getPath().equals(input.getPath()))) { + // Update input + setInput(newInput); + // Save in that file + return save(monitor); + } + else { + CompletableFuture waitForDialogToClose = new CompletableFuture<>(); + Platform.runLater(() -> { + String filename = FilenameUtils.getName(newInput.getPath()); + + final Alert dialog = new Alert(AlertType.INFORMATION); + dialog.setTitle("File is already open in another tab"); + dialog.setHeaderText("The file " + filename + " is already open in another tab"); + dialog.setContentText("An instance of " + getApplication().getAppDescriptor().getDisplayName() + " associated with " + filename + " is already running in a different tab. A different filepath must be chosen for the save operation."); + int width = 500; + int height = 200; + dialog.getDialogPane().setPrefSize(width, height); + dialog.getDialogPane().setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); + dialog.setResizable(false); + DialogHelper.positionDialog(dialog, getTabPane(), -width/2, -height/2); + dialog.showAndWait(); + waitForDialogToClose.complete(true); + }); + + waitForDialogToClose.get(); + save_as(monitor); + } } catch (Exception ex) { From a8f3b39cad1ba6932aa60b40b972e88e77111b36 Mon Sep 17 00:00:00 2001 From: Abraham Wolk Date: Fri, 11 Aug 2023 10:35:51 +0200 Subject: [PATCH 2/6] CSSTUDIO-2007 Add labels to messages.properties. --- .../java/org/phoebus/ui/application/Messages.java | 3 +++ .../org/phoebus/ui/docking/DockItemWithInput.java | 12 +++++------- .../org/phoebus/ui/application/messages.properties | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) 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 8708f628ea..3cfbb3b53f 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 @@ -113,6 +113,9 @@ public class Messages public static String SaveAsPrompt; public static String SaveDlgErrHdr; public static String SaveDlgHdr; + public static String SaveAsFileAlreadyOpen_content; + public static String SaveAsFileAlreadyOpen_header; + public static String SaveAsFileAlreadyOpen_title; public static String SaveLayoutAs; public static String SaveLayoutOfContainingWindowAs; public static String SaveLayoutWarningApplicationNoSaveFile; diff --git a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java index 421b90daa8..5b607bbc5a 100644 --- a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java +++ b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java @@ -14,18 +14,14 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.stream.Collectors; -import javafx.scene.Scene; import javafx.scene.layout.Region; -import javafx.stage.Window; import org.apache.commons.io.FilenameUtils; import org.phoebus.framework.jobs.JobManager; import org.phoebus.framework.jobs.JobMonitor; @@ -441,9 +437,11 @@ else if (response == ButtonType.NO) String filename = FilenameUtils.getName(newInput.getPath()); final Alert dialog = new Alert(AlertType.INFORMATION); - dialog.setTitle("File is already open in another tab"); - dialog.setHeaderText("The file " + filename + " is already open in another tab"); - dialog.setContentText("An instance of " + getApplication().getAppDescriptor().getDisplayName() + " associated with " + filename + " is already running in a different tab. A different filepath must be chosen for the save operation."); + dialog.setTitle(Messages.SaveAsFileAlreadyOpen_title); + String headerText = MessageFormat.format(Messages.SaveAsFileAlreadyOpen_header, filename); + dialog.setHeaderText(headerText); + String contentText = MessageFormat.format(Messages.SaveAsFileAlreadyOpen_content, getApplication().getAppDescriptor().getDisplayName(), filename); + dialog.setContentText(contentText); int width = 500; int height = 200; dialog.getDialogPane().setPrefSize(width, height); 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 61d4ef4bd5..5646f29c47 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 @@ -99,6 +99,9 @@ SaveAsHdr=Use this file extension? SaveAsPrompt=The file name\n {0}\ndoes not have the suggested file extension\ni.e. {1}.\n\nYes: Save as {2}\nNo: Continue with original name\nCancel: Do not save SaveDlgErrHdr=Name must only contain alphanumeric characters, space, underscore or '-'.\nEnter a valid layout name. SaveDlgHdr=Enter a file name to save the layout as. +SaveAsFileAlreadyOpen_content=An instance of {0} associated with {1} is already running in a different tab. A different filepath must be chosen for the save operation. +SaveAsFileAlreadyOpen_header=The file {0} is already associated with another tab. +SaveAsFileAlreadyOpen_title=File is already associated with another tab SaveLayoutAs=Save Layout As... SaveLayoutOfContainingWindowAs=Save Layout of Containing Window As... SaveLayoutWarningApplicationNoSaveFile=The following application(s) do not have associated with them save file(s). No save file association(s) will be stored for the application instance(s) in question when proceeding to save the layout. Proceed?\n\nThe application(s) in question are:\n From 38b1dbf61b5944590486b3f11e357c220cc12470 Mon Sep 17 00:00:00 2001 From: Abraham Wolk Date: Fri, 11 Aug 2023 10:37:12 +0200 Subject: [PATCH 3/6] CSSTUDIO-2007 Adjust width. --- .../src/main/java/org/phoebus/ui/docking/DockItemWithInput.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java index 5b607bbc5a..e3d9dc4c97 100644 --- a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java +++ b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java @@ -442,7 +442,7 @@ else if (response == ButtonType.NO) dialog.setHeaderText(headerText); String contentText = MessageFormat.format(Messages.SaveAsFileAlreadyOpen_content, getApplication().getAppDescriptor().getDisplayName(), filename); dialog.setContentText(contentText); - int width = 500; + int width = 550; int height = 200; dialog.getDialogPane().setPrefSize(width, height); dialog.getDialogPane().setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); From ed2f3180c79b17201fcddbd2eece008fc9091f19 Mon Sep 17 00:00:00 2001 From: Abraham Wolk Date: Fri, 11 Aug 2023 10:44:11 +0200 Subject: [PATCH 4/6] CSSTUDIO-2007 Fix typo. --- .../resources/org/phoebus/ui/application/messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5646f29c47..97b49df3ea 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 @@ -99,7 +99,7 @@ SaveAsHdr=Use this file extension? SaveAsPrompt=The file name\n {0}\ndoes not have the suggested file extension\ni.e. {1}.\n\nYes: Save as {2}\nNo: Continue with original name\nCancel: Do not save SaveDlgErrHdr=Name must only contain alphanumeric characters, space, underscore or '-'.\nEnter a valid layout name. SaveDlgHdr=Enter a file name to save the layout as. -SaveAsFileAlreadyOpen_content=An instance of {0} associated with {1} is already running in a different tab. A different filepath must be chosen for the save operation. +SaveAsFileAlreadyOpen_content=An instance of {0} associated with {1} is already running in a different tab. A different file path must be chosen for the save operation. SaveAsFileAlreadyOpen_header=The file {0} is already associated with another tab. SaveAsFileAlreadyOpen_title=File is already associated with another tab SaveLayoutAs=Save Layout As... From 2b5a13b1f206472e6818ae1ee489834e71c5fdf5 Mon Sep 17 00:00:00 2001 From: Abraham Wolk Date: Fri, 11 Aug 2023 11:29:05 +0200 Subject: [PATCH 5/6] CSSTUDIO-2007 Add version of getDockItemWithInput() that returns any DockItemWithInput whose input is the specified input. Improve check by not requiring that the application be the same. --- .../phoebus/ui/docking/DockItemWithInput.java | 4 ++-- .../org/phoebus/ui/docking/DockStage.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java index e3d9dc4c97..96a1d009dd 100644 --- a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java +++ b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java @@ -424,7 +424,7 @@ else if (response == ButtonType.NO) } URI newInput = ResourceParser.getURI(actual_file.get()); - DockItemWithInput existingInstanceWithInput = DockStage.getDockItemWithInput(getApplication().getAppDescriptor().getName(), newInput); + DockItemWithInput existingInstanceWithInput = DockStage.getDockItemWithInput(newInput); if (existingInstanceWithInput == null || (input != null && newInput.getPath().equals(input.getPath()))) { // Update input setInput(newInput); @@ -440,7 +440,7 @@ else if (response == ButtonType.NO) dialog.setTitle(Messages.SaveAsFileAlreadyOpen_title); String headerText = MessageFormat.format(Messages.SaveAsFileAlreadyOpen_header, filename); dialog.setHeaderText(headerText); - String contentText = MessageFormat.format(Messages.SaveAsFileAlreadyOpen_content, getApplication().getAppDescriptor().getDisplayName(), filename); + String contentText = MessageFormat.format(Messages.SaveAsFileAlreadyOpen_content, existingInstanceWithInput.getApplication().getAppDescriptor().getDisplayName(), filename); dialog.setContentText(contentText); int width = 550; int height = 200; diff --git a/core/ui/src/main/java/org/phoebus/ui/docking/DockStage.java b/core/ui/src/main/java/org/phoebus/ui/docking/DockStage.java index b4a1efb195..7d65b16336 100644 --- a/core/ui/src/main/java/org/phoebus/ui/docking/DockStage.java +++ b/core/ui/src/main/java/org/phoebus/ui/docking/DockStage.java @@ -366,6 +366,25 @@ public static DockItemWithInput getDockItemWithInput(final String application_na return null; } + /** Locate DockItemWithInput with input + * @param input Input, must not be null + * @return {@link DockItemWithInput} or null if not found + */ + public static DockItemWithInput getDockItemWithInput(URI input) + { + Objects.requireNonNull(input); + for (Stage stage : getDockStages()) + for (DockPane pane : getDockPanes(stage)) + for (DockItem tab : pane.getDockItems()) + if (tab instanceof DockItemWithInput) + { + DockItemWithInput item = (DockItemWithInput) tab; + if (input.equals(item.getInput())) + return item; + } + return null; + } + /** Locate any 'fixed' {@link DockPane}s and un-fix them * @param stage Stage where to clear 'fixed' panes */ From fa8c1300ccc4747067ef147f9c4fd70aa870456b Mon Sep 17 00:00:00 2001 From: Abraham Wolk Date: Tue, 15 Aug 2023 08:26:14 +0200 Subject: [PATCH 6/6] CSSTUDIO-2007 Add missing import. --- .../src/main/java/org/phoebus/ui/docking/DockItemWithInput.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java index 15fa88f442..5233668288 100644 --- a/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java +++ b/core/ui/src/main/java/org/phoebus/ui/docking/DockItemWithInput.java @@ -22,6 +22,7 @@ import java.util.stream.Collectors; import javafx.scene.layout.Region; +import javafx.stage.Window; import org.apache.commons.io.FilenameUtils; import org.phoebus.framework.jobs.JobManager; import org.phoebus.framework.jobs.JobMonitor;