sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 01/04: Use CoverageExplorer instead of GridView inside the ResourceExplorer widget. It allows to leverage more of CoverageExplorer services such as coordinate transformations.
Date Fri, 01 May 2020 22:59:42 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 130ea87b099b8473ed61916ae5b73e48f6ad5ba0
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri May 1 18:46:00 2020 +0200

    Use CoverageExplorer instead of GridView inside the ResourceExplorer widget.
    It allows to leverage more of CoverageExplorer services such as coordinate transformations.
---
 .../sis/gui/coverage/BandSelectionListener.java    |  13 ++-
 .../apache/sis/gui/coverage/CoverageExplorer.java  | 102 ++++++++++++---------
 .../org/apache/sis/gui/coverage/GridControls.java  |   7 +-
 .../java/org/apache/sis/gui/coverage/GridView.java |  75 +++++++--------
 .../apache/sis/gui/dataset/ResourceExplorer.java   |  17 ++--
 .../java/org/apache/sis/gui/map/StatusBar.java     |   2 +-
 6 files changed, 116 insertions(+), 100 deletions(-)

diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/BandSelectionListener.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/BandSelectionListener.java
index 6cf137c..8cc743e 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/BandSelectionListener.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/BandSelectionListener.java
@@ -54,11 +54,14 @@ final class BandSelectionListener implements ChangeListener<Number>
{
      */
     @Override
     public void changed(ObservableValue<? extends Number> property, Number oldValue,
Number newValue) {
-        if (!isAdjusting) try {
-            isAdjusting = true;
-            bandProperty.set(newValue.intValue());
-        } finally {
-            isAdjusting = false;
+        final int row = newValue.intValue();
+        if (row >= 0) {                         // Negative if table became empty after
image became null.
+            if (!isAdjusting) try {
+                isAdjusting = true;
+                bandProperty.set(row);
+            } finally {
+                isAdjusting = false;
+            }
         }
     }
 }
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 8712a48..2a52f87 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
@@ -24,7 +24,6 @@ import javafx.scene.control.ToggleGroup;
 import javafx.scene.control.Toggle;
 import javafx.scene.layout.Region;
 import javafx.event.ActionEvent;
-import javafx.beans.value.ObservableValue;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import org.apache.sis.coverage.grid.GridCoverage;
@@ -32,8 +31,10 @@ import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.internal.gui.Resources;
 import org.apache.sis.internal.gui.ToolbarButton;
 import org.apache.sis.internal.gui.NonNullObjectProperty;
+import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.gui.referencing.RecentReferenceSystems;
+import org.apache.sis.gui.map.StatusBar;
 import org.apache.sis.gui.Widget;
 
 
@@ -124,12 +125,12 @@ public class CoverageExplorer extends Widget {
     private boolean isCoverageAdjusting;
 
     /**
-     * The control that put everything together.
+     * The control that put everything together, created when first requested.
      * The type of control may change in any future SIS version.
      *
      * @see #getView()
      */
-    private final SplitPane content;
+    private SplitPane content;
 
     /**
      * The different views we can provide on {@link #coverageProperty},
@@ -148,24 +149,15 @@ public class CoverageExplorer extends Widget {
     public CoverageExplorer() {
         coverageProperty = new SimpleObjectProperty<>(this, "coverage");
         viewTypeProperty = new NonNullObjectProperty<>(this, "viewType", View.TABLE);
-        coverageProperty.addListener(this::onCoverageSpecified);
-        viewTypeProperty.addListener(this::onViewTypeSpecified);
+        coverageProperty.addListener((p,o,n) -> onCoverageSpecified(n));
         referenceSystems = new RecentReferenceSystems();
         referenceSystems.addUserPreferences();
         referenceSystems.addAlternatives("EPSG:4326", "EPSG:3395");         // WGS 84 / World
Mercator
         /*
-         * Prepare buttons to add on the toolbar. Those buttons are not managed by this class;
-         * they are managed by org.apache.sis.gui.dataset.DataWindow. We only declare here
the
-         * text and action for each button.
-         */
-        final View[]  viewTypes = View.values();
-        final ToggleGroup group = new ToggleGroup();
-        final Control[] buttons = new Control[viewTypes.length + 1];
-        buttons[0] = new Separator();
-        /*
          * The coverage property may be shown in various ways (tabular data, image).
          * Each visualization way is an entry in the `views` array.
          */
+        final View[]     viewTypes  = View.values();
         final Locale     locale     = null;
         final Resources  localized  = Resources.forLocale(locale);
         final Vocabulary vocabulary = Vocabulary.getResources(locale);
@@ -179,15 +171,57 @@ public class CoverageExplorer extends Widget {
             }
             SplitPane.setResizableWithParent(c.controls(), Boolean.FALSE);
             SplitPane.setResizableWithParent(c.view(),     Boolean.TRUE);
-            c.selector = new Selector(type).createButton(group, type.icon, localized, type.tooltip);
-            buttons[buttons.length - type.ordinal() - 1] = c.selector;  // Buttons in reverse
order.
             views[type.ordinal()] = c;
         }
-        final Controls c = views[0];                            // First View enumeration
is default value.
-        group.selectToggle(group.getToggles().get(0));
-        content = new SplitPane(c.controls(), c.view());
-        content.setDividerPosition(0, INITIAL_SPLIT);
-        ToolbarButton.insert(content, buttons);
+    }
+
+    /**
+     * Returns the region containing the grid or coverage view, band selector and any control
managed by this
+     * {@code CoverageExplorer}. The {@link Region} subclass returned by this method is implementation
dependent
+     * and may change in any future version.
+     *
+     * @return the region to show.
+     */
+    @Override
+    public final Region getView() {
+        if (content == null) {
+            /*
+             * Prepare buttons to add on the toolbar. Those buttons are not managed by this
class;
+             * they are managed by org.apache.sis.gui.dataset.DataWindow. We only declare
here the
+             * text and action for each button.
+             */
+            final Locale      locale  = null;
+            final ToggleGroup group   = new ToggleGroup();
+            final Control[]   buttons = new Control[views.length + 1];
+            final Resources localized = Resources.forLocale(locale);
+            buttons[0] = new Separator();
+            for (final View type : View.values()) {
+                final Controls c = views[type.ordinal()];
+                c.selector = new Selector(type).createButton(group, type.icon, localized,
type.tooltip);
+                buttons[buttons.length - type.ordinal() - 1] = c.selector;  // Buttons in
reverse order.
+            }
+            final Controls c = views[0];                            // First View enumeration
is default value.
+            group.selectToggle(group.getToggles().get(0));
+            content = new SplitPane(c.controls(), c.view());
+            content.setDividerPosition(0, INITIAL_SPLIT);
+            ToolbarButton.insert(content, buttons);
+            viewTypeProperty.addListener((p,o,n) -> onViewTypeSpecified(n));
+        }
+        return content;
+    }
+
+    /**
+     * Returns the region containing the only the data visualization part, without controls.
+     * This is a {@link GridView} or {@link CoverageCanvas} together with their {@link StatusBar}.
+     * The {@link Region} subclass returned by this method is implementation dependent and
may change
+     * in any future version.
+     *
+     * @param  view  whether to obtain a {@link GridView} or {@link CoverageCanvas}.
+     * @return the requested view for the {@link #coverageProperty}.
+     */
+    public final Region getDataView(final View view) {
+        ArgumentChecks.ensureNonNull("view", view);
+        return views[view.ordinal()].view();
     }
 
     /**
@@ -214,18 +248,6 @@ public class CoverageExplorer extends Widget {
     }
 
     /**
-     * Returns the region containing the grid view, band selector and any other control managed
-     * by this {@code CoverageExplorer}. The subclass is implementation dependent and may
change
-     * in any future version.
-     *
-     * @return the region to show.
-     */
-    @Override
-    public final Region getView() {
-        return content;
-    }
-
-    /**
      * Returns the source of sample values for this explorer.
      * This method, like all other methods in this class, shall be invoked from the JavaFX
thread.
      *
@@ -273,13 +295,9 @@ public class CoverageExplorer extends Widget {
      * This method notifies the GUI controls about the change then starts loading
      * data in a background thread.
      *
-     * @param  property  the {@link #coverageProperty} (ignored).
-     * @param  previous  ignored.
      * @param  coverage  the new coverage.
      */
-    private void onCoverageSpecified(final ObservableValue<? extends GridCoverage>
property,
-                                     final GridCoverage previous, final GridCoverage coverage)
-    {
+    private void onCoverageSpecified(final GridCoverage coverage) {
         if (!isCoverageAdjusting) {
             startLoading(null);                                         // Clear data.
             notifyCoverageChange(coverage);
@@ -364,13 +382,9 @@ public class CoverageExplorer extends Widget {
     /**
      * Invoked when a new view type has been specified.
      *
-     * @param  property  the {@link #viewTypeProperty} (ignored).
-     * @param  previous  ignored.
-     * @param  view      the new view type.
+     * @param  view  the new view type.
      */
-    private void onViewTypeSpecified(final ObservableValue<? extends View> property,
-                                     final View previous, final View view)
-    {
+    private void onViewTypeSpecified(final View view) {
         final Controls c = views[view.ordinal()];
         content.getItems().setAll(c.controls(), c.view());
         ((Toggle) c.selector).setSelected(true);
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridControls.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridControls.java
index d729726..f569356 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridControls.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridControls.java
@@ -17,7 +17,6 @@
 package org.apache.sis.gui.coverage;
 
 import javafx.beans.property.DoubleProperty;
-import javafx.beans.value.ObservableValue;
 import javafx.collections.ObservableList;
 import javafx.scene.control.Accordion;
 import javafx.scene.control.Control;
@@ -68,7 +67,7 @@ final class GridControls extends Controls {
         view = new GridView(referenceSystems);
         sampleDimensions = new CategoryCellFactory(view.cellFormat).createSampleDimensionTable(vocabulary);
         sampleDimensions.getSelectionModel().selectedIndexProperty().addListener(new BandSelectionListener(view.bandProperty));
-        view.bandProperty.addListener(this::onBandSpecified);
+        view.bandProperty.addListener((p,o,n) -> onBandSpecified(n));
         /*
          * "Coverage" section with the following controls:
          *    - Coverage domain as a list of CRS dimensions with two of them selected (TODO).
@@ -124,9 +123,7 @@ final class GridControls extends Controls {
      * Invoked when the band property changed. This method ensures that the selected row
      * in the sample dimension table matches the band which is shown in the grid view.
      */
-    private void onBandSpecified(final ObservableValue<? extends Number> property,
-                                 final Number previous, final Number band)
-    {
+    private void onBandSpecified(final Number band) {
         sampleDimensions.getSelectionModel().clearAndSelect(band.intValue());
     }
 
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 54aa1f4..3493479 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
@@ -26,12 +26,11 @@ import java.awt.image.DataBuffer;
 import javafx.beans.DefaultProperty;
 import javafx.beans.property.DoubleProperty;
 import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.IntegerPropertyBase;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleDoubleProperty;
-import javafx.beans.property.SimpleIntegerProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.property.StringProperty;
-import javafx.beans.value.ObservableValue;
 import javafx.concurrent.WorkerStateEvent;
 import javafx.scene.control.Control;
 import javafx.scene.control.Skin;
@@ -224,8 +223,8 @@ public class GridView extends Control {
      * @param  referenceSystems  the manager of reference systems chosen by the user, or
{@code null} if none.
      */
     GridView(final RecentReferenceSystems referenceSystems) {
+        bandProperty     = new BandProperty();
         imageProperty    = new SimpleObjectProperty<>(this, "image");
-        bandProperty     = new SimpleIntegerProperty (this, "band");
         headerWidth      = new SimpleDoubleProperty  (this, "headerWidth", 60);
         cellWidth        = new SimpleDoubleProperty  (this, "cellWidth",   60);
         cellHeight       = new SimpleDoubleProperty  (this, "cellHeight",  20);
@@ -238,12 +237,42 @@ public class GridView extends Control {
         tileHeight       = 1;       // For avoiding division by zero.
 
         setMinSize(120, 40);        // 2 cells on each dimension.
-        imageProperty.addListener(this::onImageSpecified);
-        bandProperty .addListener(this::onBandSpecified);
+        imageProperty.addListener((p,o,n) -> onImageSpecified(n));
         // Other listeners registered by GridViewSkin.Flow.
     }
 
     /**
+     * The property for selecting the band to show. This property verifies
+     * the validity of given band argument before to modify the value.
+     *
+     * @see #getBand()
+     * @see #setBand(int)
+     */
+    private final class BandProperty extends IntegerPropertyBase {
+        @Override public Object getBean() {return GridView.this;}
+        @Override public String getName() {return "band";}
+
+        /** Invoked when a new band is selected. */
+        @Override public void set(final int band) {
+            final RenderedImage image = getImage();
+            final SampleModel sm;
+            if (image != null && (sm = image.getSampleModel()) != null) {
+                ArgumentChecks.ensureBetween("band", 0, sm.getNumBands() - 1, band);
+                cellFormat.configure(image, band);
+            } else {
+                ArgumentChecks.ensurePositive("band", band);
+            }
+            super.set(band);
+            contentChanged(false);
+        }
+
+        /** Sets the band without performing checks, except ensuring that value is positive.
*/
+        final void setNoCheck(final int bands) {
+            super.set(Math.max(bands, 0));
+        }
+    }
+
+    /**
      * Returns the source of sample values for this table.
      * This method, like all other methods in this class, shall be invoked from the JavaFX
thread.
      *
@@ -308,13 +337,6 @@ public class GridView extends Control {
      * @throws IllegalArgumentException if the given band index is out of bounds.
      */
     public final void setBand(final int index) {
-        final RenderedImage image = getImage();
-        final SampleModel sm;
-        if (image != null && (sm = image.getSampleModel()) != null) {
-            ArgumentChecks.ensureBetween("band", 0, sm.getNumBands() - 1, index);
-        } else {
-            ArgumentChecks.ensurePositive("band", index);
-        }
         bandProperty.set(index);
     }
 
@@ -334,14 +356,10 @@ public class GridView extends Control {
      * Invoked (indirectly) when the user sets a new {@link RenderedImage}.
      * See {@link #setImage(RenderedImage)} for more description.
      *
-     * @param  property  the {@link #imageProperty} (ignored).
-     * @param  previous  the previous image (ignored).
-     * @param  image     the new image to show. May be {@code null}.
+     * @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 onImageSpecified(final ObservableValue<? extends RenderedImage> property,
-                                  final RenderedImage previous, final RenderedImage image)
-    {
+    private void onImageSpecified(final RenderedImage image) {
         if (loader != null) {
             loader.cancel();
             loader = null;
@@ -364,33 +382,18 @@ public class GridView extends Control {
             final SampleModel sm = image.getSampleModel();
             if (sm != null) {                               // Should never be null, but
we are paranoiac.
                 final int numBands = sm.getNumBands();
-                if (bandProperty.get() >= numBands) {
-                    bandProperty.set(numBands - 1);
+                if (getBand() >= numBands) {
+                    ((BandProperty) bandProperty).setNoCheck(numBands - 1);
                 }
                 final int dataType = sm.getDataType();
                 cellFormat.dataTypeisInteger = (dataType >= DataBuffer.TYPE_BYTE &&
dataType <= DataBuffer.TYPE_INT);
             }
-            cellFormat.configure(image, bandProperty.getValue());
+            cellFormat.configure(image, getBand());
         }
         contentChanged(true);
     }
 
     /**
-     * Invoked (indirectly) when the user selects a new band.
-     * See {@link #setBand(int)} for more description.
-     *
-     * @param  property  the {@link #bandProperty} (ignored).
-     * @param  previous  the previous band index (ignored).
-     * @param  band      index of the new band to show.
-     */
-    private void onBandSpecified(final ObservableValue<? extends Number> property,
-                                 final Number previous, final Number band)
-    {
-        cellFormat.configure(getImage(), band.intValue());
-        contentChanged(false);
-    }
-
-    /**
      * Invoked when the content may have changed. If {@code all} is {@code true}, then everything
      * may have changed including the number of rows and columns. If {@code all} is {@code
false}
      * then the number of rows and columns is assumed the same.
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceExplorer.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceExplorer.java
index 27a6dcf..d8fb993 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceExplorer.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/dataset/ResourceExplorer.java
@@ -23,7 +23,6 @@ import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ObservableValue;
 import javafx.collections.ListChangeListener;
 import javafx.scene.layout.Region;
-import javafx.scene.control.Control;
 import javafx.scene.control.ContextMenu;
 import javafx.scene.control.SplitPane;
 import javafx.scene.control.Tab;
@@ -34,8 +33,8 @@ import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.gui.metadata.MetadataSummary;
 import org.apache.sis.gui.metadata.MetadataTree;
 import org.apache.sis.gui.metadata.StandardMetadataTree;
-import org.apache.sis.gui.coverage.GridView;
 import org.apache.sis.gui.coverage.ImageRequest;
+import org.apache.sis.gui.coverage.CoverageExplorer;
 import org.apache.sis.internal.gui.Resources;
 import org.apache.sis.storage.GridCoverageResource;
 import org.apache.sis.util.collection.TableColumn;
@@ -43,7 +42,7 @@ import org.apache.sis.util.resources.Vocabulary;
 
 
 /**
- * A panel showing a {@linkplain ResourceTree tree of resources} together with their metadata.
+ * A panel showing a {@linkplain ResourceTree tree of resources} together with their metadata
and data views.
  *
  * @author  Smaniotto Enzo (GSoC)
  * @author  Martin Desruisseaux (Geomatys)
@@ -70,7 +69,7 @@ public class ResourceExplorer extends WindowManager {
     /**
      * The data as a grid coverage, created when first needed.
      */
-    private GridView coverage;
+    private CoverageExplorer coverage;
 
     /**
      * The widget showing metadata about a selected resource.
@@ -86,7 +85,7 @@ public class ResourceExplorer extends WindowManager {
     private final SplitPane content;
 
     /**
-     * The tab where to show {@link #features} or {@link #coverage}, depending on the kind
of resource.
+     * The tab where to show {@link #features} or {@link #coverage} numerical data, depending
on the kind of resource.
      * The data will be set only if this tab is visible, because their loading may be costly.
      */
     private final Tab dataTab;
@@ -218,16 +217,16 @@ public class ResourceExplorer extends WindowManager {
      * @param  resource  the resource to set, or {@code null} if none.
      */
     private void updateDataTab(final Resource resource) {
-        Control      view  = null;
+        Region       view  = null;
         FeatureSet   table = null;
         ImageRequest grid  = null;
         if (resource instanceof GridCoverageResource) {
             grid = new ImageRequest((GridCoverageResource) resource, null, 0);
             grid.setOverviewSize(OVERVIEW_SIZE);
             if (coverage == null) {
-                coverage = new GridView();
+                coverage = new CoverageExplorer();
             }
-            view = coverage;
+            view = coverage.getDataView(CoverageExplorer.View.TABLE);
         } else if (resource instanceof FeatureSet) {
             table = (FeatureSet) resource;
             if (features == null) {
@@ -239,7 +238,7 @@ public class ResourceExplorer extends WindowManager {
          * At least one of `grid` or `table` will be null. Invoking the following
          * setter methods with a null argument will release memory.
          */
-        if (coverage != null) coverage.setImage(grid);
+        if (coverage != null) coverage.setCoverage(grid);
         if (features != null) features.setFeatures(table);
         if (view     != null) dataTab .setContent(view);
         if (isDataTabSet) {
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
index 44716aa..e0690b5 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/map/StatusBar.java
@@ -635,7 +635,7 @@ public class StatusBar extends Widget implements EventHandler<MouseEvent>
{
      *         will return a little bit later (pending completion of a background task).
      */
     private CoordinateReferenceSystem setReplaceablePositionCRS(CoordinateReferenceSystem
crs) {
-        if (crs != null) {
+        if (crs != null && systemChooser != null) {
             final ComparisonMode mode = systemChooser.duplicationCriterion.get();
             for (final ReferenceSystem system : systemChooser.getItems()) {
                 if (Utilities.deepEquals(crs, system, mode)) {


Mime
View raw message