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 <[email protected]> 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)) {
