This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 940d30674b21a48fd8e93bf161200ba5e7c3576d
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Tue Dec 28 21:13:35 2021 +0100

    Add a menu for opening the folder containing a file.
---
 .../dataset/{CopyAction.java => PathAction.java}   | 38 +++++++++++++++++++---
 .../org/apache/sis/gui/dataset/ResourceTree.java   |  8 +++--
 .../org/apache/sis/internal/gui/Resources.java     |  5 +++
 .../apache/sis/internal/gui/Resources.properties   |  1 +
 .../sis/internal/gui/Resources_fr.properties       |  1 +
 .../sis/internal/storage/io/IOUtilities.java       | 23 ++++++++++++-
 6 files changed, 67 insertions(+), 9 deletions(-)

diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/CopyAction.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/PathAction.java
similarity index 80%
rename from 
application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/CopyAction.java
rename to 
application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/PathAction.java
index 206c014..29ea6ae 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/CopyAction.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/PathAction.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.gui.dataset;
 
+import java.awt.Desktop;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -37,27 +38,43 @@ import org.apache.sis.storage.Resource;
 
 
 /**
- * The "Copy file path" action. This class gets the file path of a resource 
and copies it in the clipboard.
+ * The "Copy file path" or "Open containing folder" action.
+ * This class gets the file path of a resource and copies it in the clipboard
+ * or open the containing folder using native file browser.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
  * @since   1.1
  * @module
  */
-final class CopyAction implements EventHandler<ActionEvent> {
+final class PathAction implements EventHandler<ActionEvent> {
     /**
      * The cell for which to provide a copy action.
      */
     private final TreeCell<Resource> cell;
 
     /**
+     * {@code true} for opening native file browser, or {@code false} for 
copying to clipboard.
+     */
+    private final boolean browser;
+
+    /**
      * Creates a new instance.
+     *
+     * @param  browser  {@code true} for opening native file browser, or 
{@code false} for copying to clipboard.
      */
-    CopyAction(final TreeCell<Resource> source) {
-        this.cell = source;
+    PathAction(final TreeCell<Resource> source, final boolean browser) {
+        this.cell    = source;
+        this.browser = browser;
     }
 
     /**
+     * Whether the "Open containing folder" operation is disabled.
+     */
+    static final boolean isBrowseDisabled = !(Desktop.isDesktopSupported() &&
+            Desktop.getDesktop().isSupported(Desktop.Action.BROWSE_FILE_DIR));
+
+    /**
      * Invoked when the user selected "Copy file path" item in the contextual 
menu of a {@link ResourceTree} cell.
      * This method copies the path of the selected resource to the clipboard.
      */
@@ -103,6 +120,17 @@ final class CopyAction implements 
EventHandler<ActionEvent> {
             // Ignore. The `uri` or `text` field that we failed to assign keep 
its original value.
         }
         /*
+         * If this action is for opening the native file browser, we can do it 
now.
+         */
+        if (browser) {
+            if (file instanceof File) try {
+                Desktop.getDesktop().browseFileDirectory((File) file);
+            } catch (Exception e) {
+                ExceptionReporter.show(cell.getTreeView(), null, null, e);
+            }
+            return;
+        }
+        /*
          * Above code obtained a single path, considered the main one. But a 
resource may also be
          * associated with many files (some kinds of data are actually 
provided as a group of files).
          * We put in the clipboard all `java.io.File` instances that we can 
get from the resource.
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceTree.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceTree.java
index c258b41..a88cdc0 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceTree.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceTree.java
@@ -685,8 +685,9 @@ public class ResourceTree extends TreeView<Resource> {
                         menu = new ContextMenu();
                         final Resources localized = tree.localized();
                         final MenuItem[] items = new MenuItem[CLOSE + 1];
-                        items[COPY_PATH] = 
localized.menu(Resources.Keys.CopyFilePath, new CopyAction(this));
-                        items[CLOSE] = localized.menu(Resources.Keys.Close, 
(e) -> {
+                        items[COPY_PATH]   = 
localized.menu(Resources.Keys.CopyFilePath, new PathAction(this, false));
+                        items[OPEN_FOLDER] = 
localized.menu(Resources.Keys.OpenContainingFolder, new PathAction(this, true));
+                        items[CLOSE]       = 
localized.menu(Resources.Keys.Close, (e) -> {
                             ((ResourceTree) 
getTreeView()).removeAndClose(getItem());
                         });
                         menu.getItems().setAll(items);
@@ -703,6 +704,7 @@ public class ResourceTree extends TreeView<Resource> {
                         unexpectedException("updateItem", e);
                     }
                     
menu.getItems().get(COPY_PATH).setDisable(!IOUtilities.isKindOfPath(path));
+                    
menu.getItems().get(OPEN_FOLDER).setDisable(PathAction.isBrowseDisabled || 
IOUtilities.toFile(path) == null);
                 }
             }
             setText(text);
@@ -715,7 +717,7 @@ public class ResourceTree extends TreeView<Resource> {
          * Position of menu items in the contextual menu built by {@link 
#updateItem(Resource, boolean)}.
          * Above method assumes that {@link #CLOSE} is the last menu item.
          */
-        private static final int COPY_PATH = 0, CLOSE = 1;
+        private static final int COPY_PATH = 0, OPEN_FOLDER = 1, CLOSE = 2;
     }
 
 
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
index 518467f..6011b18 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
@@ -303,6 +303,11 @@ public final class Resources extends IndexedResourceBundle 
{
         public static final short Open = 28;
 
         /**
+         * Open containing folder
+         */
+        public static final short OpenContainingFolder = 66;
+
+        /**
          * Open data file
          */
         public static final short OpenDataFile = 29;
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.properties
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.properties
index 70125be..9444b62 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.properties
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.properties
@@ -69,6 +69,7 @@ MainWindow             = Main window
 NewWindow              = New window
 NoFeatureTypeInfo      = No feature type information.
 Open                   = Open\u2026
+OpenContainingFolder   = Open containing folder
 OpenDataFile           = Open data file
 OpenRecentFile         = Open recent file
 Orthographic           = Orthographic
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.properties
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.properties
index d580bee..eece6be 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.properties
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.properties
@@ -74,6 +74,7 @@ MainWindow             = Fen\u00eatre principale
 NewWindow              = Nouvelle fen\u00eatre
 NoFeatureTypeInfo      = Pas d\u2019information sur le type d\u2019entit\u00e9.
 Open                   = Ouvrir\u2026
+OpenContainingFolder   = Ouvrir le dossier contenant
 OpenDataFile           = Ouvrir un fichier de donn\u00e9es
 OpenRecentFile         = Ouvrir un fichier r\u00e9cent
 Orthographic           = Orthographique
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
index 2c65096..f9a6cba 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
@@ -59,7 +59,7 @@ import org.apache.sis.internal.storage.Resources;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.1
+ * @version 1.2
  * @since   0.3
  * @module
  */
@@ -181,6 +181,27 @@ public final class IOUtilities extends Static {
     }
 
     /**
+     * Returns the given path as a {@link File}, or {@code null} if it can not 
be converted.
+     *
+     * @param  path  the object to convert to a {@link File}. Can be {@code 
null}.
+     * @return the given path as a {@link File}, or {@code null} if it can not 
be converted.
+     */
+    public static File toFile(final Object path) {
+        if (path instanceof File) {
+            return (File) path;
+        } else if (path instanceof Path) try {
+            return ((Path) path).toFile();
+        } catch (UnsupportedOperationException e) {
+            // Ignore.
+        } else if (path instanceof URI) try {
+            return new File((URI) path);
+        } catch (IllegalArgumentException e) {
+            // Ignore.
+        }
+        return null;
+    }
+
+    /**
      * Returns the given path without the directories and without the 
extension.
      * For example if the given path is {@code "/Users/name/Map.png"}, then 
this
      * method returns {@code "Map"}.

Reply via email to