From 107ad14528b65ced77b21882052a0f253d8e126f Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Mon, 2 Sep 2024 22:29:45 +0200 Subject: [PATCH 01/29] Using dolphin for testing. --- .../oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index e2a4e2ac2..511418bc3 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -352,7 +352,7 @@ public static void revealInFileBrowser(File filePath) throws IOException { } else if (EditorPlatform.IS_LINUX) { // nautilus does fine on Ubuntu, which is a Debian. // I've no idea how it does with other Linux flavors. - args.add("nautilus"); //NOI18N + args.add("dolphin"); //NOI18N // The nautilus that comes with Ubuntu up to 11.04 included doesn't // take a file path as parameter (you get an error popup), you must // provide a dir path. From 9c9a56b2189fed7fdea95de4a041cf1898cd59e7 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Mon, 2 Sep 2024 23:19:39 +0200 Subject: [PATCH 02/29] Added first draft of linux specific file browser chooser. --- .../kit/editor/EditorPlatform.java | 37 ++++----- .../kit/editor/FileBrowserDetector.java | 83 +++++++++++++++++++ .../kit/editor/FileBrowserDetectorTest.java | 21 +++++ 3 files changed, 122 insertions(+), 19 deletions(-) create mode 100644 kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java create mode 100644 kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetectorTest.java diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 511418bc3..7e9e08070 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -32,8 +32,6 @@ */ package com.oracle.javafx.scenebuilder.kit.editor; -import com.gluonhq.charm.glisten.visual.GlistenStyleClasses; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -45,7 +43,9 @@ import java.util.logging.Level; import java.util.logging.Logger; +import com.gluonhq.charm.glisten.visual.GlistenStyleClasses; import com.oracle.javafx.scenebuilder.kit.i18n.I18N; + import javafx.scene.Node; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; @@ -330,6 +330,8 @@ public static void open(String path) throws IOException { executeDaemon(args, null); } } + + private static FileBrowserDetector fileBrowserDetector = null; /** * Requests the underlying platform to "reveal" the specified folder. On @@ -350,23 +352,20 @@ public static void revealInFileBrowser(File filePath) throws IOException { args.add("explorer"); //NOI18N args.add("/select," + path); //NOI18N } else if (EditorPlatform.IS_LINUX) { - // nautilus does fine on Ubuntu, which is a Debian. - // I've no idea how it does with other Linux flavors. - args.add("dolphin"); //NOI18N - // The nautilus that comes with Ubuntu up to 11.04 included doesn't - // take a file path as parameter (you get an error popup), you must - // provide a dir path. - // Starting with Ubuntu 11.10 (the first based on kernel 3.x) a - // file path is well managed. - int osVersionNumerical = Integer.parseInt(System.getProperty("os.version").substring(0, 1)); //NOI18N - if (osVersionNumerical < 3) { - // Case Ubuntu 10.04 to 11.04: What you provide to nautilus is - // the name of the directory containing the file you want to see - // listed. See DTL-5384. - path = filePath.getAbsoluteFile().getParent(); - if (path == null) { - path = "."; //NOI18N - } + + if (fileBrowserDetector == null) { + fileBrowserDetector = new FileBrowserDetector(); + fileBrowserDetector.detect(); + } + + var fileBrowser = fileBrowserDetector.getLinuxFileBrowser(); + if (fileBrowser.isPresent()) { + args.add(fileBrowser.get()); //NOI18N + } + + path = filePath.getAbsoluteFile().getParent(); + if (path == null) { + path = "."; //NOI18N } args.add(path); } else { diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java new file mode 100644 index 000000000..ffe2cc17b --- /dev/null +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java @@ -0,0 +1,83 @@ +package com.oracle.javafx.scenebuilder.kit.editor; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + + +class FileBrowserDetector { + + private static final Logger LOGGER = Logger.getLogger(FileBrowserDetector.class.getName()); + + private Optional detectedExecutable = null; + + public Optional getLinuxFileBrowser() { + if (this.detectedExecutable == null) { + this.detectedExecutable = detectLinuxFileManager(); + } + + return this.detectedExecutable; + } + + public void detect() { + this.detectedExecutable = detectLinuxFileManager(); + } + + Optional detectLinuxFileManager() { + var filemanager = detectApplication("nautilus"); + if (filemanager.isPresent()) { + return filemanager; + } + + filemanager = detectApplication("dolphin"); + if (filemanager.isPresent()) { + return filemanager; + } + + filemanager = detectApplication("xdg-open"); + if (filemanager.isPresent()) { + return filemanager; + } + + return Optional.empty(); + } + + Optional detectApplication(String applicationName) { + var lookupCmd = EditorPlatform.IS_WINDOWS ? "where" : "which"; + List cmd = List.of(lookupCmd, String.valueOf(applicationName).strip()); + return exec(cmd); + } + + private Optional exec(List cmd) { + LOGGER.log(Level.INFO, "Attempting to run: {0}", cmd.stream().collect(Collectors.joining(" "))); + try { + ProcessBuilder builder = new ProcessBuilder(cmd); + Process proc = builder.start(); + proc.waitFor(100, TimeUnit.SECONDS); + + List lines = new ArrayList<>(); + try (BufferedReader rdr = proc.inputReader()) { + String line = null; + while((line=rdr.readLine()) != null) { + lines.add(line); + } + } + if (!lines.isEmpty()) { + return Optional.of(lines.get(0).strip()); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + return Optional.empty(); + } + +} diff --git a/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetectorTest.java b/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetectorTest.java new file mode 100644 index 000000000..835a0f7db --- /dev/null +++ b/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetectorTest.java @@ -0,0 +1,21 @@ +package com.oracle.javafx.scenebuilder.kit.editor; + +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +class FileBrowserDetectorTest { + + @Test + void test() { + + FileBrowserDetector classUnderTest = new FileBrowserDetector(); + + Optional x = classUnderTest.getLinuxFileBrowser(); + + fail("Not yet implemented"); + } + +} From f95f10ccdcd9268fe362bac2907822e675c115d2 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Mon, 2 Sep 2024 23:23:25 +0200 Subject: [PATCH 03/29] Added logging. --- .../oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 7e9e08070..9bb4ac580 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -68,6 +68,10 @@ public static OS get() { private static final String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); //NOI18N + static { + Logger.getLogger(EditorPlatform.class.getName()).log(Level.INFO, "Detected Operating System: {0}", osName); + } + /** * True if current platform is running Linux. */ From 0cf3adacd5de58e2fb9b481ffb0e10a58bc04a55 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Mon, 2 Sep 2024 23:36:56 +0200 Subject: [PATCH 04/29] Reworked file browser detection. --- .../kit/editor/FileBrowserDetector.java | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java index ffe2cc17b..19236816e 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java @@ -3,7 +3,9 @@ import java.io.BufferedReader; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.logging.Level; @@ -19,7 +21,7 @@ class FileBrowserDetector { public Optional getLinuxFileBrowser() { if (this.detectedExecutable == null) { - this.detectedExecutable = detectLinuxFileManager(); + this.detect(); } return this.detectedExecutable; @@ -29,22 +31,33 @@ public void detect() { this.detectedExecutable = detectLinuxFileManager(); } - Optional detectLinuxFileManager() { - var filemanager = detectApplication("nautilus"); - if (filemanager.isPresent()) { - return filemanager; - } + Optional detectLinuxFileManager() { + var nautilus = detectApplication("nautilus"); + var dolphin = detectApplication("dolphin"); + var xdgopen = detectApplication("xdg-open"); - filemanager = detectApplication("dolphin"); - if (filemanager.isPresent()) { - return filemanager; + Map mgrs = new HashMap<>(); + if (nautilus.isPresent()) { + mgrs.put("nautilus", nautilus.get()); } - filemanager = detectApplication("xdg-open"); - if (filemanager.isPresent()) { - return filemanager; + if (dolphin.isPresent()) { + mgrs.put("dolphin", dolphin.get()); } - + + if (xdgopen.isPresent()) { + mgrs.put("xdgopen", xdgopen.get()); + } + + boolean isKde = System.getenv().containsKey("KDE_SESSION_UID"); + if (isKde && dolphin.isPresent()) { + return dolphin; + } else if (nautilus.isPresent()) { + return nautilus; + } else if (xdgopen.isPresent()) { + return xdgopen; + } + return Optional.empty(); } From 9b76b20d6da3028b5671395aa4bcdf1b77afff31 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Tue, 3 Sep 2024 22:45:27 +0200 Subject: [PATCH 05/29] Just reconfigured EditorPlatform to use xdg-open. --- .../kit/editor/EditorPlatform.java | 31 +++--- .../kit/editor/FileBrowserDetector.java | 96 ------------------- .../kit/editor/FileBrowserDetectorTest.java | 21 ---- 3 files changed, 15 insertions(+), 133 deletions(-) delete mode 100644 kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java delete mode 100644 kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetectorTest.java diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 9bb4ac580..83b01ac27 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -42,6 +42,7 @@ import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import com.gluonhq.charm.glisten.visual.GlistenStyleClasses; import com.oracle.javafx.scenebuilder.kit.i18n.I18N; @@ -58,6 +59,8 @@ */ public class EditorPlatform { + private static final Logger LOGGER = Logger.getLogger(EditorPlatform.class.getName()); + public enum OS { LINUX, MAC, WINDOWS; @@ -69,7 +72,7 @@ public static OS get() { private static final String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); //NOI18N static { - Logger.getLogger(EditorPlatform.class.getName()).log(Level.INFO, "Detected Operating System: {0}", osName); + LOGGER.log(Level.INFO, "Detected Operating System: {0}", osName); } /** @@ -214,7 +217,7 @@ public Color getColor() { } } } catch (IOException e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to get color from stylesheet: ", e); + LOGGER.log(Level.WARNING, "Failed to get color from stylesheet: ", e); } } return color; @@ -335,11 +338,9 @@ public static void open(String path) throws IOException { } } - private static FileBrowserDetector fileBrowserDetector = null; - /** * Requests the underlying platform to "reveal" the specified folder. On - * Linux, it runs 'nautilus'. On Mac, it runs 'open'. On Windows, it runs + * Linux, it runs 'xdg-open'. On Mac, it runs 'open'. On Windows, it runs * 'explorer /select'. * * @param filePath path for the folder to be revealed @@ -357,15 +358,7 @@ public static void revealInFileBrowser(File filePath) throws IOException { args.add("/select," + path); //NOI18N } else if (EditorPlatform.IS_LINUX) { - if (fileBrowserDetector == null) { - fileBrowserDetector = new FileBrowserDetector(); - fileBrowserDetector.detect(); - } - - var fileBrowser = fileBrowserDetector.getLinuxFileBrowser(); - if (fileBrowser.isPresent()) { - args.add(fileBrowser.get()); //NOI18N - } + args.add("xdg-open"); //NOI18N path = filePath.getAbsoluteFile().getParent(); if (path == null) { @@ -374,6 +367,7 @@ public static void revealInFileBrowser(File filePath) throws IOException { args.add(path); } else { // Not Supported + LOGGER.log(Level.SEVERE, "Unsupported operating system! Cannot reveal file in file browser."); } if (!args.isEmpty()) { @@ -417,8 +411,13 @@ private static void executeDaemon(List cmd, File wDir) throws IOExceptio try { ProcessBuilder builder = new ProcessBuilder(cmd); builder = builder.directory(wDir); - builder.start(); + Process proc = builder.start(); + int exitValue = proc.exitValue(); + if (0 != exitValue) { + LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] {cmd.stream().collect(Collectors.joining(" ")), wDir}); + } } catch (RuntimeException ex) { + LOGGER.log(Level.SEVERE, "Exception during attempt to run: {0} in {1}", new Object[] {cmd.stream().collect(Collectors.joining(" ")), wDir}); throw new IOException(ex); } } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java deleted file mode 100644 index 19236816e..000000000 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetector.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.oracle.javafx.scenebuilder.kit.editor; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - - -class FileBrowserDetector { - - private static final Logger LOGGER = Logger.getLogger(FileBrowserDetector.class.getName()); - - private Optional detectedExecutable = null; - - public Optional getLinuxFileBrowser() { - if (this.detectedExecutable == null) { - this.detect(); - } - - return this.detectedExecutable; - } - - public void detect() { - this.detectedExecutable = detectLinuxFileManager(); - } - - Optional detectLinuxFileManager() { - var nautilus = detectApplication("nautilus"); - var dolphin = detectApplication("dolphin"); - var xdgopen = detectApplication("xdg-open"); - - Map mgrs = new HashMap<>(); - if (nautilus.isPresent()) { - mgrs.put("nautilus", nautilus.get()); - } - - if (dolphin.isPresent()) { - mgrs.put("dolphin", dolphin.get()); - } - - if (xdgopen.isPresent()) { - mgrs.put("xdgopen", xdgopen.get()); - } - - boolean isKde = System.getenv().containsKey("KDE_SESSION_UID"); - if (isKde && dolphin.isPresent()) { - return dolphin; - } else if (nautilus.isPresent()) { - return nautilus; - } else if (xdgopen.isPresent()) { - return xdgopen; - } - - return Optional.empty(); - } - - Optional detectApplication(String applicationName) { - var lookupCmd = EditorPlatform.IS_WINDOWS ? "where" : "which"; - List cmd = List.of(lookupCmd, String.valueOf(applicationName).strip()); - return exec(cmd); - } - - private Optional exec(List cmd) { - LOGGER.log(Level.INFO, "Attempting to run: {0}", cmd.stream().collect(Collectors.joining(" "))); - try { - ProcessBuilder builder = new ProcessBuilder(cmd); - Process proc = builder.start(); - proc.waitFor(100, TimeUnit.SECONDS); - - List lines = new ArrayList<>(); - try (BufferedReader rdr = proc.inputReader()) { - String line = null; - while((line=rdr.readLine()) != null) { - lines.add(line); - } - } - if (!lines.isEmpty()) { - return Optional.of(lines.get(0).strip()); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - e.printStackTrace(); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - return Optional.empty(); - } - -} diff --git a/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetectorTest.java b/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetectorTest.java deleted file mode 100644 index 835a0f7db..000000000 --- a/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserDetectorTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.oracle.javafx.scenebuilder.kit.editor; - -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.Optional; - -import org.junit.jupiter.api.Test; - -class FileBrowserDetectorTest { - - @Test - void test() { - - FileBrowserDetector classUnderTest = new FileBrowserDetector(); - - Optional x = classUnderTest.getLinuxFileBrowser(); - - fail("Not yet implemented"); - } - -} From 86a10ab24e4261b10415e21a9192e0ddf9ad0fb7 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Wed, 4 Sep 2024 08:13:10 +0200 Subject: [PATCH 06/29] Restored order of imports. --- .../oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 83b01ac27..9ddae5450 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -32,6 +32,8 @@ */ package com.oracle.javafx.scenebuilder.kit.editor; +import com.gluonhq.charm.glisten.visual.GlistenStyleClasses; + import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -44,9 +46,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; -import com.gluonhq.charm.glisten.visual.GlistenStyleClasses; import com.oracle.javafx.scenebuilder.kit.i18n.I18N; - import javafx.scene.Node; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; From 9e520ca3c1c94181710d89322b8b69279cf2f48a Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Tue, 24 Sep 2024 14:07:23 +0200 Subject: [PATCH 07/29] Reworked reveal-x functionality in app so that there is a unified look and feel in the error messages and so that one can look into the details of the related command line call in case of error. --- .../app/DocumentWindowController.java | 102 ++++++++++++++---- .../scenebuilder/app/ResourceController.java | 10 +- .../app/i18n/SceneBuilderApp.properties | 25 ++++- .../app/i18n/SceneBuilderApp_ja.properties | 2 - .../app/i18n/SceneBuilderApp_zh_CN.properties | 2 - 5 files changed, 106 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java index 89e1c2ef0..997b66e34 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -47,6 +47,7 @@ import com.oracle.javafx.scenebuilder.kit.editor.EditorController.ControlAction; import com.oracle.javafx.scenebuilder.kit.editor.EditorController.EditAction; import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform; +import com.oracle.javafx.scenebuilder.kit.editor.FileBrowserRevealException; import com.oracle.javafx.scenebuilder.kit.editor.job.Job; import com.oracle.javafx.scenebuilder.kit.editor.panel.content.ContentPanelController; import com.oracle.javafx.scenebuilder.kit.editor.panel.css.CssPanelController; @@ -94,6 +95,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; import javafx.beans.InvalidationListener; import javafx.beans.binding.Bindings; @@ -184,6 +187,8 @@ public enum ActionStatus { DONE } + private static final Logger LOGGER = Logger.getLogger(DocumentWindowController.class.getName()); + private final EditorController editorController = new EditorController(); private final MenuBarController menuBarController = new MenuBarController(this); private final ContentPanelController contentPanelController = new ContentPanelController(editorController); @@ -1463,14 +1468,13 @@ void onLibraryImportSelection(ActionEvent event) { @FXML void onLibraryRevealCustomFolder(ActionEvent event) { String userLibraryPath = ((UserLibrary) getEditorController().getLibrary()).getPath(); + + // ensure that there is no mixup of forward and backward slashes. + File libraryPath = Paths.get(userLibraryPath).normalize().toFile(); try { - EditorPlatform.revealInFileBrowser(new File(userLibraryPath)); - } catch(IOException x) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setMessage(I18N.getString("alert.reveal.failure.message", getStage().getTitle())); - errorDialog.setDetails(I18N.getString("alert.reveal.failure.details")); - errorDialog.setDebugInfoWithThrowable(x); - errorDialog.showAndWait(); + EditorPlatform.revealInFileBrowser(libraryPath); + } catch(Exception revealError) { + handleRevealFolderException(revealError, String.valueOf(libraryPath)); } } @@ -2188,19 +2192,26 @@ private void performRevealAction() { final URL location = editorController.getFxomDocument().getLocation(); + File fxmlFile = null; + try { + /* Using Path.normalize().toAbsolutePath() ensures that forward and backward slashes are not mixed and + * the path matches the platform requirements. It also ensures, that the file:/ prefix is removed from + * paths and users can directly use the path in their attempt to investigate the error. + */ + fxmlFile = Path.of(location.toURI()).normalize().toAbsolutePath().toFile(); + } catch (URISyntaxException e) { + handleRevealResourceException(e, String.valueOf(location)); + } + try { - final File fxmlFile = new File(location.toURI()); EditorPlatform.revealInFileBrowser(fxmlFile); - } catch(IOException | URISyntaxException x) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setMessage(I18N.getString("alert.reveal.failure.message", getStage().getTitle())); - errorDialog.setDetails(I18N.getString("alert.reveal.failure.details")); - errorDialog.setDebugInfoWithThrowable(x); - errorDialog.showAndWait(); + } catch(FileBrowserRevealException re) { + handleRevealFileException(re, String.valueOf(fxmlFile)); + } catch(IOException x) { + handleRevealResourceException(x, String.valueOf(fxmlFile)); } } - private void updateLoadFileTime() { final URL fxmlURL = editorController.getFxmlLocation(); @@ -2271,17 +2282,64 @@ private void performHelp() { private void openURL(String url) { try { + LOGGER.log(Level.FINE, "Attempting to open URL: {0}", url); EditorPlatform.open(url); } catch (IOException ioe) { - handleErrorWhenOpeningURL(ioe, url); + LOGGER.log(Level.WARNING, "Error during attempt to open URL!", ioe); + handleRevealResourceException(ioe, url); } } - private void handleErrorWhenOpeningURL(IOException ioe, String url) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setMessage(I18N.getString("alert.help.failure.message", url)); - errorDialog.setDetails(I18N.getString("alert.messagebox.failure.details")); - errorDialog.setDebugInfoWithThrowable(ioe); + /** + * When an FXML file is to be revealed and an error occurs, the file and the error are displayed in this dialog. + * The error type and its details are displayed within the details window. The dialog itself only + * notifies that there was an error. + * + * @param fileRevealException {@link FileBrowserRevealException} + * @param locationToBeRevealed {@link String} + */ + private void handleRevealFileException(FileBrowserRevealException fileRevealException, String locationToBeRevealed) { + final ErrorDialog errorDialog = new ErrorDialog(this.getStage()); + errorDialog.setTitle(I18N.getString("alert.error.file.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", locationToBeRevealed)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.reveal.details.title")); + errorDialog.setDebugInfoWithThrowable(fileRevealException); + errorDialog.showAndWait(); + } + + /** + * + * Resources may be related to files included with Scene Builder or with arbitrary files (e.g. CSS sheets) + * co-located to a given FXML file. In case of an error opening a resource, a custom dialog is shown. + * + * @param revealException {@link Exception} + * @param locationToBeRevealed {@link String} + */ + private void handleRevealResourceException(Exception revealException, String locationToBeRevealed) { + final ErrorDialog errorDialog = new ErrorDialog(this.getStage()); + errorDialog.setTitle(I18N.getString("alert.error.resource.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.resource.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.resource.reveal.details", locationToBeRevealed)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.resource.reveal.details.title")); + errorDialog.setDebugInfoWithThrowable(revealException); + errorDialog.showAndWait(); + } + + /** + * + * In some cases the resource to be revealed or opened is a directory. Hence the UI dialog should reflect this. + * + * @param revealException {@link Exception} + * @param directoryToBeRevealed {@link String} + */ + private void handleRevealFolderException(Exception revealException, String directoryToBeRevealed) { + final ErrorDialog errorDialog = new ErrorDialog(this.getStage()); + errorDialog.setTitle(I18N.getString("alert.error.directory.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.directory.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.directory.reveal.details", directoryToBeRevealed)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.directory.reveal.details.title")); + errorDialog.setDebugInfoWithThrowable(revealException); errorDialog.showAndWait(); } diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/ResourceController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/ResourceController.java index ced064bbc..384f25c9b 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/ResourceController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/ResourceController.java @@ -35,6 +35,7 @@ import com.oracle.javafx.scenebuilder.app.i18n.I18N; import com.oracle.javafx.scenebuilder.kit.editor.EditorController; import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform; +import com.oracle.javafx.scenebuilder.kit.editor.FileBrowserRevealException; import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.ErrorDialog; import javafx.stage.FileChooser; @@ -97,10 +98,11 @@ public void performRevealResource() { try { EditorPlatform.revealInFileBrowser(resourceFile); } catch (IOException ioe) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setTitle(I18N.getString("error.file.reveal.title")); - errorDialog.setMessage(I18N.getString("error.file.reveal.message")); - errorDialog.setDetails(I18N.getString("error.filesystem.details")); + final ErrorDialog errorDialog = new ErrorDialog(documentWindowController.getStage()); + errorDialog.setTitle(I18N.getString("alert.error.file.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", resourceFile)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.reveal.details.title")); errorDialog.setDebugInfoWithThrowable(ioe); errorDialog.showAndWait(); } diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties index f455f81a6..39886dcb6 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties @@ -417,8 +417,6 @@ alert.messagebox.failure.message = Could not process open request alert.messagebox.failure.details = An unexpected failure happened during open operation. Please report this failure to support. alert.revert.question.message = Do you want to revert to the last saved version of ''{0}'' ? alert.revert.question.details = Your current changes will be lost. -alert.reveal.failure.message = Could not reveal ''{0}'' -alert.reveal.failure.details = Reveal operation has failed. Check logs of the operating system. alert.copy.failure.message = Could not copy ''{0}'' alert.help.failure.message = Could not access to ''{0}'' alert.delete.fxid1of1.message = This component has an fx:id. Do you really want to delete it ? @@ -472,9 +470,26 @@ file.filter.label.video = Video Document error.file.open.title = File opening failed # {0} is a file path error.file.open.message = File {0} cannot be opened -error.filesystem.details = Please check your file system. -error.file.reveal.title = File locating failed -error.file.reveal.message = File {0} cannot be found +error.filesystem.details = File: {0} + +# File Reveal Error Dialog +alert.error.file.reveal.title = Failed to reveal file ... +alert.error.file.reveal.message = Cannot reveal file in file system viewer due to an error. +alert.error.file.reveal.details = ''{0}'' +alert.error.file.reveal.details.title = File Reveal Error Details + +# Directory Reveal Error Dialog +alert.error.directory.reveal.title = Failed to reveal folder ... +alert.error.directory.reveal.message = Cannot reveal folder in file system viewer due to an error. +alert.error.directory.reveal.details = ''{0}'' +alert.error.directory.reveal.details.title = Folder Reveal Error Details + +# Resource Reveal Error Dialog +alert.error.resource.reveal.title = Failed to reveal resource ... +alert.error.resource.reveal.message = Cannot reveal resource in file system viewer due to an error. +alert.error.resource.reveal.details = ''{0}'' +alert.error.resource.reveal.details.title = Resource Reveal Error Details + # log.start = JavaFX Scene Builder started log.stop = JavaFX Scene Builder stopped diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties index 131863bdc..38b7f4f21 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties @@ -410,8 +410,6 @@ alert.messagebox.failure.message = 開く操作を処理できませんでした alert.messagebox.failure.details = 開く操作中に予期しない問題が起きました。この問題をサポートに報告してください。 alert.revert.question.message = 最後に保存した''{0}''に戻しますか。 alert.revert.question.details = 現在の変更は失われます。 -alert.reveal.failure.message = ''{0}''を表示できませんでした -alert.reveal.failure.details = 元に戻すのに失敗しました。オペレーティング・システムのログを確認してください。 alert.copy.failure.message = コピー alert.help.failure.message = ''{0}''にアクセスできませんでした alert.delete.fxid1of1.message = このコンポーネントにはfx:idがあります。このコンポーネントを削除しますか。 diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_zh_CN.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_zh_CN.properties index 0764eba7b..2fd97b692 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_zh_CN.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_zh_CN.properties @@ -416,8 +416,6 @@ alert.messagebox.failure.message = 无法处理打开的请求 alert.messagebox.failure.details = 打开操作期间发生意外故障。请向支持部门报告此故障。 alert.revert.question.message = 是否要恢复到上次保存的 ''{0}'' 版本? alert.revert.question.details = 您当前的更改将丢失。 -alert.reveal.failure.message = 无法显示 ''{0}'' -alert.reveal.failure.details = 显示操作失败。检查操作系统的日志。 alert.copy.failure.message = 无法复制 ''{0}'' alert.help.failure.message = 无法访问 ''{0}'' alert.delete.fxid1of1.message = 此组件具有 fx:id,你真的要删除它吗? From 13e7ce499c0d92127ab562262a29411c4273be8c Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Tue, 24 Sep 2024 14:10:15 +0200 Subject: [PATCH 08/29] Reworked the way files are revealed in explorer or other file system viewers. Its now possible to react on the specific return code of the called application. --- .../kit/editor/EditorPlatform.java | 79 +++++++++++++------ .../editor/FileBrowserRevealException.java | 44 +++++++++++ .../kit/i18n/SceneBuilderKit.properties | 8 +- .../kit/i18n/SceneBuilderKit_ja.properties | 2 - .../kit/i18n/SceneBuilderKit_zh_CN.properties | 4 +- 5 files changed, 107 insertions(+), 30 deletions(-) create mode 100644 kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserRevealException.java diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 9ddae5450..8a62c4c48 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -38,14 +38,19 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Paths; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; +import com.oracle.javafx.scenebuilder.kit.editor.panel.css.SelectionPath.Path; import com.oracle.javafx.scenebuilder.kit.i18n.I18N; import javafx.scene.Node; import javafx.scene.input.MouseEvent; @@ -310,8 +315,9 @@ public static boolean isGluonMobileDark(Theme theme) { * * @param path path for the file to be opened * @throws IOException if an error occurs + * @throws FileBrowserRevealException */ - public static void open(String path) throws IOException { + public static void open(String path) throws IOException, FileBrowserRevealException { List args = new ArrayList<>(); if (EditorPlatform.IS_MAC) { args.add("open"); //NOI18N @@ -334,21 +340,22 @@ public static void open(String path) throws IOException { } if (!args.isEmpty()) { - executeDaemon(args, null); + executeDaemon(args, null, 0); } } /** - * Requests the underlying platform to "reveal" the specified folder. On - * Linux, it runs 'xdg-open'. On Mac, it runs 'open'. On Windows, it runs - * 'explorer /select'. + * Requests the underlying platform to open the specified folder in its default file system viewer. This will reveal any file therein. + * On Linux, it runs {@code 'xdg-open'}. On Mac, it runs {@code 'open'} and on Windows it runs {@code 'explorer /select'}. * * @param filePath path for the folder to be revealed - * @throws IOException if an error occurs + * @throws FileBrowserRevealException This exception allows to catch exits codes != 0 from the called process. + * @throws IOException General IOExceptions are thrown by Java System Call Processes in case of an error. */ - public static void revealInFileBrowser(File filePath) throws IOException { + public static void revealInFileBrowser(File filePath) throws IOException, FileBrowserRevealException { List args = new ArrayList<>(); - String path = filePath.toURI().toURL().toExternalForm(); + String path = Paths.get(filePath.toURI()).normalize().toAbsolutePath().toString(); + int exitCodeOk = 0; if (EditorPlatform.IS_MAC) { args.add("open"); //NOI18N args.add("-R"); //NOI18N @@ -356,10 +363,9 @@ public static void revealInFileBrowser(File filePath) throws IOException { } else if (EditorPlatform.IS_WINDOWS) { args.add("explorer"); //NOI18N args.add("/select," + path); //NOI18N - } else if (EditorPlatform.IS_LINUX) { - + exitCodeOk = 1; + } else if (EditorPlatform.IS_LINUX) { args.add("xdg-open"); //NOI18N - path = filePath.getAbsoluteFile().getParent(); if (path == null) { path = "."; //NOI18N @@ -367,11 +373,11 @@ public static void revealInFileBrowser(File filePath) throws IOException { args.add(path); } else { // Not Supported - LOGGER.log(Level.SEVERE, "Unsupported operating system! Cannot reveal file in file browser."); + LOGGER.log(Level.SEVERE, "Unsupported operating system! Cannot reveal location {0} in file browser.", path); } if (!args.isEmpty()) { - executeDaemon(args, null); + executeDaemon(args, null, exitCodeOk); } } @@ -404,22 +410,47 @@ public static boolean isAssertionEnabled() { return EditorPlatform.class.desiredAssertionStatus(); } - /* - * Private + /** + * Executes a system process using the given cmd list as command line definition within the provided + * working directory. + * + * @param cmd Command line definition as {@link List} of {@link String} + * @param wDir Working Directory as {@link File} + * @param exitCodeOk Certain applications (e.g. Windows Explorer) do report exit code 1 in case + * everything is okay. Hence one can configure the expected exit code here. + * @throws IOException Any given runtime exception is collected and re-thrown as + * IOException. + * + * @throws FileBrowserRevealException This exception is only thrown if the exit code of the command + * line call is not 0. This allows to specifically react e.g. to + * invalid command line calls or to unsuccessful calls. Not every + * cmd call which ends with an error code != 0 is creating an + * exception. */ - private static void executeDaemon(List cmd, File wDir) throws IOException { + private static void executeDaemon(List cmd, File wDir, int exitCodeOk) throws IOException, FileBrowserRevealException { + var cmdLine = cmd.stream().collect(Collectors.joining(" ")); + long timeoutSec = 5; try { - ProcessBuilder builder = new ProcessBuilder(cmd); - builder = builder.directory(wDir); - Process proc = builder.start(); - int exitValue = proc.exitValue(); - if (0 != exitValue) { - LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] {cmd.stream().collect(Collectors.joining(" ")), wDir}); + int exitValue = new Cmd().exec(cmd, wDir, timeoutSec); + if (exitCodeOk != exitValue) { + LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); + throw new FileBrowserRevealException( + "The command to reval the file exited with an error (exitValue=%s).\nCommand: %s\nWorking Dir: %s" + .formatted(Integer.toString(exitValue), cmdLine, wDir)); + } else { + LOGGER.log(Level.INFO, "Successfully executed command: {0} in {1}", new Object[] {cmdLine, wDir}); } } catch (RuntimeException ex) { - LOGGER.log(Level.SEVERE, "Exception during attempt to run: {0} in {1}", new Object[] {cmd.stream().collect(Collectors.joining(" ")), wDir}); + LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); throw new IOException(ex); + } catch (InterruptedException e) { + LOGGER.log(Level.SEVERE, "Process timeout after {0}s: {1} in {2}", new Object[] {timeoutSec, cmdLine, wDir}); + Thread.currentThread().interrupt(); + String msg = "The command to reval the file exited with an error after timeout.\nCommand: %s\nWorking Dir: %s\nTimeout (s):%s" + .formatted(cmdLine, wDir, timeoutSec); + String detailMsg = msg+"\n"+e.getMessage(); + + throw new IOException(detailMsg); } } - } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserRevealException.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserRevealException.java new file mode 100644 index 000000000..a4a3e78ab --- /dev/null +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserRevealException.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.javafx.scenebuilder.kit.editor; + +import java.io.IOException; + +public class FileBrowserRevealException extends IOException { + + private static final long serialVersionUID = -1682452255824949867L; + + public FileBrowserRevealException(String message) { + super(message); + } + +} diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties index decb59e0e..9230ed1ee 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties @@ -432,8 +432,12 @@ error.file.create.message = File {0} cannot be created error.file.open.message = File {0} cannot be opened error.file.open.title = File opening failed error.write.details = Please check your file system. -error.file.reveal.title = File locating failed -error.file.reveal.message = File {0} cannot be found + +# Alert Dialog in case of revealing a file +alert.error.file.reveal.title = Failed to reveal file ... +alert.error.file.reveal.message = Cannot reveal file in file system viewer due to an error. +alert.error.file.reveal.details.title = File Reveal Error Details +alert.error.file.reveal.details = {0} #maven log.user.maven.installed = {0} installed in local repository diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_ja.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_ja.properties index 3b62233f7..e6c5eba6a 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_ja.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_ja.properties @@ -406,8 +406,6 @@ error.file.create.message = ファイル{0}を作成できません error.file.open.message = ファイル{0}を開けません error.file.open.title = ファイルを開くのに失敗しました error.write.details = ファイル・システムを確認してください。 -error.file.reveal.title = ファイルを見つけるのに失敗しました -error.file.reveal.message = ファイル{0}が見つかりません #maven log.user.maven.installed = {0}はローカル・レポジトリにインストールされています diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties index 65e3ae0e2..8346f2abe 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties @@ -432,8 +432,8 @@ error.file.create.message = 无法创建文件 {0} error.file.open.message = 无法打开文件 {0} error.file.open.title = 文件打开失败 error.write.details = 请检查您的文件系统。 -error.file.reveal.title = 文件定位失败 -error.file.reveal.message = 未找到 {0} 文件 + + #maven log.user.maven.installed = {0} 安装在本地存储库中 From 15ea41ba3341b57819cdedb9d47fe0d08606c54d Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Tue, 24 Sep 2024 14:36:13 +0200 Subject: [PATCH 09/29] Added updated messages and error handling for remaining calls to EditorPlatform.open(..). --- .../app/SceneStyleSheetMenuController.java | 6 ++- .../app/i18n/SceneBuilderApp.properties | 1 + .../app/i18n/SceneBuilderApp_ja.properties | 2 +- .../javafx/scenebuilder/kit/editor/Cmd.java | 50 +++++++++++++++++++ .../kit/editor/EditorController.java | 27 +++++----- .../kit/editor/EditorPlatform.java | 4 +- .../kit/i18n/SceneBuilderKit.properties | 7 ++- 7 files changed, 78 insertions(+), 19 deletions(-) create mode 100644 kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneStyleSheetMenuController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneStyleSheetMenuController.java index e8c977fc6..d8dce99a9 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneStyleSheetMenuController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneStyleSheetMenuController.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -102,10 +103,11 @@ public void performOpenSceneStyleSheet(File toOpen) { try { EditorPlatform.open(toOpen.getPath()); } catch (IOException ioe) { - final ErrorDialog errorDialog = new ErrorDialog(null); + final ErrorDialog errorDialog = new ErrorDialog(documentWindowController.getStage()); errorDialog.setTitle(I18N.getString("error.file.open.title")); - errorDialog.setMessage(I18N.getString("error.file.open.message")); + errorDialog.setMessage(I18N.getString("error.file.open.message", toOpen)); errorDialog.setDetails(I18N.getString("error.filesystem.details")); + errorDialog.setDetailsTitle(I18N.getString("error.file.open.title")); errorDialog.setDebugInfoWithThrowable(ioe); errorDialog.showAndWait(); } diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties index 39886dcb6..b3f4b97ac 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties @@ -468,6 +468,7 @@ file.filter.label.image = Image Document file.filter.label.media = Media Document file.filter.label.video = Video Document error.file.open.title = File opening failed +error.file.open.details.title = File opening failed - Details # {0} is a file path error.file.open.message = File {0} cannot be opened error.filesystem.details = File: {0} diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties index 38b7f4f21..9766f7fe8 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties @@ -455,7 +455,7 @@ file.filter.label.fxml = FXMLドキュメント file.filter.label.image = イメージ・ドキュメント file.filter.label.media = メディア・ドキュメント file.filter.label.video = ビデオ・ドキュメント -error.file.open.title = ファイルを開くのに失敗しました + # {0} is a file path error.file.open.message = ファイル{0}を開けません error.filesystem.details = ファイル・システムを確認してください。 diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java new file mode 100644 index 000000000..9d3802bc4 --- /dev/null +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.javafx.scenebuilder.kit.editor; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public final class Cmd { + + public final Integer exec(List cmd, File wDir, long timeoutSec) throws IOException, InterruptedException { + ProcessBuilder builder = new ProcessBuilder(cmd); + builder = builder.directory(wDir); + Process proc = builder.start(); + proc.waitFor(timeoutSec, TimeUnit.SECONDS); + int exitValue = proc.exitValue(); + return exitValue; + } + +} diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java index 41073419a..5bb242c31 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -2331,14 +2331,15 @@ private void performEditIncludedFile() { assert includedFile != null; // Because of (1) try { EditorPlatform.open(includedFile.getAbsolutePath()); - } catch (IOException ioe) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setTitle(I18N.getString("error.file.open.title")); - errorDialog.setMessage(I18N.getString("error.file.open.message", - includedFile.getAbsolutePath())); - errorDialog.setDebugInfoWithThrowable(ioe); + } catch (IOException re) { + final ErrorDialog errorDialog = new ErrorDialog(this.ownerWindow); + errorDialog.setTitle(I18N.getString("alert.error.file.open.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.open.edit.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", includedFile.getAbsolutePath())); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.open.edit.details.title")); + errorDialog.setDebugInfoWithThrowable(re); errorDialog.showAndWait(); - } + } } private void performRevealIncludedFile() { @@ -2348,11 +2349,11 @@ private void performRevealIncludedFile() { try { EditorPlatform.revealInFileBrowser(includedFile); } catch (IOException ioe) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setTitle(I18N.getString("error.file.reveal.title")); - errorDialog.setMessage(I18N.getString("error.file.reveal.message", - includedFile.getAbsolutePath())); - errorDialog.setDetails(I18N.getString("error.write.details")); + final ErrorDialog errorDialog = new ErrorDialog(this.ownerWindow); + errorDialog.setTitle(I18N.getString("alert.error.file.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", includedFile.getAbsolutePath())); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.reveal.details.title")); errorDialog.setDebugInfoWithThrowable(ioe); errorDialog.showAndWait(); } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 8a62c4c48..a424052ad 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -314,8 +314,8 @@ public static boolean isGluonMobileDark(Theme theme) { * 'xdg-open'. On Mac, it runs 'open'. On Windows, it runs 'cmd /c start'. * * @param path path for the file to be opened - * @throws IOException if an error occurs - * @throws FileBrowserRevealException + * @throws IOException in case the application called failed to open due to an error. + * @throws FileBrowserRevealException in case the application opened indicates an error (unexpected return code). */ public static void open(String path) throws IOException, FileBrowserRevealException { List args = new ArrayList<>(); diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties index 9230ed1ee..01eedfca8 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties @@ -430,9 +430,14 @@ error.file.create.title = File creation failed # {0} is a file path error.file.create.message = File {0} cannot be created error.file.open.message = File {0} cannot be opened -error.file.open.title = File opening failed error.write.details = Please check your file system. +# Alert file open error +alert.error.file.open.title = File opening failed +alert.error.file.open.edit.message = Cannot open file for editing! +alert.error.file.open.edit.details = ''{0}'' +alert.error.file.open.edit.details.title = Details - File opening failed + # Alert Dialog in case of revealing a file alert.error.file.reveal.title = Failed to reveal file ... alert.error.file.reveal.message = Cannot reveal file in file system viewer due to an error. From c48b68204f0a80d9be02e495293cb0db460ca6de Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Tue, 24 Sep 2024 14:41:15 +0200 Subject: [PATCH 10/29] Added proper error dialog for CSS Panel Controller in case revealing a CSS fails. --- .../kit/editor/panel/css/CssPanelController.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java index 301bb095e..03deda8b2 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java @@ -46,6 +46,7 @@ import com.oracle.javafx.scenebuilder.kit.editor.panel.css.NodeCssState.CssProperty; import com.oracle.javafx.scenebuilder.kit.editor.panel.css.SelectionPath.Item; import com.oracle.javafx.scenebuilder.kit.editor.panel.util.AbstractFxmlPanelController; +import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.ErrorDialog; import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject; import com.oracle.javafx.scenebuilder.kit.editor.panel.css.SelectionPath.Path; @@ -107,6 +108,8 @@ * */ public class CssPanelController extends AbstractFxmlPanelController { + + private static final Logger LOGGER = Logger.getLogger(CssPanelController.class.getName()); @FXML private StackPane cssPanelHost; @@ -1445,7 +1448,14 @@ private void navigate(CssProperty item, PropertyState state, CssStyle style, Sty EditorPlatform.revealInFileBrowser(f); } } catch (URISyntaxException | IOException ex) { - System.out.println(ex.getMessage() + ": " + ex); + LOGGER.log(Level.SEVERE, "An unexpected error occured!", ex); + final ErrorDialog errorDialog = new ErrorDialog(editorController.getOwnerWindow()); + errorDialog.setTitle(I18N.getString("alert.error.file.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", path)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.reveal.details.title")); + errorDialog.setDebugInfoWithThrowable(ex); + errorDialog.showAndWait(); } } } else { From 0aa9317c72f7d255b5c8e270533364164abad940 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Tue, 24 Sep 2024 14:49:05 +0200 Subject: [PATCH 11/29] Removed empty lines. --- .../scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties index 8346f2abe..3e6b52b2a 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties @@ -433,8 +433,6 @@ error.file.open.message = 无法打开文件 {0} error.file.open.title = 文件打开失败 error.write.details = 请检查您的文件系统。 - - #maven log.user.maven.installed = {0} 安装在本地存储库中 log.user.maven.failed = {0} 安装失败 From f6c889b881e2046cdc35b9821f8013b71932963b Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Tue, 24 Sep 2024 14:53:06 +0200 Subject: [PATCH 12/29] Checkstyle fix. --- .../app/DocumentWindowController.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java index 997b66e34..3a802935d 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java @@ -1473,7 +1473,7 @@ void onLibraryRevealCustomFolder(ActionEvent event) { File libraryPath = Paths.get(userLibraryPath).normalize().toFile(); try { EditorPlatform.revealInFileBrowser(libraryPath); - } catch(Exception revealError) { + } catch (Exception revealError) { handleRevealFolderException(revealError, String.valueOf(libraryPath)); } } @@ -2185,29 +2185,29 @@ ActionStatus performCloseAction() { return closeConfirmed ? ActionStatus.DONE : ActionStatus.CANCELLED; } - private void performRevealAction() { assert editorController.getFxomDocument() != null; assert editorController.getFxomDocument().getLocation() != null; - + final URL location = editorController.getFxomDocument().getLocation(); - + File fxmlFile = null; try { - /* Using Path.normalize().toAbsolutePath() ensures that forward and backward slashes are not mixed and - * the path matches the platform requirements. It also ensures, that the file:/ prefix is removed from - * paths and users can directly use the path in their attempt to investigate the error. + /* + * Using Path.normalize().toAbsolutePath() ensures that forward and backward slashes are not mixed + * and the path matches the platform requirements. It also ensures, that the file:/ prefix is + * removed from paths and users can directly use the path in their attempt to investigate the error. */ fxmlFile = Path.of(location.toURI()).normalize().toAbsolutePath().toFile(); } catch (URISyntaxException e) { handleRevealResourceException(e, String.valueOf(location)); } - + try { EditorPlatform.revealInFileBrowser(fxmlFile); - } catch(FileBrowserRevealException re) { + } catch (FileBrowserRevealException re) { handleRevealFileException(re, String.valueOf(fxmlFile)); - } catch(IOException x) { + } catch (IOException x) { handleRevealResourceException(x, String.valueOf(fxmlFile)); } } From f57c761f62895228cdf6e56fcf385494bd682ad0 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 11:55:50 +0200 Subject: [PATCH 13/29] Removed accidently added illegal characters in properties file. --- .../javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties index 9766f7fe8..4a6650813 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties @@ -455,7 +455,7 @@ file.filter.label.fxml = FXMLドキュメント file.filter.label.image = イメージ・ドキュメント file.filter.label.media = メディア・ドキュメント file.filter.label.video = ビデオ・ドキュメント - + # {0} is a file path error.file.open.message = ファイル{0}を開けません error.filesystem.details = ファイル・システムを確認してください。 From 9dcb7f932d89da43f590fa822f1dfedf1635c771 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 11:58:38 +0200 Subject: [PATCH 14/29] Removed accidently pasted text from license header. --- .../javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties index 01eedfca8..55de7bffa 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties @@ -20,7 +20,7 @@ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NOlabel.action.edit.paste EVENT SHALL THE COPYRIGHT +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, From 3ec5ac3df4cb75229dc4c3a41ed9e84014f6cd30 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 13:15:38 +0200 Subject: [PATCH 15/29] Added basic test for external command execution. --- .../javafx/scenebuilder/kit/editor/Cmd.java | 36 ++++-- .../scenebuilder/kit/editor/CmdTest.java | 109 ++++++++++++++++++ .../scenebuilder/kit/editor/exit-error.cmd | 2 + .../scenebuilder/kit/editor/exit-error.sh | 2 + .../scenebuilder/kit/editor/timeout.cmd | 3 + .../javafx/scenebuilder/kit/editor/timeout.sh | 3 + 6 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/CmdTest.java create mode 100644 kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.cmd create mode 100644 kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.sh create mode 100644 kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd create mode 100644 kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java index 9d3802bc4..2712a60b2 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java @@ -36,15 +36,33 @@ import java.util.List; import java.util.concurrent.TimeUnit; -public final class Cmd { - - public final Integer exec(List cmd, File wDir, long timeoutSec) throws IOException, InterruptedException { - ProcessBuilder builder = new ProcessBuilder(cmd); - builder = builder.directory(wDir); - Process proc = builder.start(); - proc.waitFor(timeoutSec, TimeUnit.SECONDS); - int exitValue = proc.exitValue(); - return exitValue; +/** + * Cmd allows the execution of a given command line in a defined working directory. The execution is + * aborted after the timeout. + */ +final class Cmd { + + /** + * Executes a given command line using the working directory and timeout. + * + * @param cmd The command line to be executed defined as a {@link List} of {@link String} + * @param wDir The working directory, where the process shall be executed within. + * @param timeoutSec Duration in in seconds after which the execution should be stopped. + * @return exit code of the command line as an Integer + * + * @throws IOException - if the command was not found or the program execution exceeds the given timeout duration. + * @throws InterruptedException - if the current thread is interrupted while waiting + */ + public final Integer exec(List cmd, File wDir, long timeoutSec) throws IOException, + InterruptedException { + ProcessBuilder builder = new ProcessBuilder(cmd); + builder = builder.directory(wDir); + Process proc = builder.start(); + boolean completed = proc.waitFor(timeoutSec, TimeUnit.SECONDS); + if (completed) { + return proc.exitValue(); + } + throw new IOException("Process timed out after %s seconds!".formatted(timeoutSec)); } } diff --git a/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/CmdTest.java b/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/CmdTest.java new file mode 100644 index 000000000..32f25cadb --- /dev/null +++ b/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/CmdTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.javafx.scenebuilder.kit.editor; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; + +public class CmdTest { + + private Cmd classUnderTest = new Cmd(); + + private final long timeoutSeconds = 2L; + + private Path workingDir = Path.of("./src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/") + .normalize() + .toAbsolutePath(); + + @Test + void that_exception_is_created_with_not_existing_command() { + var cmdLine = List.of("this", "command", "should", "not", "exist"); + + Throwable t = assertThrows(IOException.class, + () -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertTrue(t.getMessage().startsWith("Cannot run program \"this\"")); + } + + @EnabledOnOs(value = {OS.WINDOWS}) + @Test + void that_exit_code_from_program_is_collected_on_Windows() { + var cmdLine = List.of(workingDir.resolve("exit-error.cmd").toString()); + + Integer result = assertDoesNotThrow(() -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertEquals(1, result, "Exit code must be 1"); + } + + @EnabledOnOs(value = {OS.LINUX, OS.MAC}) + @Test + void that_exit_code_is_collected_on_Linux_and_Mac() { + var cmdLine = List.of("/bin/sh", workingDir.resolve("exit-error.sh").toString()); + + Integer result = assertDoesNotThrow(() -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertEquals(1, result, "Exit code must be 1"); + } + + @EnabledOnOs(value = {OS.WINDOWS}) + @Test + void that_process_does_not_run_indefinitevely_on_Windows() { + var cmdLine = List.of(workingDir.resolve("timeout.cmd").toString()); + + Throwable t = assertThrows(IOException.class, + () -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertEquals(t.getMessage(), "Process timed out after 2 seconds!"); + } + + @EnabledOnOs(value = {OS.LINUX, OS.MAC}) + @Test + void that_process_does_not_run_indefinitevely_on_Linux_and_Mac() { + var cmdLine = List.of("/bin/sh", workingDir.resolve("timeout.sh").toString()); + + Throwable t = assertThrows(IOException.class, + () -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertEquals(t.getMessage(), "Process timed out after 2 seconds!"); + } + +} diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.cmd b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.cmd new file mode 100644 index 000000000..9e24ca57f --- /dev/null +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.cmd @@ -0,0 +1,2 @@ +ECHO Programm Error! +EXIT 1 diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.sh b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.sh new file mode 100644 index 000000000..23817e8c9 --- /dev/null +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.sh @@ -0,0 +1,2 @@ +echo Program exited with error. +exit 1 diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd new file mode 100644 index 000000000..a65f4131f --- /dev/null +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd @@ -0,0 +1,3 @@ +ECHO Waiting for 20sec +TIMEOUT /T 5 +EXIT 0 diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh new file mode 100644 index 000000000..da47afb4d --- /dev/null +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh @@ -0,0 +1,3 @@ +echo Waiting for 20sec +sleep 5 +exit 0 From bb1bfd05398bdec8b8603d33fdcd08e7d33c3709 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 13:27:25 +0200 Subject: [PATCH 16/29] Added requirement of xdg-utils for Linux to README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b5ac57c91..634b7b4fb 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ See the [documentation](http://docs.gluonhq.com/scenebuilder/) about the new fea For community support, go to [StackOverflow](https://stackoverflow.com/questions/tagged/scenebuilder). +### Requirements on Linux ### + +On Linux systems, Scene Builder uses the `xdg-open` to reveal files in the systems default file system browser or to open URLs in the default web browser. Most modern Linux Desktop Environments already provide the [xdg-utils](https://freedesktop.org/wiki/Software/xdg-utils/) package. If it is missing, it can be installed using the respective Linux package management tool such as `yum`, `apt-get`, `dnf` or `pacman`. The `xdg-utils` package is usually available on KDE based systems, some Arch based systems may require manual installations. + ## Issues and Contributions ## Issues can be reported to the [Issue tracker](https://github.com/gluonhq/scenebuilder/issues/) From db5ad5d52cabcbf0a6ba6eea86a5d97ce35a84ce Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 18:10:44 +0200 Subject: [PATCH 17/29] Shell scripts for test now properly state 5sec wait time. --- .../com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd | 2 +- .../com/oracle/javafx/scenebuilder/kit/editor/timeout.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd index a65f4131f..4f03ca5ca 100644 --- a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd @@ -1,3 +1,3 @@ -ECHO Waiting for 20sec +ECHO Waiting for 5sec TIMEOUT /T 5 EXIT 0 diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh index da47afb4d..9b5b3b78e 100644 --- a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh @@ -1,3 +1,3 @@ -echo Waiting for 20sec +echo Waiting for 5sec sleep 5 exit 0 From 281ec055257144af3fc4a6e233e07d6191b6ecb5 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 18:15:47 +0200 Subject: [PATCH 18/29] Lowered log level as proposed in PR. --- .../oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index e4f631834..d47ab7f3f 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -77,7 +77,7 @@ public static OS get() { private static final String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); //NOI18N static { - LOGGER.log(Level.INFO, "Detected Operating System: {0}", osName); + LOGGER.log(Level.FINE, "Detected Operating System: {0}", osName); } /** From 8773fae5c667b7c296df0002d0fce35e4a021c26 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 18:16:02 +0200 Subject: [PATCH 19/29] Removed whitespace. --- .../oracle/javafx/scenebuilder/kit/editor/EditorController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java index 5bb242c31..0bb065252 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java @@ -2339,7 +2339,7 @@ private void performEditIncludedFile() { errorDialog.setDetailsTitle(I18N.getString("alert.error.file.open.edit.details.title")); errorDialog.setDebugInfoWithThrowable(re); errorDialog.showAndWait(); - } + } } private void performRevealIncludedFile() { From 745a5583b01702fea61d5f1657deb75a0600093d Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 18:21:55 +0200 Subject: [PATCH 20/29] Removed whitespace --- .../javafx/scenebuilder/app/DocumentWindowController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java index 50e3974ef..ee7cc9fbc 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java @@ -2329,7 +2329,7 @@ private void handleRevealResourceException(Exception revealException, String loc errorDialog.setDebugInfoWithThrowable(revealException); errorDialog.showAndWait(); } - + /** * * In some cases the resource to be revealed or opened is a directory. Hence the UI dialog should reflect this. From 8b334bdc11bb899bf195e557b2f82a98ac10df75 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 18:23:07 +0200 Subject: [PATCH 21/29] Removed whitespace --- .../javafx/scenebuilder/app/DocumentWindowController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java index ee7cc9fbc..8fcb64064 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java @@ -2311,7 +2311,7 @@ private void handleRevealFileException(FileBrowserRevealException fileRevealExce errorDialog.setDebugInfoWithThrowable(fileRevealException); errorDialog.showAndWait(); } - + /** * * Resources may be related to files included with Scene Builder or with arbitrary files (e.g. CSS sheets) From 0693f81f2fcb2dba4a7b72519c3c516de16a41b5 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 18:49:36 +0200 Subject: [PATCH 22/29] Corrected README.md according to PR feedback. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 634b7b4fb..a8d7b77c9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For community support, go to [StackOverflow](https://stackoverflow.com/questions ### Requirements on Linux ### -On Linux systems, Scene Builder uses the `xdg-open` to reveal files in the systems default file system browser or to open URLs in the default web browser. Most modern Linux Desktop Environments already provide the [xdg-utils](https://freedesktop.org/wiki/Software/xdg-utils/) package. If it is missing, it can be installed using the respective Linux package management tool such as `yum`, `apt-get`, `dnf` or `pacman`. The `xdg-utils` package is usually available on KDE based systems, some Arch based systems may require manual installations. +On Linux systems, Scene Builder uses the `xdg-open` to command to reveal files in the system's default file system browser or to open URLs in the default web browser. Most modern Linux Desktop Environments already provide the [xdg-utils](https://freedesktop.org/wiki/Software/xdg-utils/) package. If it is missing, it can be installed using the respective Linux package management tool such as `yum`, `apt-get`, `dnf` or `pacman`. The `xdg-utils` package is usually available on KDE based systems, some Arch based systems may require manual installations. ## Issues and Contributions ## From 9a79e774493244eec9f34087f66cd653df5fc7db Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Sun, 29 Sep 2024 19:03:04 +0200 Subject: [PATCH 23/29] ExecuteDaemon is now wrapped in a Task, so that it cannot block UI anymore. Error handling is not implemented yet. --- .../kit/editor/EditorPlatform.java | 72 ++++++++++++------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index d47ab7f3f..8fcf116bb 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -52,6 +52,8 @@ import com.oracle.javafx.scenebuilder.kit.editor.panel.css.SelectionPath.Path; import com.oracle.javafx.scenebuilder.kit.i18n.I18N; + +import javafx.concurrent.Task; import javafx.scene.Node; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; @@ -381,7 +383,7 @@ public static void revealInFileBrowser(File filePath) throws IOException, FileBr } if (!args.isEmpty()) { - executeDaemon(args, null, exitCodeOk); + executeDaemon(args, null, exitCodeOk); } } @@ -413,7 +415,7 @@ public static boolean isNonContinousSelectKeyDown(MouseEvent e) { public static boolean isAssertionEnabled() { return EditorPlatform.class.desiredAssertionStatus(); } - + /** * Executes a system process using the given cmd list as command line definition within the provided * working directory. @@ -432,29 +434,47 @@ public static boolean isAssertionEnabled() { * exception. */ private static void executeDaemon(List cmd, File wDir, int exitCodeOk) throws IOException, FileBrowserRevealException { - var cmdLine = cmd.stream().collect(Collectors.joining(" ")); - long timeoutSec = 5; - try { - int exitValue = new Cmd().exec(cmd, wDir, timeoutSec); - if (exitCodeOk != exitValue) { - LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); - throw new FileBrowserRevealException( - "The command to reval the file exited with an error (exitValue=%s).\nCommand: %s\nWorking Dir: %s" - .formatted(Integer.toString(exitValue), cmdLine, wDir)); - } else { - LOGGER.log(Level.INFO, "Successfully executed command: {0} in {1}", new Object[] {cmdLine, wDir}); - } - } catch (RuntimeException ex) { - LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); - throw new IOException(ex); - } catch (InterruptedException e) { - LOGGER.log(Level.SEVERE, "Process timeout after {0}s: {1} in {2}", new Object[] {timeoutSec, cmdLine, wDir}); - Thread.currentThread().interrupt(); - String msg = "The command to reval the file exited with an error after timeout.\nCommand: %s\nWorking Dir: %s\nTimeout (s):%s" - .formatted(cmdLine, wDir, timeoutSec); - String detailMsg = msg+"\n"+e.getMessage(); - - throw new IOException(detailMsg); - } + Task cmdTask = new Task() { + @Override + protected Void call() throws Exception { + var cmdLine = cmd.stream().collect(Collectors.joining(" ")); + long timeoutSec = 5; + try { + int exitValue = new Cmd().exec(cmd, wDir, timeoutSec); + if (exitCodeOk != exitValue) { + LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); + throw new FileBrowserRevealException( + "The command to reval the file exited with an error (exitValue=%s).\nCommand: %s\nWorking Dir: %s" + .formatted(Integer.toString(exitValue), cmdLine, wDir)); + } else { + LOGGER.log(Level.INFO, "Successfully executed command: {0} in {1}", new Object[] {cmdLine, wDir}); + } + } catch (RuntimeException ex) { + LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); + throw new IOException(ex); + } catch (InterruptedException e) { + LOGGER.log(Level.SEVERE, "Process timeout after {0}s: {1} in {2}", new Object[] {timeoutSec, cmdLine, wDir}); + Thread.currentThread().interrupt(); + String msg = "The command to reval the file exited with an error after timeout.\nCommand: %s\nWorking Dir: %s\nTimeout (s):%s" + .formatted(cmdLine, wDir, timeoutSec); + String detailMsg = msg+"\n"+e.getMessage(); + + throw new IOException(detailMsg); + } + return null; + } + + @Override + protected void failed() { + + /* + * TODO: + * There is no error handling yet - at least if an exception is thrown, that must be handled. + */ + + } + }; + + new Thread(cmdTask, "executeDaemon-task").start(); } } From 007795dbd8b48f1c1fc4f4eb372a454e0bafddba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20L=C3=B6ffler?= <22102800+Oliver-Loeffler@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:03:59 +0200 Subject: [PATCH 24/29] Update README.md Corrected typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8d7b77c9..d59c37696 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For community support, go to [StackOverflow](https://stackoverflow.com/questions ### Requirements on Linux ### -On Linux systems, Scene Builder uses the `xdg-open` to command to reveal files in the system's default file system browser or to open URLs in the default web browser. Most modern Linux Desktop Environments already provide the [xdg-utils](https://freedesktop.org/wiki/Software/xdg-utils/) package. If it is missing, it can be installed using the respective Linux package management tool such as `yum`, `apt-get`, `dnf` or `pacman`. The `xdg-utils` package is usually available on KDE based systems, some Arch based systems may require manual installations. +On Linux systems, Scene Builder uses the `xdg-open` command to reveal files in the system's default file system browser or to open URLs in the default web browser. Most modern Linux Desktop Environments already provide the [xdg-utils](https://freedesktop.org/wiki/Software/xdg-utils/) package. If it is missing, it can be installed using the respective Linux package management tool such as `yum`, `apt-get`, `dnf` or `pacman`. The `xdg-utils` package is usually available on KDE based systems, some Arch based systems may require manual installations. ## Issues and Contributions ## From 2164068db4c834a9239b239e42781ebfb9c44f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20L=C3=B6ffler?= <22102800+Oliver-Loeffler@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:05:33 +0200 Subject: [PATCH 25/29] Update EditorPlatform.java Fixed indentation. --- .../oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 8fcf116bb..6cad3d41a 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -383,7 +383,7 @@ public static void revealInFileBrowser(File filePath) throws IOException, FileBr } if (!args.isEmpty()) { - executeDaemon(args, null, exitCodeOk); + executeDaemon(args, null, exitCodeOk); } } From bcd5cd06883458e18370e1063e08cd08dcf0ac9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20L=C3=B6ffler?= <22102800+Oliver-Loeffler@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:09:02 +0200 Subject: [PATCH 26/29] Changed log level according to feedbck. --- .../oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 6cad3d41a..652e30635 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -447,7 +447,7 @@ protected Void call() throws Exception { "The command to reval the file exited with an error (exitValue=%s).\nCommand: %s\nWorking Dir: %s" .formatted(Integer.toString(exitValue), cmdLine, wDir)); } else { - LOGGER.log(Level.INFO, "Successfully executed command: {0} in {1}", new Object[] {cmdLine, wDir}); + LOGGER.log(Level.FINE, "Successfully executed command: {0} in {1}", new Object[] {cmdLine, wDir}); } } catch (RuntimeException ex) { LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); From ca9f5c6a1d8f1b15ce1ef514df76a6c70276b26e Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Mon, 30 Sep 2024 22:40:26 +0200 Subject: [PATCH 27/29] Removed JavaFX task. Refactoring of the execution method will be part of a different PR. --- .../kit/editor/EditorPlatform.java | 71 +++++++------------ 1 file changed, 24 insertions(+), 47 deletions(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 652e30635..03db84acb 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -38,22 +38,17 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Paths; -import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import com.oracle.javafx.scenebuilder.kit.editor.panel.css.SelectionPath.Path; import com.oracle.javafx.scenebuilder.kit.i18n.I18N; -import javafx.concurrent.Task; import javafx.scene.Node; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; @@ -434,47 +429,29 @@ public static boolean isAssertionEnabled() { * exception. */ private static void executeDaemon(List cmd, File wDir, int exitCodeOk) throws IOException, FileBrowserRevealException { - Task cmdTask = new Task() { - @Override - protected Void call() throws Exception { - var cmdLine = cmd.stream().collect(Collectors.joining(" ")); - long timeoutSec = 5; - try { - int exitValue = new Cmd().exec(cmd, wDir, timeoutSec); - if (exitCodeOk != exitValue) { - LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); - throw new FileBrowserRevealException( - "The command to reval the file exited with an error (exitValue=%s).\nCommand: %s\nWorking Dir: %s" - .formatted(Integer.toString(exitValue), cmdLine, wDir)); - } else { - LOGGER.log(Level.FINE, "Successfully executed command: {0} in {1}", new Object[] {cmdLine, wDir}); - } - } catch (RuntimeException ex) { - LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); - throw new IOException(ex); - } catch (InterruptedException e) { - LOGGER.log(Level.SEVERE, "Process timeout after {0}s: {1} in {2}", new Object[] {timeoutSec, cmdLine, wDir}); - Thread.currentThread().interrupt(); - String msg = "The command to reval the file exited with an error after timeout.\nCommand: %s\nWorking Dir: %s\nTimeout (s):%s" - .formatted(cmdLine, wDir, timeoutSec); - String detailMsg = msg+"\n"+e.getMessage(); - - throw new IOException(detailMsg); - } - return null; - } - - @Override - protected void failed() { - - /* - * TODO: - * There is no error handling yet - at least if an exception is thrown, that must be handled. - */ - - } - }; - - new Thread(cmdTask, "executeDaemon-task").start(); + var cmdLine = cmd.stream().collect(Collectors.joining(" ")); + long timeoutSec = 5; + try { + int exitValue = new Cmd().exec(cmd, wDir, timeoutSec); + if (exitCodeOk != exitValue) { + LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); + throw new FileBrowserRevealException( + "The command to reval the file exited with an error (exitValue=%s).\nCommand: %s\nWorking Dir: %s" + .formatted(Integer.toString(exitValue), cmdLine, wDir)); + } else { + LOGGER.log(Level.FINE, "Successfully executed command: {0} in {1}", new Object[] {cmdLine, wDir}); + } + } catch (RuntimeException ex) { + LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); + throw new IOException(ex); + } catch (InterruptedException e) { + LOGGER.log(Level.SEVERE, "Process timeout after {0}s: {1} in {2}", new Object[] {timeoutSec, cmdLine, wDir}); + Thread.currentThread().interrupt(); + String msg = "The command to reval the file exited with an error after timeout.\nCommand: %s\nWorking Dir: %s\nTimeout (s):%s" + .formatted(cmdLine, wDir, timeoutSec); + String detailMsg = msg+"\n"+e.getMessage(); + + throw new IOException(detailMsg); + } } } From 0d512f62cb0dca1c74367b3ae5370134d6f86661 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Mon, 30 Sep 2024 22:55:38 +0200 Subject: [PATCH 28/29] Removed empty line. --- .../oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java | 1 - 1 file changed, 1 deletion(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 03db84acb..94bd0fcca 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -48,7 +48,6 @@ import java.util.stream.Collectors; import com.oracle.javafx.scenebuilder.kit.i18n.I18N; - import javafx.scene.Node; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; From b00da05e0a62adf2ce0cd12fd42fac0be06fa076 Mon Sep 17 00:00:00 2001 From: Oliver-Loeffler Date: Mon, 30 Sep 2024 22:58:02 +0200 Subject: [PATCH 29/29] Applied formatter. --- .../kit/editor/EditorPlatform.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index 94bd0fcca..40cf39e6d 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -427,29 +427,30 @@ public static boolean isAssertionEnabled() { * cmd call which ends with an error code != 0 is creating an * exception. */ - private static void executeDaemon(List cmd, File wDir, int exitCodeOk) throws IOException, FileBrowserRevealException { + private static void executeDaemon(List cmd, File wDir, int exitCodeOk) + throws IOException, FileBrowserRevealException { var cmdLine = cmd.stream().collect(Collectors.joining(" ")); long timeoutSec = 5; try { int exitValue = new Cmd().exec(cmd, wDir, timeoutSec); if (exitCodeOk != exitValue) { - LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); + LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] { cmdLine, wDir }); throw new FileBrowserRevealException( "The command to reval the file exited with an error (exitValue=%s).\nCommand: %s\nWorking Dir: %s" - .formatted(Integer.toString(exitValue), cmdLine, wDir)); + .formatted(Integer.toString(exitValue), cmdLine, wDir)); } else { - LOGGER.log(Level.FINE, "Successfully executed command: {0} in {1}", new Object[] {cmdLine, wDir}); + LOGGER.log(Level.FINE, "Successfully executed command: {0} in {1}", new Object[] { cmdLine, wDir }); } } catch (RuntimeException ex) { - LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] {cmdLine, wDir}); + LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] { cmdLine, wDir }); throw new IOException(ex); } catch (InterruptedException e) { - LOGGER.log(Level.SEVERE, "Process timeout after {0}s: {1} in {2}", new Object[] {timeoutSec, cmdLine, wDir}); + LOGGER.log(Level.SEVERE, "Process timeout after {0}s: {1} in {2}", + new Object[] { timeoutSec, cmdLine, wDir }); Thread.currentThread().interrupt(); String msg = "The command to reval the file exited with an error after timeout.\nCommand: %s\nWorking Dir: %s\nTimeout (s):%s" - .formatted(cmdLine, wDir, timeoutSec); - String detailMsg = msg+"\n"+e.getMessage(); - + .formatted(cmdLine, wDir, timeoutSec); + String detailMsg = msg + "\n" + e.getMessage(); throw new IOException(detailMsg); } }