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 74c479f028189dd1d041dd40dc33ef58d0d2a80c
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Nov 3 17:05:15 2018 +0100
Add a remarks columns in the metadata tree. The main intent is to notify user when the
geographic bounding box crosses the antimeridian, since it is often a source of confusion.
---
.../apache/sis/internal/metadata/Resources.java | 33 +++++++++++
.../sis/internal/metadata/Resources.properties | 1 +
.../sis/internal/metadata/Resources_fr.properties | 1 +
.../org/apache/sis/metadata/AbstractMetadata.java | 5 ++
.../org/apache/sis/metadata/MetadataFormat.java | 65 ++++++++++++++++++++++
.../org/apache/sis/metadata/MetadataStandard.java | 5 ++
.../org/apache/sis/metadata/PropertyAccessor.java | 11 +++-
.../java/org/apache/sis/metadata/SpecialCases.java | 21 ++++++-
.../java/org/apache/sis/metadata/TreeNode.java | 19 ++++++-
.../org/apache/sis/metadata/TreeTableView.java | 50 ++++++-----------
.../org/apache/sis/metadata/TreeTableViewTest.java | 30 ++++++++--
.../DefaultDataIdentificationTest.java | 2 +-
.../apache/sis/util/collection/TableColumn.java | 11 ++++
.../sis/util/collection/TreeTableFormat.java | 48 +++++++++++-----
.../java/org/apache/sis/test/TestUtilities.java | 9 +--
15 files changed, 253 insertions(+), 58 deletions(-)
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.java
index 9e4af18..2687c4e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.java
@@ -20,8 +20,10 @@ import java.net.URL;
import java.util.Locale;
import java.util.MissingResourceException;
import javax.annotation.Generated;
+import org.opengis.util.InternationalString;
import org.apache.sis.util.resources.KeyConstants;
import org.apache.sis.util.resources.IndexedResourceBundle;
+import org.apache.sis.util.resources.ResourceInternationalString;
/**
@@ -59,6 +61,11 @@ public final class Resources extends IndexedResourceBundle {
}
/**
+ * Bounding box crosses the antimeridian.
+ */
+ public static final short BoxCrossesAntiMeridian = 3;
+
+ /**
* This metadata element is already initialized with value “{0}”.
*/
public static final short ElementAlreadyInitialized_1 = 2;
@@ -125,4 +132,30 @@ public final class Resources extends IndexedResourceBundle {
{
return forLocale(null).getString(key, arg0);
}
+
+ /**
+ * The international string to be returned by {@link formatInternational}.
+ */
+ private static final class International extends ResourceInternationalString {
+ private static final long serialVersionUID = 7465539282825054584L;
+
+ International(short key) {super(key);}
+ International(short key, Object args) {super(key, args);}
+ @Override protected KeyConstants getKeyConstants() {return Resources.Keys.INSTANCE;}
+ @Override protected IndexedResourceBundle getBundle(final Locale locale) {
+ return forLocale(locale);
+ }
+ }
+
+ /**
+ * Gets an international string for the given key. This method does not check for the
key
+ * validity. If the key is invalid, then a {@link MissingResourceException} may be thrown
+ * when a {@link InternationalString#toString(Locale)} method is invoked.
+ *
+ * @param key the key for the desired string.
+ * @return an international string for the given key.
+ */
+ public static InternationalString formatInternational(final short key) {
+ return new International(key);
+ }
}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.properties
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.properties
index 5e5cfe5..1e5dda0 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.properties
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.properties
@@ -19,5 +19,6 @@
# Resources in this file are for "sis-metadata" usage only and should not be used by any
other module.
# For resources shared by all modules in the Apache SIS project, see "org.apache.sis.util.resources"
package.
#
+BoxCrossesAntiMeridian = Bounding box crosses the antimeridian.
ElementAlreadyInitialized_1 = This metadata element is already initialized with value
\u201c{0}\u201d.
UnmodifiableMetadata = This metadata is not modifiable.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_fr.properties
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_fr.properties
index 7b917c2..1184335 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_fr.properties
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_fr.properties
@@ -24,5 +24,6 @@
# U+202F NARROW NO-BREAK SPACE before ; ! and ?
# U+00A0 NO-BREAK SPACE before :
#
+BoxCrossesAntiMeridian = La bo\u00eete englobante traverse l\u2019antim\u00e9ridien.
ElementAlreadyInitialized_1 = Cet \u00e9l\u00e9ment de m\u00e9ta-donn\u00e9e est d\u00e9j\u00e0
initialis\u00e9 avec la valeur \u00ab\u202f{0}\u202f\u00bb.
UnmodifiableMetadata = Cette m\u00e9ta-donn\u00e9e n\u2019est pas modifiable.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
b/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
index 2f1c7b3..f1b83b8 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
@@ -227,6 +227,11 @@ public abstract class AbstractMetadata implements LenientComparable,
Emptiable {
* <li>{@link org.apache.sis.util.collection.TableColumn#VALUE}<br>
* The metadata value for the node. Values in this column are writable if the underlying
* metadata class have a setter method for the property represented by the node.</li>
+ *
+ * <li>{@link org.apache.sis.util.collection.TableColumn#REMARKS}<br>
+ * Remarks or warning on the property value. This is rarely present.
+ * It is provided when the value may look surprising, for example the longitude
values
+ * in a geographic bounding box spanning the anti-meridian.</li>
* </ul>
*
* <div class="section">Write operations</div>
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataFormat.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataFormat.java
new file mode 100644
index 0000000..e8b7ee9
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataFormat.java
@@ -0,0 +1,65 @@
+/*
+ * 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.metadata;
+
+import java.util.Locale;
+import java.util.TimeZone;
+import org.apache.sis.util.collection.TableColumn;
+import org.apache.sis.util.collection.TreeTableFormat;
+import org.apache.sis.internal.system.LocalizedStaticObject;
+import org.apache.sis.io.TableAppender;
+
+
+/**
+ * Default format for {@link AbstractMetadata} objects.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since 1.0
+ * @module
+ */
+@SuppressWarnings({"CloneableClassWithoutClone", "serial"}) // Not intended to be
cloned or serialized.
+final class MetadataFormat extends TreeTableFormat {
+ /**
+ * The shared instance to use for the {@link TreeTableView#toString()} method implementation.
+ * Would need to be reset to {@code null} on locale or timezone changes, but we do not
yet have
+ * any listener for such information.
+ */
+ @LocalizedStaticObject
+ static final MetadataFormat INSTANCE = new MetadataFormat();
+
+ /**
+ * Creates a new format.
+ */
+ private MetadataFormat() {
+ super(Locale.getDefault(Locale.Category.FORMAT), TimeZone.getDefault());
+ setColumns(TableColumn.NAME, TableColumn.VALUE, TableColumn.REMARKS);
+ }
+
+ /**
+ * Override the default behavior for <strong>not</strong> moving to next
column before writing remarks.
+ * Doing so put too many spaces for large metadata tree. Instead we add spaces in the
current column.
+ */
+ @Override
+ protected void writeColumnSeparator(final int nextColumn, final TableAppender out) {
+ if (nextColumn == 1) {
+ super.writeColumnSeparator(nextColumn, out);
+ } else {
+ out.append(" ! ");
+ }
+ }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
b/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
index 493fd04..daf4667 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
@@ -890,6 +890,11 @@ public class MetadataStandard implements Serializable {
* <li>{@link org.apache.sis.util.collection.TableColumn#VALUE}<br>
* The metadata value for the node. Values in this column are writable if the underlying
* metadata class have a setter method for the property represented by the node.</li>
+ *
+ * <li>{@link org.apache.sis.util.collection.TableColumn#REMARKS}<br>
+ * Remarks or warning on the property value. This is rarely present.
+ * It is provided when the value may look surprising, for example the longitude
values
+ * in a geographic bounding box spanning the anti-meridian.</li>
* </ul>
*
* <div class="section">Write operations</div>
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
b/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
index 7f98d1a..e3cbd58 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
@@ -667,6 +667,15 @@ class PropertyAccessor {
}
/**
+ * Returns a remark or warning to format with the value at the given index, or {@code
null} if none.
+ * This is provided when the value may look surprising, for example the longitude values
in a geographic
+ * bounding box spanning the anti-meridian.
+ */
+ CharSequence remarks(int index, Object metadata) {
+ return null;
+ }
+
+ /**
* Returns {@code true} if the {@link #implementation} class has at least one setter
method.
*/
final boolean isWritable() {
@@ -1100,7 +1109,7 @@ class PropertyAccessor {
*
* @see #count()
*/
- public int count(final Object metadata, final ValueExistencePolicy valuePolicy, final
int mode)
+ final int count(final Object metadata, final ValueExistencePolicy valuePolicy, final
int mode)
throws BackingStoreException
{
assert type.isInstance(metadata) : metadata;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/SpecialCases.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/SpecialCases.java
index baabcd9..edcd984 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/SpecialCases.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/SpecialCases.java
@@ -20,6 +20,7 @@ import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.extent.GeographicBoundingBox;
import org.apache.sis.measure.Latitude;
import org.apache.sis.measure.Longitude;
+import org.apache.sis.internal.metadata.Resources;
import org.apache.sis.util.collection.BackingStoreException;
@@ -30,7 +31,7 @@ import org.apache.sis.util.collection.BackingStoreException;
* {@link Latitude} instances instead of {@link Double}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.4
* @module
*/
@@ -91,6 +92,24 @@ final class SpecialCases extends PropertyAccessor {
}
/**
+ * Returns a remark or warning to format with the value at the given index, or {@code
null} if none.
+ * This is used for notifying the user that a geographic box is spanning the anti-meridian.
+ */
+ @Override
+ CharSequence remarks(final int index, final Object metadata) {
+ if (index == eastBoundLongitude) {
+ Object east = super.get(index, metadata);
+ if (east != null) {
+ Object west = super.get(westBoundLongitude, metadata);
+ if (west != null && (Double) east < (Double) west) {
+ return Resources.formatInternational(Resources.Keys.BoxCrossesAntiMeridian);
+ }
+ }
+ }
+ return super.remarks(index, metadata);
+ }
+
+ /**
* Delegates to {@link PropertyAccessor#get(int, Object)}, then substitutes the value
for the properties
* handled in a special way.
*/
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java
index 735e484..1cfa971 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeNode.java
@@ -59,7 +59,7 @@ import org.apache.sis.util.resources.Vocabulary;
* depends on the instantiation order).</div>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
@@ -232,6 +232,13 @@ class TreeNode implements Node {
}
/**
+ * Gets remarks about the value in this node, or {@code null} if none.
+ */
+ CharSequence getRemarks() {
+ return null;
+ }
+
+ /**
* Appends an identifier for this node in the given buffer, for {@link #toString()} implementation.
* The appended value is similar to the value returned by {@link #getIdentifier()} (except
for the
* root node), but may contains additional information like the index in a collection.
@@ -411,6 +418,14 @@ class TreeNode implements Node {
}
/**
+ * Gets remarks about the value in this node, or {@code null} if none.
+ */
+ @Override
+ CharSequence getRemarks() {
+ return accessor.remarks(indexInData, metadata);
+ }
+
+ /**
* Fetches the node value from the metadata object.
*/
@Override
@@ -841,6 +856,8 @@ class TreeNode implements Node {
value = children.getParentTitle();
}
}
+ } else if (column == TableColumn.REMARKS) {
+ value = getRemarks();
}
return column.getElementType().cast(value);
}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
index 6e61c71..3e6cca4 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/TreeTableView.java
@@ -17,9 +17,6 @@
package org.apache.sis.metadata;
import java.util.List;
-import java.util.Locale;
-import java.util.TimeZone;
-import java.text.Format;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -33,7 +30,6 @@ import org.apache.sis.internal.util.UnmodifiableArrayList;
import org.apache.sis.internal.jaxb.SpecializedIdentifier;
import org.apache.sis.internal.jaxb.NonMarshalledAuthority;
import org.apache.sis.internal.util.TreeFormatCustomization;
-import org.apache.sis.internal.system.LocalizedStaticObject;
import org.apache.sis.internal.system.Semaphores;
@@ -47,6 +43,7 @@ import org.apache.sis.internal.system.Semaphores;
* <li>{@link TableColumn#NAME} - the human-readable property name, inferred
from the identifier and index.</li>
* <li>{@link TableColumn#TYPE} - the base interface of property values.</li>
* <li>{@link TableColumn#VALUE} - the property value.</li>
+ * <li>{@link TableColumn#REMARKS} - remarks on the property value.</li>
* </ul>
*
* @author Martin Desruisseaux (Geomatys)
@@ -68,18 +65,11 @@ final class TreeTableView implements TreeTable, TreeFormatCustomization,
Seriali
TableColumn.INDEX,
TableColumn.NAME,
TableColumn.TYPE,
- TableColumn.VALUE
+ TableColumn.VALUE,
+ TableColumn.REMARKS
});
/**
- * The {@link TreeTableFormat} to use for the {@link #toString()} method implementation.
- * Created when first needed. Would need to be reset to {@code null} on locale or timezone
- * changes, but we do not yet have any listener for such information.
- */
- @LocalizedStaticObject
- private static Format format;
-
- /**
* The root of the metadata tree.
* Consider this field as final - it is modified only on
* deserialization by {@link #readObject(ObjectInputStream)}.
@@ -140,27 +130,21 @@ final class TreeTableView implements TreeTable, TreeFormatCustomization,
Seriali
*/
@Override
public String toString() {
- synchronized (TreeTableView.class) {
- if (format == null) {
- final TreeTableFormat f = new TreeTableFormat(
- Locale.getDefault(Locale.Category.FORMAT), TimeZone.getDefault());
- f.setColumns(TableColumn.NAME, TableColumn.VALUE);
- format = f;
+ /*
+ * The NULL_COLLECTION semaphore prevents creation of new empty collections by getter
methods
+ * (a consequence of lazy instantiation). The intent is to avoid creation of unnecessary
objects
+ * for all unused properties. Users should not see behavioral difference, except
if they override
+ * some getters with an implementation invoking other getters. However in such cases,
users would
+ * have been exposed to null values at XML marshalling time anyway.
+ */
+ final boolean allowNull = Semaphores.queryAndSet(Semaphores.NULL_COLLECTION);
+ try {
+ synchronized (MetadataFormat.INSTANCE) {
+ return MetadataFormat.INSTANCE.format(this);
}
- /*
- * The NULL_COLLECTION semaphore prevents creation of new empty collections by
getter methods
- * (a consequence of lazy instantiation). The intent is to avoid creation of
unnecessary objects
- * for all unused properties. Users should not see behavioral difference, except
if they override
- * some getters with an implementation invoking other getters. However in such
cases, users would
- * have been exposed to null values at XML marshalling time anyway.
- */
- final boolean allowNull = Semaphores.queryAndSet(Semaphores.NULL_COLLECTION);
- try {
- return format.format(this);
- } finally {
- if (!allowNull) {
- Semaphores.clear(Semaphores.NULL_COLLECTION);
- }
+ } finally {
+ if (!allowNull) {
+ Semaphores.clear(Semaphores.NULL_COLLECTION);
}
}
}
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
index 9d0c6e9..93e1454 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
@@ -21,6 +21,7 @@ import java.io.ObjectOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import org.opengis.metadata.citation.Citation;
+import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
@@ -28,7 +29,7 @@ import org.junit.Test;
import static org.apache.sis.test.Assert.*;
import static org.apache.sis.test.TestUtilities.toTreeStructure;
-import static org.apache.sis.test.TestUtilities.formatNameAndValue;
+import static org.apache.sis.test.TestUtilities.formatMetadata;
/**
@@ -73,13 +74,13 @@ public final strictfp class TreeTableViewTest extends TestCase {
/**
* Tests {@link TreeTableView#toString()}.
- * Since the result is locale-dependant, we can not compare against an exact string.
+ * Since the result is locale-dependent, we can not compare against an exact string.
* We will only compare the beginning of each line.
*/
@Test
public void testToString() {
final TreeTableView metadata = create(ValueExistencePolicy.COMPACT);
- assertMultilinesEquals(EXPECTED, formatNameAndValue(metadata));
// Locale-independent
+ assertMultilinesEquals(EXPECTED, formatMetadata(metadata));
// Locale-independent
assertArrayEquals(toTreeStructure(EXPECTED), toTreeStructure(metadata.toString()));
// Locale-dependent.
}
@@ -102,6 +103,27 @@ public final strictfp class TreeTableViewTest extends TestCase {
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data)))
{
deserialized = in.readObject();
}
- assertMultilinesEquals(EXPECTED, formatNameAndValue((TreeTableView) deserialized));
+ assertMultilinesEquals(EXPECTED, formatMetadata((TreeTableView) deserialized));
+ }
+
+ /**
+ * Tests formatting a tree containing a remark. We use a geographic bounding box spanning
the anti-meridian.
+ * In this test the longitude value and the remarks and separated by "……" characters,
but this is because we
+ * use the default {@link org.apache.sis.util.collection.TreeTableFormat}. When using
{@link MetadataFormat}
+ * specialization, the formatting is a little bit different
+ *
+ * @since 1.0
+ */
+ @Test
+ public void testRemarks() {
+ final DefaultGeographicBoundingBox bbox = new DefaultGeographicBoundingBox(170, -160,
-30, 40);
+ final String text = formatMetadata(bbox.asTreeTable());
+ assertMultilinesEquals(
+ "Geographic bounding box\n" +
+ " ├─West bound longitude…… 170°E\n" +
+ " ├─East bound longitude…… 160°W…… Bounding box crosses the
antimeridian.\n" + // See method javadoc.
+ " ├─South bound latitude…… 30°S\n" +
+ " ├─North bound latitude…… 40°N\n" +
+ " └─Extent type code……………… true\n", text);
}
}
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
index 52f6d46..2a2d621 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
@@ -157,7 +157,7 @@ public final strictfp class DefaultDataIdentificationTest extends TestCase
{
" ├─Language (1 of 2)………………………………… en_US\n"
+
" ├─Language (2 of 2)………………………………… en\n"
+
" └─Character set……………………………………………
US-ASCII\n",
- TestUtilities.formatNameAndValue(create().asTreeTable()));
+ TestUtilities.formatMetadata(create().asTreeTable()));
}
/**
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/TableColumn.java
b/core/sis-utility/src/main/java/org/apache/sis/util/collection/TableColumn.java
index 304fff5..3f2da9d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/TableColumn.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/TableColumn.java
@@ -161,6 +161,17 @@ public class TableColumn<V> implements CheckedContainer<V>
{
Number.class, Vocabulary.Keys.Value);
/**
+ * Frequently-used constant for a column of remarks.
+ * The column {@linkplain #getHeader() header} is <cite>"Remarks"</cite>
(eventually localized) and
+ * the column elements are typically instances of {@link String} or {@link InternationalString},
+ * depending on whether the data provide localization support or not.
+ *
+ * @since 1.0
+ */
+ public static final TableColumn<CharSequence> REMARKS = new Constant<>("REMARKS",
+ CharSequence.class, Vocabulary.Keys.Remarks);
+
+ /**
* A map containing only the {@link #NAME} column.
* This is the default set of columns when parsing a tree table.
*/
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
b/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
index a0328be..8578a7b 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
@@ -631,18 +631,6 @@ public class TreeTableFormat extends TabularFormat<TreeTable> {
}
/**
- * Writes the column separator to the given appendable. This is a helper method for the
- * {@link Writer} inner class, defined here because it uses many protected fields from
- * the superclass. Accessing those fields from the inner class generate many synthetic
- * methods, so we are better to define only one method here doing the work.
- */
- final void writeColumnSeparator(final Appendable out) throws IOException {
- // We have a TableAppender instance if and only if there is 2 or more columns.
- ((TableAppender) out.append(beforeFill)).nextColumn(fillCharacter);
- out.append(columnSeparator);
- }
-
- /**
* Creates string representation of the node values. Tabulations are replaced by spaces,
* and line feeds are replaced by the Pilcrow character. This is necessary in order to
* avoid conflict with the characters expected by {@link TableAppender}.
@@ -881,7 +869,8 @@ public class TreeTableFormat extends TabularFormat<TreeTable> {
}
for (int i=0; i<=n; i++) {
if (i != 0) {
- writeColumnSeparator(out);
+ // We have a TableAppender instance if and only if there is 2 or more
columns.
+ writeColumnSeparator(i, (TableAppender) out);
}
columnFormat = formats[i];
formatValue(values[i], false);
@@ -1014,6 +1003,39 @@ public class TreeTableFormat extends TabularFormat<TreeTable>
{
}
/**
+ * Writes characters between columns. The default implementation applies the configuration
+ * specified by {@link #setColumnSeparatorPattern(String)} as below:
+ *
+ * <blockquote><code>
+ * out.append({@linkplain #beforeFill beforeFill});
+ * out.nextColumn({@linkplain #fillCharacter fillCharacter});
+ * out.append({@linkplain #columnSeparator columnSeparator});
+ * </code></blockquote>
+ *
+ * The output with default values is like below:
+ *
+ * {@preformat text
+ * root
+ * └─column0…… column1…… column2…… column3
+ * }
+ *
+ * Subclasses can override this method if different column separators are desired.
+ * Note however that doing so may prevent the {@link #parse parse(…)} method to work.
+ *
+ * @param nextColumn zero-based index of the column to be written after the separator.
+ * @param out where to write the column separator.
+ *
+ * @see TableAppender#nextColumn(char)
+ *
+ * @since 1.0
+ */
+ protected void writeColumnSeparator(final int nextColumn, final TableAppender out) {
+ out.append(beforeFill);
+ out.nextColumn(fillCharacter);
+ out.append(columnSeparator);
+ }
+
+ /**
* Returns a clone of this format.
*
* @return a clone of this format.
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java b/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java
index e2a4212..5008a2d 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java
@@ -53,7 +53,7 @@ import static org.apache.sis.internal.util.StandardDateFormat.UTC;
* Miscellaneous utility methods for test cases.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
@@ -268,18 +268,19 @@ public final strictfp class TestUtilities extends Static {
}
/**
- * Returns a unlocalized string representation of {@code NAME} and {@code VALUE} columns
of the given tree table.
+ * Returns a unlocalized string representation of {@code NAME}, {@code VALUE} and {@code
REMARKS} columns
+ * of the given tree table. They are the columns included in default string representation
of metadata.
* Dates and times, if any, will be formatted using the {@code "yyyy-MM-dd HH:mm:ss"}
pattern in UTC timezone.
* This method is used mostly as a convenient way to verify the content of an ISO 19115
metadata object.
*
* @param table the table for which to get a string representation.
* @return a unlocalized string representation of the given tree table.
*/
- public static String formatNameAndValue(final TreeTable table) {
+ public static String formatMetadata(final TreeTable table) {
synchronized (TestUtilities.class) {
if (tableFormat == null) {
final TreeTableFormat f = new TreeTableFormat(null, null);
- f.setColumns(TableColumn.NAME, TableColumn.VALUE);
+ f.setColumns(TableColumn.NAME, TableColumn.VALUE, TableColumn.REMARKS);
tableFormat = f;
}
return tableFormat.format(table);
|