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 b07299c Connect Gridview to the ResourceExplorer: grid data are now
shown when a GridCoverageResource is selected.
b07299c is described below
commit b07299cbb7780e743242249a75474481096bfcde
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Jan 29 19:54:43 2020 +0100
Connect Gridview to the ResourceExplorer: grid data are now shown when a
GridCoverageResource is selected.
---
.../java/org/apache/sis/gui/coverage/GridRow.java | 1 +
.../java/org/apache/sis/gui/coverage/GridView.java | 65 +++++--
.../org/apache/sis/gui/coverage/GridViewSkin.java | 9 +-
.../org/apache/sis/gui/coverage/ImageLoader.java | 129 +++++++++++++
.../org/apache/sis/gui/coverage/ImageRequest.java | 199 +++++++++++++++++++++
.../apache/sis/gui/dataset/ResourceExplorer.java | 49 ++++-
.../org/apache/sis/gui/metadata/MetadataTree.java | 6 +-
7 files changed, 434 insertions(+), 24 deletions(-)
diff --git
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRow.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRow.java
index 721d2aa..732ce9a 100644
---
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRow.java
+++
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridRow.java
@@ -65,6 +65,7 @@ final class GridRow extends IndexedCell<Void> {
view = (GridView) owner.getParent();
setPrefWidth(view.getContentWidth());
setFont(Font.font(null, FontWeight.BOLD, -1)); // Apply only to
the header column.
+ setManaged(false);
}
/**
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 1a44ed4..bc40188 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
@@ -31,12 +31,14 @@ import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
+import javafx.concurrent.WorkerStateEvent;
import javafx.scene.control.Control;
import javafx.scene.control.Skin;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.internal.gui.BackgroundThreads;
/**
@@ -46,8 +48,8 @@ import org.apache.sis.coverage.grid.GridCoverage;
* dimension).
*
* <p>This class is designed for large images, with tiles loaded in a
background thread only when first needed.
- * For matrices of relatively small size (e.g. less than 100 columns),
consider using the standard JavaFX
- * {@link javafx.scene.control.TableView} instead.</p>
+ * This is not a general purpose grid viewer; for matrices of relatively small
size (e.g. less than 100 columns),
+ * consider using the standard JavaFX {@link javafx.scene.control.TableView}
instead.</p>
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.1
@@ -69,6 +71,13 @@ public class GridView extends Control {
static final String OUT_OF_BOUNDS = "";
/**
+ * If a loading is in progress, the loading process. Otherwise {@code
null}.
+ *
+ * @see #coverageDefined(WorkerStateEvent)
+ */
+ private ImageLoader loader;
+
+ /**
* The data shown in this table. Note that setting this property to a
non-null value may not
* modify the grid content immediately. Instead, a background process will
request the tiles.
*
@@ -225,12 +234,13 @@ public class GridView extends Control {
tileHeight = 1; // For avoiding division by zero.
setMinSize(120, 40); // 2 cells on each dimension.
- imageProperty.addListener(this::startImageLoading);
+ imageProperty.addListener(this::imageDefined);
// Other listeners registered by GridViewSkin.Flow.
}
/**
* 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.
*
* @return the image shown in this table, or {@code null} if none.
*
@@ -241,12 +251,9 @@ public class GridView extends Control {
}
/**
- * Sets the image to show in this table. This method loads an arbitrary
amount of tiles
- * in a background thread. It does not load all tiles if the image is
large, unless the
- * user scroll over all tiles.
- *
- * <p><b>Note:</b> the table content may appear unmodified after this
method returns.
- * The modifications will appear at an undetermined amount of time
later.</p>
+ * Sets the image to show in this table.
+ * This method shall be invoked from JavaFX thread and returns quickly; it
does not attempt to fetch any tile.
+ * Calls to {@link RenderedImage#getTile(int, int)} will be done in a
background thread when first needed.
*
* @param image the image to show in this table, or {@code null} if none.
*
@@ -257,6 +264,27 @@ public class GridView extends Control {
}
/**
+ * Loads image in a background thread from the given source.
+ * This method shall be invoked from JavaFX thread and returns immediately.
+ * The grid content may appear unmodified after this method returns;
+ * the modifications will appear after an undetermined amount of time.
+ *
+ * @param source the coverage or resource to load, or {@code null} if
none.
+ */
+ public void setImage(final ImageRequest source) {
+ if (source == null) {
+ setImage((RenderedImage) null);
+ } else {
+ if (loader != null) {
+ loader.cancel();
+ }
+ loader = new ImageLoader(source);
+ loader.setOnSucceeded(this::coverageDefined);
+ BackgroundThreads.execute(loader);
+ }
+ }
+
+ /**
* Returns the index of the band shown in this grid view.
*
* @return index of the currently visible band number.
@@ -286,6 +314,15 @@ public class GridView extends Control {
}
/**
+ * Invoked in JavaFX thread after {@link #loader} completed its task
successfully.
+ */
+ private void coverageDefined(final WorkerStateEvent event) {
+ final ImageLoader result = loader;
+ loader = null;
+ setImage(result.getValue());
+ }
+
+ /**
* Invoked (indirectly) when the user sets a new {@link RenderedImage}.
* See {@link #setImage(RenderedImage)} for method description.
*
@@ -294,9 +331,13 @@ 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 startImageLoading(final ObservableValue<? extends
RenderedImage> property,
- final RenderedImage previous, final
RenderedImage image)
+ private void imageDefined(final ObservableValue<? extends RenderedImage>
property,
+ final RenderedImage previous, final
RenderedImage image)
{
+ if (loader != null) {
+ loader.cancel();
+ loader = null;
+ }
tiles.clear(); // Let garbage collector dispose the rasters.
lastTile = null;
width = 0;
@@ -332,8 +373,8 @@ public class GridView extends Control {
cellFormat.setMaximumFractionDigits(1);
}
formatChanged(false);
- contentChanged(true);
}
+ contentChanged(true);
}
/**
diff --git
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridViewSkin.java
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridViewSkin.java
index e5a346d..e40f577 100644
---
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridViewSkin.java
+++
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridViewSkin.java
@@ -28,6 +28,8 @@ import javafx.scene.control.skin.VirtualFlow;
import javafx.scene.control.skin.VirtualContainerBase;
import javafx.scene.layout.HBox;
import javafx.scene.shape.Rectangle;
+import javafx.scene.text.FontWeight;
+import javafx.scene.text.Font;
/**
@@ -382,8 +384,11 @@ final class GridViewSkin extends
VirtualContainerBase<GridView, GridRow> {
children.remove(missing + count, count); // Too
many children. Remove the extra ones.
} else {
final GridCell[] more = new GridCell[missing];
+ final Font font = Font.font(null, FontWeight.BOLD, -1);
for (int i=0; i<missing; i++) {
- more[i] = new GridCell();
+ final GridCell cell = new GridCell();
+ cell.setFont(font);
+ more[i] = cell;
}
children.addAll(more); // Single addAll(…)
operation for sending only one event.
}
@@ -392,7 +397,7 @@ final class GridViewSkin extends
VirtualContainerBase<GridView, GridRow> {
int column = firstVisibleColumn;
for (final Node cell : children) {
((GridCell) cell).setText(view.formatHeaderValue(column++,
false));
- layoutInArea(cell, pos, y, cellWidth, headerHeight,
Node.BASELINE_OFFSET_SAME_AS_HEIGHT, HPos.CENTER, VPos.CENTER);
+ layoutInArea(cell, pos, y, cellWidth, headerHeight,
Node.BASELINE_OFFSET_SAME_AS_HEIGHT, HPos.RIGHT, VPos.CENTER);
pos += cellWidth;
}
}
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
new file mode 100644
index 0000000..236b0f0
--- /dev/null
+++
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageLoader.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.gui.coverage;
+
+import java.awt.image.RenderedImage;
+import javafx.concurrent.Task;
+import javafx.event.EventHandler;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.storage.event.StoreListeners;
+import org.apache.sis.internal.gui.ExceptionReporter;
+
+
+/**
+ * A task for loading {@link GridCoverage} from a resource in a background
thread, then fetching an image from it.
+ * Callers needs to define a task to execute on success with {@link
#setOnSucceeded(EventHandler)}.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since 1.1
+ * @module
+ */
+final class ImageLoader extends Task<RenderedImage> {
+ /**
+ * The {@value} value, for identifying code that assume two-dimensional
objects.
+ */
+ public static final int BIDIMENSIONAL = 2;
+
+ /**
+ * The image source together with optional parameters for reading only a
subset.
+ */
+ private final ImageRequest request;
+
+ /**
+ * The grid coverage obtained from the resource.
+ */
+ private volatile GridCoverage coverage;
+
+ /**
+ * Creates a new task for loading an image from the specified resource.
+ *
+ * @param request source of the image to load.
+ */
+ ImageLoader(final ImageRequest request) {
+ this.request = request;
+ coverage = request.coverage;
+ }
+
+ /**
+ * Returns the grid coverage loaded by this method.
+ * This method can be invoked from any thread.
+ *
+ * @return the coverage, or {@code null} if none.
+ */
+ final GridCoverage getCoverage() {
+ return coverage;
+ }
+
+ /**
+ * Loads the image. Current implementation reads the full image. If the
coverage has more than 2 dimensions,
+ * only two of them are taken for the image; for all other dimensions,
only the values at lowest index will
+ * be read.
+ *
+ * @return the image loaded from the source given at construction time.
+ * @throws DataStoreException if an error occurred while loading the grid
coverage.
+ */
+ @Override
+ protected RenderedImage call() throws DataStoreException {
+ GridCoverage cv = coverage;
+ if (cv == null) {
+ final GridGeometry domain = request.getDomain().orElse(null);
+ final int[] range = request.getRange() .orElse(null);
+ coverage = cv = request.resource.read(domain, range); // May
be long to execute.
+ }
+ if (isCancelled()) {
+ return null;
+ }
+ GridExtent sliceExtent = request.getSliceExtent().orElse(null);
+ if (sliceExtent == null) {
+ final GridGeometry gg = cv.getGridGeometry();
+ if (gg != null && gg.getDimension() > BIDIMENSIONAL) { //
Should never be null but we are paranoiac.
+ final GridExtent extent = gg.getExtent();
+ final int dimension = extent.getDimension();
+ final int[] sliceDimensions = new int[BIDIMENSIONAL];
+ int k = 0;
+ for (int i=0; i<dimension; i++) {
+ if (extent.getLow(i) != extent.getHigh(i)) {
+ sliceDimensions[k] = i;
+ if (++k >= BIDIMENSIONAL) break;
+ }
+ }
+ sliceExtent = gg.derive().sliceByRatio(0,
sliceDimensions).getIntersection();
+ }
+ }
+ return cv.render(sliceExtent);
+ }
+
+ /**
+ * Invoked in JavaFX thread on failure.
+ * This method popups a dialog box for reporting the error.
+ */
+ @Override
+ protected void failed() {
+ super.failed();
+ final GridCoverageResource resource = request.resource;
+ if (resource instanceof StoreListeners) {
+ ExceptionReporter.canNotReadFile(((StoreListeners)
resource).getSourceName(), getException());
+ } else {
+ ExceptionReporter.canNotUseResource(getException());
+ }
+ }
+}
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
new file mode 100644
index 0000000..05b8b87
--- /dev/null
+++
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/ImageRequest.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.gui.coverage;
+
+import java.util.Optional;
+import java.util.concurrent.Future;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.util.ArgumentChecks;
+
+
+/**
+ * A request for a two-dimensional view of a grid coverage. Those requests can
be used for
+ * {@linkplain GridCoverageResource#read(GridGeometry, int...) reading} or
+ * {@linkplain GridCoverage#render(GridExtent) rendering} and image in a
background thread.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since 1.1
+ * @module
+ */
+public class ImageRequest {
+ /**
+ * The source from where to read the image, specified at construction time.
+ */
+ GridCoverageResource resource;
+
+ /**
+ * The source for rendering the image, specified at construction time.
+ * After class initialization, only one of {@link #resource} and {@link
#coverage} is non-null.
+ * But after task execution, this field will be set to the coverage which
has been read.
+ */
+ volatile GridCoverage coverage;
+
+ /**
+ * Desired grid extent and resolution, or {@code null} for reading the
whole domain.
+ * This is used only if the data source is a {@link GridCoverageResource}.
+ */
+ private GridGeometry domain;
+
+ /**
+ * 0-based indices of sample dimensions to read, or {@code null} for
reading them all.
+ * This is used only if the data source is a {@link GridCoverageResource}.
+ */
+ private int[] range;
+
+ /**
+ * A subspace of the grid coverage extent to render, or {@code null} for
the whole extent.
+ * If the extent has more than two dimensions, then the image will be
rendered along the
+ * two first dimensions having a size greater than 1 cell.
+ */
+ private GridExtent sliceExtent;
+
+ /**
+ * 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
+ * in the {@linkplain GridCoverageResource#read(GridGeometry, int...) read
method javadoc}.
+ *
+ * @param source source of the image to load.
+ * @param domain desired grid extent and resolution, or {@code null} for
reading the whole domain.
+ * @param range 0-based indices of sample dimensions to read, or {@code
null} or an empty sequence for reading them all.
+ *
+ * @see GridCoverageResource#read(GridGeometry, int...)
+ */
+ public ImageRequest(final GridCoverageResource source, final GridGeometry
domain, final int[] range) {
+ ArgumentChecks.ensureNonNull("source", source);
+ this.resource = source;
+ this.domain = domain;
+ this.range = (range != null && range.length != 0) ? range.clone() :
null;
+ }
+
+ /**
+ * Creates a new request for loading an image from the specified coverage.
+ * If the {@code sliceExtent} argument is null, then the full coverage
will be rendered
+ * in the first two dimensions having a size greater than 1 cell. For
rendering a smaller amount of data,
+ * or for rendering data along other dimensions, a slice extent can be
specified as documented in the
+ * {@linkplain GridCoverage#render(GridExtent) render method javadoc}.
+ *
+ * @param source source of the image to load.
+ * @param sliceExtent a subspace of the grid coverage extent to render,
or {@code null} for the whole extent.
+ *
+ * @see GridCoverage#render(GridExtent)
+ */
+ public ImageRequest(final GridCoverage source, final GridExtent
sliceExtent) {
+ ArgumentChecks.ensureNonNull("source", source);
+ this.coverage = source;
+ this.sliceExtent = sliceExtent;
+ }
+
+ /**
+ * Returns the desired grid extent and resolution, if any.
+ * This is the {@code domain} argument specified to the following
constructor:
+ *
+ * <blockquote>{@link #ImageRequest(GridCoverageResource, GridGeometry,
int[])}</blockquote>
+ *
+ * and this argument will be transferred verbatim to the following method
+ * (see its javadoc for more explanation):
+ *
+ * <blockquote>{@link GridCoverageResource#read(GridGeometry,
int...)}</blockquote>
+ *
+ * This property is always empty if this image request has been created
with the
+ * {@link #ImageRequest(GridCoverage, GridExtent)} constructor, since no
read
+ * operation will happen in such case.
+ *
+ * @return the desired grid extent and resolution of the coverage.
+ */
+ public Optional<GridGeometry> getDomain() {
+ return Optional.ofNullable(domain);
+ }
+
+ /**
+ * Returns the 0-based indices of sample dimensions to read, or an empty
value for reading them all.
+ * This is the {@code range} argument specified to the following
constructor:
+ *
+ * <blockquote>{@link #ImageRequest(GridCoverageResource, GridGeometry,
int[])}</blockquote>
+ *
+ * and this argument will be transferred verbatim to the following method
+ * (see its javadoc for more explanation):
+ *
+ * <blockquote>{@link GridCoverageResource#read(GridGeometry,
int...)}</blockquote>
+ *
+ * This property is always empty if this image request has been created
with the
+ * {@link #ImageRequest(GridCoverage, GridExtent)} constructor, since no
read
+ * operation will happen in such case.
+ *
+ * @return the 0-based indices of sample dimensions to read.
+ */
+ public Optional<int[]> getRange() {
+ return (range != null) ? Optional.of(range.clone()) : Optional.empty();
+ }
+
+ /**
+ * Returns the subspace of the grid coverage extent to render.
+ * This is the {@code sliceExtent} argument specified to the following
constructor:
+ *
+ * <blockquote>{@link #ImageRequest(GridCoverage, GridExtent)}</blockquote>
+ *
+ * and this argument will be transferred verbatim to the following method
+ * (see its javadoc for more explanation):
+ *
+ * <blockquote>{@link GridCoverage#render(GridExtent)}</blockquote>
+ *
+ * If non-empty, then all dimensions except two should have a size of 1
cell.
+ *
+ * @return subspace of the grid coverage extent to render.
+ */
+ public Optional<GridExtent> getSliceExtent() {
+ return Optional.ofNullable(sliceExtent);
+ }
+
+ /**
+ * Sets a new subspace of the grid coverage extent to render. This {@code
sliceExtent} argument is not specified
+ * to the {@link #ImageRequest(GridCoverageResource, GridGeometry, int[])}
constructor because when reading data
+ * from a {@link GridCoverageResource}, a slicing can already be done by
the {@link GridGeometry} {@code domain}
+ * argument. However in the following scenario, it may be useful to
specify both the {@code domain} and the
+ * {@code sliceExtent}:
+ *
+ * <ol>
+ * <li>A {@link GridCoverageResource} is read with more data than what
we want to show at first.</li>
+ * <li>A subset of loaded data is shown (this is the purpose of {@code
sliceExtent}).</li>
+ * <li>The full coverage is obtained by a call to {@link #getCoverage()}
for performing other operations on it.</li>
+ * </ol>
+ *
+ * That setter method make such scenario possible.
+ *
+ * @param sliceExtent subspace of the grid coverage extent to render.
+ */
+ public void setSliceExtent(final GridExtent sliceExtent) {
+ this.sliceExtent = sliceExtent;
+ }
+
+ /**
+ * Provides the grid coverage when it become available. If the grid
coverage was specified at construction time,
+ * then a call to {@link Future#get()} will return it immediately.
Otherwise that getter method will block until
+ * the read operation completed.
+ *
+ * @return the grid coverage.
+ */
+ public Future<GridCoverage> getCoverage() {
+ throw new UnsupportedOperationException(); // TODO
+ }
+}
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 d3f77c8..5bde500 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
@@ -19,6 +19,7 @@ package org.apache.sis.gui.dataset;
import java.util.Collection;
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;
@@ -28,7 +29,10 @@ import org.apache.sis.storage.Resource;
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.coverage.GridView;
+import org.apache.sis.gui.coverage.ImageRequest;
import org.apache.sis.internal.gui.Resources;
+import org.apache.sis.storage.GridCoverageResource;
/**
@@ -47,9 +51,20 @@ public class ResourceExplorer extends WindowManager {
private final ResourceTree resources;
/**
- * The data as a table.
+ * The tab where to show {@link #features} or {@link #coverage},
+ * depending on the kind of resource.
*/
- private final FeatureTable features;
+ private final Tab dataTab;
+
+ /**
+ * The data as a table, created when first needed.
+ */
+ private FeatureTable features;
+
+ /**
+ * The data as a grid coverage, created when first needed.
+ */
+ private GridView coverage;
/**
* The widget showing metadata about a selected resource.
@@ -70,11 +85,10 @@ public class ResourceExplorer extends WindowManager {
public ResourceExplorer() {
resources = new ResourceTree();
metadata = new MetadataSummary();
- features = new FeatureTable();
content = new SplitPane();
final Resources localized = localized();
- final Tab dataTab = new Tab(localized.getString(Resources.Keys.Data),
features);
+ dataTab = new Tab(localized.getString(Resources.Keys.Data));
dataTab.setContextMenu(new ContextMenu(createNewWindowMenu()));
final TabPane tabs = new TabPane(
new Tab(localized.getString(Resources.Keys.Summary),
metadata.getView()), dataTab,
@@ -143,10 +157,31 @@ public class ResourceExplorer extends WindowManager {
if (resource != null) break;
}
}
- final FeatureSet data = (resource instanceof FeatureSet) ?
(FeatureSet) resource : null;
+ Control view = null;
+ FeatureSet table = null;
+ ImageRequest grid = null;
+ if (resource instanceof GridCoverageResource) {
+ grid = new ImageRequest((GridCoverageResource) resource, null,
null);
+ if (coverage == null) {
+ coverage = new GridView();
+ }
+ view = coverage;
+ } else if (resource instanceof FeatureSet) {
+ table = (FeatureSet) resource;
+ if (features == null) {
+ features = new FeatureTable();
+ }
+ view = features;
+ }
+ /*
+ * 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 (features != null) features.setFeatures(table);
+ dataTab.setContent(view);
metadata.setMetadata(resource);
- features.setFeatures(data);
- setNewWindowDisabled(data == null);
+ setNewWindowDisabled(view == null);
}
/**
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 d809a2f..397303c 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
@@ -291,7 +291,7 @@ public class MetadataTree extends
TreeTableView<TreeTable.Node> {
copy = new MenuItem(md.copy);
copyAsXML = new MenuItem();
copyAsWKT = new MenuItem("WKT — Well Known Text");
- copyAsLegacy = new MenuItem("XML — ISO 19139:2007");
+ copyAsLegacy = new MenuItem("XML — Metadata (2007)");
copyAs = new Menu(md.copyAs, null, copyAsWKT, copyAsXML,
copyAsLegacy);
menu = new ContextMenu(copy, copyAs);
copyAsLegacy.setOnAction(this);
@@ -313,12 +313,12 @@ public class MetadataTree extends
TreeTableView<TreeTable.Node> {
final Object obj = node.getUserObject();
if (obj != null) {
if
(MetadataStandard.ISO_19115.isMetadata(obj.getClass())) {
- copyAsXML.setText("XML — ISO 19115-3:2016");
+ copyAsXML.setText("XML — Metadata (2016)");
copyAsWKT.setDisable(true);
copyAsLegacy.setDisable(false);
disabled = false;
} else if (obj instanceof IdentifiedObject) {
- copyAsXML.setText("GML — Geographic Markup
Language");
+ copyAsXML.setText("XML — Geographic Markup
Language");
copyAsWKT.setDisable(false);
copyAsLegacy.setDisable(true);
disabled = false;