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 32af8e44e5 Implement `ImagePyramid.toString()` for easier debugging.
Use that string representation for now in the widget.
32af8e44e5 is described below
commit 32af8e44e57cc15db0e9043a297fe9aaf6c252c1
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Feb 23 19:46:46 2026 +0100
Implement `ImagePyramid.toString()` for easier debugging.
Use that string representation for now in the widget.
---
.../apache/sis/coverage/grid/GridDerivation.java | 2 +-
.../main/org/apache/sis/referencing/CommonCRS.java | 8 +-
.../referencing/internal/shared/WKTUtilities.java | 4 +-
.../sis/referencing/operation/matrix/Matrices.java | 4 +-
.../operation/transform/PassThroughTransform.java | 2 +-
.../apache/sis/storage/tiling/ImagePyramid.java | 23 +-
.../apache/sis/storage/tiling/ImageTileMatrix.java | 14 +-
.../sis/storage/tiling/TileMatrixFormatter.java | 310 +++++++++++++++++++++
.../sis/storage/tiling/TiledGridCoverage.java | 14 +-
.../storage/tiling/TiledGridCoverageResource.java | 18 +-
.../main/org/apache/sis/math/DecimalFunctions.java | 2 +-
.../main/org/apache/sis/math/Vector.java | 2 +-
.../apache/sis/util/internal/shared/Numerics.java | 55 ++--
.../org/apache/sis/util/resources/Vocabulary.java | 10 +
.../sis/util/resources/Vocabulary.properties | 2 +
.../sis/util/resources/Vocabulary_fr.properties | 4 +-
.../main/org/apache/sis/gui/Widget.java | 8 +-
.../apache/sis/gui/controls/SyncWindowList.java | 6 +-
.../apache/sis/gui/coverage/CoverageExplorer.java | 4 +-
.../apache/sis/gui/coverage/GridSliceSelector.java | 12 +-
.../sis/gui/coverage/ImagePropertyExplorer.java | 6 +-
.../apache/sis/gui/coverage/TileMatrixSetPane.java | 138 +++++----
.../main/org/apache/sis/gui/dataset/LogViewer.java | 5 +-
.../apache/sis/gui/dataset/ResourceExplorer.java | 41 ++-
.../org/apache/sis/gui/dataset/package-info.java | 2 +-
.../apache/sis/gui/internal/io/FileAccessView.java | 4 +-
.../main/org/apache/sis/gui/map/StatusBar.java | 6 +-
.../apache/sis/gui/metadata/MetadataSummary.java | 8 +-
28 files changed, 543 insertions(+), 171 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridDerivation.java
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridDerivation.java
index 982c68a090..8baa7b22f7 100644
---
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridDerivation.java
+++
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridDerivation.java
@@ -336,7 +336,7 @@ public class GridDerivation {
}
/**
- * Specifies an number of cells by which to expand {@code GridExtent}
after rounding.
+ * Specifies a number of cells by which to expand {@code GridExtent} after
rounding.
* This setting modifies computations performed by the following methods:
* <ul>
* <li>{@link #subgrid(GridGeometry)}</li>
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
index a70311ecab..6b09decb55 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
@@ -393,18 +393,18 @@ public enum CommonCRS {
/**
* The Universal Transverse Mercator (UTM) or Universal Polar
Stereographic (UPS) projections,
- * created when first needed. The UPS projections are arbitrarily given
zone numbers
+ * created when first needed. The <abbr>UPS</abbr> projections are
arbitrarily given zone numbers
* {@value #POLAR} and -{@value #POLAR} for North and South poles
respectively.
*
* <p>All accesses to this map shall be synchronized on {@code
cachedProjections}.</p>
*
* @see #universal(double, double)
*/
- private final Map<Integer,ProjectedCRS> cachedProjections;
+ private final Map<Integer, ProjectedCRS> cachedProjections;
/**
* The special zone number used as key in {@link #cachedProjections} for
polar stereographic projections.
- * Must be outside the range of UTM zone numbers.
+ * Must be outside the range of <abbr>UTM</abbr> zone numbers.
*/
private static final int POLAR = 90;
@@ -1193,7 +1193,7 @@ public enum CommonCRS {
CartesianCS cs = null;
if (isUTM) {
synchronized (DEFAULT.cachedProjections) {
- for (final Map.Entry<Integer,ProjectedCRS> entry :
DEFAULT.cachedProjections.entrySet()) {
+ for (final Map.Entry<Integer, ProjectedCRS> entry :
DEFAULT.cachedProjections.entrySet()) {
if (Math.abs(entry.getKey()) != POLAR) {
cs = entry.getValue().getCoordinateSystem();
break;
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/shared/WKTUtilities.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/shared/WKTUtilities.java
index 17a19e841f..840fff8344 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/shared/WKTUtilities.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/shared/WKTUtilities.java
@@ -281,7 +281,7 @@ public final class WKTUtilities {
}
/**
- * Suggests an number of fraction digits to use for formatting numbers in
each column of the given matrix.
+ * Suggests a number of fraction digits to use for formatting numbers in
each column of the given matrix.
* The number of fraction digits may be negative if we could round the
numbers to 10, 100, <i>etc</i>.
*
* @param rows the matrix rows. It is not required that each row has the
same length.
@@ -318,7 +318,7 @@ public final class WKTUtilities {
}
/**
- * Suggests an number of fraction digits to use for formatting numbers in
each column of the given sequence
+ * Suggests a number of fraction digits to use for formatting numbers in
each column of the given sequence
* of points. The number of fraction digits may be negative if we could
round the numbers to 10, <i>etc</i>.
*
* @param crs the coordinate reference system for each points, or
{@code null} if unknown.
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/Matrices.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/Matrices.java
index 66bed3e256..0f9574d43c 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/Matrices.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/matrix/Matrices.java
@@ -609,12 +609,12 @@ public final class Matrices {
*
* <p>This method builds a new matrix with the following content:</p>
* <ul>
- * <li>An number of {@code firstAffectedCoordinate} rows and columns are
inserted before the first
+ * <li>A number of {@code firstAffectedCoordinate} rows and columns are
inserted before the first
* row and columns of the sub-matrix. The elements for the new rows
and columns are set to 1
* on the diagonal, and 0 elsewhere.</li>
* <li>The sub-matrix - except for its last row and column - is copied
in the new matrix starting
* at index ({@code firstAffectedCoordinate}, {@code
firstAffectedCoordinate}).</li>
- * <li>An number of {@code numTrailingCoordinates} rows and columns are
appended after the above sub-matrix.
+ * <li>A number of {@code numTrailingCoordinates} rows and columns are
appended after the above sub-matrix.
* Their elements are set to 1 on the pseudo-diagonal ending in the
lower-right corner, and 0 elsewhere.</li>
* <li>The last sub-matrix row is copied in the last row of the new
matrix, and the last sub-matrix column
* is copied in the last column of the sub-matrix.</li>
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
index fd1e6c7d78..bacccd1442 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
@@ -233,7 +233,7 @@ public class PassThroughTransform extends
AbstractMathTransform implements Seria
* then the current implementation of this method adds the following
restrictions:
*
* <ul>
- * <li>The sub-transform must have an number of target dimensions equal
to the number of source dimensions.</li>
+ * <li>The sub-transform must have a number of target dimensions equal
to the number of source dimensions.</li>
* <li>The sub-transform must be {@linkplain TransformSeparator
separable}.</li>
* </ul>
*
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImagePyramid.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImagePyramid.java
index e89c072a44..5f5b8f3b5c 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImagePyramid.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImagePyramid.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.SortedMap;
@@ -32,7 +33,6 @@ import org.apache.sis.coverage.grid.GridCoverageProcessor;
import org.apache.sis.coverage.grid.IncompleteGridGeometryException;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.geometry.ImmutableEnvelope;
-import org.apache.sis.measure.NumberRange;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.base.StoreUtilities;
import org.apache.sis.util.collection.BackingStoreException;
@@ -40,7 +40,6 @@ import org.apache.sis.util.iso.Names;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.internal.shared.AbstractMap;
-import org.apache.sis.util.internal.shared.Strings;
/**
@@ -98,20 +97,28 @@ final class ImagePyramid extends AbstractMap<GenericName,
ImageTileMatrix>
*/
private final GridCoverageProcessor processor;
+ /**
+ * The locale for error messages, or {@code null} for the default locale.
+ */
+ final Locale locale;
+
/**
* Creates a new tile matrix set.
*
* @param parent identifier of the {@code TiledResource} that
contains this {@code TileMatrixSet}.
* @param provider information about the tile matrices to create, and
provider of pyramid levels.
* @param processor the grid coverage processor to use when tiles use a
subset of the bands.
+ * @param locale the locale for error messages, or {@code null} for
the default locale.
*/
@SuppressWarnings("LocalVariableHidesMemberVariable")
ImagePyramid(final GenericName parent,
final TiledGridCoverageResource.Pyramid provider,
- final GridCoverageProcessor processor)
+ final GridCoverageProcessor processor,
+ final Locale locale)
{
this.provider = provider;
this.processor = processor;
+ this.locale = locale;
identifier = Names.createScopedName(parent, null,
provider.identifier());
matrices = new ArrayList<>();
lowerMatrixIndex = 0;
@@ -125,6 +132,7 @@ final class ImagePyramid extends AbstractMap<GenericName,
ImageTileMatrix>
this.identifier = parent.identifier;
this.provider = parent.provider;
this.processor = parent.processor;
+ this.locale = parent.locale;
this.matrices = parent.matrices;
this.lowerMatrixIndex = lowerMatrixIndex;
this.upperMatrixIndex = upperMatrixIndex;
@@ -196,7 +204,7 @@ final class ImagePyramid extends AbstractMap<GenericName,
ImageTileMatrix>
}
}
if (required) {
- throw new
IllegalArgumentException(Errors.format(Errors.Keys.NoSuchValue_1, name));
+ throw new
IllegalArgumentException(Errors.forLocale(locale).getString(Errors.Keys.NoSuchValue_1,
name));
}
return -1;
}
@@ -432,16 +440,15 @@ final class ImagePyramid extends AbstractMap<GenericName,
ImageTileMatrix>
/**
* Returns a string representation for debugging purposes.
+ * The tile matrices are formatted in a table.
*
* @return a string representation for debugging purposes.
*/
@Override
public String toString() {
- final Object upper;
+ final var f = new TileMatrixFormatter(locale);
synchronized (matrices) {
- final Integer max = (upperMatrixIndex == Integer.MAX_VALUE) ? null
: upperMatrixIndex;
- upper = (matrices.size() >= upperMatrixIndex) ? max : new
NumberRange<>(Integer.class, lowerMatrixIndex, true, max, true);
+ return f.format(this);
}
- return Strings.toString(getClass(), null, identifier.toString(),
"lowerMatrixIndex", lowerMatrixIndex, "upperMatrixIndex", upper);
}
}
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImageTileMatrix.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImageTileMatrix.java
index 51feda835d..7cf69fe985 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImageTileMatrix.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ImageTileMatrix.java
@@ -38,6 +38,7 @@ import org.apache.sis.coverage.grid.GridExtent;
import org.apache.sis.coverage.grid.GridGeometry;
import org.apache.sis.coverage.grid.GridCoverage2D;
import org.apache.sis.coverage.grid.GridCoverageProcessor;
+import org.apache.sis.coverage.grid.IncompleteGridGeometryException;
import org.apache.sis.image.internal.shared.ReshapedImage;
import org.apache.sis.pending.jdk.JDK18;
import org.apache.sis.util.ArgumentChecks;
@@ -183,6 +184,9 @@ final class ImageTileMatrix implements TileMatrix {
* Returns the resolution (in units of CRS axes) at which tiles in this
matrix should be used.
* The array length is the number of <abbr>CRS</abbr> dimensions, and
value at index <var>i</var>
* is the resolution along CRS dimension <var>i</var> in units of the CRS
axis <var>i</var>.
+ *
+ * @throws IncompleteGridGeometryException if the tiling scheme has no
resolution.
+ * Tile matrices with such tiling scheme should not have been
constructed.
*/
@Override
public double[] getResolution() {
@@ -193,6 +197,14 @@ final class ImageTileMatrix implements TileMatrix {
}
}
+ /**
+ * Returns the tile size of the given matrix if known, or {@code null}
otherwise.
+ * This method returns a direct reference to the internal array, caller
shall not modify.
+ */
+ static int[] getTileSize(final TileMatrix matrix) {
+ return (matrix instanceof ImageTileMatrix) ? ((ImageTileMatrix)
matrix).tileSize : null;
+ }
+
/**
* Returns a description about how space is partitioned into individual
tiled units.
* The description contains the extent of valid tile indices, the spatial
reference system,
@@ -367,7 +379,7 @@ final class ImageTileMatrix implements TileMatrix {
low [i] = Math.max(extent.getLow(i),
tileToCell(indiceRanges.getLow(i), i));
final long span = high[i] - low[i];
if (span < 0 || span > Integer.MAX_VALUE) {
- throw new
ArithmeticException(Errors.format(Errors.Keys.IntegerOverflow_1, Integer.SIZE));
+ throw new
ArithmeticException(resource.errors().getString(Errors.Keys.IntegerOverflow_1,
Integer.SIZE));
}
if (coverage.deferredTileReading) {
final long remain = Math.min(extent.getSize(i),
Integer.MAX_VALUE) - span;
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixFormatter.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixFormatter.java
new file mode 100644
index 0000000000..21b7123042
--- /dev/null
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TileMatrixFormatter.java
@@ -0,0 +1,310 @@
+/*
+ * 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.storage.tiling;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Locale;
+import java.util.ArrayList;
+import java.text.NumberFormat;
+import org.opengis.util.GenericName;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.internal.shared.Numerics;
+import org.apache.sis.util.collection.TableColumn;
+import org.apache.sis.util.collection.TreeTableFormat;
+import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.IncompleteGridGeometryException;
+import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
+import org.apache.sis.io.TableAppender;
+
+
+/**
+ * Formatter of tile matrix sets.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ */
+final class TileMatrixFormatter {
+ /**
+ * Helper class for string representation of an image pyramids as a table.
+ * Each instance describes one table row for one {@link ImageTileMatrix}.
+ */
+ private static final class Row {
+ /** The tile matrix identifier. */
+ private final String identifier;
+
+ /** The tile matrix resolution in each <abbr>CRS</abbr> dimensions. */
+ private final double[] resolution;
+
+ /** The string representations of the tile matrix resolution. */
+ private final String[] formattedResolution;
+
+ /** The number of tiles in each grid dimension. */
+ private final String[] tileCount;
+
+ /** The tile sizes in pixels. */
+ private final String[] tileSize;
+
+ /**
+ * Creates one row in the table for the given matrix.
+ *
+ * @param matrix the matrix for which to store information.
+ * @param integerFormat the format to use for integer values.
+ * @throws BackingStoreException if an error occurred while extracting
information.
+ * @throws IncompleteGridGeometryException if the tiling scheme has
not extent or resolution.
+ * Tile matrices with such tiling scheme should not have been
constructed in first place.
+ */
+ private Row(final TileMatrix matrix, final NumberFormat integerFormat)
{
+ final GenericName id = matrix.getIdentifier();
+ identifier = (id != null) ? id.toString() : "";
+ resolution = matrix.getResolution();
+ formattedResolution = new String[resolution.length];
+ final GridExtent ge = matrix.getTilingScheme().getExtent();
+ tileCount = new String[ge.getDimension()];
+ for (int i=0; i<tileCount.length; i++) {
+ tileCount[i] = integerFormat.format(ge.getSize(i));
+ }
+ final int[] ts = ImageTileMatrix.getTileSize(matrix);
+ tileSize = new String[ts != null ? ts.length : 0];
+ for (int i=0; i<tileSize.length; i++) {
+ tileSize[i] = integerFormat.format(ts[i]);
+ }
+ }
+
+ /**
+ * Creates the string representation of resolutions.
+ */
+ final void formatResolutions(final NumberFormat[] formats) {
+ for (int i=0; i<resolution.length; i++) {
+ formattedResolution[i] = formats[i].format(resolution[i]);
+ }
+ }
+ }
+
+ /**
+ * The locale specified at construction time. May be {@code null}.
+ */
+ private final Locale locale;
+
+ /**
+ * Resources for table header.
+ */
+ private final Vocabulary vocabulary;
+
+ /**
+ * The object to use for formatting integer values.
+ */
+ private final NumberFormat integerFormat;
+
+ /**
+ * The error that occurred while formatting a value.
+ */
+ private Throwable error;
+
+ /**
+ * Creates a new formatter using the given locale.
+ */
+ TileMatrixFormatter(final Locale locale) {
+ this.locale = locale;
+ vocabulary = Vocabulary.forLocale(locale);
+ integerFormat = (locale != null)
+ ? NumberFormat.getIntegerInstance(locale)
+ : NumberFormat.getIntegerInstance();
+ }
+
+ /**
+ * Returns a string representation of the given tile matrices.
+ * Each tile matrix is formatted as a row in a table.
+ *
+ * @param matrices the tile matrices to format.
+ * @return the string representation of the table of tile matrices.
+ */
+ final String format(final TileMatrixSet matrices) {
+ final var buffer = new StringBuilder(1000);
+ try {
+ formatHeader(matrices, buffer);
+ formatTable(matrices, buffer);
+ if (error == null) {
+ return buffer.toString();
+ }
+ final var writer = new
StringWriter(buffer.length()).append(buffer);
+ vocabulary.appendLabel(Vocabulary.Keys.Warnings, writer);
+ error.printStackTrace(new PrintWriter(writer.append(' ')));
+ return writer.append(System.lineSeparator()).toString();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * Formats the header of the Tile Matrix Set (<abbr>TMS</abbr>)
representation.
+ * The header contains the <abbr>TMS</abbr> identifier, the Coordinate
Reference System
+ * and the geographic bounding box.
+ *
+ * @param matrices the Tile Matrix Set (<abbr>TMS</abbr>) to format.
+ * @param buffer where to format the header.
+ * @throws IOException should never happen but handled by the caller for
convenience.
+ */
+ private void formatHeader(final TileMatrixSet matrices, final
StringBuilder buffer) throws IOException {
+
buffer.append(vocabulary.getString(Vocabulary.Keys.TileMatrixSets)).append(' ')
+ .append(vocabulary.getString(Vocabulary.Keys.Quoted_1,
matrices.getIdentifier()))
+ .append(System.lineSeparator());
+ try {
+ final String crs =
IdentifiedObjects.getDisplayName(matrices.getCoordinateReferenceSystem(),
locale);
+ if (crs != null) {
+ vocabulary.appendLabel(Vocabulary.Keys.ReferenceSystem,
buffer);
+ buffer.append(' ').append(crs).append(System.lineSeparator());
+ }
+ matrices.getEnvelope().ifPresent((envelope) -> {
+ try {
+ final var bbox = new DefaultGeographicBoundingBox();
+ bbox.setBounds(envelope);
+ bbox.setInclusion(null);
+ final var mf = new TreeTableFormat(locale, null);
+ mf.setColumns(TableColumn.NAME, TableColumn.VALUE);
+ buffer.append(mf.format(bbox.asTreeTable()));
+ } catch (TransformException e) {
+ addError(e);
+ }
+ });
+ } catch (BackingStoreException e) {
+ addError(e.getCause());
+ }
+ }
+
+ /**
+ * Updates an array of maximal length of string representations in the
given columns.
+ * The {@code lenghts} array is updated in-place.
+ */
+ private static void updateMaximalLengths(final int[] lengths, final
String[] columns) {
+ for (int i = Math.min(lengths.length, columns.length); --i >= 0;) {
+ final int length = columns[i].length();
+ if (length > lengths[i]) {
+ lengths[i] = length;
+ }
+ }
+ }
+
+ /**
+ * Appends spaces in front of the given columns in order to have the
specified lengths.
+ */
+ private static void rightAlign(final int[] lengths, final String[]
columns) {
+ for (int i = Math.min(lengths.length, columns.length); --i >= 0;) {
+ final String column = columns[i];
+ final int more = lengths[i] - column.length();
+ if (more > 0) {
+ columns[i] = CharSequences.spaces(more) + columns[i];
+ }
+ }
+ }
+
+ /**
+ * Formats the main body of the Tile Matrix Set (<abbr>TMS</abbr>)
representation.
+ * This is formatted as a table.
+ *
+ * @param matrices the Tile Matrix Set (<abbr>TMS</abbr>) to format.
+ * @param buffer where to format the main body.
+ * @throws IOException should never happen but handled by the caller for
convenience.
+ */
+ private void formatTable(final TileMatrixSet matrices, final StringBuilder
buffer) throws IOException {
+ final var rows = new ArrayList<Row>();
+ int crsDimension = 0, gridDimension = 0, sizeDimension = 0;
+ for (final TileMatrix matrix : matrices.getTileMatrices().values())
try {
+ final var row = new Row(matrix, integerFormat);
+ crsDimension = Math.max(crsDimension,
row.formattedResolution.length);
+ gridDimension = Math.max(gridDimension, row.tileCount.length);
+ sizeDimension = Math.max(sizeDimension, row.tileSize.length);
+ rows.add(row); // Add only on success.
+ } catch (RuntimeException e) {
+ addError(e);
+ }
+ /*
+ * Find the number of fraction digits to use for showing the
resolution.
+ */
+ final var values = new double[rows.size()];
+ final var formats = new NumberFormat[crsDimension];
+ for (int i=0; i<crsDimension; i++) {
+ for (int j=0; j<values.length; j++) {
+ values[j] = rows.get(j).resolution[i];
+ }
+ final NumberFormat format = (locale != null)
+ ? NumberFormat.getNumberInstance(locale)
+ : NumberFormat.getNumberInstance();
+ final int n = Numerics.suggestFractionDigits(values);
+ format.setMinimumFractionDigits(n);
+ format.setMaximumFractionDigits(n);
+ formats[i] = format;
+ }
+ /*
+ * At this point, all values have been formatted as character strings.
+ * Compute the maximum lengths in each column in order to align the
values.
+ */
+ final int[] resolutionLengths = new int[crsDimension];
+ final int[] tileCountLengths = new int[gridDimension];
+ final int[] tileSizeLengths = new int[sizeDimension];
+ for (final Row row : rows) {
+ row.formatResolutions(formats);
+ updateMaximalLengths(resolutionLengths, row.formattedResolution);
+ updateMaximalLengths(tileCountLengths, row.tileCount);
+ updateMaximalLengths(tileSizeLengths, row.tileSize);
+ }
+ for (final Row row : rows) {
+ rightAlign(resolutionLengths, row.formattedResolution);
+ rightAlign(tileCountLengths, row.tileCount);
+ rightAlign(tileSizeLengths, row.tileSize);
+ }
+ /*
+ * All data are prepared. Write the table.
+ */
+ final var table = new TableAppender(buffer);
+ table.appendHorizontalSeparator();
+
table.append(vocabulary.getString(Vocabulary.Keys.Identifier)).nextColumn();
+ if (crsDimension != 0)
table.append(vocabulary.getString(Vocabulary.Keys.Resolution)).nextColumn();
+ if (gridDimension != 0)
table.append(vocabulary.getString(Vocabulary.Keys.TileCount)) .nextColumn();
+ if (sizeDimension != 0)
table.append(vocabulary.getString(Vocabulary.Keys.TileSize)) .nextColumn();
+ table.appendHorizontalSeparator();
+ for (final Row row : rows) {
+ table.setCellAlignment(TableAppender.ALIGN_LEFT);
+ table.append(row.identifier).nextColumn();
+ table.setCellAlignment(TableAppender.ALIGN_RIGHT);
+ if (crsDimension != 0) table.append(String.join(" × ",
row.formattedResolution)).nextColumn();
+ if (gridDimension != 0) table.append(String.join(" × ",
row.tileCount)) .nextColumn();
+ if (sizeDimension != 0) table.append(String.join(" × ",
row.tileSize)) .nextColumn();
+ table.nextLine();
+ }
+ table.appendHorizontalSeparator();
+ table.flush();
+ }
+
+ /**
+ * Records that an error occurred.
+ *
+ * @param e the error that occurred.
+ */
+ private void addError(final Throwable e) {
+ if (error == null) {
+ error = e;
+ } else {
+ error.addSuppressed(e);
+ }
+ }
+}
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java
index 151beac5fe..c3561e64a3 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverage.java
@@ -333,6 +333,13 @@ public abstract class TiledGridCoverage extends
GridCoverage {
return null;
}
+ /**
+ * Returns the localized resources for error messages.
+ */
+ private Errors errors() {
+ return Errors.forLocale(getLocale());
+ };
+
/**
* Returns a unique name that identifies this coverage.
* The name shall be unique in the {@link TileMatrixSet}.
@@ -546,8 +553,8 @@ public abstract class TiledGridCoverage extends
GridCoverage {
} else {
final int sd = sliceExtent.getDimension();
if (sd < dimension || sd > available.getDimension()) {
- throw new MismatchedDimensionException(Errors.format(
- Errors.Keys.MismatchedDimension_3, "sliceExtent",
dimension, sd));
+ throw new MismatchedDimensionException(errors().getString(
+ Errors.Keys.MismatchedDimension_3, "sliceExtent",
dimension, sd));
}
}
final int[] selectedDimensions =
sliceExtent.getSubspaceDimensions(BIDIMENSIONAL);
@@ -569,8 +576,7 @@ public abstract class TiledGridCoverage extends
GridCoverage {
final long tileUp =
incrementExact(coverageCellToResourceTile(Math.min(aoiMax, max), i));
final long tileLo =
coverageCellToResourceTile(Math.max(aoiMin, min), i);
if (tileUp <= tileLo) {
- final String message = Errors.forLocale(getLocale())
- .getString(Errors.Keys.IllegalRange_2, aoiMin,
aoiMax);
+ final String message =
errors().getString(Errors.Keys.IllegalRange_2, aoiMin, aoiMax);
if (aoiMin > aoiMax) {
throw new IllegalArgumentException(message);
} else {
diff --git
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
index 9df789e7fe..14854d64de 100644
---
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
+++
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java
@@ -172,13 +172,6 @@ public abstract class TiledGridCoverageResource extends
AbstractGridCoverageReso
*/
private int yDimension;
- /**
- * The resolutions of each levels of the default pyramid. Computed when
first needed, then cached.
- *
- * @see #getResolutions()
- */
- private List<double[]> resolutions;
-
/**
* Creates a new resource.
*
@@ -497,7 +490,7 @@ check: if (dataType.isInteger()) {
() ->
pyramids.get(0).nameFactory().createLocalName(null, listeners.getSourceName()));
final var processor = new GridCoverageProcessor();
for (int i=0; i<sets.length; i++) {
- sets[i] = new ImagePyramid(scope, pyramids.get(i),
processor);
+ sets[i] = new ImagePyramid(scope, pyramids.get(i),
processor, listeners.getLocale());
}
}
tileMatrixSets = List.of(sets);
@@ -1072,7 +1065,7 @@ check: if (dataType.isInteger()) {
ArgumentChecks.ensureBetween("xDimension", 0, max, xDimension);
ArgumentChecks.ensureBetween("yDimension", 0, max, yDimension);
if (xDimension == yDimension) {
- throw new
IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2,
"yDimension", "xDimension"));
+ throw new
IllegalArgumentException(errors().getString(Errors.Keys.IllegalArgumentValue_2,
"yDimension", "xDimension"));
}
this.xDimension = xDimension;
this.yDimension = yDimension;
@@ -1211,4 +1204,11 @@ check: if (dataType.isInteger()) {
return DefaultNameFactory.provider();
}
}
+
+ /**
+ * Returns the localized resources for error messages.
+ */
+ final Errors errors() {
+ return Errors.forLocale(listeners.getLocale());
+ }
}
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/math/DecimalFunctions.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/math/DecimalFunctions.java
index 3a5bfac210..62bb3b7288 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/math/DecimalFunctions.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/math/DecimalFunctions.java
@@ -433,7 +433,7 @@ public final class DecimalFunctions {
* is a choice:
*
* <ul>
- * <li>If after rounding the given {@code value} to an number of
fraction digits given by ({@code fractionDigits}
+ * <li>If after rounding the given {@code value} to a number of fraction
digits given by ({@code fractionDigits}
* - {@code uncertainDigits}) the 4 last fraction digits before the
rounded ones are zero, then this method
* returns {@code fractionDigits} - {@code uncertainDigits}.</li>
* <li>Otherwise this method returns {@code fractionDigits}.</li>
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/math/Vector.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/math/Vector.java
index 103815c47d..71af8410fb 100644
--- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/math/Vector.java
+++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/math/Vector.java
@@ -669,7 +669,7 @@ public abstract class Vector extends AbstractList<Number>
implements RandomAcces
* array to be returned. Following algorithm applies to deeper
levels.
*
* The `skip` variable is an optimization. Code below would work
with skip = 0 all the times, but this is
- * very slow when r0 = 1 because equals(…) is invoked for all
values. Computing an number of values that
+ * very slow when r0 = 1 because equals(…) is invoked for all
values. Computing a number of values that
* we can skip in the special case where r0 = 1 increases the
speed a lot.
*/
int candidateIndex = 0;
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Numerics.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Numerics.java
index 2a584b08d5..dae6a203b6 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Numerics.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/Numerics.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.util.internal.shared;
+import java.util.Arrays;
import java.text.Format;
import java.text.DecimalFormat;
import java.math.BigInteger;
@@ -220,7 +221,7 @@ public final class Numerics {
public static int snapToCeil(int value, final int divisor) {
final int r = value % divisor; // Always has the sign of `value`.
if (r > 0) {
- value += Math.abs(divisor) - r;
+ value += abs(divisor) - r;
} else {
value -= r;
}
@@ -295,8 +296,8 @@ public final class Numerics {
* @return the value clamped to the range convertible to {@code double}
without precision lost.
*/
public static long roundAndClamp(final double value) {
- return Math.max(-MAX_INTEGER_CONVERTIBLE_TO_DOUBLE,
- Math.min(+MAX_INTEGER_CONVERTIBLE_TO_DOUBLE,
Math.round(value)));
+ return max(-MAX_INTEGER_CONVERTIBLE_TO_DOUBLE,
+ min(+MAX_INTEGER_CONVERTIBLE_TO_DOUBLE, Math.round(value)));
}
/**
@@ -553,7 +554,7 @@ public final class Numerics {
}
/**
- * Suggests an number of fraction digits for formatting in base 10 numbers
of the given accuracy.
+ * Suggests a number of fraction digits for formatting in base 10 numbers
of the given accuracy.
* This method uses heuristic rules that may change in any future SIS
version:
*
* <ul>
@@ -574,34 +575,54 @@ public final class Numerics {
* @see DecimalFunctions#fractionDigitsForDelta(double, boolean)
*/
public static int fractionDigitsForDelta(final double ulp) {
- return (ulp != 0) ? Math.max(0, Math.min(16,
DecimalFunctions.fractionDigitsForDelta(ulp, false))) : 0;
+ return (ulp != 0) ? max(0, min(16,
DecimalFunctions.fractionDigitsForDelta(ulp, false))) : 0;
}
/**
- * Suggests an number of fraction digits for the given values, ignoring
NaN and infinities.
- * This method uses heuristic rules that may change in any future SIS
version.
- * Current implementation returns a value which avoid printing "garbage"
digits
- * with highest numbers, at the cost of loosing significant digits on
smallest numbers.
+ * Suggests a number of fraction digits for the given values, ignoring NaN
and infinities.
+ * This method uses heuristic rules that may change in any future
<abbr>SIS</abbr> version.
+ * Current implementation returns a value which avoid printing "garbage"
digits with highest numbers,
+ * at the cost of loosing significant digits on smallest numbers. It may
further reduce the number of
+ * digits if this is sufficient for distinguishing the given values.
* An arbitrary limit is set to 16 digits, which is the number of digits
for {@code Math.ulp(1.0)}}.
*
+ * <p>This method modifies the given array in-place. Callers should not
pass original data.</p>
+ *
* @param values the values for which to get suggested number of
fraction digits.
* @return suggested number of fraction digits for the given values.
Always positive.
*/
public static int suggestFractionDigits(final double... values) {
+ switch (values.length) {
+ case 0: return 0;
+ case 1: return DecimalFunctions.fractionDigitsForValue(values[0]);
+ }
+ for (int i=0; i<values.length; i++) {
+ values[i] = abs(values[i]);
+ }
+ Arrays.sort(values);
double ulp = 0;
- if (values != null) {
- for (final double v : values) {
- final double e = Math.ulp(v);
- if (e > ulp && e != Double.POSITIVE_INFINITY) {
- ulp = e;
+ double delta = Double.POSITIVE_INFINITY;
+ for (int i = values.length; --i >= 0;) {
+ double value = values[i];
+ if (Double.isFinite(value)) {
+ ulp = ulp(value);
+ while (--i >= 0) {
+ final double lower = values[i];
+ final double diff = value - lower;
+ if (diff > 0 && diff < delta) {
+ delta = diff;
+ }
+ value = lower;
}
+ break;
}
}
- return fractionDigitsForDelta(ulp);
+ // Arbitrarily add 6 digits the the difference between values.
+ return min(fractionDigitsForDelta(ulp), fractionDigitsForDelta(delta)
+ 6);
}
/**
- * Suggests an number of fraction digits for data having the given
statistics.
+ * Suggests a number of fraction digits for data having the given
statistics.
* This method uses heuristic rules that may be modified in any future SIS
version.
*
* @param stats statistics on the data to format.
@@ -646,7 +667,7 @@ public final class Numerics {
final DecimalFormat df = (DecimalFormat) format;
final int maxFD = df.getMaximumFractionDigits();
final double m = abs(((Number) value).doubleValue());
- if (m > 0 && (m >= 1E+9 || m <
MathFunctions.pow10(-Math.min(maxFD, 6)))) {
+ if (m > 0 && (m >= 1E+9 || m < MathFunctions.pow10(-min(maxFD,
6)))) {
final int minFD = df.getMinimumFractionDigits();
final String pattern = df.toPattern();
try {
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java
index 51f06ea65a..2bf1d664eb 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.java
@@ -1249,6 +1249,11 @@ public class Vocabulary extends IndexedResourceBundle {
*/
public static final short Thermal = 260;
+ /**
+ * Tile count
+ */
+ public static final short TileCount = 284;
+
/**
* Tile matrix sets
*/
@@ -1259,6 +1264,11 @@ public class Vocabulary extends IndexedResourceBundle {
*/
public static final short TileSize = 194;
+ /**
+ * Tiling
+ */
+ public static final short Tiling = 283;
+
/**
* Time
*/
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties
index ce0dbaabdc..da9cf8472e 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary.properties
@@ -255,7 +255,9 @@ TemporalExtent = Temporal extent
TemporaryFiles = Temporary files
Thermal = Thermal
TileMatrixSets = Tile matrix sets
+TileCount = Tile count
TileSize = Tile size
+Tiling = Tiling
Time = Time
Time_1 = {0} time
Timezone = Timezone
diff --git
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties
index 0075eb99e2..67fa5590ea 100644
---
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties
+++
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/Vocabulary_fr.properties
@@ -261,8 +261,10 @@ Temporal_1 = Temporel ({0})
TemporalExtent = Plage temporelle
TemporaryFiles = Fichiers temporaires
Thermal = Thermique
-TileMatrixSets = Set de matrices de tuile
+TileMatrixSets = Ensembles de matrices de tuiles
+TileCount = Nombre de tuiles
TileSize = Taille des tuiles
+Tiling = Tuilage
Time = Temps
Time_1 = Heure {0}
Timezone = Fuseau horaire
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/Widget.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/Widget.java
index 548bab1de2..6f79c0704d 100644
--- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/Widget.java
+++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/Widget.java
@@ -22,13 +22,13 @@ import org.apache.sis.util.Localized;
/**
- * Base class of user interfaces provided by Apache SIS.
+ * Base class of user interfaces provided by Apache <abbr>SIS</abbr>.
* This base class is used for components that encapsulate JavaFX controls
instead of extending them.
- * We use this indirection level for hiding implementation details such as the
exact JavaFX classes used
- * for implementing the widget.
+ * We use this indirection level for hiding implementation details such as the
exact JavaFX classes
+ * used for implementing the widget.
*
* <h2>Other controls</h2>
- * Not all Apache SIS widgets extent this class.
+ * Not all Apache <abbr>SIS</abbr> widgets extent this class.
* Other widgets extending directly a JavaFX control or other classes are
* {@link org.apache.sis.gui.metadata.MetadataTree},
* {@link org.apache.sis.gui.dataset.ResourceTree},
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/controls/SyncWindowList.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/controls/SyncWindowList.java
index 0dee5df9a4..25ae55f80c 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/controls/SyncWindowList.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/controls/SyncWindowList.java
@@ -134,7 +134,7 @@ public final class SyncWindowList extends TabularWidget
implements ListChangeLis
* @param vocabulary localized resources, given because already known by
the caller
* (those arguments would be removed if this
constructor was public API).
*/
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({"this-escape", "unchecked"})
public SyncWindowList(final WindowHandler owner, final Resources
resources, final Vocabulary vocabulary) {
this.owner = owner;
table = newTable();
@@ -171,7 +171,7 @@ public final class SyncWindowList extends TabularWidget
implements ListChangeLis
* @return the new row.
*/
private static TableRow<Link> newRow(final TableView<Link> table) {
- TableRow<Link> row = new TableRow<>();
+ final var row = new TableRow<Link>();
row.addEventFilter(MouseEvent.MOUSE_CLICKED,
SyncWindowList::onMouseClicked);
return row;
}
@@ -198,7 +198,7 @@ public final class SyncWindowList extends TabularWidget
implements ListChangeLis
}
/**
- * Returns the encapsulated JavaFX component to add in a scene graph for
making the table visible.
+ * Returns the encapsulated JavaFX component to add in a scene graph for
making the widget visible.
* The {@code Region} subclass is implementation dependent and may change
in any future SIS version.
*
* @return the JavaFX component to insert in a scene graph.
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageExplorer.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageExplorer.java
index 8e6f1b9e4b..427ff26992 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageExplorer.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CoverageExplorer.java
@@ -344,13 +344,13 @@ public class CoverageExplorer extends Widget {
* {@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.
+ * @return the JavaFX component to insert in a scene graph.
*
* @see #getDataView(View)
* @see #getControls(View)
*/
@Override
- public final Region getView() {
+ public Region getView() {
assert Platform.isFxApplicationThread();
/*
* We build when first requested because `ResourceExplorer` for
example will never request this view.
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridSliceSelector.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridSliceSelector.java
index a8c2354969..28bd73e208 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridSliceSelector.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/GridSliceSelector.java
@@ -40,7 +40,6 @@ import javafx.beans.property.SimpleObjectProperty;
import javax.measure.Unit;
import org.opengis.geometry.Envelope;
import org.opengis.util.FactoryException;
-import org.opengis.metadata.spatial.DimensionNameType;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.TemporalCRS;
@@ -447,12 +446,9 @@ public class GridSliceSelector extends Widget {
/*
* Fallback on grid axis name if no CRS axis name is found.
*/
- final DimensionNameType axis =
extent.getAxisType(dimension).orElse(null);
- if (axis != null) {
- return Types.getCodeTitle(axis).toString(locale);
- } else {
- return vocabulary.getString(Vocabulary.Keys.Axis_1, dimension);
- }
+ return extent.getAxisType(dimension)
+ .map((axisType) ->
Types.getCodeTitle(axisType).toString(locale))
+ .orElseGet(() ->
vocabulary.getString(Vocabulary.Keys.Axis_1, dimension));
}
/**
@@ -622,7 +618,7 @@ public class GridSliceSelector extends Widget {
* @return the JavaFX component to insert in a scene graph.
*/
@Override
- public final Region getView() {
+ public Region getView() {
return view;
}
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/ImagePropertyExplorer.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/ImagePropertyExplorer.java
index 881fbfd841..ba33fc6082 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/ImagePropertyExplorer.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/ImagePropertyExplorer.java
@@ -790,10 +790,10 @@ nextProp: for (final String property : properties) {
}
/**
- * Returns the view of this explorer. The subclass is implementation
dependent
- * and may change in any future version.
+ * Returns the encapsulated JavaFX component to add in a scene graph for
making the explorer visible.
+ * The {@code Region} subclass is implementation dependent and may change
in any future SIS version.
*
- * @return this explorer view.
+ * @return the JavaFX component to insert in a scene graph.
*/
@Override
public Region getView() {
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/TileMatrixSetPane.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/TileMatrixSetPane.java
index 453af8e00b..d12c51bb99 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/TileMatrixSetPane.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/TileMatrixSetPane.java
@@ -16,113 +16,105 @@
*/
package org.apache.sis.gui.coverage;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
import javafx.scene.control.TextArea;
-import javafx.scene.layout.BorderPane;
-import org.apache.sis.geometry.GeneralEnvelope;
-import org.apache.sis.referencing.IdentifiedObjects;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.value.ObservableValue;
+import javafx.scene.layout.Region;
import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.Resource;
-import org.apache.sis.storage.tiling.TileMatrix;
import org.apache.sis.storage.tiling.TileMatrixSet;
import org.apache.sis.storage.tiling.TiledResource;
-import org.apache.sis.util.Classes;
+import org.apache.sis.gui.Widget;
+
/**
- * A view to the internal tile matrices defined in a Resource.
+ * A visual representation of the internal tile matrices defined in a {@link
TiledResource}.
*
* @todo change the text area to a split pane with a tree view on the left and
a description pane on the right
* @todo if the resource is writable, add tiling modification controls
+ *
* @author Johann Sorel (Geomatys)
+ *
+ * @sinec 1.7
*/
-public class TileMatrixSetPane extends BorderPane{
+public class TileMatrixSetPane extends Widget {
+ /**
+ * The data shown in this widget.
+ *
+ * @see #getContent()
+ * @see #setContent(TiledResource)
+ */
+ public final ObjectProperty<TiledResource> contentProperty;
private final TextArea area = new TextArea();
+ /**
+ * Creates an initially empty pane showing the content of a tile matrix.
+ */
public TileMatrixSetPane() {
area.setMaxSize(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
area.setEditable(false);
- setCenter(area);
+ contentProperty = new SimpleObjectProperty<>(this, "content");
+ contentProperty.addListener(TileMatrixSetPane::applyChange);
}
- public void setContent(Resource resource) {
- final StringBuilder sb = new StringBuilder();
- if (resource instanceof TiledResource) {
- final TiledResource tr = (TiledResource) resource;
- try {
- for (TileMatrixSet tms : tr.getTileMatrixSets()) {
- sb.append(toString(tms));
- }
- } catch (DataStoreException ex){
- sb.append(ex.getMessage());
- }
- } else {
- sb.append("Resource has no tile matrices.");
- }
-
- area.setText(sb.toString());
+ /**
+ * Sets the data for which to show the tiling.
+ * This is a convenience method for setting {@link #contentProperty} value.
+ *
+ * @param data the data for which to show the tiling, or {@code null} if
none.
+ */
+ public final void setContent(final TiledResource data) {
+ contentProperty.setValue(data);
}
/**
- * Pretty print output of given pyramid.
- * @param pyramid not null
+ * Returns the data for which the tiling is currently shown, or {@code
null} if none.
+ * This is a convenience method for fetching {@link #contentProperty}
value.
+ *
+ * @return the table for which the tiling is currently shown, or {@code
null} if none.
+ *
+ * @see #contentProperty
+ * @see #setContent(TiledResource)
*/
- public static String toString(TileMatrixSet pyramid) {
- final List<String> elements = new ArrayList<>();
- elements.add("id : " + pyramid.getIdentifier());
- elements.add("crs : " +
IdentifiedObjects.getIdentifierOrName(pyramid.getCoordinateReferenceSystem()));
- elements.add(toStringTree("matrices",
pyramid.getTileMatrices().values().stream().map(TileMatrixSetPane::toString).toList()));
- return toStringTree(Classes.getShortClassName(pyramid), elements);
+ public final TiledResource getContent() {
+ return contentProperty.getValue();
}
/**
- * Pretty print outut of given mosaic.
- * @param matrix not null
+ * Returns the region containing the visual components managed by this
{@code TileMatrixSetPane}.
+ * The subclass is implementation dependent and may change in any future
version.
+ *
+ * @return the JavaFX component to insert in a scene graph.
*/
- public static String toString(TileMatrix matrix) {
- final StringBuilder sb = new
StringBuilder(Classes.getShortClassName(matrix));
- sb.append(" id = ").append(matrix.getIdentifier());
- sb.append(" resolution =
").append(Arrays.toString(matrix.getTilingScheme().getResolution(true)));
- sb.append(" gridSize =
").append(matrix.getTilingScheme().getExtent());
- sb.append(" bbox = ").append(new
GeneralEnvelope(matrix.getTilingScheme().getEnvelope()).toString());
- return sb.toString();
+ @Override
+ public Region getView() {
+ return area;
}
/**
- * Returns a graphical representation of the specified objects. This
representation can be
- * printed to the {@linkplain System#out standard output stream} (for
example) if it uses
- * a monospaced font and supports unicode.
+ * Invoked when {@link #contentProperty} value changed.
*
- * @param root The root name of the tree to format.
- * @param objects The objects to format as root children.
- * @return A string representation of the tree.
+ * @param property the property which has been modified.
+ * @param oldValue the old tree table.
+ * @param newValue the tree table to use for building new content.
*/
- public static String toStringTree(String root, final Iterable<?> objects) {
- final StringBuilder sb = new StringBuilder();
- if (root != null) {
- sb.append(root);
+ private static void applyChange(final ObservableValue<? extends
TiledResource> property,
+ final TiledResource oldValue, final
TiledResource newValue)
+ {
+ final var s = (TileMatrixSetPane) ((SimpleObjectProperty)
property).getBean();
+ if (newValue == null) {
+ s.area.setText(null);
+ return;
}
- if (objects != null) {
- final Iterator<?> ite = objects.iterator();
- while (ite.hasNext()) {
- sb.append('\n');
- final Object next = ite.next();
- final boolean last = !ite.hasNext();
- sb.append(last ? "\u2514\u2500 " : "\u251C\u2500 ");
-
- final String[] parts = String.valueOf(next).split("\n");
- sb.append(parts[0]);
- for (int k=1;k<parts.length;k++) {
- sb.append('\n');
- sb.append(last ? ' ' : '\u2502');
- sb.append(" ");
- sb.append(parts[k]);
- }
+ final var sb = new StringBuilder();
+ try {
+ for (TileMatrixSet tms : newValue.getTileMatrixSets()) {
+ sb.append(tms);
}
+ } catch (DataStoreException ex) {
+ sb.append(ex.getMessage());
}
- return sb.toString();
+ s.area.setText(sb.toString());
}
}
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/LogViewer.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/LogViewer.java
index 9e4612ab17..0d15552d8d 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/LogViewer.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/LogViewer.java
@@ -507,6 +507,7 @@ public class LogViewer extends Widget {
* Invoked when a log record is selected.
*/
private void selected(final LogRecord log) {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
String level = null, time = null, logger = null, classe = null, method
= null;
if (log != null) {
level = toString(log.getLevel());
@@ -613,8 +614,8 @@ public class LogViewer extends Widget {
}
/**
- * Returns the control to show in the scene graph.
- * The implementation class may change in any future version.
+ * Returns the encapsulated JavaFX component to add in a scene graph for
making the logs visible.
+ * The {@code Region} subclass is implementation dependent and may change
in any future SIS version.
*/
@Override
public Region getView() {
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/ResourceExplorer.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/ResourceExplorer.java
index 53f0798734..15b183dce3 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/ResourceExplorer.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/ResourceExplorer.java
@@ -44,6 +44,7 @@ import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreProvider;
import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.tiling.TiledResource;
import org.apache.sis.gui.Widget;
import org.apache.sis.gui.metadata.MetadataSummary;
import org.apache.sis.gui.metadata.MetadataTree;
@@ -65,7 +66,8 @@ import org.apache.sis.gui.internal.LogHandler;
*
* @author Smaniotto Enzo (GSoC)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.3
+ * @author Johann Sorel (Geomatys)
+ * @version 1.7
* @since 1.1
*/
public class ResourceExplorer extends Widget {
@@ -97,7 +99,7 @@ public class ResourceExplorer extends Widget {
* The widget showing selected resource tile matrix sets.
* Its content will be updated only when the tab is visible.
*/
- private final TileMatrixSetPane matrices;
+ private final TileMatrixSetPane tiling;
/**
* The tab containing {@link #nativeMetadata}.
@@ -106,9 +108,9 @@ public class ResourceExplorer extends Widget {
private final Tab nativeMetadataTab;
/**
- * The tab containing TileMatrixSet view.
+ * The tab containing the view over the tile matrices of a resource.
*/
- private final Tab tileMatrixSetTab;
+ private final Tab tilingTab;
/**
* Default label for {@link #nativeMetadataTab} when no resource is
selected.
@@ -190,7 +192,7 @@ public class ResourceExplorer extends Widget {
resources.getSelectionModel().getSelectedItems().addListener(this::onResourceSelected);
resources.setPrefWidth(400);
final Vocabulary vocabulary = Vocabulary.forLocale(resources.locale);
- final TitledPane resourcesPane = new
TitledPane(vocabulary.getString(Vocabulary.Keys.Resources), resources);
+ final var resourcesPane = new
TitledPane(vocabulary.getString(Vocabulary.Keys.Resources), resources);
controls = new Accordion(resourcesPane);
controls.setExpandedPane(resourcesPane);
expandedPane = new EnumMap<>(CoverageExplorer.View.class);
@@ -202,24 +204,25 @@ public class ResourceExplorer extends Widget {
*/
metadata = new MetadataSummary();
nativeMetadata = new MetadataTree(metadata);
- matrices = new TileMatrixSetPane();
- final LogViewer logging = new LogViewer(vocabulary);
+ tiling = new TileMatrixSetPane();
+ final var logging = new LogViewer(vocabulary);
selectedResource = new ReadOnlyObjectWrapper<>(this,
"selectedResource");
logging.source.bind(selectedResource);
final Tab summaryTab, metadataTab, loggingTab;
- final TabPane tabs = new TabPane(
+ final var tabs = new TabPane(
summaryTab = new
Tab(vocabulary.getString(Vocabulary.Keys.Summary), metadata.getView()),
viewTab = new
Tab(vocabulary.getString(Vocabulary.Keys.Visual)),
tableTab = new
Tab(vocabulary.getString(Vocabulary.Keys.Data)),
metadataTab = new
Tab(vocabulary.getString(Vocabulary.Keys.Metadata), new
StandardMetadataTree(metadata)),
nativeMetadataTab = new
Tab(vocabulary.getString(Vocabulary.Keys.Format), nativeMetadata),
- tileMatrixSetTab = new
Tab(vocabulary.getString(Vocabulary.Keys.TileMatrixSets), matrices),
+ tilingTab = new
Tab(vocabulary.getString(Vocabulary.Keys.Tiling), tiling.getView()),
loggingTab = new
Tab(vocabulary.getString(Vocabulary.Keys.Logs), logging.getView()));
tabs.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
tabs.setTabDragPolicy(TabPane.TabDragPolicy.REORDER);
defaultNativeTabLabel = nativeMetadataTab.getText();
nativeMetadataTab.setDisable(true);
+ tilingTab.setDisable(true);
/*
* Build the main pane which put everything together.
*/
@@ -267,10 +270,10 @@ public class ResourceExplorer extends Widget {
* by this {@code ResourceExplorer}. The subclass is implementation
dependent and may change in
* any future version.
*
- * @return the region to show.
+ * @return the JavaFX component to insert in a scene graph.
*/
@Override
- public final Region getView() {
+ public Region getView() {
return content;
}
@@ -400,6 +403,7 @@ public class ResourceExplorer extends Widget {
selectedResource.set(resource);
metadata.setMetadata(metadataShown.get() ? resource : null);
updateDataTabWithDefault(dataShown.get() ? resource : null);
+ updateTilingTab(resource);
/*
* Update the label and disabled state of the native metadata tab. We
do not have a reliable way
* to know if metadata are present without trying to fetch them, so
current implementation only
@@ -428,6 +432,15 @@ public class ResourceExplorer extends Widget {
}
}
+ /**
+ * Updates the "Tiling" tab with the content of the given resource.
+ */
+ private void updateTilingTab(final Resource resource) {
+ final TiledResource tiled = (resource instanceof TiledResource) ?
(TiledResource) resource : null;
+ tilingTab.setDisable(tiled == null);
+ tiling.setContent(tiled);
+ }
+
/**
* Loads native metadata in a background thread and shows them in the
"native metadata" tab.
* This method is invoked when the tab become visible, or when a new
resource is loaded.
@@ -481,7 +494,6 @@ public class ResourceExplorer extends Widget {
* @see #updateDataTabWithDefault(Resource)
*/
private boolean updateDataTab(final Resource resource) {
- if (resource != null)
System.out.println(resource.getClass().getName());
Region image = null;
Region table = null;
FeatureSet data = null;
@@ -502,7 +514,6 @@ public class ResourceExplorer extends Widget {
}
grid = new ImageRequest((GridCoverageResource) resource, null,
null);
cpanes = coverage.getControls(type);
- matrices.setContent(resource);
} else if (resource instanceof FeatureSet) {
data = (FeatureSet) resource;
if (features == null) {
@@ -578,7 +589,9 @@ public class ResourceExplorer extends Widget {
/** Invoked in JavaFX thread for showing the resource. */
@Override protected void succeeded() {
if (getSelectedResource() == resource) {
- updateDataTab(getValue());
+ Resource result = getValue();
+ updateTilingTab(result);
+ updateDataTab(result);
}
}
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/package-info.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/package-info.java
index 92f497b3b1..132ef13ed2 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/package-info.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/package-info.java
@@ -24,7 +24,7 @@
* @author Smaniotto Enzo (GSoC)
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.6
+ * @version 1.7
* @since 1.1
*/
package org.apache.sis.gui.dataset;
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/io/FileAccessView.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/io/FileAccessView.java
index f1a9571a8a..47f4313396 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/io/FileAccessView.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/internal/io/FileAccessView.java
@@ -78,9 +78,7 @@ public final class FileAccessView extends Widget implements
UnaryOperator<Channe
}
/**
- * Returns the node to show in a window.
- *
- * @return the node to show.
+ * Returns the encapsulated JavaFX component to add in a scene graph for
making the widget visible.
*/
@Override
public Region getView() {
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
index 546894f452..396b1a2eda 100644
--- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
+++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/map/StatusBar.java
@@ -635,10 +635,11 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
}
/**
- * Returns the node to add to the scene graph for showing the status bar.
+ * Returns the encapsulated JavaFX component to add in a scene graph for
making the status bar visible.
+ * The {@code Region} subclass is implementation dependent and may change
in any future SIS version.
*/
@Override
- public final Region getView() {
+ public Region getView() {
return view;
}
@@ -1347,6 +1348,7 @@ public class StatusBar extends Widget implements
EventHandler<MouseEvent> {
* @param y the <var>y</var> coordinate local to the view.
* @return string representation of coordinates or an error message.
*/
+ @SuppressWarnings("UseSpecificCatch")
private String formatLocalCoordinates(final double x, final double y) {
sourceCoordinates[xDimension] = x;
sourceCoordinates[yDimension] = y;
diff --git
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/metadata/MetadataSummary.java
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/metadata/MetadataSummary.java
index de8c591e6c..6202a35172 100644
---
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/metadata/MetadataSummary.java
+++
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/metadata/MetadataSummary.java
@@ -155,13 +155,13 @@ public class MetadataSummary extends Widget {
}
/**
- * Returns the region containing the visual components managed by this
{@code MetadataSummary}.
- * The subclass is implementation dependent and may change in any future
version.
+ * Returns the encapsulated JavaFX component to add in a scene graph for
making the metadata visible.
+ * The {@code Region} subclass is implementation dependent and may change
in any future SIS version.
*
- * @return the region to show.
+ * @return the JavaFX component to insert in a scene graph.
*/
@Override
- public final Region getView() {
+ public Region getView() {
return content;
}