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 45fcb329921882cbe7a7d498a9aa6517a0d0547f
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Jan 12 02:55:10 2022 +0100

    Use the localization provided by `CompoundFormat` for formatting values in 
the metadata tree.
    This is a cleaner solution than previous code for solving a problem of 
geographic extent not property formatted.
---
 .../org/apache/sis/gui/metadata/MetadataTree.java  |   4 +-
 .../sis/internal/gui/PropertyValueFormatter.java   |  16 +--
 .../org/apache/sis/internal/gui/PropertyView.java  | 114 +++++-------------
 .../org/apache/sis/internal/gui/TextFormats.java   | 132 +++++++++++++++++++++
 .../apache/sis/internal/util/PropertyFormat.java   |   4 +-
 5 files changed, 175 insertions(+), 95 deletions(-)

diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataTree.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataTree.java
index 0effac0..c8c2558 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataTree.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/MetadataTree.java
@@ -372,7 +372,7 @@ check:      if (data != null) {
             final MetadataTree view = (MetadataTree) cell.getTreeTableView();
             Object value = getValue(cell, view.valueSourceColumn);
             if (value instanceof IdentifiedObject) {
-                value = IdentifiedObjects.getDisplayName((IdentifiedObject) 
value, locale);
+                value = IdentifiedObjects.getDisplayName((IdentifiedObject) 
value, getLocale());
             }
             try {
                 clear();
@@ -474,7 +474,7 @@ check:      if (data != null) {
      */
     private void showPropertyValue(final Object value) {
         if (propertyViewer == null) {
-            propertyViewer = new PropertyView(getLocale(), null, null);
+            propertyViewer = new PropertyView(formatter);
             propertyDialog = new Dialog<>();
             propertyDialog.setResizable(true);
             
propertyDialog.setTitle(Resources.forLocale(getLocale()).getString(Resources.Keys.PropertyValue));
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyValueFormatter.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyValueFormatter.java
index c6adcd2..7d82d79 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyValueFormatter.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyValueFormatter.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.internal.gui;
 
-import java.util.Date;
 import java.util.Locale;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.CharSequences;
@@ -34,10 +33,10 @@ import org.apache.sis.internal.util.PropertyFormat;
  */
 public class PropertyValueFormatter extends PropertyFormat {
     /**
-     * The locale to use for objects. This is usually {@link 
Locale#getDefault()}.
-     * This value is given to {@link InternationalString#toString(Locale)} 
calls.
+     * The formats to use for objects. Its locale is usually {@link 
Locale#getDefault()}.
+     * The locale is also given to {@link 
InternationalString#toString(Locale)} calls.
      */
-    protected final Locale locale;
+    final TextFormats formats;
 
     /**
      * Creates a formatter for the specified locale.
@@ -47,8 +46,8 @@ public class PropertyValueFormatter extends PropertyFormat {
      */
     public PropertyValueFormatter(final Appendable buffer, final Locale 
locale) {
         super(buffer);
-        this.locale = locale;
         setLineSeparator(" ¶ ");
+        formats = new TextFormats(locale);
     }
 
     /**
@@ -56,7 +55,7 @@ public class PropertyValueFormatter extends PropertyFormat {
      */
     @Override
     public final Locale getLocale() {
-        return locale;
+        return formats.getLocale();
     }
 
     /**
@@ -65,8 +64,9 @@ public class PropertyValueFormatter extends PropertyFormat {
      */
     @Override
     protected String toString(final Object value) {
-        if (value instanceof Number || value instanceof Date) {             // 
See super-class javadoc.
-            return value.toString();
+        String text = formats.formatValue(value, false);
+        if (text != null) {
+            return text;
         }
         return Classes.getShortClassName(value) + "(…)";
     }
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
index 2a30407..69cdc19 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/PropertyView.java
@@ -20,11 +20,6 @@ import java.util.Locale;
 import java.util.Objects;
 import java.util.Collection;
 import java.lang.reflect.Array;
-import java.io.IOException;
-import java.text.Format;
-import java.text.FieldPosition;
-import java.text.ParsePosition;
-import java.text.ParseException;
 import java.awt.Rectangle;
 import java.awt.image.RenderedImage;
 import javafx.beans.value.ChangeListener;
@@ -43,9 +38,8 @@ import javafx.scene.layout.GridPane;
 import javafx.scene.layout.Pane;
 import javafx.scene.layout.Priority;
 import org.opengis.referencing.IdentifiedObject;
-import org.apache.sis.io.CompoundFormat;
 import org.apache.sis.math.Statistics;
-import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.util.Localized;
 import org.apache.sis.util.resources.Vocabulary;
 
 
@@ -53,16 +47,20 @@ import org.apache.sis.util.resources.Vocabulary;
  * A viewer for property value. The property may be of various class (array, 
image, <i>etc</i>).
  * If the type is unrecognized, the property is shown as text.
  *
- * <p>This class extends {@link CompoundFormat} and implements {@code 
ChangeListener} for
- * implementation convenience only. Users should not rely on this 
implementation details.</p>
+ * <p>This class implements {@code ChangeListener} for implementation 
convenience only.
+ * Users should not rely on this implementation details.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.2
  * @since   1.1
  * @module
  */
-@SuppressWarnings({"serial","CloneableImplementsClone"})            // Not 
intended to be serialized.
-public final class PropertyView extends CompoundFormat<Object> implements 
ChangeListener<Number> {
+public final class PropertyView implements Localized, ChangeListener<Number> {
+    /**
+     * Provider for {@link java.text.NumberFormat}, {@link 
java.text.DateFormat}, <i>etc</i>.
+     */
+    private final TextFormats formats;
+
     /**
      * The current property value. This is used for detecting changes.
      */
@@ -131,18 +129,25 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
     private ImageConverter runningTask, pendingTask;
 
     /**
-     * Creates a new property view.
+     * Creates a new property view which will use the given formatter for 
formatting values.
+     *
+     * @param  formatter  the formatter to use for formatting values.
+     */
+    public PropertyView(final PropertyValueFormatter formatter) {
+        formats = formatter.formats;
+        view = new SimpleObjectProperty<>(this, "view");
+    }
+
+    /**
+     * Creates a new property view which will set the node on the given 
property.
      *
      * @param  locale      the locale for numbers formatting.
-     * @param  view        the property where to set the node showing the 
value, or {@code null} for a default one.
+     * @param  view        the property where to set the node showing the 
value.
      * @param  background  the image background color, or {@code null} if none.
      */
     @SuppressWarnings("ThisEscapedInObjectConstruction")
-    public PropertyView(final Locale locale, ObjectProperty<Node> view, final 
ObjectProperty<Background> background) {
-        super(locale, null);
-        if (view == null) {
-            view = new SimpleObjectProperty<>(this, "view");
-        }
+    public PropertyView(final Locale locale, final ObjectProperty<Node> view, 
final ObjectProperty<Background> background) {
+        formats = new TextFormats(locale);
         this.view = view;
         if (background != null) {
             getImageCanvas().backgroundProperty().bind(background);
@@ -150,66 +155,13 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
     }
 
     /**
-     * Required by {@link CompoundFormat} but not used.
-     *
-     * @return the base type of values formatted by this {@code PropertyView} 
instance.
-     */
-    @Override
-    public Class<? extends Object> getValueType() {
-        return Object.class;
-    }
-
-    /**
-     * Unsupported operation.
+     * Returns the locale for formatting messages and values.
      *
-     * @param  text ignored.
-     * @param  pos  ignored.
-     * @return never return.
-     * @throws ParseException always thrown.
+     * @return the locale used by formats.
      */
     @Override
-    public Object parse(CharSequence text, ParsePosition pos) throws 
ParseException {
-        throw new ParseException(null, 0);
-    }
-
-    /**
-     * Formats the given property value. Current implementation requires 
{@code toAppendTo}
-     * to be an instance of {@link StringBuffer}. This method is not intended 
to be invoked
-     * outside internal usage.
-     *
-     * @param  value       the property value to format.
-     * @param  toAppendTo  where to append the property value.
-     */
-    @Override
-    public void format(final Object value, final Appendable toAppendTo) throws 
IOException {
-        final Format f = getFormat(value.getClass());
-        if (f != null) {
-            f.format(value, (StringBuffer) toAppendTo, new FieldPosition(0));
-        } else {
-            toAppendTo.append(value.toString());
-        }
-    }
-
-    /**
-     * Formats a single value. This method does the same work than the 
inherited
-     * {@link #format(Object)} final method but in a more efficient way.
-     */
-    private String formatValue(final Object value) {
-        final Format f = getFormat(value.getClass());
-        if (f == null) {
-            return value.toString();
-        } else if (value instanceof Number) {
-            return Numerics.useScientificNotationIfNeeded(f, value, 
Format::format);
-        } else {
-            return f.format(value);
-        }
-    }
-
-    /**
-     * Formats the given value, using scientific notation if needed.
-     */
-    private static void format(final Format f, final double value, final 
StringBuffer buffer, final FieldPosition pos) {
-        Numerics.useScientificNotationIfNeeded(f, value, (nf,v) -> 
{nf.format(v, buffer, pos); return null;});
+    public Locale getLocale() {
+        return formats.getLocale();
     }
 
     /**
@@ -247,7 +199,7 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
                 } else if (newValue.getClass().isArray()) {
                     content = setList(newValue);
                 } else {
-                    content = setText(formatValue(newValue));
+                    content = setText(formats.formatValue(newValue, true));
                 }
             }
             view.set(content);
@@ -288,7 +240,7 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
         }
         final String[] list = new String[Array.getLength(array)];
         for (int i=0; i<list.length; i++) {
-            list[i] = formatValue(Array.get(array, i));
+            list[i] = formats.formatValue(Array.get(array, i), true);
         }
         listView.getItems().setAll(list);
         return node;
@@ -395,16 +347,12 @@ public final class PropertyView extends 
CompoundFormat<Object> implements Change
         String mean  = null;
         if (statistics != null && statistics.length != 0) {
             final Statistics s = statistics[0];
-            final FieldPosition pos = new FieldPosition(0);
             final StringBuffer buffer = new StringBuffer();
-            final Format f = getFormat(Number.class);
-            format(f, s.minimum(), buffer, pos); buffer.append(" … ");
-            format(f, s.maximum(), buffer, pos);
+            formats.formatPair(s.minimum(), " … ", s.maximum(), buffer);
             range = buffer.toString();
 
             buffer.setLength(0);
-            format(f, s.mean(), buffer, pos); buffer.append(" ± ");
-            format(f, s.standardDeviation(false), buffer, pos);
+            formats.formatPair(s.mean(), " ± ", s.standardDeviation(false), 
buffer);
 
             final Vocabulary vocabulary = Vocabulary.getResources(getLocale());
             buffer.append(" 
(").append(vocabulary.getString(Vocabulary.Keys.StandardDeviation)).append(')');
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/TextFormats.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/TextFormats.java
new file mode 100644
index 0000000..11ca158
--- /dev/null
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/TextFormats.java
@@ -0,0 +1,132 @@
+/*
+ * 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.internal.gui;
+
+import java.util.Locale;
+import java.util.TimeZone;
+import java.text.Format;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.text.ParseException;
+import java.io.IOException;
+import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.io.CompoundFormat;
+
+
+/**
+ * A provider for {@link java.text.NumberFormat}, {@link 
java.text.DateFormat}, <i>etc</i>.
+ * Used for formatting values in {@link PropertyValueFormatter}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.2
+ * @since   1.2
+ * @module
+ */
+@SuppressWarnings({"serial","CloneableImplementsClone"})            // Not 
intended to be serialized.
+final class TextFormats extends CompoundFormat<Object> {
+    /**
+     * Creates a new format for the given locale.
+     */
+    TextFormats(final Locale locale) {
+        super(locale, TimeZone.getDefault());
+    }
+
+    /**
+     * Required by {@link CompoundFormat} but not used.
+     *
+     * @return the base type of values formatted by this {@code PropertyView} 
instance.
+     */
+    @Override
+    public final Class<? extends Object> getValueType() {
+        return Object.class;
+    }
+
+    /**
+     * Unsupported operation.
+     *
+     * @param  text ignored.
+     * @param  pos  ignored.
+     * @return never return.
+     * @throws ParseException always thrown.
+     */
+    @Override
+    public Object parse(CharSequence text, ParsePosition pos) throws 
ParseException {
+        throw new ParseException(null, 0);
+    }
+
+    /**
+     * Formats the given property value. Current implementation requires 
{@code toAppendTo}
+     * to be an instance of {@link StringBuffer}. This method is not intended 
to be invoked
+     * outside internal usage.
+     *
+     * @param  value       the property value to format.
+     * @param  toAppendTo  where to append the property value.
+     */
+    @Override
+    public void format(final Object value, final Appendable toAppendTo) throws 
IOException {
+        final StringBuffer buffer = (StringBuffer) toAppendTo;
+        final Format f = getFormat(value.getClass());
+        if (f != null) {
+            f.format(value, buffer, new FieldPosition(0));
+        } else {
+            buffer.append(value);
+        }
+    }
+
+    /**
+     * Formats a single value. This method does the same work than the 
inherited
+     * {@link #format(Object)} final method but in a more efficient way.
+     *
+     * @param  value            the value to format.
+     * @param  toStringAllowed  whether to fallback on {@link 
Object#toString()} if there is no format
+     *         for the given object. If {@code false}, then {@code null} will 
be returned instead.
+     * @return formatted string representation of the given value.
+     */
+    public String formatValue(final Object value, final boolean 
toStringAllowed) {
+        final Format f = getFormat(value.getClass());
+        if (f == null) {
+            return value.toString();
+        } else if (value instanceof Number) {
+            return Numerics.useScientificNotationIfNeeded(f, value, 
Format::format);
+        } else {
+            return f.format(value);
+        }
+    }
+
+    /**
+     * Formats a pair of values in the given buffer. If can be used for 
formatting a range
+     * like "minimum … maximum" or for formatting a value with uncertainty 
like "mean ± std".
+     *
+     * @param  first       the first value of the range.
+     * @param  separator   string to insert between the two values.
+     * @param  second      the maximum value of the range.
+     * @param  toAppendTo  where to append the property value.
+     */
+    public void formatPair(final double first, final String separator, final 
double second, final StringBuffer toAppendTo) {
+        final FieldPosition pos = new FieldPosition(0);
+        final Format f = getFormat(Number.class);
+        format(f, first,  toAppendTo, pos); toAppendTo.append(separator);
+        format(f, second, toAppendTo, pos);
+    }
+
+    /**
+     * Formats the given value, using scientific notation if needed.
+     */
+    private static void format(final Format f, final double value, final 
StringBuffer buffer, final FieldPosition pos) {
+        Numerics.useScientificNotationIfNeeded(f, value, (nf,v) -> 
{nf.format(v, buffer, pos); return null;});
+    }
+}
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/internal/util/PropertyFormat.java
 
b/core/sis-utility/src/main/java/org/apache/sis/internal/util/PropertyFormat.java
index 3fbcecf..e8595a4 100644
--- 
a/core/sis-utility/src/main/java/org/apache/sis/internal/util/PropertyFormat.java
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/internal/util/PropertyFormat.java
@@ -155,8 +155,8 @@ public abstract class PropertyFormat extends LineAppender 
implements Localized {
      * to be handled in a special way. Some of the types handled in a special 
way are {@link InternationalString},
      * {@link ControlledVocabulary}, {@link Enum}, {@link Type}, {@link 
Locale}, {@link TimeZone}, {@link Charset},
      * {@link Currency}, {@link Record}, {@link Iterable} and arrays. Other 
types should be handled by this method.
-     * In particular, {@link Number} and {@link java.util.Date} are 
<strong>not</strong> handled by default by this
-     * {@link PropertyFormat} class and should be handled here.
+     * In particular, {@link Number}, {@link java.util.Date} and {@link 
org.apache.sis.measure.Angle}
+     * are <strong>not</strong> handled by default by this {@link 
PropertyFormat} class and should be handled here.
      *
      * @param  value  the value to format (never {@code null}).
      * @return the formatted value.

Reply via email to