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 18eff4603a64538e3a1fc10e32bfe814e8fd5053
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Nov 29 15:30:21 2023 +0100

    Add an `info` sub-command to the SIS command-line for showing the grid 
geometry of a file.
---
 .../main/org/apache/sis/console/CRSCommand.java    |   2 +-
 .../main/org/apache/sis/console/Command.java       |   1 +
 .../org/apache/sis/console/Commands.properties     |   3 +-
 .../org/apache/sis/console/Commands_fr.properties  |   3 +-
 .../apache/sis/console/FormattedOutputCommand.java |  11 +-
 .../main/org/apache/sis/console/InfoCommand.java   | 153 +++++++++++++++++++++
 .../org/apache/sis/console/MetadataCommand.java    |   5 +-
 .../sis/storage/geotiff/ImageFileDirectory.java    |  22 ++-
 .../org/apache/sis/util/collection/TreeTables.java |  26 +++-
 9 files changed, 210 insertions(+), 16 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java
 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java
index d0c5a76eec..0b2238708e 100644
--- 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java
+++ 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/CRSCommand.java
@@ -36,7 +36,7 @@ final class CRSCommand extends FormattedOutputCommand {
     }
 
     /**
-     * Prints metadata or CRS information.
+     * Prints CRS information.
      *
      * @return 0 on success, or an exit code if the command failed for a 
reason other than an uncaught Java exception.
      */
diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java
index 6a6f4c9111..adf3405508 100644
--- 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java
+++ 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Command.java
@@ -155,6 +155,7 @@ public final class Command {
                 case "mime-type":  command = new MimeTypeCommand  
(commandIndex, args); break;
                 case "metadata":   command = new MetadataCommand  
(commandIndex, args); break;
                 case "crs":        command = new CRSCommand       
(commandIndex, args); break;
+                case "info":       command = new InfoCommand      
(commandIndex, args); break;
                 case "identifier": command = new 
IdentifierCommand(commandIndex, args); break;
                 case "transform":  command = new TransformCommand 
(commandIndex, args); break;
                 case "translate":  command = new TranslateCommand 
(commandIndex, args); break;
diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands.properties
 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands.properties
index 14e23b348f..09d6e5534c 100644
--- 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands.properties
+++ 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands.properties
@@ -6,7 +6,8 @@ Usage=Usage: sis <command> [options] [files]
 help=Show a help overview.
 about=Show information about Apache SIS and system configuration.
 mime-type=Show MIME type for the given file.
-metadata=Show metadata information for the given file.
+info=Show information about the content of the given file.
+metadata=Show ISO 19115 metadata information for the given file.
 crs=Show Coordinate Reference System (CRS) information for the given file.
 identifier=Show identifiers for metadata and referencing systems in the given 
file.
 transform=Convert or transform coordinates from given source CRS to target CRS.
diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands_fr.properties
 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands_fr.properties
index 65747e839d..c91847685a 100644
--- 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands_fr.properties
+++ 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/Commands_fr.properties
@@ -6,7 +6,8 @@ Usage=Usage: sis <commande> [options] [fichiers]
 help=Affiche un \u00e9cran d\u2019aide.
 about=Affiche des informations \u00e0 propos de Apache SIS et de la 
configuration du syst\u00e8me.
 mime-type=Affiche le type MIME du fichier sp\u00e9cifi\u00e9.
-metadata=Affiche les m\u00e9ta-donn\u00e9es du fichier sp\u00e9cifi\u00e9.
+info=Affiche des informations \u00e0 propos du contenu du fichier 
sp\u00e9cifi\u00e9.
+metadata=Affiche les m\u00e9ta-donn\u00e9es ISO 19115 du fichier 
sp\u00e9cifi\u00e9.
 crs=Affiche le syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es du 
fichier sp\u00e9cifi\u00e9.
 identifier=Affiche les identifiants des m\u00e9ta-donn\u00e9es et des 
syst\u00e8mes de r\u00e9f\u00e9rences du fichier sp\u00e9cifi\u00e9.
 transform=Transforme des coordonn\u00e9es du syst\u00e8me de 
r\u00e9f\u00e9rence source vers le syst\u00e8me destination donn\u00e9.
diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java
 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java
index 504a66ce43..fab233f71c 100644
--- 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java
+++ 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/FormattedOutputCommand.java
@@ -88,7 +88,6 @@ abstract class FormattedOutputCommand extends CommandRunner {
 
     /**
      * Creates a new sub-command with the given command-line arguments.
-     * This constructor is for {@code MetadataCommand} subclasses.
      *
      * @param  commandIndex      index of the {@code arguments} element 
containing the sub-command name, or -1 if none.
      * @param  arguments         the command-line arguments provided by the 
user.
@@ -217,7 +216,7 @@ abstract class FormattedOutputCommand extends CommandRunner 
{
                 final TreeTable tree = 
MetadataStandard.ISO_19115.asTreeTable(object,
                         (object instanceof Metadata) ? Metadata.class : null,
                         ValueExistencePolicy.COMPACT);
-                final TreeTableFormat tf = new TreeTableFormat(locale, 
timezone);
+                final var tf = new TreeTableFormat(locale, timezone);
                 tf.setColumns(TableColumn.NAME, TableColumn.VALUE);
                 tf.setNodeFilter(getNodeFilter());
                 tf.format(tree, out);
@@ -225,7 +224,7 @@ abstract class FormattedOutputCommand extends CommandRunner 
{
             }
 
             case WKT: {
-                final WKTFormat f = new WKTFormat(locale, timezone);
+                final var f = new WKTFormat(locale, timezone);
                 if (convention != null) {
                     f.setConvention(convention);
                 }
@@ -238,7 +237,7 @@ abstract class FormattedOutputCommand extends CommandRunner 
{
             }
 
             case XML: {
-                final MarshallerPool pool = new MarshallerPool(null);
+                final var pool = new MarshallerPool(null);
                 final Marshaller marshaller = pool.acquireMarshaller();
                 marshaller.setProperty(XML.LOCALE,   locale);
                 marshaller.setProperty(XML.TIMEZONE, timezone);
@@ -254,7 +253,7 @@ abstract class FormattedOutputCommand extends CommandRunner 
{
             }
 
             default: {
-                final StorageConnector connector = new StorageConnector(out);
+                final var connector = new StorageConnector(out);
                 connector.setOption(OptionKey.TIMEZONE, timezone);
                 connector.setOption(OptionKey.LOCALE,   locale);
                 connector.setOption(OptionKey.ENCODING, encoding);
@@ -266,7 +265,7 @@ abstract class FormattedOutputCommand extends CommandRunner 
{
                      * Note: after such generalization is done, revert the 
xml-store dependency
                      *       scope in pom.xml from "compile" to "runtime".
                      */
-                    final org.apache.sis.storage.gpx.WritableStore fs = 
(org.apache.sis.storage.gpx.WritableStore) store;
+                    final var fs = (org.apache.sis.storage.gpx.WritableStore) 
store;
                     if (version != null) {
                         fs.setVersion(version);
                     }
diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java
 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java
new file mode 100644
index 0000000000..4ed829c9b0
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/InfoCommand.java
@@ -0,0 +1,153 @@
+/*
+ * 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.console;
+
+import java.util.EnumSet;
+import org.apache.sis.coverage.Category;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.DataStores;
+import org.apache.sis.storage.Resource;
+import org.apache.sis.storage.Aggregate;
+import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.GridCoverageResource;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.measure.RangeFormat;
+import org.apache.sis.util.collection.TreeTable;
+import org.apache.sis.util.collection.TreeTables;
+import org.apache.sis.util.collection.TableColumn;
+import org.apache.sis.util.collection.TreeTableFormat;
+import org.apache.sis.util.collection.DefaultTreeTable;
+import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.util.resources.Vocabulary;
+
+
+/**
+ * The "info" sub-command.
+ * The content varies depending on the resource type.
+ * For grid coverage, it contains the grid geometry.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+final class InfoCommand extends FormattedOutputCommand {
+    /**
+     * Returns valid options for the {@code "metadata"} command.
+     */
+    static EnumSet<Option> options() {
+        return EnumSet.of(Option.LOCALE, Option.TIMEZONE, Option.COLORS, 
Option.VERBOSE, Option.HELP, Option.DEBUG);
+    }
+
+    /**
+     * The bit mask of information to request from a grid geometry.
+     */
+    private int gridBitMask;
+
+    /**
+     * Creates the {@code "info"} sub-command.
+     *
+     * @param  commandIndex  index of the {@code arguments} element containing 
the {@code "info"} command name, or -1 if none.
+     * @param  arguments     the command-line arguments provided by the user.
+     * @throws InvalidOptionException if an illegal option has been provided, 
or the option has an illegal value.
+     */
+    InfoCommand(final int commandIndex, final String... arguments) throws 
InvalidOptionException {
+        super(commandIndex, arguments, options(), OutputFormat.TEXT);
+        gridBitMask = GridGeometry.EXTENT | GridGeometry.GEOGRAPHIC_EXTENT | 
GridGeometry.TEMPORAL_EXTENT
+                    | GridGeometry.CRS | GridGeometry.RESOLUTION;
+        if (options.containsKey(Option.VERBOSE)) {
+            gridBitMask |= GridGeometry.ENVELOPE | GridGeometry.GRID_TO_CRS;
+        }
+    }
+
+    /**
+     * Prints resource information.
+     *
+     * @return 0 on success, or an exit code if the command failed for a 
reason other than an uncaught Java exception.
+     */
+    @Override
+    public int run() throws Exception {
+        final Object input;
+        final String name;
+        if (useStandardInput()) {
+            input = System.in;
+            name  = "stdin";
+        } else {
+            if (hasUnexpectedFileCount = hasUnexpectedFileCount(1, 1)) {
+                return Command.INVALID_ARGUMENT_EXIT_CODE;
+            }
+            input = name = files.get(0);
+        }
+        final var tree = new DefaultTreeTable(TableColumn.VALUE_AS_TEXT);
+        try (DataStore store = DataStores.open(input)) {
+            define(tree.getRoot(), store);
+        } catch (BackingStoreException e) {
+            throw e.unwrapOrRethrow(DataStoreException.class);
+        }
+        final var tf = new TreeTableFormat(locale, timezone);
+        tf.format(tree, out);
+        return 0;
+    }
+
+    /**
+     * Sets the values of the given node using information in the given 
resource.
+     *
+     * @param  target  the tree node to define.
+     * @param  source  the resource from which to get the information.
+     * @throws DataStoreException if an error occurred while reading the 
resource.
+     */
+    private void define(final TreeTable.Node target, final Resource source) 
throws DataStoreException {
+        String name = source.getIdentifier().map((id) -> 
id.toInternationalString().toString(locale))
+                .orElseGet(() -> 
Vocabulary.getResources(locale).getString(Vocabulary.Keys.Unnamed));
+        target.setValue(TableColumn.VALUE_AS_TEXT, name);
+        if (source instanceof GridCoverageResource) {
+            final var grid = (GridCoverageResource) source;
+            TreeTable.Node root = grid.getGridGeometry().toTree(locale, 
gridBitMask).getRoot();
+            TreeTables.moveChildren(root, target);
+            toTree(grid.getSampleDimensions(), target.newChild(), 
TableColumn.VALUE_AS_TEXT);
+        } else if (source instanceof Aggregate) {
+            for (Resource component : ((Aggregate) source).components()) {
+                define(target.newChild(), component);
+            }
+        }
+    }
+
+    /**
+     * Appends information about the sample dimensions in a tree.
+     *
+     * @param bands   the sample dimensions to format.
+     * @param target  where to format the sample dimensions.
+     * @param column  the column where to write the texts.
+     */
+    private void toTree(final Iterable<SampleDimension> bands, final 
TreeTable.Node target,
+                        final TableColumn<? super String> column)
+    {
+        target.setValue(column, 
Vocabulary.getResources(locale).getString(Vocabulary.Keys.SampleDimensions));
+        final var rf = new RangeFormat(locale, timezone);
+        final var sb = new StringBuffer();
+        for (SampleDimension band : bands) {
+            band = band.forConvertedValues(true);
+            final TreeTable.Node bn = target.newChild();
+            bn.setValue(column, 
band.getName().toInternationalString().toString(locale));
+            for (final Category category : band.getCategories()) {
+                final TreeTable.Node cn = bn.newChild();
+                sb.append(category.getName().toString(locale)).append(" (");
+                rf.format(category.getSampleRange(), sb, null).append(')');
+                cn.setValue(column, sb.toString());
+                sb.setLength(0);
+            }
+        }
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java
 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java
index 9e22472a51..61c64bbaad 100644
--- 
a/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java
+++ 
b/endorsed/src/org.apache.sis.console/main/org/apache/sis/console/MetadataCommand.java
@@ -28,6 +28,7 @@ import org.apache.sis.util.collection.TreeTable;
 
 /**
  * The "metadata" sub-command.
+ * This command shows ISO 19115 metadata for the content of a file.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
@@ -52,7 +53,7 @@ final class MetadataCommand extends FormattedOutputCommand {
     }
 
     /**
-     * Prints metadata or CRS information.
+     * Prints metadata.
      *
      * @return 0 on success, or an exit code if the command failed for a 
reason other than an uncaught Java exception.
      */
@@ -68,7 +69,7 @@ final class MetadataCommand extends FormattedOutputCommand {
         }
         if (metadata != null) {
             if (!(metadata instanceof Metadata)) {
-                final DefaultMetadata md = new DefaultMetadata();
+                final var md = new DefaultMetadata();
                 md.setReferenceSystemInfo(Set.of((ReferenceSystem) metadata));
                 metadata = md;
             }
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index 52a0dca631..0477b3cfc4 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -56,6 +56,7 @@ import org.apache.sis.coverage.grid.j2d.SampleModelFactory;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.internal.UnmodifiableArrayList;
 import org.apache.sis.util.internal.Numerics;
 import org.apache.sis.util.internal.Strings;
@@ -1519,7 +1520,26 @@ final class ImageFileDirectory extends DataCube {
                                 minValues.get(Math.min(band, 
minValues.size()-1)), true,
                                 maxValues.get(Math.min(band, 
maxValues.size()-1)), true);
                     }
-                    builder.setName(band + 
1).setBackground(getFillValue(true));
+                    short nameKey = 0;
+                    switch (photometricInterpretation) {
+                        case PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO:
+                        case PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO: nameKey 
= Vocabulary.Keys.Grayscale;  break;
+                        case PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR: nameKey 
= Vocabulary.Keys.ColorIndex; break;
+                        case PHOTOMETRIC_INTERPRETATION_RGB: {
+                            switch (band) {
+                                case 0: nameKey = Vocabulary.Keys.Red;   break;
+                                case 1: nameKey = Vocabulary.Keys.Green; break;
+                                case 2: nameKey = Vocabulary.Keys.Blue;  break;
+                            }
+                            break;
+                        }
+                    }
+                    if (nameKey != 0) {
+                        
builder.setName(Vocabulary.formatInternational(nameKey));
+                    } else {
+                        builder.setName(band + 1);
+                    }
+                    builder.setBackground(getFillValue(true));
                     final SampleDimension sd;
                     if (isIndexValid) {
                         sd = reader.store.customizer.customize(index, band, 
sampleRange, builder);
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/TreeTables.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/TreeTables.java
index dd212c1d1b..6d176b35d6 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/TreeTables.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/TreeTables.java
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.util.collection;
 
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -34,9 +36,6 @@ import org.apache.sis.util.ArgumentChecks;
  * This class provides methods for some tasks considered generic enough,
  * and example codes for more specialized tasks that developers can customize.
  *
- * <p>The remaining of this class javadoc contains example codes placed in 
public domain.
- * Developers can copy and adapt those examples as they see fit.</p>
- *
  * <h2>Example 1: Reduce the depth of a tree</h2>
  * For every branch containing exactly one child, the following method 
concatenates in-place
  * that branch and its child together. This method can be used for simplifying 
depth trees into
@@ -99,7 +98,7 @@ import org.apache.sis.util.ArgumentChecks;
  * }
  *
  * @author  Martin Desruisseaux
- * @version 0.3
+ * @version 1.5
  *
  * @see TreeTable
  *
@@ -254,6 +253,25 @@ public final class TreeTables extends Static {
         return changes;
     }
 
+    /**
+     * Removes all children of the given source, then adds them to the given 
target.
+     * Children need to be removed first because they cannot have two parents.
+     * Caller should ensure that the two tables use the same columns.
+     *
+     * @param  source  source from which to remove children.
+     * @param  target  where to add the children.
+     *
+     * @since 1.5
+     */
+    public static void moveChildren(final TreeTable.Node source, final 
TreeTable.Node target) {
+        ArgumentChecks.ensureNonNull("source", source);
+        ArgumentChecks.ensureNonNull("target", target);
+        final Collection<TreeTable.Node> children = source.getChildren();
+        final TreeTable.Node[] array = children.toArray(TreeTable.Node[]::new);
+        children.clear();
+        target.getChildren().addAll(Arrays.asList(array));
+    }
+
     /**
      * Returns a string representation of the given tree table.
      * The current implementation uses a shared instance of {@link 
TreeTableFormat}.

Reply via email to