Return-Path: X-Original-To: apmail-sis-commits-archive@www.apache.org Delivered-To: apmail-sis-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1D74210597 for ; Thu, 15 Aug 2013 17:34:04 +0000 (UTC) Received: (qmail 37653 invoked by uid 500); 15 Aug 2013 17:34:03 -0000 Delivered-To: apmail-sis-commits-archive@sis.apache.org Received: (qmail 37623 invoked by uid 500); 15 Aug 2013 17:33:57 -0000 Mailing-List: contact commits-help@sis.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: sis-dev@sis.apache.org Delivered-To: mailing list commits@sis.apache.org Received: (qmail 37594 invoked by uid 99); 15 Aug 2013 17:33:56 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 15 Aug 2013 17:33:56 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 15 Aug 2013 17:33:48 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 87F182388999; Thu, 15 Aug 2013 17:33:26 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: svn commit: r1514390 [2/2] - in /sis/branches/JDK6: ./ application/sis-console/ application/sis-console/src/main/artifact/ core/sis-metadata/ core/sis-metadata/src/main/java/org/apache/sis/metadata/ core/sis-metadata/src/main/java/org/apache/sis/metada... Date: Thu, 15 Aug 2013 17:33:24 -0000 To: commits@sis.apache.org From: desruisseaux@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20130815173326.87F182388999@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java [UTF-8] (original) +++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java [UTF-8] Thu Aug 15 17:33:23 2013 @@ -59,45 +59,64 @@ import org.apache.sis.internal.jdk7.Obje * {@code s}The fractional part of seconds * {@code #}Fraction digits shown only if non-zero * {@code .}The decimal separator + * {@code ?}Omit the preceding field if zero * * * Upper-case letters {@code D}, {@code M} and {@code S} stand for the integer parts of degrees, - * minutes and seconds respectively. They shall appear in this order. For example {@code M'D} is - * illegal because "M" and "S" are in reverse order; {@code D°S} is illegal too because "M" is - * missing between "D" and "S". + * minutes and seconds respectively. If present, they shall appear in that order. * - *

Lower-case letters {@code d}, {@code m} and {@code s} stand for fractional parts of degrees, - * minutes and seconds respectively. Only one of those may appears in a pattern, and it must be - * the last special symbol. For example {@code D.dd°MM'} is illegal because "d" is followed by - * "M"; {@code D.mm} is illegal because "m" is not the fractional part of "D".

+ * {@example "M′D" is illegal because "M" and "S" are in reverse order. + * "D°S" is also illegal because "M" is missing between "D" and + * "S".} * - *

The number of occurrence of {@code D}, {@code M}, {@code S} and their lower-case counterpart - * is the number of digits to format. For example, {@code DD.ddd} will format angles with two digits - * for the integer part and three digits for the fractional part (e.g. 4.4578 will be formatted as - * "04.458").

+ * Lower-case letters {@code d}, {@code m} and {@code s} stand for fractional parts of degrees, minutes and + * seconds respectively. Only one of those can appear in a pattern. If present, they must be in the last field. * - *

Separator characters like {@code °}, {@code ′} and {@code ″} are inserted "as-is" in the - * formatted string, except the decimal separator dot ({@code .}) which is replaced by the - * local-dependent decimal separator. Separator characters may be completely omitted; - * {@code AngleFormat} will still differentiate degrees, minutes and seconds fields according - * the pattern. For example, "{@code 0480439}" with the pattern {@code DDDMMmm} will be parsed - * as 48°04.39'.

+ * {@example "D.dd°MM′" is illegal because "d" is followed by "M". + * "D.mm" is also illegal because "m" is not the fractional part of + * "D".} * - *

The following table gives some pattern examples:

+ * The number of occurrences of {@code D}, {@code M}, {@code S} and their lower-case counterpart is the number + * of digits to format. * + * {@example "DD.ddd" will format angles with two digits for the integer part and three digits + * for the fractional part (e.g. 4.4578 will be formatted as "04.458").} + * + * Separator characters like {@code °}, {@code ′} and {@code ″} are inserted "as-is" in the formatted string, + * except the decimal separator dot ({@code .}) which is replaced by the local-dependent decimal separator. + * Separator characters may be completely omitted; {@code AngleFormat} will still differentiate degrees, + * minutes and seconds fields according the pattern. + * + * {@example "0480439" with the "DDDMMmm" pattern will be parsed as 48°04.39′.} + * + * The {@code ?} modifier specifies that the preceding field can be omitted if its value is zero. + * Any field can be omitted for {@link Angle} object, but only trailing fields are omitted for + * {@li{@link Longitude} and {@link Latitude}. + * + * {@example "DD°MM′?SS″?" will format an angle of 12.01° as 12°36″, + * but a longitude of 12.01°N as 12°00′36″N (not 12°36″N).} + * + * The above special case exists because some kind of angles are expected to be very small (e.g. rotation angles in + * {@linkplain org.apache.sis.referencing.datum.BursaWolfParameters Bursa-Wolf parameters} are given in arc-seconds), + * while longitude and latitude values are usually distributed over their full ±180° or ±90° range. Since longitude + * or latitude values without the degrees field are unusual, omitting that field is likely to increase the + * risk of confusion in those cases. + * + * {@section Examples} * - * - * - * - * - * - * - * + * + * + * + * + * + * + * + * *
Pattern Example
{@code DD°MM′SS″ } 48°30′00″
{@code DD°MM′ } 48°30′
{@code DD.ddd } 48.500
{@code DD.### } 48.5
{@code DDMM } 4830
{@code DDMMSS } 483000
Pattern 48.5 -12.53125
{@code DD°MM′SS.#″} 48°30′00″ -12°31′52.5″
{@code DD°MM′} 48°30′ -12°32′
{@code DD.ddd} 48.500 -12.531
{@code DD.###} 48.5 -12.531
{@code DDMM} 4830 -1232
{@code DDMMSSs} 4830000 -1231525
{@code DD°MM′?SS.s″?} 48°30′ -12°31′52.5″
* * @author Martin Desruisseaux (MPO, IRD, Geomatys) * @since 0.3 (derived from geotk-1.0) - * @version 0.3 + * @version 0.4 * @module * * @see Angle @@ -165,10 +184,15 @@ public class AngleFormat extends Format static final int HEMISPHERE_FIELD = 4; /** + * Index for the {@link #SYMBOLS} character which stands for optional field. + */ + private static final int OPTIONAL_FIELD = 4; + + /** * Symbols for degrees (0), minutes (1), seconds (2) and optional fraction digits (3). * The index of each symbol shall be equal to the corresponding {@code *_FIELD} constant. */ - private static final char[] SYMBOLS = {'D', 'M', 'S', '#'}; + private static final int[] SYMBOLS = {'D', 'M', 'S', '#', '?'}; /** * Defines constants that are used as attribute keys in the iterator returned from @@ -254,6 +278,13 @@ public class AngleFormat extends Format maximumTotalWidth; /** + * A bitmask of optional fields. Optional fields are formatted only if their value is different than zero. + * The bit position is given by a {@code *_FIELD} constant, and the actual bitmask is computed by + * {@code 1 << *_FIELD}. A value of zero means that no field is optional. + */ + private byte optionalFields; + + /** * Characters to insert before the text to format, and after each field. * A {@code null} value means that there is nothing to insert. */ @@ -282,6 +313,16 @@ public class AngleFormat extends Format private boolean useDecimalSeparator; /** + * If {@code true}, {@link #optionalFields} never apply to fields to leading fields. + * If the minutes field is declared optional but the degrees and seconds are formatted, + * then minutes will be formatted too un order to reduce the risk of confusion + * + * {@example Value 12.01 is formatted as 12°00′36″ if true + * and as 12°36″ if false.} + */ + private transient boolean showLeadingFields; + + /** * Format to use for writing numbers (degrees, minutes or seconds) when formatting an angle. * The pattern given to this {@code DecimalFormat} shall NOT accept exponential notation, * because "E" of "Exponent" would be confused with "E" of "East". @@ -360,14 +401,15 @@ public class AngleFormat extends Format public AngleFormat(final Locale locale) { ArgumentChecks.ensureNonNull("locale", locale); this.locale = locale; - degreesFieldWidth = 1; - minutesFieldWidth = 2; - secondsFieldWidth = 2; - fractionFieldWidth = 16; // Number of digits for accurate representation of 1″ ULP. - degreesSuffix = "°"; - minutesSuffix = "′"; - secondsSuffix = "″"; - useDecimalSeparator = true; + degreesFieldWidth = 1; + minutesFieldWidth = 2; + secondsFieldWidth = 2; + fractionFieldWidth = 16; // Number of digits for accurate representation of 1″ ULP. + optionalFields = (1 << DEGREES_FIELD) | (1 << MINUTES_FIELD) | (1 << SECONDS_FIELD); + degreesSuffix = "°"; + minutesSuffix = "′"; + secondsSuffix = "″"; + useDecimalSeparator = true; } /** @@ -390,6 +432,7 @@ public class AngleFormat extends Format * @throws IllegalArgumentException If the specified pattern is illegal. */ public AngleFormat(final String pattern, final Locale locale) throws IllegalArgumentException { + ArgumentChecks.ensureNonEmpty("pattern", pattern); ArgumentChecks.ensureNonNull("locale", locale); this.locale = locale; applyPattern(pattern, SYMBOLS, '.'); @@ -406,137 +449,182 @@ public class AngleFormat extends Format * @see #setMaximumFractionDigits(int) */ public void applyPattern(final String pattern) throws IllegalArgumentException { - applyPattern(pattern, SYMBOLS, '.'); - } - - /** - * Actual implementation of {@link #applyPattern(String)}, - * as a private method for use by the constructor. - * - * @param symbols An array of 3 characters containing the reserved symbols as upper-case letters. - * This is always the {@link #SYMBOLS} array, unless we apply localized patterns. - * @param decimalSeparator The code point which represent decimal separator in the pattern. - */ - @SuppressWarnings("fallthrough") - private void applyPattern(final String pattern, final char[] symbols, final int decimalSeparator) { ArgumentChecks.ensureNonEmpty("pattern", pattern); - degreesFieldWidth = 1; + degreesFieldWidth = 0; minutesFieldWidth = 0; secondsFieldWidth = 0; fractionFieldWidth = 0; minimumFractionDigits = 0; maximumTotalWidth = 0; + optionalFields = 0; prefix = null; degreesSuffix = null; minutesSuffix = null; secondsSuffix = null; + useDecimalSeparator = false; + applyPattern(pattern, SYMBOLS, '.'); + } + + /** + * Actual implementation of {@link #applyPattern(String)}, as a private method for use by the constructor. + * All fields related to the pattern shall be set to 0 or null before this method call. + * + * @param symbols An array of code points containing the reserved symbols as upper-case letters. + * This is always the {@link #SYMBOLS} array, unless we apply localized patterns. + * @param decimalSeparator The code point which represent decimal separator in the pattern. + */ + @SuppressWarnings("fallthrough") + private void applyPattern(final String pattern, final int[] symbols, final int decimalSeparator) { + degreesFieldWidth = 1; useDecimalSeparator = true; int expectedField = PREFIX_FIELD; int endPreviousField = 0; boolean parseFinished = false; final int length = pattern.length(); -scan: for (int i=0; i endPreviousField) ? pattern.substring(endPreviousField, i) : null; - int width = 1; - while ((i += charCount) < length && pattern.codePointAt(i) == c) { - width++; - } - final byte wb = toByte(width); - switch (field) { - case DEGREES_FIELD: prefix = previousSuffix; degreesFieldWidth = wb; break; - case MINUTES_FIELD: degreesSuffix = previousSuffix; minutesFieldWidth = wb; break; - case SECONDS_FIELD: minutesSuffix = previousSuffix; secondsFieldWidth = wb; break; - default: throw new AssertionError(field); - } - } else { - /* - * If the reserved letter is lower-case or the symbol for optional fraction - * digit, the part before that letter will be the decimal separator rather - * than the suffix of previous field. The count the number of occurrences of - * the lower-case letter; this will be the precision of the fraction part. - */ - if (i == endPreviousField) { - useDecimalSeparator = false; - } else { - final int b = pattern.codePointAt(endPreviousField); - if (b != decimalSeparator || endPreviousField + Character.charCount(b) != i) { - throw new IllegalArgumentException(Errors.format( - Errors.Keys.IllegalFormatPatternForClass_2, Angle.class, pattern)); - } - } - int width = 1; - while ((i += charCount) < length) { - final int fc = pattern.codePointAt(i); - if (fc != c) { - if (fc != symbols[FRACTION_FIELD]) break; - // Switch the search from mandatory to optional digits. - minimumFractionDigits = toByte(width); - charCount = Character.charCount(c = fc); + String previousSuffix = null; + if (endPreviousField < i) { + int endPreviousSuffix = i; + if (pattern.codePointBefore(endPreviousSuffix) == symbols[OPTIONAL_FIELD]) { + // If we find the '?' character, then the previous field is optional. + if (--endPreviousSuffix == endPreviousField) { + throw illegalPattern(pattern); } - width++; + optionalFields |= (1 << (field - 1)); } - 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; + previousSuffix = pattern.substring(endPreviousField, endPreviousSuffix); + } + int width = 1; + while ((i += charCount) < length && pattern.codePointAt(i) == c) { + width++; + } + final byte wb = toByte(width); + switch (field) { + case DEGREES_FIELD: prefix = previousSuffix; degreesFieldWidth = wb; break; + case MINUTES_FIELD: degreesSuffix = previousSuffix; minutesFieldWidth = wb; break; + case SECONDS_FIELD: minutesSuffix = previousSuffix; secondsFieldWidth = wb; break; + default: throw new AssertionError(field); + } + } else { + /* + * If the reserved letter is lower-case or the symbol for optional fraction digit, + * then the part before that letter will be the decimal separator rather than the + * suffix of previous field. The number of occurrences of the lower-case letter will + * be the precision of the fraction part. + */ + if (i == endPreviousField) { + useDecimalSeparator = false; + } else { + final int b = pattern.codePointAt(endPreviousField); + if (b != decimalSeparator || endPreviousField + Character.charCount(b) != i) { + throw illegalPattern(pattern); + } + } + int width = 1; + while ((i += charCount) < length) { + final int fc = pattern.codePointAt(i); + if (fc != c) { + if (fc != symbols[FRACTION_FIELD]) break; + // Switch the search from mandatory to optional digits. + minimumFractionDigits = toByte(width); + charCount = Character.charCount(c = fc); + } + width++; + } + 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)); } - endPreviousField = i; - continue scan; + parseFinished = true; } - i += charCount; + endPreviousField = i; } + /* + * At this point, we finished parsing the pattern. We may have some trailing characters which have not + * been processed by the main loop. Those trailing characters will be the suffix of the last field. + */ if (endPreviousField < length) { - final String suffix = pattern.substring(endPreviousField); + int endPreviousSuffix = length; + if (pattern.codePointBefore(endPreviousSuffix) == symbols[OPTIONAL_FIELD]) { + if (--endPreviousSuffix == endPreviousField) { + throw illegalPattern(pattern); + } + optionalFields |= (1 << expectedField); + } + final String suffix = pattern.substring(endPreviousField, endPreviousSuffix); switch (expectedField) { case DEGREES_FIELD: degreesSuffix = suffix; break; case MINUTES_FIELD: minutesSuffix = suffix; break; case SECONDS_FIELD: secondsSuffix = suffix; break; default: { // Happen if no symbol has been recognized in the pattern. - throw new IllegalArgumentException(Errors.format( - Errors.Keys.IllegalFormatPatternForClass_2, Angle.class, pattern)); + throw illegalPattern(pattern); } } } } /** + * Returns the field index for the given upper case character, or -1 if none. + * + * @param symbols An array of code points containing the reserved symbols as upper-case letters. + * @param c The symbol to search, as an upper-case character (code point actually). + * @return The index of the given character, or -1 if not found. + */ + private static int fieldForSymbol(final int[] symbols, final int c) { + for (int field=DEGREES_FIELD; field<=FRACTION_FIELD; field++) { + if (c == symbols[field]) { + return field; + } + } + return -1; + } + + /** + * Returns an exception for an illegal pattern. + */ + private static IllegalArgumentException illegalPattern(final String pattern) { + return new IllegalArgumentException(Errors.format( + Errors.Keys.IllegalFormatPatternForClass_2, Angle.class, pattern)); + } + + /** * Returns the pattern used for parsing and formatting angles. * See class description for an explanation of how patterns work. * @@ -550,14 +638,16 @@ scan: for (int i=0; i 0); } - if (previousSuffix != null) { - buffer.append(previousSuffix); - } - break; // We are done. + /* + * The code for writing the suffix is common to this "if" case (the fraction part of + * the pattern) and the "normal" case below. So we write the suffix outside the "if" + * block and will exit the main loop immediately after that. + */ } - /* - * This is the normal part of the loop, before the final fractional part handled - * in the above block. Write the suffix of the previous field, then the pattern - * for the integer part of degrees, minutes or second field. - */ if (previousSuffix != null) { buffer.append(previousSuffix); } + if (previousWasOptional) { + buffer.appendCodePoint(symbols[OPTIONAL_FIELD]); + } + if (width <= 0) { + break; // The "if" case above has been executed for writing the fractional part, so we are done. + } + /* + * This is the main part of the loop, before the final fractional part handled in the above "if" case. + * Write the pattern for the integer part of degrees, minutes or second field. + */ symbol = symbols[field]; - do buffer.append(symbol); + do buffer.appendCodePoint(symbol); while (--width > 0); + previousWasOptional = (optionalFields & (1 << field)) != 0; } return buffer.toString(); } @@ -809,32 +906,44 @@ scan: for (int i=0; i= 60) { // We do not expect > 60 (only == 60), but let be safe. + seconds = 0; + minutes++; + } } else { - final double puissance = pow10(fractionFieldWidth); - minutes = rint(minutes * puissance) / puissance; + minutes = rint(minutes * p) / p; // Correction for rounding errors. + } + if (minutes >= 60) { // We do not expect > 60 (only == 60), but let be safe. + minutes = 0; + degrees += Math.signum(angle); + } + // Note: a previous version was doing a unconditional addition to the 'degrees' variable, + // in the form 'degrees += correction'. However -0.0 + 0 == +0.0, while we really need to + // preserve the sign of negative zero. See [SIS-120]. + } + /* + * Avoid formatting values like 12.01°N as 12°36″N because of the risk of confusion. + * In such cases, force the formatting of minutes field as in 12°00′36″. + */ + byte effectiveOptionalFields = optionalFields; + if (showLeadingFields) { + effectiveOptionalFields &= ~(1 << DEGREES_FIELD); + if (minutes == 0 && ((effectiveOptionalFields & (1 << SECONDS_FIELD)) == 0 || seconds != 0)) { + effectiveOptionalFields &= ~(1 << MINUTES_FIELD); } - final double correction = truncate(minutes / 60); - minutes -= correction * 60; - degrees += correction; } /* * At this point the 'degrees', 'minutes' and 'seconds' variables contain the final values @@ -853,11 +962,10 @@ scan: for (int i=0; i - *
  • If the given type is {@code Double.class}, then this method returns + *
  • If the given value is {@code null} or an instance of the given type, then it is returned unchanged.
  • + *
  • Otherwise if the given type is {@code Double.class}, then this method returns * {@linkplain Double#valueOf(double) Double.valueOf}(number.doubleValue());
  • - *
  • If the given type is {@code Float.class}, then this method returns + *
  • Otherwise if the given type is {@code Float.class}, then this method returns * {@linkplain Float#valueOf(float) Float.valueOf}(number.floatValue());
  • *
  • And likewise for all remaining known types.
  • * Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java [UTF-8] (original) +++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java [UTF-8] Thu Aug 15 17:33:23 2013 @@ -326,6 +326,10 @@ abstract class Pooled { mask |= Context.SUBSTITUTE_LANGUAGE; } else if (CharSequences.equalsIgnoreCase(substitute, "country")) { mask |= Context.SUBSTITUTE_COUNTRY; + } else if (CharSequences.equalsIgnoreCase(substitute, "filename")) { + mask |= Context.SUBSTITUTE_FILENAME; + } else if (CharSequences.equalsIgnoreCase(substitute, "mimetype")) { + mask |= Context.SUBSTITUTE_MIMETYPE; } } } @@ -369,9 +373,11 @@ abstract class Pooled { if (name.equals(XML.WARNING_LISTENER)) return warningListener; if (name.equals(XML.STRING_SUBSTITUTES)) { int n = 0; - final String[] substitutes = new String[2]; + final String[] substitutes = new String[4]; if ((bitMasks & Context.SUBSTITUTE_LANGUAGE) != 0) substitutes[n++] = "language"; if ((bitMasks & Context.SUBSTITUTE_COUNTRY) != 0) substitutes[n++] = "country"; + if ((bitMasks & Context.SUBSTITUTE_FILENAME) != 0) substitutes[n++] = "filename"; + if ((bitMasks & Context.SUBSTITUTE_MIMETYPE) != 0) substitutes[n++] = "mimetype"; return (n != 0) ? ArraysExt.resize(substitutes, n) : null; } else { Modified: sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java [UTF-8] (original) +++ sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java [UTF-8] Thu Aug 15 17:33:23 2013 @@ -237,8 +237,10 @@ public final class XML extends Static { * The value for this property shall be a {@code String[]} array of any of the following values: * *
      - *
    • "{@code language}"
    • - *
    • "{@code country}"
    • + *
    • "{@code language}" for substituting {@code } elements
    • + *
    • "{@code country}" for substituting {@code } elements
    • + *
    • "{@code filename}" for substituting {@code } elements
    • + *
    • "{@code mimetype}" for substituting {@code } elements
    • *
    * * {@section Example} Modified: sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java [UTF-8] (original) +++ sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java [UTF-8] Thu Aug 15 17:33:23 2013 @@ -187,7 +187,8 @@ public final strictfp class StringConver @Test public void testAngle() { final ObjectConverter c = new StringConverter.Angle(); - runInvertibleConversion(c, "42°30′00″", new Angle(42.5)); + runInvertibleConversion(c, "42°30′", new Angle(42.5)); + runInvertibleConversion(c, "42°30′56.25″", new Angle(42.515625)); tryUnconvertibleValue(c); assertSerializedEquals(c); } Modified: sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java [UTF-8] (original) +++ sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java [UTF-8] Thu Aug 15 17:33:23 2013 @@ -56,8 +56,10 @@ public final strictfp class MathFunction */ @Test public void testTruncate() { - assertEquals(+4, truncate(+4.9), 0); - assertEquals(-4, truncate(-4.9), 0); + assertEquals(+4.0, truncate(+4.9), 0); + assertEquals(-4.0, truncate(-4.9), 0); + assertEquals(+0.0, truncate(+0.1), 0); + assertEquals(-0.0, truncate(-0.1), 0); assertEquals("Positive zero", Double.doubleToLongBits(+0.0), Double.doubleToLongBits(truncate(+0.5))); Modified: sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java [UTF-8] (original) +++ sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/measure/AngleFormatTest.java [UTF-8] Thu Aug 15 17:33:23 2013 @@ -19,6 +19,7 @@ package org.apache.sis.measure; import java.util.Locale; import java.text.FieldPosition; import java.text.AttributedCharacterIterator; +import java.text.ParseException; import org.apache.sis.test.TestCase; import org.apache.sis.test.DependsOn; import org.apache.sis.test.DependsOnMethod; @@ -33,7 +34,7 @@ import static org.apache.sis.test.TestUt * * @author Martin Desruisseaux (MPO, IRD, Geomatys) * @since 0.3 (derived from geotk-2.0) - * @version 0.3 + * @version 0.4 * @module */ @DependsOn({ @@ -60,6 +61,24 @@ public final strictfp class AngleFormatT } /** + * Tests a {@code '?'} symbol without suffix. + */ + @Test(expected = IllegalArgumentException.class) + public void testIllegalOptionalField() { + final AngleFormat f = new AngleFormat(Locale.CANADA); + f.applyPattern("DD°MM?SS.m″"); + } + + /** + * Tests a {@code '?'} symbol without suffix. + */ + @Test(expected = IllegalArgumentException.class) + public void testIllegalOptionalLastField() { + final AngleFormat f = new AngleFormat(Locale.CANADA); + f.applyPattern("DD°MM?"); + } + + /** * Tests using {@link Locale#CANADA}. */ @Test @@ -73,6 +92,7 @@ public final strictfp class AngleFormatT assertEquals("-12.247°", formatAndParse(f, new Angle (-12.247))); assertEquals( "13.214°N", formatAndParse(f, new Latitude( 13.214))); assertEquals( "12.782°S", formatAndParse(f, new Latitude(-12.782))); + assertEquals("-00.010°", formatAndParse(f, new Angle (-0.01))); } /** @@ -83,9 +103,10 @@ public final strictfp class AngleFormatT final AngleFormat f = new AngleFormat("DD.ddd°", Locale.FRANCE); assertEquals(3, f.getMinimumFractionDigits()); assertEquals(3, f.getMaximumFractionDigits()); - assertEquals( "DD.ddd°", f.toPattern()); - assertEquals("19,457°E", formatAndParse(f, new Longitude( 19.457))); - assertEquals("78,124°S", formatAndParse(f, new Latitude (-78.124))); + assertEquals( "DD.ddd°", f.toPattern()); + assertEquals( "19,457°E", formatAndParse(f, new Longitude( 19.457))); + assertEquals( "78,124°S", formatAndParse(f, new Latitude (-78.124))); + assertEquals("-00,010°", formatAndParse(f, new Angle (-0.01))); } /** @@ -96,9 +117,10 @@ public final strictfp class AngleFormatT final AngleFormat f = new AngleFormat("DDddd", Locale.CANADA); assertEquals(3, f.getMinimumFractionDigits()); assertEquals(3, f.getMaximumFractionDigits()); - assertEquals("DDddd", f.toPattern()); - assertEquals("19457E", formatAndParse(f, new Longitude( 19.457))); - assertEquals("78124S", formatAndParse(f, new Latitude (-78.124))); + assertEquals( "DDddd", f.toPattern()); + assertEquals( "19457E", formatAndParse(f, new Longitude( 19.457))); + assertEquals( "78124S", formatAndParse(f, new Latitude (-78.124))); + assertEquals("-00010", formatAndParse(f, new Angle (-0.01))); } /** @@ -113,6 +135,7 @@ public final strictfp class AngleFormatT assertEquals( "DD°MM.m", f.toPattern()); assertEquals( "12°30.0", formatAndParse(f, new Angle( 12.50))); assertEquals("-10°15.0", formatAndParse(f, new Angle(-10.25))); + assertEquals("-00°00.6", formatAndParse(f, new Angle( -0.01))); } /** @@ -127,6 +150,74 @@ public final strictfp class AngleFormatT assertEquals( "DD°MM′SS.sss″", f.toPattern()); assertEquals( "12°30′56.250″", formatAndParse(f, new Angle( 12.515625))); assertEquals("-12°30′56.250″", formatAndParse(f, new Angle(-12.515625))); + assertEquals("-00°00′36.000″", formatAndParse(f, new Angle( -0.01))); + } + + /** + * Tests values that have to be rounded, especially the values near zero. + */ + @Test + @DependsOnMethod("testDegreeMinutesSeconds") + public void testRounding() { + final AngleFormat f = new AngleFormat("DD°MM′SS.sss″", Locale.CANADA); + assertEquals( "01°00′00.000″", f.format(new Angle(+(59 + (59.9999 / 60)) / 60))); + assertEquals("-01°00′00.000″", f.format(new Angle(-(59 + (59.9999 / 60)) / 60))); + assertEquals("-00°59′59.999″", f.format(new Angle(-(59 + (59.9988 / 60)) / 60))); + } + + /** + * Tests with optional minutes and seconds fields. + */ + @Test + @DependsOnMethod("testDegreeMinutesSeconds") + public void testOptionalFields() { + final AngleFormat f = new AngleFormat(Locale.CANADA); + assertEquals("D°?MM′?SS.################″?", f.toPattern()); + assertEquals("12°", formatAndParse(f, new Angle(12))); + assertEquals("12°30′", formatAndParse(f, new Angle(12.5))); + assertEquals("12°36″", formatAndParse(f, new Angle(12.01))); + assertEquals("12°00′36″N", formatAndParse(f, new Latitude(12.01))); + assertEquals("12°30′56.25″", formatAndParse(f, new Angle(12.515625))); + assertEquals("-36″", formatAndParse(f, new Angle(-0.01))); + assertEquals("0°00′36″S", formatAndParse(f, new Latitude(-0.01))); + } + + /** + * Tests the example provided in the {@link AngleFormat} javadoc. + * + * @throws ParseException If a string can not be parsed. + */ + @Test + @DependsOnMethod("testOptionalFields") + public void testJavadocExamples() throws ParseException { + final AngleFormat f = new AngleFormat(Locale.CANADA); + testExample(f, "DD°MM′SS.#″", "48°30′00″", "-12°31′52.5″", 0.000); + testExample(f, "DD°MM′", "48°30′", "-12°32′", 0.003); + testExample(f, "DD.ddd", "48.500", "-12.531", 2.500); + testExample(f, "DD.###", "48.5", "-12.531", 2.500); + testExample(f, "DDMM", "4830", "-1232", 0.003); + testExample(f, "DDMMSSs", "4830000", "-1231525", 0.000); + testExample(f, "DD°MM′?SS.s″?", "48°30′", "-12°31′52.5″", 0.000); + } + + /** + * Tests a single line of Javadoc examples. + * + * @param f The angle format to test. + * @param pattern The pattern to apply for the test. + * @param e1 The expected string value of 48.5. + * @param e2 The expected string value of -12.53125. + * @param eps The tolerance for comparing the parsed value of {@code e2}. + */ + private static void testExample(final AngleFormat f, final String pattern, final String e1, final String e2, + final double eps) throws ParseException + { + f.applyPattern(pattern); + assertEquals("toPattern()", pattern, f.toPattern()); + assertEquals("format(double)", e1, f.format(48.5)); + assertEquals("format(double)", e2, f.format(-12.53125)); + assertEquals("parse(String)", 48.5, f.parse(e1).degrees(), 0.0); + assertEquals("parse(String)", -12.53125, f.parse(e2).degrees(), eps); } /** @@ -160,7 +251,7 @@ public final strictfp class AngleFormatT @Test @DependsOnMethod("testOptionalFractionDigits") public void testSetMaximumWidth() { - final AngleFormat f = new AngleFormat(Locale.CANADA); + final AngleFormat f = new AngleFormat("D°MM′SS.################″", Locale.CANADA); assertEquals("D°MM′SS.################″", f.toPattern()); f.setMaximumWidth(12); Modified: sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java [UTF-8] (original) +++ sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/measure/AngleTest.java [UTF-8] Thu Aug 15 17:33:23 2013 @@ -29,7 +29,7 @@ import static org.junit.Assert.*; * * @author Martin Desruisseaux (MPO, IRD, Geomatys) * @since 0.3 (derived from geotk-2.0) - * @version 0.3 + * @version 0.4 * @module */ @DependsOn(AngleFormatTest.class) @@ -39,9 +39,11 @@ public final strictfp class AngleTest ex */ @Test public void testToString() { - assertEquals("45°30′00″", new Angle (45.5).toString()); - assertEquals("45°30′00″N", new Latitude (45.5).toString()); - assertEquals("45°30′00″E", new Longitude(45.5).toString()); + assertEquals("45°", new Angle (45 ).toString()); + assertEquals("45°30′", new Angle (45.5).toString()); + assertEquals("45°30′N", new Latitude (45.5).toString()); + assertEquals("45°30′E", new Longitude(45.5).toString()); + assertEquals("45°30′56.25″E", new Longitude(45.515625).toString()); // Angle out of expected range. assertEquals( "720.0°E", new Longitude( 720).toString()); @@ -59,6 +61,7 @@ public final strictfp class AngleTest ex */ @Test public void testParse() { + assertEquals(new Angle (45.5), new Angle ("45°30′")); assertEquals(new Angle (45.5), new Angle ("45°30′00″")); assertEquals(new Latitude (45.5), new Latitude ("45°30′00″N")); assertEquals(new Longitude(45.5), new Longitude("45°30′00″E")); @@ -75,13 +78,13 @@ public final strictfp class AngleTest ex */ @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))); + assertEquals("5°30′36″", String.format(Locale.CANADA, "%s", new Angle (5.51))); + assertEquals("5°30′36″N", String.format(Locale.CANADA, "%s", new Latitude(5.51))); + assertEquals(" 5°31′", String.format(Locale.CANADA, "%7.5s", new Angle (5.51))); + assertEquals(" 5.5°N", String.format(Locale.CANADA, "%7.5s", new Latitude(5.51))); + assertEquals(" 5,5°N", String.format(Locale.FRANCE, "%7.5s", new Latitude(5.51))); + assertEquals("5,5°N ", String.format(Locale.FRANCE, "%-7.5s", new Latitude(5.51))); + assertEquals("N", String.format(Locale.FRANCE, "%1.1s", new Latitude(5.51))); + assertEquals(" ", String.format(Locale.FRANCE, "%1.0s", new Latitude(5.51))); } } Modified: sis/branches/JDK6/ide-project/NetBeans/nbproject/project.properties URL: http://svn.apache.org/viewvc/sis/branches/JDK6/ide-project/NetBeans/nbproject/project.properties?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/ide-project/NetBeans/nbproject/project.properties [ISO-8859-1] (original) +++ sis/branches/JDK6/ide-project/NetBeans/nbproject/project.properties [ISO-8859-1] Thu Aug 15 17:33:23 2013 @@ -72,7 +72,7 @@ jdom1.version = 1.0 jdom2.version = 2.0.4 jee.version = 6.0 osgi.version = 5.0.0 -netcdf.version = 4.3.17 +netcdf.version = 4.3.18 joda-time.version = 2.0 httpclient.version = 3.1 slf4j.version = 1.6.4 Modified: sis/branches/JDK6/pom.xml URL: http://svn.apache.org/viewvc/sis/branches/JDK6/pom.xml?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/pom.xml (original) +++ sis/branches/JDK6/pom.xml Thu Aug 15 17:33:23 2013 @@ -374,7 +374,7 @@ Apache SIS is a free software, Java lang =================================================================== --> 3.1-M04 - 4.3.17 + 4.3.18 2.5.2 UTF-8 UTF-8 Modified: sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java?rev=1514390&r1=1514389&r2=1514390&view=diff ============================================================================== --- sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java [UTF-8] (original) +++ sis/branches/JDK6/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java [UTF-8] Thu Aug 15 17:33:23 2013 @@ -113,10 +113,10 @@ public final strictfp class MetadataRead "  │   ├─Spatial representation type……………………………… Grid\n" + "  │   ├─Extent\n" + "  │   │   ├─Geographic element\n" + - "  │   │   │   ├─West bound longitude…………………………… -180.0\n" + - "  │   │   │   ├─East bound longitude…………………………… 180.0\n" + - "  │   │   │   ├─South bound latitude…………………………… -90.0\n" + - "  │   │   │   ├─North bound latitude…………………………… 90.0\n" + + "  │   │   │   ├─West bound longitude…………………………… 180°W\n" + + "  │   │   │   ├─East bound longitude…………………………… 180°E\n" + + "  │   │   │   ├─South bound latitude…………………………… 90°S\n" + + "  │   │   │   ├─North bound latitude…………………………… 90°N\n" + "  │   │   │   └─Extent type code……………………………………… true\n" + "  │   │   └─Vertical element\n" + "  │   │       ├─Minimum value……………………………………………… 0.0\n" +