This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 0d5e5d119de637d4e635ef656ed244f2ac007d8b
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon May 18 14:50:54 2026 +0200

    Fix an anomaly in the display of the tree of GeoHEIF boxes.
---
 .../org/apache/sis/metadata/TreeTableView.java     |   2 +-
 .../sis/util/internal/shared/TreeTableForGUI.java  |   2 +-
 .../org/apache/sis/storage/isobmff/Extension.java  |   2 +-
 .../apache/sis/storage/isobmff}/NodeSummary.java   |   8 +-
 .../org/apache/sis/storage/isobmff/TreeNode.java   | 112 ++++++++++-----------
 .../isobmff/geo/TiledImageConfiguration.java       |   6 +-
 6 files changed, 64 insertions(+), 68 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeTableView.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeTableView.java
index 56fbb43c45..c01f9cea09 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeTableView.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/TreeTableView.java
@@ -126,7 +126,7 @@ final class TreeTableView implements TreeTableForGUI, 
Serializable {
     }
 
     /**
-     * Returns whether the given value produces by the given node is a title.
+     * Returns whether the given value produced by the given node is a title.
      */
     @Override
     public boolean isNodeTitle(final Node node, final Object value) {
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/TreeTableForGUI.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/TreeTableForGUI.java
index 9a7f40eb96..25e748ce33 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/TreeTableForGUI.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/TreeTableForGUI.java
@@ -26,7 +26,7 @@ import org.apache.sis.util.collection.TreeTable;
  */
 public interface TreeTableForGUI extends TreeTable {
     /**
-     * Returns whether the given value produces by the given node is a title.
+     * Returns whether the given value produced by the given node is a title.
      * Title are a short description of the node, typically copied from one of 
the children.
      * For example for the code of a {@code Citation} object, this is the 
{@code title} property.
      *
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Extension.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Extension.java
index 0bedee9003..caf43a0418 100644
--- 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Extension.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/Extension.java
@@ -74,6 +74,6 @@ public abstract class Extension extends Box {
     @Override
     protected void prependTreeNodes(final TreeBuilder tree, final 
TreeTable.Node target) {
         super.prependTreeNodes(tree, target);
-        tree.addNode(target, "extendedType", extendedType());
+        tree.addNode(target, "extended type", extendedType());
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/metadata/NodeSummary.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/NodeSummary.java
similarity index 90%
rename from 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/metadata/NodeSummary.java
rename to 
incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/NodeSummary.java
index 7634c498ad..d8276d245c 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/metadata/NodeSummary.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/NodeSummary.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.storage.metadata;
+package org.apache.sis.storage.isobmff;
 
 import org.apache.sis.util.SimpleInternationalString;
 
@@ -28,7 +28,7 @@ import org.apache.sis.util.SimpleInternationalString;
  *
  * @see org.apache.sis.metadata.TitleProperty
  */
-public final class NodeSummary extends SimpleInternationalString {
+final class NodeSummary extends SimpleInternationalString {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -39,7 +39,7 @@ public final class NodeSummary extends 
SimpleInternationalString {
      *
      * @param text the string for all locales.
      */
-    private NodeSummary(final String text) {
+    NodeSummary(final String text) {
         super(text);
     }
 
@@ -49,7 +49,7 @@ public final class NodeSummary extends 
SimpleInternationalString {
      * @param  text  the text to wrap, or {@code null}.
      * @return the wrapped text, or {@code null} if the given text was null.
      */
-    public static NodeSummary of(final CharSequence text) {
+    static NodeSummary of(final CharSequence text) {
         if (text == null || text instanceof NodeSummary) {
             return (NodeSummary) text;
         } else {
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/TreeNode.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/TreeNode.java
index 510c2125ba..0bd7b6134e 100644
--- 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/TreeNode.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/TreeNode.java
@@ -45,7 +45,6 @@ import org.apache.sis.util.internal.shared.PropertyFormat;
 import org.apache.sis.util.internal.shared.TreeTableForGUI;
 import org.apache.sis.storage.isobmff.base.ItemInfoEntry;
 import org.apache.sis.storage.geoheif.GeoHeifStore;
-import org.apache.sis.storage.metadata.NodeSummary;
 
 
 /**
@@ -113,21 +112,7 @@ public abstract class TreeNode {
          */
         IDENTIFIER {
             @Override String format(final TreeBuilder tree, final Number 
value) {
-                 return Long.toUnsignedString(switch (value) {
-                     case Byte    i -> Byte   .toUnsignedLong(i);
-                     case Short   i -> Short  .toUnsignedLong(i);
-                     case Integer i -> Integer.toUnsignedLong(i);
-                     default        -> value.longValue();
-                 });
-            }
-
-            @Override CharSequence summary(final TreeBuilder tree, final 
Number value, final String text) {
-                final String name = tree.getItemName(value);
-                if (name != null) {
-                    // Do not wrap in `NodeSummary` because we want to keep 
that name always visible.
-                    return name;
-                }
-                return super.summary(tree, value, text);
+                return formatUnsigned(value);
             }
         },
 
@@ -162,18 +147,6 @@ public abstract class TreeNode {
             return tree.integerFormat.format(value);
         }
 
-        /**
-         * Returns the text to show as the summary of a node when the node is 
collapsed.
-         *
-         * @param  tree   builder of the tree to format.
-         * @param  value  the integer value which has been formatted.
-         * @param  text   the {@link #format(TreeBuilder, Number)} result.
-         * @return text to show as a summary of a collapsed node.
-         */
-        CharSequence summary(final TreeBuilder tree, final Number value, final 
String text) {
-            return NodeSummary.of(text);
-        }
-
         /**
          * Returns the value of the given annotation, or {@code null} if none.
          *
@@ -206,6 +179,21 @@ public abstract class TreeNode {
         }, StandardCharsets.ISO_8859_1).trim();
     }
 
+    /**
+     * Returns the string representation of the given number interpreted as an 
unsigned integer.
+     *
+     * @param  value  the value to format as an unsigned integer.
+     * @return the formatted value.
+     */
+    static String formatUnsigned(final Number value) {
+        return Long.toUnsignedString(switch (value) {
+            case Byte    i -> Byte   .toUnsignedLong(i);
+            case Short   i -> Short  .toUnsignedLong(i);
+            case Integer i -> Integer.toUnsignedLong(i);
+            default        -> value.longValue();
+        });
+    }
+
     /**
      * Creates a new box or item.
      */
@@ -286,7 +274,7 @@ public abstract class TreeNode {
         }
 
         /**
-         * Returns whether the given value produces by the given node is a 
title.
+         * Returns whether the given value produced by the given node is a 
title.
          */
         @Override
         public boolean isNodeTitle(final TreeTable.Node node, final Object 
value) {
@@ -453,9 +441,7 @@ public abstract class TreeNode {
                 if (value instanceof TreeNode[]) {
                     for (final TreeNode child : (TreeNode[]) value) {
                         if (child != null) {
-                            final TreeTable.Node node = target.newChild();
-                            node.setValue(TableColumn.NAME, child.typeName());
-                            appendProperties(child, node);
+                            appendProperties(child, addNode(target, 
child.typeName(), child, null));
                         }
                     }
                 } else if (value.getClass().isArray()) {
@@ -465,7 +451,13 @@ public abstract class TreeNode {
                      * the names of the identified items.
                      */
                     final Type type = 
Type.of(field.getAnnotation(Interpretation.class));
-                    final TreeTable.Node addTo = (type == Type.IDENTIFIER) ? 
addNode(target, field, value) : null;
+                    final TreeTable.Node addTo;
+                    if (type == Type.IDENTIFIER) {
+                        addTo = addNode(target, camelCaseToWords(field), 
value, null);
+                        // No `VALUE_AS_TEXT` because this is an array that we 
will develop below.
+                    } else {
+                        addTo = null;
+                    }
                     final var values = new String[Array.getLength(value)];
                     for (int i=0; i < values.length; i++) {
                         final Object element = Array.get(value, i);
@@ -473,7 +465,7 @@ public abstract class TreeNode {
                             if (type != null) {
                                 final var n = (Number) element;
                                 if (addTo != null) {
-                                    addNode(addTo, Type.UNSIGNED.format(this, 
n), n, getItemName(n));
+                                    addNode(addTo, formatUnsigned(n), n, 
getItemName(n));
                                 } else {
                                     values[i] = type.format(this, n);
                                 }
@@ -483,16 +475,16 @@ public abstract class TreeNode {
                         }
                     }
                     if (addTo == null) {
-                        addNode(target, field.getName(), value, String.join(", 
", values));
+                        addNode(target, camelCaseToWords(field), value, 
String.join(", ", values));
                     }
                 } else {
                     /*
-                     * Case of a single element.
+                     * Case where the property is a single element (not an 
array).
                      * Identifier codes will be converted to their 
four-character code (4CC) representations.
                      * The fields to convert to 4CC are identified by the 
`@Interpretation` annotation.
                      */
                     if (value instanceof TreeNode addTo) {
-                        appendProperties(addTo, addNode(target, field, value));
+                        appendProperties(addTo, addNode(target, 
camelCaseToWords(field), addTo, null));
                     } else {
                         final Interpretation itpr = 
field.getAnnotation(Interpretation.class);
                         final Type type = Type.of(itpr);
@@ -503,10 +495,20 @@ public abstract class TreeNode {
                             text = formatUsingStringBuilder(value);
                         }
                         if (text != null) {
-                            addNode(target, field.getName(), value, text);
+                            addNode(target, camelCaseToWords(field), value, 
text);
                         }
+                        /*
+                         * If the field is annotated with `Interpretation(…, 
summary=true)`,
+                         * take the field value is a summary of the whole node.
+                         */
                         if (summary == null && withSummary && itpr != null && 
itpr.summary()) {
-                            summary = (type != null) ? type.summary(this, 
(Number) value, text) : text;
+                            if (type == Type.IDENTIFIER) {
+                                String name = getItemName((Number) value);
+                                if (name != null) summary = name;
+                                // Do not wrap in `NodeSummary` because we 
want that name always visible.
+                            } else if (text != null) {
+                                summary = new NodeSummary(text);
+                            }
                         }
                     }
                 }
@@ -529,11 +531,11 @@ public abstract class TreeNode {
         }
 
         /**
-         * Convenience method for adding a child node.
+         * Convenience method for adding a child node if the given value is 
non-null.
          *
-         * @param target  where to add the node.
-         * @param name    the programmatic (camel-case) name of the node.
-         * @param value   value of the node, or {@code null} if none.
+         * @param  target  where to add the node.
+         * @param  name    name of the node or property to add.
+         * @param  value   value of the node, or {@code null} for skipping the 
node.
          */
         public final void addNode(final TreeTable.Node target, final String 
name, final Object value) {
             if (value != null) {
@@ -545,33 +547,27 @@ public abstract class TreeNode {
          * Convenience method for adding a child node.
          *
          * @param  target       where to add the node.
-         * @param  name         the programmatic (camel-case) name of the node.
-         * @param  value        value of the node. Should not be null.
-         * @param  valueAsText  string representation of the value.
+         * @param  name         name of the node or property to add.
+         * @param  value        value of the node, or {@code null} for a node 
without value.
+         * @param  valueAsText  string representation of the value, or {@code 
null} if none.
          * @return the node which has been added.
          */
         public static TreeTable.Node addNode(final TreeTable.Node target, 
String name, Object value, String valueAsText) {
             final TreeTable.Node child = target.newChild();
-            child.setValue(TableColumn.NAME,  
CharSequences.camelCaseToWords(name, true).toString());
+            child.setValue(TableColumn.NAME, name);
             child.setValue(TableColumn.VALUE, value);
             child.setValue(TableColumn.VALUE_AS_TEXT, valueAsText);
             return child;
         }
 
         /**
-         * Adds a node for a field. The {@code NAME} and {@code VALUE} columns 
are set to values
-         * derived from the given arguments. The {@code VALUE_AS_TEXT} column 
is left {@code null}.
+         * Returns the name of the given field with camel-case converted to a 
sentence of words.
          *
-         * @param  target  where to add the node.
-         * @param  field   field of the property to represent as a node.
-         * @param  value   value of the property to represent as a node.
-         * @return the node which has been added.
+         * @param  field  the field for which to get the name.
+         * @return field name as a sequence of words.
          */
-        private static TreeTable.Node addNode(final TreeTable.Node target, 
final Field field, final Object value) {
-            final TreeTable.Node child = target.newChild();
-            child.setValue(TableColumn.NAME, 
CharSequences.camelCaseToWords(field.getName(), false).toString());
-            child.setValue(TableColumn.VALUE, value);
-            return child;
+        private static String camelCaseToWords(final Field field) {
+            return CharSequences.camelCaseToWords(field.getName(), 
false).toString();
         }
     }
 
diff --git 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/geo/TiledImageConfiguration.java
 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/geo/TiledImageConfiguration.java
index d12d1284c5..94b9bb993f 100644
--- 
a/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/geo/TiledImageConfiguration.java
+++ 
b/incubator/src/org.apache.sis.storage.geoheif/main/org/apache/sis/storage/isobmff/geo/TiledImageConfiguration.java
@@ -157,8 +157,8 @@ public final class TiledImageConfiguration extends FullBox {
      */
     @Override
     protected void appendFlagDescriptions(final TreeBuilder tree, final 
TreeTable.Node target) {
-        tree.addNode(target, "offsetFieldLength", offsetFieldLength());
-        tree.addNode(target, "sizeFieldLength",   sizeFieldLength());
-        tree.addNode(target, "sequential",        sequential());
+        tree.addNode(target, "offset field length", offsetFieldLength());
+        tree.addNode(target, "size field length",   sizeFieldLength());
+        tree.addNode(target, "sequential",          sequential());
     }
 }

Reply via email to