sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1402411 - in /sis/branches/JDK7/sis-utility/src: main/java/org/apache/sis/internal/util/ main/java/org/apache/sis/measure/ main/java/org/apache/sis/util/resources/ main/java/org/apache/sis/util/type/ test/java/org/apache/sis/measure/
Date Fri, 26 Oct 2012 07:20:17 GMT
Author: desruisseaux
Date: Fri Oct 26 07:20:17 2012
New Revision: 1402411

URL: http://svn.apache.org/viewvc?rev=1402411&view=rev
Log:
Angle implements Formattable.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
  (with props)
Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Angle.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractInternationalString.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java?rev=1402411&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
Fri Oct 26 07:20:17 2012
@@ -0,0 +1,70 @@
+/*
+ * 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.util;
+
+import java.util.Formatter;
+import java.util.FormattableFlags;
+import org.apache.sis.util.Static;
+import org.apache.sis.util.CharSequences;
+
+
+/**
+ * Miscellaneous utilities which should not be put in public API.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-3.00)
+ * @version 0.3
+ * @module
+ */
+public final class Utilities extends Static {
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private Utilities() {
+    }
+
+    /**
+     * Formats the given character sequence to the given formatter. This method takes in
account
+     * the {@link FormattableFlags#UPPERCASE} and {@link FormattableFlags#LEFT_JUSTIFY} flags.
+     *
+     * @param formatter The formatter in which to format the value.
+     * @param flags     The formatting flags.
+     * @param width     Minimal number of characters to write, padding with {@code ' '} if
necessary.
+     * @param value     The text to format.
+     */
+    public static void formatTo(final Formatter formatter, final int flags, int width, String
value) {
+        final String format;
+        final Object[] args;
+        boolean isUpperCase = (flags & FormattableFlags.UPPERCASE) != 0;
+        if (isUpperCase && width > 0) {
+            // May change the string length in some locales.
+            value = value.toUpperCase(formatter.locale());
+            isUpperCase = false;
+        }
+        final int length = value.length();
+        // Double check since length() is faster than codePointCount(...).
+        if (width > length && (width -= value.codePointCount(0, length)) >
0) {
+            format = "%s%s";
+            args = new Object[] {value, value};
+            args[(flags & FormattableFlags.LEFT_JUSTIFY) != 0 ? 1 : 0] = CharSequences.spaces(width);
+        } else {
+            format = isUpperCase ? "%S" : "%s";
+            args = new Object[] {value};
+        }
+        formatter.format(format, args);
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Angle.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Angle.java?rev=1402411&r1=1402410&r2=1402411&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Angle.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Angle.java Fri Oct
26 07:20:17 2012
@@ -17,6 +17,9 @@
 package org.apache.sis.measure;
 
 import java.util.Locale;
+import java.util.Formatter;
+import java.util.Formattable;
+import java.util.FormattableFlags;
 import java.text.Format;
 import java.text.ParseException;
 import java.io.Serializable;
@@ -30,6 +33,12 @@ import org.apache.sis.math.MathFunctions
  * plane into coincidence with another, generally measured in degrees, sexagesimal degrees
or
  * grads.
  *
+ * {@section Formatting angles}
+ * The recommended way to format angles is to instantiate an {@link AngleFormat} once, then
to
+ * reuse it many times. As a convenience, {@code Angle} objects can also be formatted by
the
+ * {@code "%s"} conversion specifier of {@link Formatter}, but this is less efficient for
this
+ * class.
+ *
  * @author  Martin Desruisseaux (MPO, IRD, Geomatys)
  * @since   0.3 (derived from geotk-1.0)
  * @version 0.3
@@ -40,7 +49,7 @@ import org.apache.sis.math.MathFunctions
  * @see AngleFormat
  */
 @Immutable
-public class Angle implements Comparable<Angle>, Serializable {
+public class Angle implements Comparable<Angle>, Formattable, Serializable {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -192,7 +201,7 @@ public class Angle implements Comparable
     public String toString() {
         StringBuffer buffer = new StringBuffer(16);
         double m = Math.abs(θ);
-        final boolean isSmall = m <= (1 / 3600E+6); // 1 micro-second.
+        final boolean isSmall = m <= (1 / 3600E+3); // 1E-3 arc-second.
         if (isSmall || m > maximum()) {
             final char h = hemisphere(MathFunctions.isNegative(θ));
             if (h == 0) {
@@ -235,4 +244,46 @@ public class Angle implements Comparable
         }
         return format;
     }
+
+    /**
+     * Formats this angle using the provider formatter. This method is invoked when an
+     * {@code Angle} object is formatted using the {@code "%s"} conversion specifier of
+     * {@link Formatter}. Users don't need to invoke this method explicitely.
+     *
+     * <p>Special cases:</p>
+     * <ul>
+     *   <li>If the precision is 0, then this method formats an empty string.</li>
+     *   <li>If the precision is 1 and this angle is a {@link Latitude} or {@link Longitude},
+     *       then this method formats only the hemisphere symbol.</li>
+     *   <li>Otherwise the precision, if positive, is given to {@link AngleFormat#setMaximumWidth(int)}.
+     *       That formatter will try to respect the precision limit, but the formatted angle
may
+     *       still be wider if the precision is too small or the angle magnitude too large.</li>
+     * </ul>
+     *
+     * @param formatter The formatter in which to format this angle.
+     * @param flags     {@link FormattableFlags#LEFT_JUSTIFY} for left alignment, or 0 for
right alignment.
+     * @param width     Minimal number of characters to write, padding with {@code ' '} if
necessary.
+     * @param precision Maximal number of characters to write, or -1 if no limit.
+     */
+    @Override
+    public void formatTo(final Formatter formatter, final int flags, final int width, int
precision) {
+        final String value;
+        if (precision == 0) {
+            value = "";
+        } else {
+            if (precision > 0) {
+                final char h = hemisphere(MathFunctions.isNegative(θ));
+                if (h != 0 && --precision == 0) {
+                    formatter.format("%c", h);
+                    return;
+                }
+            }
+            final AngleFormat format = new AngleFormat(formatter.locale());
+            if (precision > 0) {
+                format.setMaximumWidth(precision);
+            }
+            value = format.format(this, new StringBuffer(16), null).toString();
+        }
+        org.apache.sis.internal.util.Utilities.formatTo(formatter, flags, width, value);
+    }
 }

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java?rev=1402411&r1=1402410&r2=1402411&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java Fri
Oct 26 07:20:17 2012
@@ -173,12 +173,14 @@ public class AngleFormat extends Format 
      * Minimal amount of spaces to be used by the degrees, minutes and seconds fields,
      * and by the decimal digits. A value of 0 means that the field is not formatted.
      * {@code fractionFieldWidth} applies to the last non-zero field.
+     * {@code maximumTotalWidth} is 0 (the default) if there is no restriction.
      */
     private byte degreesFieldWidth,
                  minutesFieldWidth,
                  secondsFieldWidth,
                  fractionFieldWidth,
-                 minimumFractionDigits;
+                 minimumFractionDigits,
+                 maximumTotalWidth;
 
     /**
      * Characters to insert before the text to format, and after each field.
@@ -340,6 +342,7 @@ public class AngleFormat extends Format 
         secondsFieldWidth     = 0;
         fractionFieldWidth    = 0;
         minimumFractionDigits = 0;
+        maximumTotalWidth     = 0;
         prefix                = null;
         degreesSuffix         = null;
         minutesSuffix         = null;
@@ -386,7 +389,7 @@ scan:   for (int i=0; i<length;) {
                     while ((i += charCount) < length && pattern.codePointAt(i)
== c) {
                         width++;
                     }
-                    final byte wb = (byte) Math.min(width, Byte.MAX_VALUE);
+                    final byte wb = toByte(width);
                     switch (field) {
                         case DEGREES_FIELD: prefix        = previousSuffix; degreesFieldWidth
= wb; break;
                         case MINUTES_FIELD: degreesSuffix = previousSuffix; minutesFieldWidth
= wb; break;
@@ -415,15 +418,18 @@ scan:   for (int i=0; i<length;) {
                         if (fc != c) {
                             if (fc != symbols[FRACTION_FIELD]) break;
                             // Switch the search from mandatory to optional digits.
-                            minimumFractionDigits = (byte) Math.min(width, Byte.MAX_VALUE);
+                            minimumFractionDigits = toByte(width);
                             charCount = Character.charCount(c = fc);
                         }
                         width++;
                     }
-                    fractionFieldWidth = (byte) Math.min(width, Byte.MAX_VALUE);
+                    fractionFieldWidth = toByte(width);
                     if (c != symbols[FRACTION_FIELD]) {
                         // The pattern contains only mandatory digits.
                         minimumFractionDigits = fractionFieldWidth;
+                    } else if (!useDecimalSeparator) {
+                        // Variable number of digits not allowed if there is no decimal separator.
+                        throw new IllegalArgumentException(Errors.format(Errors.Keys.RequireDecimalSeparator));
                     }
                     parseFinished = true;
                 }
@@ -523,6 +529,14 @@ scan:   for (int i=0; i<length;) {
     }
 
     /**
+     * Returns the given value as a byte. Values greater
+     * than the maximal supported value are clamped.
+     */
+    private static byte toByte(final int n) {
+        return (byte) Math.min(n, Byte.MAX_VALUE);
+    }
+
+    /**
      * Returns the minimum number of digits allowed in the fraction portion of the last field.
      * This value can be set by the repetition of {@code 'd'}, {@code 'm'} or {@code 's'}
symbol
      * in the pattern.
@@ -546,7 +560,11 @@ scan:   for (int i=0; i<length;) {
      */
     public void setMinimumFractionDigits(final int count) {
         ArgumentChecks.ensurePositive("count", count);
-        minimumFractionDigits = (byte) Math.min(count, Byte.MAX_VALUE);
+        if (!useDecimalSeparator) {
+            throw new IllegalStateException(Errors.format(Errors.Keys.RequireDecimalSeparator));
+        }
+        maximumTotalWidth = 0; // Means "no restriction".
+        minimumFractionDigits = toByte(count);
         if (minimumFractionDigits > fractionFieldWidth) {
             fractionFieldWidth = minimumFractionDigits;
         }
@@ -575,13 +593,89 @@ scan:   for (int i=0; i<length;) {
      */
     public void setMaximumFractionDigits(final int count) {
         ArgumentChecks.ensurePositive("count", count);
-        fractionFieldWidth = (byte) Math.min(count, Byte.MAX_VALUE);
+        if (!useDecimalSeparator) {
+            throw new IllegalStateException(Errors.format(Errors.Keys.RequireDecimalSeparator));
+        }
+        maximumTotalWidth = 0; // Means "no restriction".
+        fractionFieldWidth = toByte(count);
         if (fractionFieldWidth < minimumFractionDigits) {
             minimumFractionDigits = fractionFieldWidth;
         }
     }
 
     /**
+     * Modifies, if needed, the pattern in order to fit formatted angles in the given maximum
+     * total width. This method applies zero, one or more of the following changes, in that
order:
+     *
+     * <ol>
+     *   <li>If needed, reduce the {@linkplain #setMaximumFractionDigits(int) maximum
number of
+     *       fraction digits}.</li>
+     *   <li>If omitting all fraction digits would not be sufficient for fitting a
formatted
+     *       angle in the given width, remove the seconds field (if any) from the pattern.</li>
+     *   <li>If the above changes are not sufficient, remove the minutes field (if
any) from
+     *       the pattern.</li>
+     *   <li>If the above changes are not sufficient, set the minimal width of degrees
field to 1.</li>
+     * </ol>
+     *
+     * Note that despite the above changes, formatted angles may still be larger than the
given
+     * width if that width is small, or if the formatted angles are too large in magnitude.
+     *
+     * <p>This method does not take into account the space needed for the hemisphere
symbol when
+     * formatting {@link Latitude} or {@link Longitude} objects.</p>
+     *
+     * @param width The maximum total width of formatted angle.
+     */
+    @SuppressWarnings("fallthrough")
+    public void setMaximumWidth(int width) {
+        ArgumentChecks.ensureStrictlyPositive("width", width);
+        if (!useDecimalSeparator) {
+            throw new IllegalStateException(Errors.format(Errors.Keys.RequireDecimalSeparator));
+        }
+        maximumTotalWidth = toByte(width);
+        for (int field=PREFIX_FIELD; field<=SECONDS_FIELD; field++) {
+            final int previousWidth = width;
+            final String suffix;
+            switch (field) {
+                case PREFIX_FIELD:                              suffix = prefix;        break;
+                case DEGREES_FIELD: width -= degreesFieldWidth; suffix = degreesSuffix; break;
+                case MINUTES_FIELD: width -= minutesFieldWidth; suffix = minutesSuffix; break;
+                case SECONDS_FIELD: width -= secondsFieldWidth; suffix = secondsSuffix; break;
+                default: throw new AssertionError(field);
+            }
+            if (suffix != null) {
+                width -= suffix.length();
+            }
+            /*
+             * At this point, we computed the spaces remaining after formatting the angle
up to
+             * the field identified by the 'field' variable. If there is not enough space,
remove
+             * that field (if we are allowed to) and all subsequent fields from the pattern,
then
+             * reset the 'width' variable to its previous value.
+             */
+            if (width < 0) {
+                switch (field) {
+                    default:  width += (degreesFieldWidth-1); degreesFieldWidth = 1; // Fall
through
+                    case MINUTES_FIELD: minutesSuffix = null; minutesFieldWidth = 0; // Fall
through
+                    case SECONDS_FIELD: secondsSuffix = null; secondsFieldWidth = 0;
+                }
+                if (field >= MINUTES_FIELD) {
+                    width = previousWidth;
+                }
+                break;
+            }
+        }
+        /*
+         * Removes 1 for the space needed by the decimal separator, then
+         * set the maximum number of fraction digits to the remaining space.
+         */
+        if (--width < fractionFieldWidth) {
+            fractionFieldWidth = toByte(Math.max(width, 0));
+            if (fractionFieldWidth < minimumFractionDigits) {
+                minimumFractionDigits = fractionFieldWidth;
+            }
+        }
+    }
+
+    /**
      * Formats an angle. The angle will be formatted according the pattern given to the last
call
      * of {@link #applyPattern(String)}.
      *
@@ -657,71 +751,74 @@ scan:   for (int i=0; i<length;) {
             }
         }
         /*
-         * Formatting fields.
+         * Formats fields in a loop from DEGREES_FIELD to SECONDS_FIELD inclusive.
          */
-        if (prefix != null) {
-            toAppendTo.append(prefix);
-        }
-        final int field;
+        int field    = DEGREES_FIELD;
+        int fieldPos = PREFIX_FIELD; // Dummy value not in the DEGREES … SECONDS_FIELD
range.
         if (pos != null) {
-            field = pos.getField();
+            fieldPos = pos.getField();
             pos.setBeginIndex(0);
             pos.setEndIndex(0);
-        } else {
-            field = PREFIX_FIELD;
         }
-        toAppendTo = formatField(degrees, toAppendTo, (field == DEGREES_FIELD) ? pos : null,
-                degreesFieldWidth, (minutesFieldWidth == 0) ? maximumFractionDigits : -1,
degreesSuffix);
-        if (!isNaN(minutes)) {
-            toAppendTo = formatField(minutes, toAppendTo, (field == MINUTES_FIELD) ? pos
: null,
-                    minutesFieldWidth, (secondsFieldWidth == 0) ? maximumFractionDigits :
-1, minutesSuffix);
-        }
-        if (!isNaN(seconds)) {
-            toAppendTo = formatField(seconds, toAppendTo, (field == SECONDS_FIELD) ? pos
: null,
-                    secondsFieldWidth, maximumFractionDigits, secondsSuffix);
+        final int offset = toAppendTo.length();
+        if (prefix != null) {
+            toAppendTo.append(prefix);
         }
-        return toAppendTo;
-    }
-
-    /**
-     * Formats a single field value.
-     *
-     * @param value      The field value.
-     * @param toAppendTo The buffer where to append the formatted angle.
-     * @param pos        An optional object where to store the position of a field in the
formatted text.
-     * @param width      The field width.
-     * @param suffix     Suffix to append, or {@code null} if none.
-     * @param maximumFractionDigits
-     *          Maximal number of digits for formatting the decimal digits (last field only),
-     *          or -1 for formatting an other field than the last one.
-     */
-    private StringBuffer formatField(double value, StringBuffer toAppendTo, final FieldPosition
pos,
-            final int width, final int maximumFractionDigits, final String suffix)
-    {
         final NumberFormat numberFormat = numberFormat();
-        final int startPosition = toAppendTo.length();
-        if (maximumFractionDigits < 0) {
-            numberFormat.setMinimumIntegerDigits(width);
-            numberFormat.setMaximumFractionDigits(0);
-            toAppendTo = numberFormat.format(value, toAppendTo, dummyFieldPosition());
-        } else if (useDecimalSeparator) {
-            numberFormat.setMinimumIntegerDigits(width);
-            numberFormat.setMinimumFractionDigits(minimumFractionDigits);
-            numberFormat.setMaximumFractionDigits(maximumFractionDigits);
-            toAppendTo = numberFormat.format(value, toAppendTo, dummyFieldPosition());
-        } else {
-            value *= pow10(fractionFieldWidth);
-            numberFormat.setMaximumFractionDigits(0);
-            numberFormat.setMinimumIntegerDigits(width + fractionFieldWidth);
-            toAppendTo = numberFormat.format(value, toAppendTo, dummyFieldPosition());
-        }
-        if (suffix != null) {
-            toAppendTo.append(suffix);
-        }
-        if (pos != null) {
-            pos.setBeginIndex(startPosition);
-            pos.setEndIndex(toAppendTo.length() - 1);
-        }
+        boolean hasMore;
+        do {
+            int    width;
+            double value;
+            String suffix;
+            switch (field) {
+                case DEGREES_FIELD: value=degrees; width=degreesFieldWidth; suffix=degreesSuffix;
hasMore=(minutesFieldWidth != 0); break;
+                case MINUTES_FIELD: value=minutes; width=minutesFieldWidth; suffix=minutesSuffix;
hasMore=(secondsFieldWidth != 0); break;
+                case SECONDS_FIELD: value=seconds; width=secondsFieldWidth; suffix=secondsSuffix;
hasMore=false; break;
+                default: throw new AssertionError(field);
+            }
+            final int startPosition = toAppendTo.length();
+            if (hasMore) {
+                numberFormat.setMinimumIntegerDigits(width);
+                numberFormat.setMaximumFractionDigits(0);
+                toAppendTo = numberFormat.format(value, toAppendTo, dummyFieldPosition());
+            } else if (useDecimalSeparator) {
+                numberFormat.setMinimumIntegerDigits(width);
+                if (maximumTotalWidth != 0) {
+                    /*
+                     * If we are required to fit the formatted angle in some maximal total
width
+                     * (i.e. the user called the setMaximumWidth(int) method), compute the
space
+                     * available for fraction digits after we removed the space for the integer
+                     * digits, the decimal separator (this is the -1 below) and the suffix.
+                     */
+                    int available = maximumTotalWidth - toAppendTo.codePointCount(offset,
toAppendTo.length()) - width - 1;
+                    if (suffix != null) {
+                        width -= suffix.length();
+                    }
+                    for (double scale=pow10(width); value >= scale; scale *= 10) {
+                        if (--available <= 0) break;
+                    }
+                    if (available < maximumFractionDigits) {
+                        maximumFractionDigits = Math.max(available, 0);
+                    }
+                }
+                numberFormat.setMinimumFractionDigits(minimumFractionDigits);
+                numberFormat.setMaximumFractionDigits(maximumFractionDigits);
+                toAppendTo = numberFormat.format(value, toAppendTo, dummyFieldPosition());
+            } else {
+                value *= pow10(fractionFieldWidth);
+                numberFormat.setMaximumFractionDigits(0);
+                numberFormat.setMinimumIntegerDigits(width + fractionFieldWidth);
+                toAppendTo = numberFormat.format(value, toAppendTo, dummyFieldPosition());
+            }
+            if (suffix != null) {
+                toAppendTo.append(suffix);
+            }
+            if (field == fieldPos) {
+                pos.setBeginIndex(startPosition);
+                pos.setEndIndex(toAppendTo.length() - 1);
+            }
+            field++;
+        } while (hasMore);
         return toAppendTo;
     }
 

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1402411&r1=1402410&r2=1402411&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
Fri Oct 26 07:20:17 2012
@@ -147,6 +147,11 @@ public final class Errors extends Indexe
         public static final int RecursiveCreateCallForKey_1 = 18;
 
         /**
+         * A decimal separator is required.
+         */
+        public static final int RequireDecimalSeparator = 33;
+
+        /**
          * Argument ‘{0}’ has {1} dimensions, while {2} was expected.
          */
         public static final int UnexpectedArgumentDimension_3 = 5;

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1402411&r1=1402410&r2=1402411&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
Fri Oct 26 07:20:17 2012
@@ -34,6 +34,7 @@ NotANumber_1                    = Argume
 NotAPrimitiveWrapper_1          = Class \u2018{0}\u2019 is not a primitive type wrapper.
 NullArgument_1                  = Argument \u2018{0}\u2019 shall not be null.
 RecursiveCreateCallForKey_1     = Recursive call while creating an object for the \u201c{0}\u201d
key.
+RequireDecimalSeparator         = A decimal separator is required.
 UnexpectedArgumentDimension_3   = Argument \u2018{0}\u2019 has {1} dimensions, while {2}
was expected.
 UnexpectedEndOfString_1         = More characters were expected at the end of \u201c{0}\u201d.
 UnmodifiableAffineTransform     = This affine transform is unmodifiable.

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1402411&r1=1402410&r2=1402411&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
Fri Oct 26 07:20:17 2012
@@ -34,6 +34,7 @@ NotANumber_1                    = L\u201
 NotAPrimitiveWrapper_1          = La classe \u2018{0}\u2019 n\u2019est pas un adaptateur
d\u2019un type primitif.
 NullArgument_1                  = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre nul.
 RecursiveCreateCallForKey_1     = Appel r\u00e9cursif lors de la cr\u00e9ation d\u2019un
objet pour la cl\u00e9 \u201c{0}\u201d.
+RequireDecimalSeparator         = Un s\u00e9parateur d\u00e9cimal est requis.
 UnexpectedArgumentDimension_3   = L\u2019argument \u2018{0}\u2019 a {1} dimensions, alors
qu\u2019on en attendait {2}.
 UnexpectedEndOfString_1         = D\u2019autres caract\u00e8res \u00e9taient attendus \u00e0
la fin du texte \u201c{0}\u201d.
 UnmodifiableAffineTransform     = Cette transformation affine n\u2019est pas modifiable.

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractInternationalString.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractInternationalString.java?rev=1402411&r1=1402410&r2=1402411&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractInternationalString.java
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/AbstractInternationalString.java
Fri Oct 26 07:20:17 2012
@@ -20,8 +20,8 @@ import java.util.Locale;
 import java.util.Formatter;
 import java.util.Formattable;
 import java.util.FormattableFlags;
-import org.apache.sis.util.CharSequences;
 import org.opengis.util.InternationalString;
+import org.apache.sis.internal.util.Utilities;
 
 
 /**
@@ -166,23 +166,28 @@ public abstract class AbstractInternatio
      *                  or -1 for no restriction.
      */
     @Override
-    public void formatTo(final Formatter formatter, final int flags, int width, final int
precision) {
+    public void formatTo(final Formatter formatter, int flags, final int width, int precision)
{
         final Locale locale = formatter.locale();
         String value = toString(locale);
-        if ((flags & FormattableFlags.UPPERCASE) != 0) {
-            value = value.toUpperCase(locale);
-        }
-        if (precision >= 0 && precision < value.length()) {
-            value = value.substring(0, precision);
-        }
-        final Object[] args = new Object[] {value, value};
-        width -= value.length();
-        String format = "%s";
-        if (width >= 0) {
-            format = "%s%s";
-            args[(flags & FormattableFlags.LEFT_JUSTIFY) != 0 ? 1 : 0] = CharSequences.spaces(width);
+        if (precision >= 0) {
+            if ((flags & FormattableFlags.UPPERCASE) != 0) {
+                value = value.toUpperCase(locale); // May change the length in some locales.
+                flags &= ~FormattableFlags.UPPERCASE;
+            }
+            final int length = value.length();
+            if (precision < length) {
+                try {
+                    precision = value.offsetByCodePoints(0, precision);
+                } catch (IndexOutOfBoundsException e) {
+                    precision = length;
+                    // Happen if the string has fewer code-points than 'precision'. We could
+                    // avoid the try-catch block by checking value.codePointCount(…),
but it
+                    // would result in scanning the string twice.
+                }
+                value = value.substring(0, precision);
+            }
         }
-        formatter.format(format, args);
+        Utilities.formatTo(formatter, flags, width, value);
     }
 
     /**

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java?rev=1402411&r1=1402410&r2=1402411&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java
(original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java
Fri Oct 26 07:20:17 2012
@@ -148,4 +148,53 @@ public final strictfp class AngleFormatT
         assertEquals( "12°33′45″", formatAndParse(f, new Angle( 12.5625)));
         assertEquals("-12°33′45″", formatAndParse(f, new Angle(-12.5625)));
     }
+
+    /**
+     * Tests the {@link AngleFormat#setMaximumWidth(int)} method.
+     */
+    @Test
+    @DependsOnMethod("testOptionalFractionDigits")
+    public void testSetMaximumWidth() {
+        final AngleFormat f = new AngleFormat(Locale.CANADA);
+        assertEquals("D°MM′SS.################″", f.toPattern());
+
+        f.setMaximumWidth(12);
+        assertEquals("D°MM′SS.###″", f.toPattern());
+        assertEquals("8°07′24.442″", f.format(new Angle( 8.123456)));
+        assertEquals("20°07′24.44″", f.format(new Angle(20.123456)));
+
+        f.setMaximumWidth(10);
+        assertEquals("D°MM′SS.#″", f.toPattern());
+        assertEquals("8°07′24.4″", f.format(new Angle( 8.123456)));
+        assertEquals("20°07′24″",  f.format(new Angle(20.123456)));
+
+        f.setMaximumWidth(9);
+        assertEquals("D°MM′SS″", f.toPattern());
+        f.setMaximumWidth(8);
+        assertEquals("D°MM′SS″", f.toPattern());
+
+        // Test the drop of seconds field.
+        f.setMaximumFractionDigits(6);
+        f.setMaximumWidth(7);
+        assertEquals("D°MM.#′",  f.toPattern());
+        assertEquals("8°07.4′",  f.format(new Angle( 8.123456)));
+        assertEquals("20°07.4′", f.format(new Angle(20.123456)));
+
+        f.setMaximumWidth(6);
+        assertEquals("D°MM′",  f.toPattern());
+        assertEquals("8°07′",  f.format(new Angle( 8.123456)));
+        assertEquals("20°07′", f.format(new Angle(20.123456)));
+
+        // Test the drop of minutes field.
+        f.setMaximumFractionDigits(6);
+        f.setMaximumWidth(4);
+        assertEquals("D.#°", f.toPattern());
+        assertEquals("8.1°", f.format(new Angle( 8.123456)));
+        assertEquals("20°",  f.format(new Angle(20.123456)));
+
+        f.setMaximumWidth(3);
+        assertEquals("D°",  f.toPattern());
+        assertEquals("8°",  f.format(new Angle( 8.123456)));
+        assertEquals("20°", f.format(new Angle(20.123456)));
+    }
 }

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java?rev=1402411&r1=1402410&r2=1402411&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java (original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java Fri
Oct 26 07:20:17 2012
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.measure;
 
+import java.util.Locale;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
@@ -68,4 +69,19 @@ public final strictfp class AngleTest ex
         assertEquals(new Longitude(455.), new Longitude("45.5E1"));
         assertEquals(new Longitude(4.55), new Longitude("45.5E-1"));
     }
+
+    /**
+     * Tests the {@link Angle#formatTo(Formatter, int, int, int)} method.
+     */
+    @Test
+    public void testFormatTo() {
+        assertEquals("5°30′00″",  String.format(Locale.CANADA,  "%s",    new
Angle   (5.5)));
+        assertEquals("5°30′00″N", String.format(Locale.CANADA,  "%s",    new
Latitude(5.5)));
+        assertEquals("  5°30′",   String.format(Locale.CANADA,  "%7.5s", new Angle
  (5.5)));
+        assertEquals("  5.5°N",   String.format(Locale.CANADA,  "%7.5s", new Latitude(5.5)));
+        assertEquals("  5,5°N",   String.format(Locale.FRANCE,  "%7.5s", new Latitude(5.5)));
+        assertEquals("5,5°N  ",   String.format(Locale.FRANCE, "%-7.5s", new Latitude(5.5)));
+        assertEquals("N",         String.format(Locale.FRANCE,  "%1.1s", new Latitude(5.5)));
+        assertEquals(" ",         String.format(Locale.FRANCE,  "%1.0s", new Latitude(5.5)));
+    }
 }



Mime
View raw message