Frames | No Frames |
1: /* DecimalFormatSymbols.java -- Format symbols used by DecimalFormat 2: Copyright (C) 1999, 2000, 2001, 2004, 2007 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.text; 40: 41: import gnu.java.locale.LocaleHelper; 42: 43: import java.io.IOException; 44: import java.io.ObjectInputStream; 45: import java.io.Serializable; 46: 47: import java.text.spi.DecimalFormatSymbolsProvider; 48: 49: import java.util.Currency; 50: import java.util.Locale; 51: import java.util.MissingResourceException; 52: import java.util.ResourceBundle; 53: import java.util.ServiceLoader; 54: 55: /** 56: * This class is a container for the symbols used by 57: * <code>DecimalFormat</code> to format numbers and currency. These are 58: * normally handled automatically, but an application can override 59: * values as desired using this class. 60: * 61: * @author Tom Tromey (tromey@cygnus.com) 62: * @author Aaron M. Renn (arenn@urbanophile.com) 63: * @date February 24, 1999 64: */ 65: /* Written using "Java Class Libraries", 2nd edition, plus online 66: * API docs for JDK 1.2 from http://www.javasoft.com. 67: * Status: Believed complete and correct to 1.2. 68: */ 69: public final class DecimalFormatSymbols implements Cloneable, Serializable 70: { 71: public Object clone () 72: { 73: try 74: { 75: return super.clone (); 76: } 77: catch(CloneNotSupportedException e) 78: { 79: return null; 80: } 81: } 82: 83: /** 84: * This method initializes a new instance of 85: * <code>DecimalFormatSymbols</code> for the default locale. 86: * This constructor only obtains instances using the runtime's resources; 87: * to also include {@link java.text.spi.DateFormatSymbolsProvider} instances, 88: * call {@link #getInstance()} instead. 89: * 90: * @see #getInstance() 91: */ 92: public DecimalFormatSymbols () 93: { 94: this (Locale.getDefault()); 95: } 96: 97: private String safeGetString(ResourceBundle bundle, 98: String name, String def) 99: { 100: if (bundle != null) 101: { 102: try 103: { 104: return bundle.getString(name); 105: } 106: catch (MissingResourceException x) 107: { 108: } 109: } 110: return def; 111: } 112: 113: private char safeGetChar(ResourceBundle bundle, 114: String name, char def) 115: { 116: String r = null; 117: if (bundle != null) 118: { 119: try 120: { 121: r = bundle.getString(name); 122: } 123: catch (MissingResourceException x) 124: { 125: } 126: } 127: if (r == null || r.length() < 1) 128: return def; 129: return r.charAt(0); 130: } 131: 132: /** 133: * This method initializes a new instance of 134: * <code>DecimalFormatSymbols</code> for the specified locale. 135: * <strong>Note</strong>: if the locale does not have an associated 136: * <code>Currency</code> instance, the currency symbol and 137: * international currency symbol will be set to the strings "?" 138: * and "XXX" respectively. This generally happens with language 139: * locales (those with no specified country), such as 140: * <code>Locale.ENGLISH</code>. This constructor only obtains 141: * instances using the runtime's resources; to also include 142: * {@link java.text.spi.DecimalFormatSymbolsProvider} instances, 143: * call {@link #getInstance(java.util.Locale)} instead. 144: * 145: * @param loc The local to load symbols for. 146: * @throws NullPointerException if the locale is null. 147: * @see #getInstance(java.util.Locale) 148: */ 149: public DecimalFormatSymbols (Locale loc) 150: { 151: ResourceBundle res; 152: try 153: { 154: res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 155: loc, ClassLoader.getSystemClassLoader()); 156: } 157: catch (MissingResourceException x) 158: { 159: res = null; 160: } 161: currency = Currency.getInstance("XXX"); 162: currencySymbol = "?"; 163: intlCurrencySymbol = "XXX"; 164: try 165: { 166: Currency localeCurrency = Currency.getInstance(loc); 167: if (localeCurrency != null) 168: { 169: setCurrency(localeCurrency); 170: } 171: } 172: catch(IllegalArgumentException exception) 173: { 174: /* Locale has an invalid currency */ 175: } 176: decimalSeparator = safeGetChar (res, "decimalSeparator", '.'); 177: digit = safeGetChar (res, "digit", '#'); 178: exponential = safeGetChar (res, "exponential", 'E'); 179: groupingSeparator = safeGetChar (res, "groupingSeparator", ','); 180: infinity = safeGetString (res, "infinity", "\u221e"); 181: try 182: { 183: monetarySeparator = safeGetChar (res, "monetarySeparator", '.'); 184: } 185: catch (MissingResourceException x) 186: { 187: monetarySeparator = decimalSeparator; 188: } 189: minusSign = safeGetChar (res, "minusSign", '-'); 190: NaN = safeGetString (res, "NaN", "\ufffd"); 191: patternSeparator = safeGetChar (res, "patternSeparator", ';'); 192: percent = safeGetChar (res, "percent", '%'); 193: perMill = safeGetChar (res, "perMill", '\u2030'); 194: zeroDigit = safeGetChar (res, "zeroDigit", '0'); 195: locale = loc; 196: } 197: 198: /** 199: * This method this this object for equality against the specified object. 200: * This will be true if and only if the following criteria are met with 201: * regard to the specified object: 202: * <p> 203: * <ul> 204: * <li>It is not <code>null</code>.</li> 205: * <li>It is an instance of <code>DecimalFormatSymbols</code>.</li> 206: * <li>All of its symbols are identical to the symbols in this object.</li> 207: * </ul> 208: * 209: * @return <code>true</code> if the specified object is equal to this 210: * object, <code>false</code> otherwise. 211: */ 212: public boolean equals (Object obj) 213: { 214: if (! (obj instanceof DecimalFormatSymbols)) 215: return false; 216: DecimalFormatSymbols dfs = (DecimalFormatSymbols) obj; 217: return (currencySymbol.equals(dfs.currencySymbol) 218: && decimalSeparator == dfs.decimalSeparator 219: && digit == dfs.digit 220: && exponential == dfs.exponential 221: && groupingSeparator == dfs.groupingSeparator 222: && infinity.equals(dfs.infinity) 223: && intlCurrencySymbol.equals(dfs.intlCurrencySymbol) 224: && minusSign == dfs.minusSign 225: && monetarySeparator == dfs.monetarySeparator 226: && NaN.equals(dfs.NaN) 227: && patternSeparator == dfs.patternSeparator 228: && percent == dfs.percent 229: && perMill == dfs.perMill 230: && zeroDigit == dfs.zeroDigit); 231: } 232: 233: /** 234: * Returns the currency corresponding to the currency symbol stored 235: * in the instance of <code>DecimalFormatSymbols</code>. 236: * 237: * @return An instance of <code>Currency</code> which matches 238: * the currency used, or null if there is no corresponding 239: * instance. 240: */ 241: public Currency getCurrency () 242: { 243: return currency; 244: } 245: 246: /** 247: * This method returns the currency symbol in local format. For example, 248: * "$" for Canadian dollars. 249: * 250: * @return The currency symbol in local format. 251: */ 252: public String getCurrencySymbol () 253: { 254: return currencySymbol; 255: } 256: 257: /** 258: * This method returns the character used as the decimal point. 259: * 260: * @return The character used as the decimal point. 261: */ 262: public char getDecimalSeparator () 263: { 264: return decimalSeparator; 265: } 266: 267: /** 268: * This method returns the character used to represent a digit in a 269: * format pattern string. 270: * 271: * @return The character used to represent a digit in a format 272: * pattern string. 273: */ 274: public char getDigit () 275: { 276: return digit; 277: } 278: 279: // This is our own extension. 280: char getExponential () 281: { 282: return exponential; 283: } 284: 285: /** 286: * This method sets the character used to separate groups of digits. For 287: * example, the United States uses a comma (,) to separate thousands in 288: * a number. 289: * 290: * @return The character used to separate groups of digits. 291: */ 292: public char getGroupingSeparator () 293: { 294: return groupingSeparator; 295: } 296: 297: /** 298: * This method returns the character used to represent infinity. 299: * 300: * @return The character used to represent infinity. 301: */ 302: public String getInfinity () 303: { 304: return infinity; 305: } 306: 307: /** 308: * This method returns the currency symbol in international format. For 309: * example, "C$" for Canadian dollars. 310: * 311: * @return The currency symbol in international format. 312: */ 313: public String getInternationalCurrencySymbol () 314: { 315: return intlCurrencySymbol; 316: } 317: 318: /** 319: * This method returns the character used to represent the minus sign. 320: * 321: * @return The character used to represent the minus sign. 322: */ 323: public char getMinusSign () 324: { 325: return minusSign; 326: } 327: 328: /** 329: * This method returns the character used to represent the decimal 330: * point for currency values. 331: * 332: * @return The decimal point character used in currency values. 333: */ 334: public char getMonetaryDecimalSeparator () 335: { 336: return monetarySeparator; 337: } 338: 339: /** 340: * This method returns the string used to represent the NaN (not a number) 341: * value. 342: * 343: * @return The string used to represent NaN 344: */ 345: public String getNaN () 346: { 347: return NaN; 348: } 349: 350: /** 351: * This method returns the character used to separate positive and negative 352: * subpatterns in a format pattern. 353: * 354: * @return The character used to separate positive and negative subpatterns 355: * in a format pattern. 356: */ 357: public char getPatternSeparator () 358: { 359: return patternSeparator; 360: } 361: 362: /** 363: * This method returns the character used as the percent sign. 364: * 365: * @return The character used as the percent sign. 366: */ 367: public char getPercent () 368: { 369: return percent; 370: } 371: 372: /** 373: * This method returns the character used as the per mille character. 374: * 375: * @return The per mille character. 376: */ 377: public char getPerMill () 378: { 379: return perMill; 380: } 381: 382: /** 383: * This method returns the character used to represent the digit zero. 384: * 385: * @return The character used to represent the digit zero. 386: */ 387: public char getZeroDigit () 388: { 389: return zeroDigit; 390: } 391: 392: /** 393: * This method returns a hash value for this object. 394: * 395: * @return A hash value for this object. 396: */ 397: public int hashCode () 398: { 399: // Compute based on zero digit, grouping separator, and decimal 400: // separator -- JCL book. This probably isn't a very good hash 401: // code. 402: return zeroDigit << 16 + groupingSeparator << 8 + decimalSeparator; 403: } 404: 405: /** 406: * This method sets the currency symbol and ISO 4217 currency 407: * code to the values obtained from the supplied currency. 408: * 409: * @param currency the currency from which to obtain the values. 410: * @throws NullPointerException if the currency is null. 411: */ 412: public void setCurrency (Currency currency) 413: { 414: setCurrencySymbol (currency.getSymbol()); 415: this.currency = currency; 416: } 417: 418: /** 419: * This method sets the currency symbol to the specified value. 420: * 421: * @param currency The new currency symbol 422: */ 423: public void setCurrencySymbol (String currency) 424: { 425: currencySymbol = currency; 426: } 427: 428: /** 429: * This method sets the decimal point character to the specified value. 430: * 431: * @param decimalSep The new decimal point character 432: */ 433: public void setDecimalSeparator (char decimalSep) 434: { 435: decimalSeparator = decimalSep; 436: } 437: 438: /** 439: * This method sets the character used to represents a digit in a format 440: * string to the specified value. 441: * 442: * @param digit The character used to represent a digit in a format pattern. 443: */ 444: public void setDigit (char digit) 445: { 446: this.digit = digit; 447: } 448: 449: // This is our own extension. 450: void setExponential (char exp) 451: { 452: exponential = exp; 453: } 454: 455: /** 456: * This method sets the character used to separate groups of digits. 457: * 458: * @param groupSep The character used to separate groups of digits. 459: */ 460: public void setGroupingSeparator (char groupSep) 461: { 462: groupingSeparator = groupSep; 463: } 464: 465: /** 466: * This method sets the string used to represents infinity. 467: * 468: * @param infinity The string used to represent infinity. 469: */ 470: public void setInfinity (String infinity) 471: { 472: this.infinity = infinity; 473: } 474: 475: /** 476: * This method sets the international currency symbol to the 477: * specified value. If a valid <code>Currency</code> instance 478: * exists for the international currency code, then this is 479: * used for the currency attribute, and the currency symbol 480: * is set to the corresponding value from this instance. 481: * Otherwise, the currency attribute is set to null and the 482: * symbol is left unmodified. 483: * 484: * @param currencyCode The new international currency symbol. 485: */ 486: public void setInternationalCurrencySymbol (String currencyCode) 487: { 488: intlCurrencySymbol = currencyCode; 489: try 490: { 491: currency = Currency.getInstance(currencyCode); 492: } 493: catch (IllegalArgumentException exception) 494: { 495: currency = null; 496: } 497: if (currency != null) 498: { 499: setCurrencySymbol(currency.getSymbol(locale)); 500: } 501: } 502: 503: /** 504: * This method sets the character used to represent the minus sign. 505: * 506: * @param minusSign The character used to represent the minus sign. 507: */ 508: public void setMinusSign (char minusSign) 509: { 510: this.minusSign = minusSign; 511: } 512: 513: /** 514: * This method sets the character used for the decimal point in currency 515: * values. 516: * 517: * @param decimalSep The decimal point character used in currency values. 518: */ 519: public void setMonetaryDecimalSeparator (char decimalSep) 520: { 521: monetarySeparator = decimalSep; 522: } 523: 524: /** 525: * This method sets the string used to represent the NaN (not a 526: * number) value. 527: * 528: * @param nan The string used to represent NaN 529: */ 530: public void setNaN (String nan) 531: { 532: NaN = nan; 533: } 534: 535: /** 536: * This method sets the character used to separate positive and negative 537: * subpatterns in a format pattern. 538: * 539: * @param patternSep The character used to separate positive and 540: * negative subpatterns in a format pattern. 541: */ 542: public void setPatternSeparator (char patternSep) 543: { 544: patternSeparator = patternSep; 545: } 546: 547: /** 548: * This method sets the character used as the percent sign. 549: * 550: * @param percent The character used as the percent sign. 551: */ 552: public void setPercent (char percent) 553: { 554: this.percent = percent; 555: } 556: 557: /** 558: * This method sets the character used as the per mille character. 559: * 560: * @param perMill The per mille character. 561: */ 562: public void setPerMill (char perMill) 563: { 564: this.perMill = perMill; 565: } 566: 567: /** 568: * This method sets the character used to represent the digit zero. 569: * 570: * @param zeroDigit The character used to represent the digit zero. 571: */ 572: public void setZeroDigit (char zeroDigit) 573: { 574: this.zeroDigit = zeroDigit; 575: } 576: 577: /** 578: * @serial A string used for the local currency 579: */ 580: private String currencySymbol; 581: /** 582: * @serial The <code>char</code> used to separate decimals in a number. 583: */ 584: private char decimalSeparator; 585: /** 586: * @serial This is the <code>char</code> used to represent a digit in 587: * a format specification. 588: */ 589: private char digit; 590: /** 591: * @serial This is the <code>char</code> used to represent the exponent 592: * separator in exponential notation. 593: */ 594: private char exponential; 595: /** 596: * @serial This separates groups of thousands in numbers. 597: */ 598: private char groupingSeparator; 599: /** 600: * @serial This string represents infinity. 601: */ 602: private String infinity; 603: /** 604: * @serial This string represents the local currency in an international 605: * context, eg, "C$" for Canadian dollars. 606: */ 607: private String intlCurrencySymbol; 608: /** 609: * @serial This is the character used to represent the minus sign. 610: */ 611: private char minusSign; 612: /** 613: * @serial This character is used to separate decimals when formatting 614: * currency values. 615: */ 616: private char monetarySeparator; 617: /** 618: * @serial This string is used the represent the Java NaN value for 619: * "not a number". 620: */ 621: private String NaN; 622: /** 623: * @serial This is the character used to separate positive and negative 624: * subpatterns in a format pattern. 625: */ 626: private char patternSeparator; 627: /** 628: * @serial This is the percent symbols 629: */ 630: private char percent; 631: /** 632: * @serial This character is used for the mille percent sign. 633: */ 634: private char perMill; 635: /** 636: * @serial This value represents the type of object being de-serialized. 637: * 0 indicates a pre-Java 1.1.6 version, 1 indicates 1.1.6 or later. 638: * 0 indicates a pre-Java 1.1.6 version, 1 indicates 1.1.6 or later, 639: * 2 indicates 1.4 or later 640: */ 641: private int serialVersionOnStream = 2; 642: /** 643: * @serial This is the character used to represent 0. 644: */ 645: private char zeroDigit; 646: 647: /** 648: * @serial The locale of these currency symbols. 649: */ 650: private Locale locale; 651: 652: /** 653: * The currency used for the symbols in this instance. 654: * This is stored temporarily for efficiency reasons, 655: * as well as to ensure that the correct instance 656: * is restored from the currency code. 657: * 658: * @serial Ignored. 659: */ 660: private transient Currency currency; 661: 662: private static final long serialVersionUID = 5772796243397350300L; 663: 664: private void readObject(ObjectInputStream stream) 665: throws IOException, ClassNotFoundException 666: { 667: stream.defaultReadObject(); 668: if (serialVersionOnStream < 1) 669: { 670: monetarySeparator = decimalSeparator; 671: exponential = 'E'; 672: } 673: if (serialVersionOnStream < 2) 674: locale = Locale.getDefault(); 675: 676: serialVersionOnStream = 2; 677: } 678: 679: /** 680: * Returns a {@link DecimalFormatSymbols} instance for the 681: * default locale obtained from either the runtime itself 682: * or one of the installed 683: * {@link java.text.spi.DecimalFormatSymbolsProvider} instances. 684: * This is equivalent to calling 685: * <code>getInstance(Locale.getDefault())</code>. 686: * 687: * @return a {@link DecimalFormatSymbols} instance for the default 688: * locale. 689: * @since 1.6 690: */ 691: public static final DecimalFormatSymbols getInstance() 692: { 693: return getInstance(Locale.getDefault()); 694: } 695: 696: /** 697: * Returns a {@link DecimalFormatSymbols} instance for the 698: * specified locale obtained from either the runtime itself 699: * or one of the installed 700: * {@link java.text.spi.DecimalFormatSymbolsProvider} instances. 701: * 702: * @param locale the locale for which an instance should be 703: * returned. 704: * @return a {@link DecimalFormatSymbols} instance for the specified 705: * locale. 706: * @throws NullPointerException if <code>locale</code> is 707: * <code>null</code>. 708: * @since 1.6 709: */ 710: public static final DecimalFormatSymbols getInstance(Locale locale) 711: { 712: try 713: { 714: if (!locale.equals(Locale.ROOT)) 715: ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 716: locale, 717: ClassLoader.getSystemClassLoader()); 718: return new DecimalFormatSymbols(locale); 719: } 720: catch (MissingResourceException x) 721: { 722: /* This means runtime support for the locale 723: * is not available, so we check providers. */ 724: } 725: for (DecimalFormatSymbolsProvider p : 726: ServiceLoader.load(DecimalFormatSymbolsProvider.class)) 727: { 728: for (Locale loc : p.getAvailableLocales()) 729: { 730: if (loc.equals(locale)) 731: { 732: DecimalFormatSymbols syms = p.getInstance(locale); 733: if (syms != null) 734: return syms; 735: break; 736: } 737: } 738: } 739: return getInstance(LocaleHelper.getFallbackLocale(locale)); 740: } 741: 742: }