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 d8e23f1abe2faa0083418c759ce9c9c6c1f69b72
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Oct 8 12:55:32 2026 +0200

    Add a `TableRowList` internal class and uses it in `PropertyFormat` for 
better formatting of tabular data.
---
 .../apache/sis/util/internal/shared/Numerics.java  |   2 +-
 .../sis/util/internal/shared/PropertyFormat.java   |  66 ++++++++++---
 .../sis/util/internal/shared/TableRowList.java     | 103 +++++++++++++++++++++
 3 files changed, 156 insertions(+), 15 deletions(-)

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 b1b53c0cdc..7d0e261754 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
@@ -657,7 +657,7 @@ public final class Numerics {
      * @return the result of {@code action}.
      */
     @Workaround(library="JDK", version="10")
-    public static String useScientificNotationIfNeeded(final Format format, 
final Object value, final BiFunction<Format,Object,String> action) {
+    public static String useScientificNotationIfNeeded(final Format format, 
final Object value, final BiFunction<Format, Object, String> action) {
         if (value instanceof Number && format instanceof DecimalFormat) {
             final DecimalFormat df = (DecimalFormat) format;
             final int maxFD = df.getMaximumFractionDigits();
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/PropertyFormat.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/PropertyFormat.java
index 50cfe95def..1012173e36 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/PropertyFormat.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/PropertyFormat.java
@@ -24,6 +24,7 @@ import java.util.TimeZone;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.nio.charset.Charset;
+import java.text.Format;
 import org.opengis.util.Type;
 import org.opengis.util.Record;
 import org.opengis.util.GenericName;
@@ -57,7 +58,23 @@ public abstract class PropertyFormat extends LineAppender 
implements Localized {
     /**
      * {@code true} if this method is invoking itself for writing collection 
values.
      */
-    private transient boolean recursive;
+    private boolean recursive;
+
+    /**
+     * Number of collection elements that have already been written.
+     */
+    private byte formattedItemCount;
+
+    /**
+     * Index of the column to format if formating a table.
+     */
+    private int columnIndex;
+
+    /**
+     * Supplier of the formats to use for the next values, or {@code null} if 
none.
+     * Used for formatting items in a collection.
+     */
+    private TableRowList<?,?> sourceTable;
 
     /**
      * Creates a new instance which will write to the given appendable.
@@ -135,7 +152,7 @@ public abstract class PropertyFormat extends LineAppender 
implements Localized {
             appendCollection(Arrays.asList((Object[]) value));
             return;
         } else if (value instanceof Map.Entry<?,?>) {
-            final Map.Entry<?,?> entry = (Map.Entry<?,?>) value;
+            final var entry = (Map.Entry<?,?>) value;
             final Object k = entry.getKey();
             final Object v = entry.getValue();
             if (k == null) {
@@ -149,7 +166,12 @@ public abstract class PropertyFormat extends LineAppender 
implements Localized {
             }
             return;
         } else {
-            text = toString(value);
+            final Format v;
+            if (sourceTable != null && (v = 
sourceTable.createFormat(getLocale(), columnIndex)) != null) {
+                text = v.format(value);
+            } else {
+                text = toString(value);
+            }
         }
         append(text);
     }
@@ -192,25 +214,41 @@ public abstract class PropertyFormat extends LineAppender 
implements Localized {
      */
     private void appendCollection(final Iterable<?> values) throws IOException 
{
         if (values != null) {
-            if (recursive) {
-                append('…');                                // Do not format 
collections inside collections.
-            } else {
-                int count = 0;
+            final var parent = sourceTable;
+            if (values instanceof TableRowList<?,?>) {
+                sourceTable = (TableRowList<?,?>) values;
+            }
+            final boolean isEnclosed = recursive;
+            if (isEnclosed) {
+                append('{');
+            }
+            final int parentIndex = columnIndex;
+            try {
+                columnIndex = 0;
+                recursive = true;
                 for (final Object value : values) {
                     if (value != null) {
-                        if (count != 0) append(", ");
-                        try {
-                            recursive = true;
-                            appendValue(value);
-                        } finally {
-                            recursive = false;
+                        if (columnIndex != 0) {
+                            append(", ");
                         }
-                        if (++count == 10) {                // Arbitrary limit.
+                        appendValue(value);
+                        if (++formattedItemCount >= 10) {       // Arbitrary 
limit.
                             append(", …");
                             break;
                         }
+                        columnIndex++;
                     }
                 }
+                if (isEnclosed) {
+                    append('}');
+                }
+            } finally {
+                sourceTable = parent;
+                columnIndex = parentIndex;
+                recursive   = isEnclosed;
+                if (!isEnclosed) {
+                    formattedItemCount = 0;
+                }
             }
         }
     }
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/TableRowList.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/TableRowList.java
new file mode 100644
index 0000000000..e39df92d94
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/TableRowList.java
@@ -0,0 +1,103 @@
+/*
+ * 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.util.internal.shared;
+
+import java.util.AbstractList;
+import java.text.Format;
+import java.util.Locale;
+import org.apache.sis.io.TableAppender;
+
+
+/**
+ * A list of row items (for example records) which can be separated in finer 
items (field values).
+ * This class is not used directly by the utility module, but is defined for 
allowing transfer of
+ * information between (for example) GeoTIFF and <abbr>GUI</abbr> modules.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ *
+ * @param  <E>  type of row items in the list.
+ * @param  <V>  type of value in columns.
+ */
+public abstract class TableRowList<E, V> extends AbstractList<E> {
+    /**
+     * Creates a new list.
+     */
+    protected TableRowList() {
+    }
+
+    /**
+     * Returns the title of each column, in order.
+     * The length of this array is the number of columns.
+     *
+     * @return the column titles.
+     */
+    public abstract String[] columns();
+
+    /**
+     * Returns the value in the given column of the given row.
+     *
+     * @param  row     the row, from 0 inclusive to {@link #size()} exclusive.
+     * @param  column  the column, from 0 inclusive to {@code 
columns().length} exclusive.
+     * @return value in the given column of the given row.
+     * @throws IndexOutOfBoundsException if the row of column index is invalid.
+     */
+    public abstract V get(int row, int column);
+
+    /**
+     * Returns the format to use for the given column (optional).
+     *
+     * @param  locale  the locale of the format to create.
+     * @param  column  the column for which to get a format.
+     * @return format configured for the given column, or {@code null} if none.
+     */
+    public Format createFormat(Locale locale, int column) {
+        return null;
+    }
+
+    /**
+     * Formats this list as a table.
+     *
+     * @return a string representation of this list formatted as a table.
+     */
+    @Override
+    public String toString() {
+        final var locale = Locale.getDefault();
+        final var table = new TableAppender();
+        final String[] columns = columns();
+        final Format[] formats = new Format[columns.length];
+        table.setCellAlignment(TableAppender.ALIGN_RIGHT);
+        table.setMultiLinesCells(true);
+        table.nextLine('═');
+        for (int column = 0; column < columns.length; column++) {
+            formats[column] = createFormat(locale, column);
+            table.append(columns[column]);
+            table.nextColumn();
+        }
+        table.nextLine();
+        table.nextLine('─');
+        final int size = size();
+        for (int row = 0; row < size; row++) {
+            for (int column = 0; column < columns.length; column++) {
+                table.append(formats[column].format(get(row, column)));
+                table.nextColumn();
+            }
+            table.nextLine();
+        }
+        table.nextLine('═');
+        return table.toString();
+    }
+}

Reply via email to