You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2020/01/31 19:16:51 UTC

[sis] branch geoapi-4.0 updated: List the sample dimensions in CoverageExplorer.

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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 5e91876  List the sample dimensions in CoverageExplorer.
5e91876 is described below

commit 5e91876fd2255373ca0a339e10f8b6cfe0f98d07
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Fri Jan 31 20:16:37 2020 +0100

    List the sample dimensions in CoverageExplorer.
---
 .../apache/sis/gui/coverage/CoverageExplorer.java  | 49 ++++++++++++++++++---
 .../java/org/apache/sis/gui/coverage/GridView.java | 12 +++---
 .../org/apache/sis/gui/coverage/ImageLoader.java   | 14 +++++-
 .../org/apache/sis/gui/coverage/ImageRequest.java  | 50 ++++++++++++++++++++++
 .../apache/sis/internal/gui/ExceptionReporter.java | 30 ++++++++++---
 .../org/apache/sis/internal/gui/Resources.java     | 10 +++++
 .../apache/sis/internal/gui/Resources.properties   |  2 +
 .../sis/internal/gui/Resources_fr.properties       |  2 +
 .../org/apache/sis/util/resources/Vocabulary.java  |  5 +++
 .../sis/util/resources/Vocabulary.properties       |  1 +
 .../sis/util/resources/Vocabulary_fr.properties    |  1 +
 11 files changed, 157 insertions(+), 19 deletions(-)

diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageExplorer.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageExplorer.java
index 2aebfda..d45a69a 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageExplorer.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/CoverageExplorer.java
@@ -16,20 +16,24 @@
  */
 package org.apache.sis.gui.coverage;
 
+import java.util.Locale;
 import java.awt.image.RenderedImage;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ObservableValue;
+import javafx.collections.ObservableList;
 import javafx.scene.control.Accordion;
 import javafx.scene.control.Label;
 import javafx.scene.control.ListView;
 import javafx.scene.control.SplitPane;
 import javafx.scene.control.TitledPane;
+import javafx.scene.control.ListCell;
 import javafx.scene.layout.Region;
 import javafx.scene.layout.VBox;
 import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridCoverage;
 import org.apache.sis.internal.gui.Styles;
+import org.apache.sis.util.resources.Vocabulary;
 
 
 /**
@@ -78,6 +82,8 @@ public class CoverageExplorer {
     public CoverageExplorer() {
         gridView         = new GridView();
         sampleDimensions = new ListView<>();
+        sampleDimensions.setCellFactory(SampleDimensionCell::new);
+        final Vocabulary vocabulary = Vocabulary.getResources((Locale) null);
         /*
          * Create the "Coverage" pane with the following controls:
          *    - Coverage domain as a list of CRS dimensions with two of them selected (TODO).
@@ -85,13 +91,13 @@ public class CoverageExplorer {
          */
         final VBox coveragePane;
         {   // Block for making variables locale to this scope.
-            final Label label = new Label("Sample dimensions:");
+            final Label label = new Label(vocabulary.getString(Vocabulary.Keys.SampleDimensions));
             label.setLabelFor(sampleDimensions);
             coveragePane = new VBox(label, sampleDimensions);
         }
 
         final Accordion controls = new Accordion(
-                new TitledPane("Coverage", coveragePane)
+                new TitledPane(vocabulary.getString(Vocabulary.Keys.Coverage), coveragePane)
                 // TODO: more controls to be added in a future version.
         );
         content = new SplitPane(controls, gridView);
@@ -100,7 +106,7 @@ public class CoverageExplorer {
         content.setDividerPosition(0, Styles.INITIAL_SPLIT);
 
         coverageProperty = new SimpleObjectProperty<>(this, "coverage");
-        coverageProperty.addListener(this::coverageDefined);
+        coverageProperty.addListener(this::onCoverageSpecified);
     }
 
     /**
@@ -152,6 +158,7 @@ public class CoverageExplorer {
         if (source == null) {
             setCoverage((GridCoverage) null);
         } else {
+            source.addListener(this);
             gridView.setImage(source);
         }
     }
@@ -163,8 +170,8 @@ public class CoverageExplorer {
      * @param  previous  ignored.
      * @param  coverage  the new coverage.
      */
-    private void coverageDefined(final ObservableValue<? extends GridCoverage> property,
-                                 final GridCoverage previous, final GridCoverage coverage)
+    private void onCoverageSpecified(final ObservableValue<? extends GridCoverage> property,
+                                     final GridCoverage previous, final GridCoverage coverage)
     {
         gridView.setImage((RenderedImage) null);
         if (coverage != null) {
@@ -174,4 +181,36 @@ public class CoverageExplorer {
             sampleDimensions.getItems().clear();
         }
     }
+
+    /**
+     * Invoked in JavaFX thread by {@link ImageLoader} when the coverage has been read.
+     * This method does not set the image because it will be set by {@link ImageLoader}.
+     * This method is invoked only as a step during the loading process, which is continuing
+     * after this method invocation.
+     *
+     * @param  coverage  the new coverage, or {@code null} if loading failed.
+     */
+    final void onLoadStep(final GridCoverage coverage) {
+        final ObservableList<SampleDimension> items = sampleDimensions.getItems();
+        if (coverage != null) {
+            items.setAll(coverage.getSampleDimensions());
+        } else {
+            items.clear();
+        }
+    }
+
+    /**
+     * A row in the list of sample dimensions.
+     */
+    private static final class SampleDimensionCell extends ListCell<SampleDimension> {
+        /** Invoked by lambda function (needs this exact signature). */
+        SampleDimensionCell(final ListView<SampleDimension> list) {
+        }
+
+        /** Invoked when a new sample dimension needs to be shown. */
+        @Override public void updateItem(final SampleDimension item, final boolean empty) {
+            super.updateItem(item, empty);
+            setText(empty ? "" : item.getName().toString());
+        }
+    }
 }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
index 0e14c1d..e9cec04 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
@@ -254,8 +254,8 @@ public class GridView extends Control {
         tileHeight       = 1;       // For avoiding division by zero.
 
         setMinSize(120, 40);        // 2 cells on each dimension.
-        imageProperty.addListener(this::imageDefined);
-        bandProperty .addListener(this::bandDefined);
+        imageProperty.addListener(this::onImageSpecified);
+        bandProperty .addListener(this::onBandSpecified);
         // Other listeners registered by GridViewSkin.Flow.
     }
 
@@ -352,8 +352,8 @@ public class GridView extends Control {
      * @param  image     the new image to show. May be {@code null}.
      * @throws ArithmeticException if the "tile grid x/y offset" property is too large.
      */
-    private void imageDefined(final ObservableValue<? extends RenderedImage> property,
-                              final RenderedImage previous, final RenderedImage image)
+    private void onImageSpecified(final ObservableValue<? extends RenderedImage> property,
+                                  final RenderedImage previous, final RenderedImage image)
     {
         if (loader != null) {
             loader.cancel();
@@ -396,8 +396,8 @@ public class GridView extends Control {
      * @param  previous  the previous band index (ignored).
      * @param  band      index of the new band to show.
      */
-    private void bandDefined(final ObservableValue<? extends Number> property,
-                             final Number previous, final Number band)
+    private void onBandSpecified(final ObservableValue<? extends Number> property,
+                                 final Number previous, final Number band)
     {
         configureCellFormat(getImage(), band.intValue());
         contentChanged(false);
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageLoader.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageLoader.java
index 69b6dfa..eb3ff25 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageLoader.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageLoader.java
@@ -17,6 +17,7 @@
 package org.apache.sis.gui.coverage;
 
 import java.awt.image.RenderedImage;
+import javafx.application.Platform;
 import javafx.concurrent.Task;
 import javafx.event.EventHandler;
 import org.apache.sis.coverage.grid.GridCoverage;
@@ -117,6 +118,7 @@ final class ImageLoader extends Task<RenderedImage> {
             cv = request.resource.read(domain, range);                      // May be long to execute.
             cv = cv.forConvertedValues(converted);
             request.coverage = cv;
+            Platform.runLater(request::notifyLoaded);
         }
         if (isCancelled()) {
             return null;
@@ -133,11 +135,12 @@ final class ImageLoader extends Task<RenderedImage> {
 
     /**
      * Invoked in JavaFX thread on failure.
-     * This method popups a dialog box for reporting the error.
+     * Current implementation popups a dialog box for reporting the error.
      */
     @Override
     protected void failed() {
         super.failed();
+        request.notifyListeners(null);
         final GridCoverageResource resource = request.resource;
         if (resource instanceof StoreListeners) {
             ExceptionReporter.canNotReadFile(((StoreListeners) resource).getSourceName(), getException());
@@ -145,4 +148,13 @@ final class ImageLoader extends Task<RenderedImage> {
             ExceptionReporter.canNotUseResource(getException());
         }
     }
+
+    /**
+     * Invoked in JavaFX thread in case of cancellation.
+     */
+    @Override
+    protected void cancelled() {
+        super.cancelled();
+        request.notifyListeners(null);
+    }
 }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageRequest.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageRequest.java
index 3f32f09..b766222 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageRequest.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageRequest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.gui.coverage;
 
+import java.util.Arrays;
 import java.util.Optional;
 import java.util.OptionalInt;
 import org.apache.sis.storage.GridCoverageResource;
@@ -90,6 +91,15 @@ public class ImageRequest {
     private int overviewSize;
 
     /**
+     * The coverage explorers to inform when {@link #coverage} become available, or {@code null} if none.
+     * We do not provide a more generic listeners API for now, but it could be done in the future if there
+     * is a need for that.
+     *
+     * @see #addListener(CoverageExplorer)
+     */
+    private CoverageExplorer[] listeners;
+
+    /**
      * Creates a new request for loading an image from the specified resource.
      * If {@code domain} and {@code range} arguments are null, then the full coverage will be loaded.
      * For loading a smaller amount of data, sub-domain or sub-range can be specified as documented
@@ -238,4 +248,44 @@ public class ImageRequest {
         ArgumentChecks.ensureStrictlyPositive("size", size);
         overviewSize = size;
     }
+
+    /**
+     * Adds a listener to inform when {@link #coverage} become available. We do not provide a more
+     * generic listeners API for now, but it could be done in the future if there is a need for that.
+     *
+     * <p>All listeners are discarded after the reading process.</p>
+     */
+    final void addListener(final CoverageExplorer listener) {
+        final int n;
+        if (listeners == null) {                        // Usual case.
+            n = 0;
+            listeners = new CoverageExplorer[1];
+        } else {                                        // Should be very rare.
+            n = listeners.length;
+            listeners = Arrays.copyOf(listeners, n+1);
+        }
+        listeners[n] = listener;
+    }
+
+    /**
+     * Notifies all listeners that the given coverage has been read or failed to be read,
+     * then discards the listeners. This method shall be invoked in JavaFX thread.
+     *
+     * @param  result  the result, or {@code null} on failure.
+     */
+    final void notifyListeners(final GridCoverage result) {
+        final CoverageExplorer[] snapshot = listeners;
+        listeners = null;                                   // Clear now in case an error happen.
+        for (final CoverageExplorer e : snapshot) {
+            e.onLoadStep(result);
+        }
+    }
+
+    /**
+     * Notifies all listeners that the coverage has been read, then discards the listeners.
+     * This method shall be invoked in JavaFX thread.
+     */
+    final void notifyLoaded() {
+        notifyListeners(coverage);
+    }
 }
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 b11d1ca..8e0c617 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
@@ -21,13 +21,13 @@ 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.geometry.Pos;
 import javafx.scene.control.Alert;
 import javafx.scene.control.ContextMenu;
 import javafx.scene.control.DialogPane;
 import javafx.scene.control.Label;
+import javafx.scene.control.Menu;
 import javafx.scene.input.Clipboard;
 import javafx.scene.input.ClipboardContent;
 import javafx.scene.layout.Region;
@@ -47,13 +47,18 @@ import org.apache.sis.util.Classes;
  * @since   1.1
  * @module
  */
-public final class ExceptionReporter implements EventHandler<ActionEvent> {
+public final class ExceptionReporter {
     /**
      * The margin to use for the stack trace. We add some spaces on the top and left sides.
      */
     private static final Insets MARGIN = new Insets(9, 0, 0, 40);
 
     /**
+     * The exception that occurred.
+     */
+    private final Throwable exception;
+
+    /**
      * The component where to show the stack trace.
      */
     private final Label trace;
@@ -63,14 +68,17 @@ public final class ExceptionReporter implements EventHandler<ActionEvent> {
      *
      * @param  exception  the error to report.
      */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")
     public ExceptionReporter(final Throwable exception) {
+        this.exception = exception;
         trace = new Label(getStackTrace(exception));
         trace.setAlignment(Pos.TOP_LEFT);
         trace.setPadding(MARGIN);
 
         final Resources localized = Resources.getInstance();
-        final ContextMenu menu = new ContextMenu();
-        menu.getItems().add(localized.menu(Resources.Keys.Copy, this));
+        final Menu sendTo = new Menu(localized.getString(Resources.Keys.SendTo));
+        sendTo.getItems().add(localized.menu(Resources.Keys.StandardErrorStream, this::printStackTrace));
+        final ContextMenu menu = new ContextMenu(localized.menu(Resources.Keys.Copy, this::copy), sendTo);
         trace.setContextMenu(menu);
     }
 
@@ -205,14 +213,22 @@ public final class ExceptionReporter implements EventHandler<ActionEvent> {
 
     /**
      * 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) {
+    private void copy(final ActionEvent event) {
         final ClipboardContent content = new ClipboardContent();
         content.putString(trace.getText());
         Clipboard.getSystemClipboard().setContent(content);
     }
+
+    /**
+     * Invoked when the user selected the "Send to ⏵ Standard error stream" action in contextual menu.
+     *
+     * @param event ignored.
+     */
+    @SuppressWarnings("CallToPrintStackTrace")
+    private void printStackTrace(final ActionEvent event) {
+        exception.printStackTrace();
+    }
 }
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 f5e3199..782474b 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
@@ -271,11 +271,21 @@ public final class Resources extends IndexedResourceBundle {
         public static final short SelectCRS = 37;
 
         /**
+         * Send to
+         */
+        public static final short SendTo = 49;
+
+        /**
          * Spatial representation
          */
         public static final short SpatialRepresentation = 24;
 
         /**
+         * Standard error stream
+         */
+        public static final short StandardErrorStream = 50;
+
+        /**
          * Summary
          */
         public static final short Summary = 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 8328640..581194d 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
@@ -64,6 +64,8 @@ ReferenceSystem        = Reference system:
 ResourceIdentification = Resource identification
 SpatialRepresentation  = Spatial representation
 SelectCRS              = Select a coordinate reference system
+SendTo                 = Send to
+StandardErrorStream    = Standard error stream
 Summary                = Summary
 TopicCategory          = Topic category:
 TypeOfResource         = Type of resource:
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 a23fb87..de60cb6 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
@@ -69,6 +69,8 @@ ReferenceSystem        = Syst\u00e8me de r\u00e9f\u00e9rence\u00a0:
 ResourceIdentification = Identification de la ressource
 SpatialRepresentation  = Repr\u00e9sentation spatiale
 SelectCRS              = Choisir un syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es
+SendTo                 = Envoyer vers
+StandardErrorStream    = Flux d\u2019erreur standard
 Summary                = R\u00e9sum\u00e9
 TopicCategory          = Cat\u00e9gorie th\u00e9matique\u00a0:
 TypeOfResource         = Type de ressource\u00a0:
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
index 94f8285..9f3d6c0 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
@@ -210,6 +210,11 @@ public final class Vocabulary extends IndexedResourceBundle {
         public static final short Correlation = 28;
 
         /**
+         * Coverage
+         */
+        public static final short Coverage = 190;
+
+        /**
          * Coverage domain
          */
         public static final short CoverageDomain = 29;
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
index 6d2e80a..f605ae9 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
@@ -45,6 +45,7 @@ Conversion              = Conversion
 Coordinate              = Coordinate
 CoordinateRefSys        = Coordinate reference system
 Correlation             = Correlation
+Coverage                = Coverage
 CoverageDomain          = Coverage domain
 Create                  = Create
 CurrentDateTime         = Current date and time
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
index bc1779e..f10f4f1 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
@@ -52,6 +52,7 @@ Conversion              = Conversion
 Coordinate              = Coordonn\u00e9e
 CoordinateRefSys        = Syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es
 Correlation             = Corr\u00e9lation
+Coverage                = Couverture de donn\u00e9es
 CoverageDomain          = Domaine de la couverture de donn\u00e9es
 Create                  = Cr\u00e9ation
 CurrentDateTime         = Date et heure courantes