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 aa78fbc72ea01823805b4e6d106f3b6dbbd3c57a
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Tue Dec 28 02:23:30 2021 +0100

    Improvements in the handling of "Copy" actions from contextual menu.
---
 .../org/apache/sis/gui/metadata/MetadataTree.java  | 81 ++++++++++++++++++++--
 .../sis/gui/metadata/StandardMetadataTree.java     | 73 +++++++------------
 2 files changed, 100 insertions(+), 54 deletions(-)

diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataTree.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataTree.java
index 3d322fa..4c2f9cb 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataTree.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataTree.java
@@ -29,15 +29,23 @@ import javafx.beans.property.ReadOnlyStringWrapper;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ObservableValue;
 import javafx.collections.ObservableList;
+import javafx.scene.control.ContextMenu;
+import javafx.scene.control.MenuItem;
 import javafx.scene.control.TreeItem;
+import javafx.scene.control.TreeTableRow;
 import javafx.scene.control.TreeTableView;
 import javafx.scene.control.TreeTableColumn;
 import javafx.scene.control.TreeTableColumn.CellDataFeatures;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.input.Clipboard;
+import javafx.scene.input.ClipboardContent;
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.IdentifiedObject;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.internal.util.PropertyFormat;
 import org.apache.sis.internal.system.Modules;
+import org.apache.sis.internal.gui.Resources;
 import org.apache.sis.util.collection.TreeTable;
 import org.apache.sis.util.collection.TableColumn;
 import org.apache.sis.util.resources.Vocabulary;
@@ -64,7 +72,7 @@ import org.apache.sis.util.logging.Logging;
  *       For changing content, use the {@link #contentProperty} instead.</li>
  * </ul>
  *
- * @todo Add a panel for controlling the number/date/angle format pattern.
+ * @todo Add menu items for controlling the number/date/angle format pattern.
  *
  * @author  Siddhesh Rane (GSoC)
  * @author  Martin Desruisseaux (Geomatys)
@@ -89,7 +97,7 @@ public class MetadataTree extends 
TreeTableView<TreeTable.Node> {
      * The column for metadata property value in the model.
      * This is usually {@link TableColumn#VALUE} or {@link 
TableColumn#VALUE_AS_TEXT}.
      */
-    TableColumn<?> valueSourceColumn;
+    private TableColumn<?> valueSourceColumn;
 
     /**
      * The data shown in this tree table. The {@link 
ObjectProperty#set(Object)} method requires
@@ -146,7 +154,7 @@ check:      if (data != null) {
      * Creates a new initially empty metadata tree.
      */
     public MetadataTree() {
-        this(null, false);
+        this(null);
     }
 
     /**
@@ -157,6 +165,8 @@ check:      if (data != null) {
      */
     public MetadataTree(final MetadataSummary controller) {
         this(controller, false);
+        setRowFactory(Row::new);
+        setShowRoot(false);
     }
 
     /**
@@ -183,9 +193,6 @@ check:      if (data != null) {
         setColumnResizePolicy(CONSTRAINED_RESIZE_POLICY);
         getColumns().setAll(nameColumn, valueColumn);
         contentProperty.addListener(MetadataTree::applyChange);
-        if (!standard) {
-            setShowRoot(false);
-        }
     }
 
     /**
@@ -375,4 +382,66 @@ check:      if (data != null) {
             return new ReadOnlyObjectWrapper<>(value);
         }
     }
+
+    /**
+     * A row in a metadata tree view, used for adding contextual menu on a 
row-by-row basis.
+     */
+    static class Row extends TreeTableRow<TreeTable.Node> implements 
EventHandler<ActionEvent> {
+        /**
+         * The context menu, to be added only if this row is non-empty.
+         */
+        protected final ContextMenu menu;
+
+        /**
+         * The menu item for copying current row.
+         */
+        protected final MenuItem copy;
+
+        /**
+         * Creates a new row for the given tree table.
+         */
+        @SuppressWarnings("ThisEscapedInObjectConstruction")
+        Row(final TreeTableView<TreeTable.Node> view) {
+            final MetadataTree md = (MetadataTree) view;
+            final Resources localized = Resources.forLocale(md.getLocale());
+            copy = new MenuItem(localized.getString(Resources.Keys.Copy));
+            menu = new ContextMenu(copy);
+            copy.setOnAction(this);
+        }
+
+        /**
+         * Invoked when a new row is selected. This method sets the contextual 
menu on the row.
+         */
+        @Override
+        protected void updateItem​(final TreeTable.Node item, final boolean 
empty) {
+            super.updateItem(item, empty);
+            setContextMenu(empty ? null : menu);
+            copy.setDisable(empty || getValue() == null);
+        }
+
+        /**
+         * Returns the object in the "value" column of current row, or {@code 
null} if none.
+         */
+        private Object getValue() {
+            final TreeTable.Node node = getItem();
+            if (node != null) {
+                final Object obj = node.getUserObject();
+                return (obj != null) ? obj : node.getValue(((MetadataTree) 
getTreeTableView()).valueSourceColumn);
+            }
+            return null;
+        }
+
+        /**
+         * Invoked when user selected a menu item.
+         */
+        @Override
+        public void handle(final ActionEvent event) {
+            final Object value = getValue();
+            if (value != null) {
+                final ClipboardContent content = new ClipboardContent();
+                content.putString(value.toString());
+                Clipboard.getSystemClipboard().setContent(content);
+            }
+        }
+    }
 }
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/StandardMetadataTree.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/StandardMetadataTree.java
index e46986e..afe4730 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/StandardMetadataTree.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/StandardMetadataTree.java
@@ -20,12 +20,9 @@ import java.util.Collections;
 import java.io.StringWriter;
 import javax.xml.transform.stream.StreamResult;
 import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.scene.control.ContextMenu;
 import javafx.scene.control.Menu;
 import javafx.scene.control.MenuItem;
 import javafx.scene.control.TreeTableView;
-import javafx.scene.control.TreeTableRow;
 import javafx.scene.input.Clipboard;
 import javafx.scene.input.ClipboardContent;
 import org.opengis.metadata.Metadata;
@@ -67,17 +64,12 @@ import org.apache.sis.xml.XML;
  *
  * @author  Siddhesh Rane (GSoC)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
  * @since   1.1
  * @module
  */
 public class StandardMetadataTree extends MetadataTree {
     /**
-     * The "copy" and "copy as" localized string, used for contextual menus.
-     */
-    private final String copy, copyAs;
-
-    /**
      * Creates a new initially empty metadata tree.
      */
     public StandardMetadataTree() {
@@ -94,9 +86,6 @@ public class StandardMetadataTree extends MetadataTree {
      */
     public StandardMetadataTree(final MetadataSummary controller) {
         super(controller, true);
-        final Resources localized = Resources.forLocale(getLocale());
-        copy   = localized.getString(Resources.Keys.Copy);
-        copyAs = localized.getString(Resources.Keys.CopyAs);
         setRowFactory(Row::new);
         if (controller != null) {
             controller.metadataProperty.addListener((p,o,n) -> setContent(n));
@@ -104,43 +93,35 @@ public class StandardMetadataTree extends MetadataTree {
     }
 
     /**
-     * Returns the given metadata as a tree table.
-     */
-    private static TreeTable toTree(final Object metadata) {
-        if (metadata instanceof AbstractMetadata) {
-            return ((AbstractMetadata) metadata).asTreeTable();
-        } else {
-            // `COMPACT` is the default policy of 
`AbstractMetadata.asTreeTable()`.
-            return MetadataStandard.ISO_19115.asTreeTable(metadata, null, 
ValueExistencePolicy.COMPACT);
-        }
-    }
-
-    /**
      * Sets the metadata to show in this tree table. This method gets a {@link 
TreeTable} view
      * of the given metadata, then delegates to {@link #setContent(TreeTable)}.
      *
      * @param  metadata  the metadata to show in this tree table view, or 
{@code null} if none.
      */
     public void setContent(final Metadata metadata) {
-        setContent(metadata == null ? null : toTree(metadata));
+        final TreeTable tree;
+        if (metadata == null) {
+            tree = null;
+        } else if (metadata instanceof AbstractMetadata) {
+            tree = ((AbstractMetadata) metadata).asTreeTable();
+        } else {
+            // `COMPACT` is the default policy of 
`AbstractMetadata.asTreeTable()`.
+            tree = MetadataStandard.ISO_19115.asTreeTable(metadata, null, 
ValueExistencePolicy.COMPACT);
+        }
+        setContent(tree);
     }
 
     /**
      * A row in a metadata tree view, used for adding contextual menu on a 
row-by-row basis.
      */
-    private static final class Row extends TreeTableRow<TreeTable.Node> 
implements EventHandler<ActionEvent> {
-        /**
-         * The context menu, to be added only if this row is non-empty.
-         */
-        private final ContextMenu menu;
-
+    private static final class Row extends MetadataTree.Row {
         /**
          * The menu items for XML or WKT formats.
          */
         private final MenuItem copyAsXML, copyAsLegacy, copyAsWKT;
 
         /**
-         * The menu items for copying in XML formats, to be disabled if we can 
not do this export.
+         * The group of menu items for copying in various formats, to be 
disabled if we can not do this export.
          */
         private final Menu copyAs;
 
@@ -149,21 +130,21 @@ public class StandardMetadataTree extends MetadataTree {
          */
         @SuppressWarnings("ThisEscapedInObjectConstruction")
         Row(final TreeTableView<TreeTable.Node> view) {
+            super(view);
             final StandardMetadataTree md = (StandardMetadataTree) view;
-            final MenuItem copy;
-            copy         = new MenuItem(md.copy);
+            final Resources localized = Resources.forLocale(md.getLocale());
             copyAsXML    = new MenuItem();
             copyAsWKT    = new MenuItem("WKT — Well Known Text");
             copyAsLegacy = new MenuItem("XML — Metadata (2007)");
-            copyAs       = new Menu(md.copyAs, null, copyAsWKT, copyAsXML, 
copyAsLegacy);
-            menu         = new ContextMenu(copy, copyAs);
+            copyAs       = new 
Menu(localized.getString(Resources.Keys.CopyAs), null, copyAsWKT, copyAsXML, 
copyAsLegacy);
+            menu        .getItems().add(copyAs);
             copyAsLegacy.setOnAction(this);
             copyAsXML   .setOnAction(this);
-            copy        .setOnAction(this);
+            copyAsWKT   .setOnAction(this);
         }
 
         /**
-         * Invoked when a new row is selected. This method enable or disable 
the "copy as" menu
+         * Invoked when a new row is selected. This method enables or disables 
the "copy as" menu
          * depending on whether or not we can format XML document for 
currently selected row.
          */
         @Override
@@ -190,7 +171,6 @@ public class StandardMetadataTree extends MetadataTree {
                 }
                 copyAs.setDisable(disabled);
             }
-            setContextMenu(empty ? null : menu);
         }
 
         /**
@@ -203,7 +183,9 @@ public class StandardMetadataTree extends MetadataTree {
             final TreeTable.Node node = getItem();
             if (node != null) {
                 final Object obj = node.getUserObject();
-                if (obj != null) {
+                if (obj == null) {
+                    super.handle(event);
+                } else {
                     final Object source = event.getSource();
                     final ClipboardContent content = new ClipboardContent();
                     final String text;
@@ -220,21 +202,16 @@ public class StandardMetadataTree extends MetadataTree {
                                     
Collections.singletonMap(XML.METADATA_VERSION, LegacyNamespaces.VERSION_2007));
                             text = output.toString();
                             content.put(DataFormats.ISO_19139, text);
-                        } else if 
(MetadataStandard.ISO_19115.isMetadata(obj.getClass())) {
-                            text = toTree(obj).toString();
                         } else {
-                            final Object value = node.getValue(((MetadataTree) 
getTreeTableView()).valueSourceColumn);
-                            if (value == null) return;
-                            text = value.toString();
+                            text = obj.toString();
                         }
+                        content.putString(text);
+                        Clipboard.getSystemClipboard().setContent(content);
                     } catch (Exception e) {
                         final Resources localized = 
Resources.forLocale(((MetadataTree) getTreeTableView()).getLocale());
                         ExceptionReporter.show(this, 
localized.getString(Resources.Keys.ErrorExportingData),
                                                      
localized.getString(Resources.Keys.CanNotCreateXML), e);
-                        return;
                     }
-                    content.putString(text);
-                    Clipboard.getSystemClipboard().setContent(content);
                 }
             }
         }

Reply via email to