sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 02/03: Show the stack trace when we failed to load a resource.
Date Tue, 05 Nov 2019 12:05:35 GMT
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 ab93f5adc7f8539723ae915e78d79e8a83519276
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Tue Nov 5 11:09:24 2019 +0100

    Show the stack trace when we failed to load a resource.
---
 .../org/apache/sis/gui/dataset/package-info.java   |   5 +-
 .../apache/sis/gui/metadata/MetadataSummary.java   |  53 +++++++----
 .../org/apache/sis/gui/metadata/MetadataTree.java  |  21 +++--
 .../org/apache/sis/gui/metadata/package-info.java  |   2 +
 .../apache/sis/internal/gui/ExceptionReporter.java | 100 +++++++++++++++++----
 .../apache/sis/internal/gui/ResourceLoader.java    |   3 +-
 .../org/apache/sis/internal/gui/Resources.java     |   5 ++
 .../apache/sis/internal/gui/Resources.properties   |   1 +
 .../sis/internal/gui/Resources_fr.properties       |   1 +
 9 files changed, 145 insertions(+), 46 deletions(-)

diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/package-info.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/package-info.java
index 10040b2..318155f 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/package-info.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/package-info.java
@@ -16,7 +16,10 @@
  */
 
 /**
- * Widgets about data {@link org.apache.sis.storage.Resource} and their metadata.
+ * Widgets about data store resources and their metadata.
+ * Those widgets can show a hierarchical collection of {@link org.apache.sis.storage.Resource}s
in a tree,
+ * and show their content in other panel when a resource is selected. The resources can optionally
be loaded
+ * from a file in background thread.
  *
  * @author  Smaniotto Enzo (GSoC)
  * @author  Johann Sorel (Geomatys)
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataSummary.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataSummary.java
index a61b4e2..1f6d473 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataSummary.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataSummary.java
@@ -42,10 +42,12 @@ import org.opengis.util.ControlledVocabulary;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.gui.BackgroundThreads;
+import org.apache.sis.internal.gui.ExceptionReporter;
 import org.apache.sis.internal.gui.Resources;
 import org.apache.sis.internal.util.Strings;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.Resource;
+import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.logging.Logging;
 
@@ -123,10 +125,9 @@ public class MetadataSummary {
 
     /**
      * If the metadata or the grid geometry can not be obtained, the reason.
-     *
-     * @todo show in this control.
+     * This is created only when first needed.
      */
-    private Throwable error;
+    private ExceptionReporter error;
 
     /**
      * The pane where to show information about resource identification, spatial representation,
etc.
@@ -152,6 +153,13 @@ public class MetadataSummary {
     }
 
     /**
+     * Returns the children inside the view.
+     */
+    private ObservableList<Node> getChildren() {
+        return ((VBox) content.getContent()).getChildren();
+    }
+
+    /**
      * Returns the region containing the visual components managed by this {@code MetadataSummary}.
      * The subclass is implementation dependent and may change in any future version.
      *
@@ -208,21 +216,8 @@ public class MetadataSummary {
                 /**
                  * Shows the result, unless another {@link #setMetadata(Resource)} has been
invoked.
                  */
-                @Override protected void succeeded() {
-                    if (!isCancelled()) {
-                        setMetadata(getValue());
-                    }
-                }
-
-                /**
-                 * Invoked when an error occurred while fetching metadata.
-                 */
-                @Override protected void failed() {
-                    if (!isCancelled()) {
-                        setMetadata((Metadata) null);
-                        error = getException();
-                    }
-                }
+                @Override protected void succeeded() {if (!isCancelled()) setMetadata(getValue());}
+                @Override protected void failed()    {if (!isCancelled()) setError(getException());}
             }
             BackgroundThreads.execute(new Getter());
         }
@@ -256,6 +251,23 @@ public class MetadataSummary {
     }
 
     /**
+     * Clears the metadata panel and write instead an exception report.
+     *
+     * @param  exception  the exception that occurred.
+     */
+    public final void setError(final Throwable exception) {
+        ArgumentChecks.ensureNonNull("exception", exception);
+        setMetadata((Metadata) null);
+        if (error == null) {
+            error = new ExceptionReporter(exception);
+        } else {
+            error.setException(exception);
+        }
+        final ObservableList<Node> children = getChildren();
+        children.setAll(error.getView());
+    }
+
+    /**
      * Invoked when {@link #metadataProperty} value changed.
      *
      * @param  property  the property which has been modified.
@@ -268,7 +280,10 @@ public class MetadataSummary {
         final MetadataSummary s = (MetadataSummary) ((SimpleObjectProperty<?>) property).getBean();
         s.error = null;
         if (metadata != oldValue) {
-            final ObservableList<Node> children = ((VBox) s.content.getContent()).getChildren();
+            final ObservableList<Node> children = s.getChildren();
+            if (!children.isEmpty() && !(children.get(0) instanceof Section)) {
+                children.clear();       // If we were previously showing an error, clear
all.
+            }
             /*
              * We want to include only the non-empty panes in the children list. But instead
of
              * removing everything and adding back non-empty panes, we check case-by-case
if a
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 f5b043a..70ce16f 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
@@ -57,6 +57,11 @@ import org.apache.sis.util.iso.Types;
  * <p>While this view is designed mostly for metadata, it can actually be used
  * for other kinds of data provided by the {@link TreeTable} interface.</p>
  *
+ * @todo Add contextual menu for saving or copying in clipboard the XML starting from the
selected node.
+ *       Add contextual menu for showing a node in the summary pane (we would store in memory
the path,
+ *       including sequence number for multi-values property, and apply it to all opened
resources).
+ *       Add a panel for controlling the number/date/angle format pattern.
+ *
  * @author  Siddhesh Rane (GSoC)
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.1
@@ -130,7 +135,6 @@ public class MetadataTree extends TreeTableView<TreeTable.Node>
{
         nameColumn .setCellValueFactory(MetadataTree::getPropertyName);
         valueColumn.setCellValueFactory(MetadataTree::getPropertyValue);
 
-        setShowRoot(false);
         setColumnResizePolicy(CONSTRAINED_RESIZE_POLICY);
         getColumns().setAll(nameColumn, valueColumn);
         contentProperty.addListener(MetadataTree::applyChange);
@@ -209,15 +213,16 @@ public class MetadataTree extends TreeTableView<TreeTable.Node>
{
      */
     private static final class Item extends TreeItem<TreeTable.Node> {
         /**
-         * +1 if this item is a leaf, +2 if it has children, or 0 if not yet determined.
+         * Whether this node is a leaf.
          */
-        private byte isLeaf;
+        private final boolean isLeaf;
 
         /**
          * Creates a new node.
          */
         Item(final TreeTable.Node node) {
             super(node);
+            isLeaf = node.isLeaf() || node.getChildren().isEmpty();
         }
 
         /**
@@ -225,11 +230,7 @@ public class MetadataTree extends TreeTableView<TreeTable.Node>
{
          */
         @Override
         public boolean isLeaf() {
-            if (isLeaf == 0) {
-                final TreeTable.Node node = getValue();
-                isLeaf = (node.isLeaf() || node.getChildren().isEmpty()) ? (byte) 1 : 2;
-            }
-            return isLeaf == 1;
+            return isLeaf;
         }
 
         /**
@@ -283,6 +284,10 @@ public class MetadataTree extends TreeTableView<TreeTable.Node>
{
     /**
      * Returns the value of the metadata property wrapped by the given argument.
      * This method is invoked by JavaFX when a new cell needs to be rendered.
+     *
+     * @todo Format other kinds of objects (numbers, dates, timezones, etc.).
+     *       See {@link org.apache.sis.util.collection.TreeTableFormat},
+     *       if possible by putting some code in common.
      */
     private static ObservableValue<Object> getPropertyValue(final CellDataFeatures<TreeTable.Node,
Object> cell) {
         final MetadataTree view = (MetadataTree) cell.getTreeTableView();
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/package-info.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/package-info.java
index 8699d96..4dab566 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/package-info.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/package-info.java
@@ -17,6 +17,8 @@
 
 /**
  * Widgets about metadata.
+ * Those widgets can show a {@link org.opengis.metadata.Metadata} instance in a tree,
+ * or show only a summary.
  *
  * @author  Smaniotto Enzo (GSoC)
  * @author  Johann Sorel (Geomatys)
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java
index 107b419..326c2de 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java
@@ -20,9 +20,16 @@ import java.io.PrintWriter;
 import java.io.StringWriter;
 import javafx.concurrent.Worker;
 import javafx.concurrent.WorkerStateEvent;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
 import javafx.scene.control.Alert;
+import javafx.scene.control.ContextMenu;
 import javafx.scene.control.DialogPane;
-import javafx.scene.control.TextArea;
+import javafx.scene.control.Label;
+import javafx.scene.input.Clipboard;
+import javafx.scene.input.ClipboardContent;
+import javafx.scene.layout.Region;
 import org.apache.sis.util.Classes;
 
 
@@ -39,11 +46,58 @@ import org.apache.sis.util.Classes;
  * @since   1.1
  * @module
  */
-public final class ExceptionReporter {
+public final class ExceptionReporter implements EventHandler<ActionEvent> {
     /**
-     * Do not allow instantiation of this class.
+     * The margin to use for the stack trace. We add some spaces on the top and left sides.
      */
-    private ExceptionReporter() {
+    private static final Insets MARGIN = new Insets(9, 0, 0, 40);
+
+    /**
+     * The component where to show the stack trace.
+     */
+    private final Label trace;
+
+    /**
+     * Creates a new exception reporter showing the stack trace of the given exception.
+     *
+     * @param  exception  the error to report.
+     */
+    public ExceptionReporter(final Throwable exception) {
+        trace = new Label(getStackTrace(exception));
+        trace.setPadding(MARGIN);
+
+        final Resources localized = Resources.getInstance();
+        final ContextMenu menu = new ContextMenu();
+        menu.getItems().add(localized.menu(Resources.Keys.Copy, this));
+        trace.setContextMenu(menu);
+    }
+
+    /**
+     * Updates the content of this reporter with a new stack trace.
+     *
+     * @param  exception  the new error to report.
+     */
+    public void setException(final Throwable exception) {
+        trace.setText(getStackTrace(exception));
+    }
+
+    /**
+     * Gets the stack trace of the given exception.
+     */
+    private static String getStackTrace(final Throwable exception) {
+        final StringWriter buffer = new StringWriter();
+        final PrintWriter  writer = new PrintWriter(buffer);
+        exception.printStackTrace(writer);
+        return buffer.toString();
+    }
+
+    /**
+     * Returns the control to insert in a scene for showing the stack trace.
+     *
+     * @return the stack trace viewer.
+     */
+    public final Region getView() {
+        return trace;
     }
 
     /**
@@ -73,6 +127,17 @@ public final class ExceptionReporter {
     }
 
     /**
+     * Shows the reporter for a failure to close a file.
+     * This method does nothing if the exception is null.
+     *
+     * @param  file       the file that can not be closed.
+     * @param  exception  the error that occurred.
+     */
+    public static void canNotCloseFile(final String file, final Throwable exception) {
+        show(Resources.Keys.ErrorClosingFile, Resources.Keys.CanNotClose_1, new Object[]
{file}, exception);
+    }
+
+    /**
      * Constructs and shows the exception reporter. The title and text are keys from the
{@link Resources}.
      * If the title and/or text are 0, then the {@link Alert} default title and text will
be used.
      *
@@ -81,7 +146,7 @@ public final class ExceptionReporter {
      * @param arguments   the arguments for creating the text identified by the {@code text}
key.
      * @param exception   the exception to report.
      */
-    static void show(final short title, final short text, final Object[] arguments, final
Throwable exception) {
+    private static void show(final short title, final short text, final Object[] arguments,
final Throwable exception) {
         if (exception != null) {
             String message = exception.getLocalizedMessage();
             if (message == null) {
@@ -98,20 +163,23 @@ public final class ExceptionReporter {
                 }
             }
             alert.setContentText(message);
-            /*
-             * Format the stack trace to be shown in the expandable section.
-             */
-            final StringWriter buffer = new StringWriter();
-            final PrintWriter  writer = new PrintWriter(buffer);
-            exception.printStackTrace(writer);
-            final TextArea trace = new TextArea(buffer.toString());
-            trace.setPrefRowCount​(20);
-            trace.setEditable(false);
-
             final DialogPane pane = alert.getDialogPane();
-            pane.setExpandableContent(trace);
+            pane.setExpandableContent(new ExceptionReporter(exception).trace);
             pane.setPrefWidth(650);
             alert.show();
         }
     }
+
+    /**
+     * Invoked when the user selected the "Copy" action in contextual menu.
+     * This method is public as an implementation side-effect; do not use.
+     *
+     * @param event ignored.
+     */
+    @Override
+    public void handle(final ActionEvent event) {
+        final ClipboardContent content = new ClipboardContent();
+        content.putString(trace.getText());
+        Clipboard.getSystemClipboard().setContent(content);
+    }
 }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ResourceLoader.java
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ResourceLoader.java
index 581dd42..734c0e7 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ResourceLoader.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ResourceLoader.java
@@ -209,8 +209,7 @@ public final class ResourceLoader extends Task<Resource> {
                 toClose.close();
             } catch (final Throwable e) {
                 Platform.runLater(() -> {
-                    ExceptionReporter.show(Resources.Keys.ErrorClosingFile, Resources.Keys.CanNotClose_1,
-                                           new Object[] {toClose.getDisplayName()}, e);
+                    ExceptionReporter.canNotCloseFile(toClose.getDisplayName(), e);
                 });
             }
         });
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 ab69265..8273092 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
@@ -91,6 +91,11 @@ public final class Resources extends IndexedResourceBundle {
         public static final short Close = 8;
 
         /**
+         * Copy
+         */
+        public static final short Copy = 31;
+
+        /**
          * Creation date:
          */
         public static final short CreationDate = 16;
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 13f1571..2f88906 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
@@ -26,6 +26,7 @@ CanNotReadFile_1       = Can not open \u201c{0}\u201d.
 CanNotClose_1          = Can not close \u201c{0}\u201d. Data may be lost.
 CellGeometry           = Cell geometry:
 Close                  = Close
+Copy                   = Copy
 CreationDate           = Creation date:
 Credit                 = Credit:
 CRSs                   = Coordinate Reference Systems
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 697962f..4aab7f8 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
@@ -31,6 +31,7 @@ CanNotReadFile_1       = Ne peut pas ouvrir \u00ab\u202f{0}\u202f\u00bb.
 CanNotClose_1          = Ne peut pas fermer \u00ab\u202f{0}\u202f\u00bb. Il pourrait y avoir
une perte de donn\u00e9es.
 CellGeometry           = G\u00e9om\u00e9trie des cellules\u00a0:
 Close                  = Fermer
+Copy                   = Copier
 CreationDate           = Date de cr\u00e9ation\u00a0:
 Credit                 = Cr\u00e9dit\u00a0:
 CRSs                   = Syst\u00e8mes de r\u00e9f\u00e9rence des coordonn\u00e9es


Mime
View raw message