0001: /*
0002: *******************************************************************************
0003: * Copyright (C) 1996-2006, International Business Machines Corporation and *
0004: * others. All Rights Reserved. *
0005: *******************************************************************************
0006: */
0007: package com.ibm.icu.text;
0008:
0009: import com.ibm.icu.impl.ICUResourceBundle;
0010: import com.ibm.icu.util.Currency;
0011: import com.ibm.icu.util.ULocale;
0012: import com.ibm.icu.util.UResourceBundle;
0013:
0014: import java.io.IOException;
0015: import java.io.ObjectInputStream;
0016: import java.io.Serializable;
0017: import java.text.ChoiceFormat;
0018: import java.util.Hashtable;
0019: import java.util.Locale;
0020: import java.util.MissingResourceException;
0021:
0022: /**
0023: * This class represents the set of symbols (such as the decimal separator, the
0024: * grouping separator, and so on) needed by <code>DecimalFormat</code> to format
0025: * numbers. <code>DecimalFormat</code> creates for itself an instance of
0026: * <code>DecimalFormatSymbols</code> from its locale data. If you need to
0027: * change any of these symbols, you can get the
0028: * <code>DecimalFormatSymbols</code> object from your <code>DecimalFormat</code>
0029: * and modify it.
0030: *
0031: * <p><strong>This is an enhanced version of <code>DecimalFormatSymbols</code> that
0032: * is based on the standard version in the JDK. New or changed functionality
0033: * is labeled
0034: * <strong><font face=helvetica color=red>NEW</font></strong>.</strong>
0035: *
0036: * @see java.util.Locale
0037: * @see DecimalFormat
0038: * @author Mark Davis
0039: * @author Alan Liu
0040: * @stable ICU 2.0
0041: */
0042:
0043: final public class DecimalFormatSymbols implements Cloneable,
0044: Serializable {
0045:
0046: /**
0047: * Create a DecimalFormatSymbols object for the default locale.
0048: * @stable ICU 2.0
0049: */
0050: public DecimalFormatSymbols() {
0051: initialize(ULocale.getDefault());
0052: }
0053:
0054: /**
0055: * Create a DecimalFormatSymbols object for the given locale.
0056: * @param locale the locale
0057: * @stable ICU 2.0
0058: */
0059: public DecimalFormatSymbols(Locale locale) {
0060: initialize(ULocale.forLocale(locale));
0061: }
0062:
0063: /**
0064: * Create a DecimalFormatSymbols object for the given locale.
0065: * @param locale the locale
0066: * @draft ICU 3.2
0067: * @provisional This API might change or be removed in a future release.
0068: */
0069: public DecimalFormatSymbols(ULocale locale) {
0070: initialize(locale);
0071: }
0072:
0073: /**
0074: * Return the character used for zero. Different for Arabic, etc.
0075: * @return the character
0076: * @stable ICU 2.0
0077: */
0078: public char getZeroDigit() {
0079: return zeroDigit;
0080: }
0081:
0082: /**
0083: * Set the character used for zero.
0084: * @param zeroDigit the zero character.
0085: * @stable ICU 2.0
0086: */
0087: public void setZeroDigit(char zeroDigit) {
0088: this .zeroDigit = zeroDigit;
0089: }
0090:
0091: /**
0092: * Return the character used to represent a significant digit in a pattern.
0093: * @return the significant digit pattern character
0094: * @stable ICU 3.0
0095: */
0096: public char getSignificantDigit() {
0097: return sigDigit;
0098: }
0099:
0100: /**
0101: * Set the character used to represent a significant digit in a pattern.
0102: * @param sigDigit the significant digit pattern character
0103: * @stable ICU 3.0
0104: */
0105: public void setSignificantDigit(char sigDigit) {
0106: this .sigDigit = sigDigit;
0107: }
0108:
0109: /**
0110: * Return the character used for thousands separator. Different for French, etc.
0111: * @return the thousands character
0112: * @stable ICU 2.0
0113: */
0114: public char getGroupingSeparator() {
0115: return groupingSeparator;
0116: }
0117:
0118: /**
0119: * Set the character used for thousands separator. Different for French, etc.
0120: * @param groupingSeparator the thousands character
0121: * @stable ICU 2.0
0122: */
0123: public void setGroupingSeparator(char groupingSeparator) {
0124: this .groupingSeparator = groupingSeparator;
0125: }
0126:
0127: /**
0128: * Return the character used for decimal sign. Different for French, etc.
0129: * @return the decimal character
0130: * @stable ICU 2.0
0131: */
0132: public char getDecimalSeparator() {
0133: return decimalSeparator;
0134: }
0135:
0136: /**
0137: * Set the character used for decimal sign. Different for French, etc.
0138: * @param decimalSeparator the decimal character
0139: * @stable ICU 2.0
0140: */
0141: public void setDecimalSeparator(char decimalSeparator) {
0142: this .decimalSeparator = decimalSeparator;
0143: }
0144:
0145: /**
0146: * Return the character used for mille percent sign. Different for Arabic, etc.
0147: * @return the mille percent character
0148: * @stable ICU 2.0
0149: */
0150: public char getPerMill() {
0151: return perMill;
0152: }
0153:
0154: /**
0155: * Set the character used for mille percent sign. Different for Arabic, etc.
0156: * @param perMill the mille percent character
0157: * @stable ICU 2.0
0158: */
0159: public void setPerMill(char perMill) {
0160: this .perMill = perMill;
0161: }
0162:
0163: /**
0164: * Return the character used for percent sign. Different for Arabic, etc.
0165: * @return the percent character
0166: * @stable ICU 2.0
0167: */
0168: public char getPercent() {
0169: return percent;
0170: }
0171:
0172: /**
0173: * Set the character used for percent sign. Different for Arabic, etc.
0174: * @param percent the percent character
0175: * @stable ICU 2.0
0176: */
0177: public void setPercent(char percent) {
0178: this .percent = percent;
0179: }
0180:
0181: /**
0182: * Return the character used for a digit in a pattern.
0183: * @return the digit pattern character
0184: * @stable ICU 2.0
0185: */
0186: public char getDigit() {
0187: return digit;
0188: }
0189:
0190: /**
0191: * Set the character used for a digit in a pattern.
0192: * @param digit the digit pattern character
0193: * @stable ICU 2.0
0194: */
0195: public void setDigit(char digit) {
0196: this .digit = digit;
0197: }
0198:
0199: /**
0200: * Return the character used to separate positive and negative subpatterns
0201: * in a pattern.
0202: * @return the pattern separator character
0203: * @stable ICU 2.0
0204: */
0205: public char getPatternSeparator() {
0206: return patternSeparator;
0207: }
0208:
0209: /**
0210: * Set the character used to separate positive and negative subpatterns
0211: * in a pattern.
0212: * @param patternSeparator the pattern separator character
0213: * @stable ICU 2.0
0214: */
0215: public void setPatternSeparator(char patternSeparator) {
0216: this .patternSeparator = patternSeparator;
0217: }
0218:
0219: /**
0220: * Return the String used to represent infinity. Almost always left
0221: * unchanged.
0222: * @return the Infinity string
0223: * @stable ICU 2.0
0224: */
0225: //Bug 4194173 [Richard/GCL]
0226: public String getInfinity() {
0227: return infinity;
0228: }
0229:
0230: /**
0231: * Set the String used to represent infinity. Almost always left
0232: * unchanged.
0233: * @param infinity the Infinity String
0234: * @stable ICU 2.0
0235: */
0236: public void setInfinity(String infinity) {
0237: this .infinity = infinity;
0238: }
0239:
0240: /**
0241: * Return the String used to represent NaN. Almost always left
0242: * unchanged.
0243: * @return the NaN String
0244: * @stable ICU 2.0
0245: */
0246: //Bug 4194173 [Richard/GCL]
0247: public String getNaN() {
0248: return NaN;
0249: }
0250:
0251: /**
0252: * Set the String used to represent NaN. Almost always left
0253: * unchanged.
0254: * @param NaN the NaN String
0255: * @stable ICU 2.0
0256: */
0257: public void setNaN(String NaN) {
0258: this .NaN = NaN;
0259: }
0260:
0261: /**
0262: * Return the character used to represent minus sign. If no explicit
0263: * negative format is specified, one is formed by prefixing
0264: * minusSign to the positive format.
0265: * @return the minus sign character
0266: * @stable ICU 2.0
0267: */
0268: public char getMinusSign() {
0269: return minusSign;
0270: }
0271:
0272: /**
0273: * Set the character used to represent minus sign. If no explicit
0274: * negative format is specified, one is formed by prefixing
0275: * minusSign to the positive format.
0276: * @param minusSign the minus sign character
0277: * @stable ICU 2.0
0278: */
0279: public void setMinusSign(char minusSign) {
0280: this .minusSign = minusSign;
0281: }
0282:
0283: /**
0284: * Return the string denoting the local currency.
0285: * @return the local currency String.
0286: * @stable ICU 2.0
0287: */
0288: public String getCurrencySymbol() {
0289: return currencySymbol;
0290: }
0291:
0292: /**
0293: * Set the string denoting the local currency.
0294: * @param currency the local currency String.
0295: * @stable ICU 2.0
0296: */
0297: public void setCurrencySymbol(String currency) {
0298: currencySymbol = currency;
0299: }
0300:
0301: /**
0302: * Return the international string denoting the local currency.
0303: * @return the international string denoting the local currency
0304: * @stable ICU 2.0
0305: */
0306: public String getInternationalCurrencySymbol() {
0307: return intlCurrencySymbol;
0308: }
0309:
0310: /**
0311: * Set the international string denoting the local currency.
0312: * @param currency the international string denoting the local currency.
0313: * @stable ICU 2.0
0314: */
0315: public void setInternationalCurrencySymbol(String currency) {
0316: intlCurrencySymbol = currency;
0317: }
0318:
0319: /**
0320: * Returns the currency symbol, for JDK 1.4 compatibility only.
0321: * ICU clients should use the Currency API directly.
0322: * @return the currency used, or null
0323: * @draft ICU 3.4
0324: * @provisional This API might change or be removed in a future release.
0325: */
0326: public Currency getCurrency() {
0327: return currency;
0328: }
0329:
0330: /**
0331: * ICU does not use the DecimalFormatSymbols for the
0332: * currency any more. This API is present
0333: * for API compatibility only.
0334: *
0335: * This also sets the currency symbol attribute to the currency's symbol
0336: * in the DecimalFormatSymbols' locale, and the international currency
0337: * symbol attribute to the currency's ISO 4217 currency code.
0338: *
0339: * @param currency the new currency to be used
0340: * @throws NullPointerException if <code>currency</code> is null
0341: * @see #setCurrencySymbol
0342: * @see #setInternationalCurrencySymbol
0343: *
0344: * @draft ICU 3.4
0345: * @provisional This API might change or be removed in a future release.
0346: */
0347: public void setCurrency(Currency currency) {
0348: if (currency == null) {
0349: throw new NullPointerException();
0350: }
0351: this .currency = currency;
0352: intlCurrencySymbol = currency.getCurrencyCode();
0353: currencySymbol = currency.getSymbol(locale);
0354: }
0355:
0356: /**
0357: * Return the monetary decimal separator.
0358: * @return the monetary decimal separator character
0359: * @stable ICU 2.0
0360: */
0361: public char getMonetaryDecimalSeparator() {
0362: return monetarySeparator;
0363: }
0364:
0365: /**
0366: * Return the monetary decimal separator.
0367: * @return the monetary decimal separator character
0368: * @draft ICU 3.6
0369: * @provisional This API might change or be removed in a future release.
0370: */
0371: public char getMonetaryGroupingSeparator() {
0372: return monetaryGroupingSeparator;
0373: }
0374:
0375: /**
0376: * Internal API for NumberFormat
0377: * @return String currency pattern string
0378: * @internal
0379: */
0380: String getCurrencyPattern() {
0381: return currencyPattern;
0382: }
0383:
0384: /**
0385: * Set the monetary decimal separator.
0386: * @param sep the monetary decimal separator character
0387: * @stable ICU 2.0
0388: */
0389: public void setMonetaryDecimalSeparator(char sep) {
0390: monetarySeparator = sep;
0391: }
0392:
0393: /**
0394: * Set the monetary decimal separator.
0395: * @param sep the monetary decimal separator character
0396: * @draft ICU 3.6
0397: * @provisional This API might change or be removed in a future release.
0398: */
0399: public void setMonetaryGroupingSeparator(char sep) {
0400: monetaryGroupingSeparator = sep;
0401: }
0402:
0403: /**
0404: * <strong><font face=helvetica color=red>NEW</font></strong>
0405: * Return the string used to separate the mantissa from the exponent.
0406: * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
0407: * @return the localized exponent symbol, used in localized patterns
0408: * and formatted strings
0409: * @see #setExponentSeparator
0410: * @stable ICU 2.0
0411: */
0412: public String getExponentSeparator() {
0413: return exponentSeparator;
0414: }
0415:
0416: /**
0417: * <strong><font face=helvetica color=red>NEW</font></strong>
0418: * Set the string used to separate the mantissa from the exponent.
0419: * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
0420: * @param exp the localized exponent symbol, used in localized patterns
0421: * and formatted strings
0422: * @see #getExponentSeparator
0423: * @stable ICU 2.0
0424: */
0425: public void setExponentSeparator(String exp) {
0426: exponentSeparator = exp;
0427: }
0428:
0429: /**
0430: * <strong><font face=helvetica color=red>NEW</font></strong>
0431: * Return the localized plus sign.
0432: * @return the plus sign, used in localized patterns and formatted
0433: * strings
0434: * @see #setPlusSign
0435: * @see #setMinusSign
0436: * @see #getMinusSign
0437: * @stable ICU 2.0
0438: */
0439: public char getPlusSign() {
0440: return plusSign;
0441: }
0442:
0443: /**
0444: * <strong><font face=helvetica color=red>NEW</font></strong>
0445: * Set the localized plus sign.
0446: * @param plus the plus sign, used in localized patterns and formatted
0447: * strings
0448: * @see #getPlusSign
0449: * @see #setMinusSign
0450: * @see #getMinusSign
0451: * @stable ICU 2.0
0452: */
0453: public void setPlusSign(char plus) {
0454: plusSign = plus;
0455: }
0456:
0457: /**
0458: * <strong><font face=helvetica color=red>NEW</font></strong>
0459: * Return the character used to pad numbers out to a specified width. This
0460: * is not the pad character itself; rather, it is the special pattern
0461: * character <em>preceding</em> the pad character. In the pattern
0462: * "*_#,##0", '*' is the pad escape, and '_' is the pad character.
0463: * @return the character
0464: * @see #setPadEscape
0465: * @see DecimalFormat#getFormatWidth
0466: * @see DecimalFormat#getPadPosition
0467: * @see DecimalFormat#getPadCharacter
0468: * @stable ICU 2.0
0469: */
0470: public char getPadEscape() {
0471: return padEscape;
0472: }
0473:
0474: /**
0475: * <strong><font face=helvetica color=red>NEW</font></strong>
0476: * Set the character used to pad numbers out to a specified width. This is
0477: * not the pad character itself; rather, it is the special pattern character
0478: * <em>preceding</em> the pad character. In the pattern "*_#,##0", '*' is
0479: * the pad escape, and '_' is the pad character.
0480: * @see #getPadEscape
0481: * @see DecimalFormat#setFormatWidth
0482: * @see DecimalFormat#setPadPosition
0483: * @see DecimalFormat#setPadCharacter
0484: * @stable ICU 2.0
0485: */
0486: public void setPadEscape(char c) {
0487: padEscape = c;
0488: }
0489:
0490: /**
0491: * Returns the locale for which this object was constructed.
0492: * @return the locale for which this object was constructed
0493: * @stable ICU 2.0
0494: */
0495: public Locale getLocale() {
0496: return locale;
0497: }
0498:
0499: /**
0500: * Returns the locale for which this object was constructed.
0501: * @return the locale for which this object was constructed
0502: * @draft ICU 3.2
0503: * @provisional This API might change or be removed in a future release.
0504: */
0505: public ULocale getULocale() {
0506: return ulocale;
0507: }
0508:
0509: /**
0510: * Standard override.
0511: * @stable ICU 2.0
0512: */
0513: public Object clone() {
0514: try {
0515: return (DecimalFormatSymbols) super .clone();
0516: // other fields are bit-copied
0517: } catch (CloneNotSupportedException e) {
0518: ///CLOVER:OFF
0519: throw new IllegalStateException();
0520: ///CLOVER:ON
0521: }
0522: }
0523:
0524: /**
0525: * Override equals.
0526: * @stable ICU 2.0
0527: */
0528: public boolean equals(Object obj) {
0529: if (obj == null)
0530: return false;
0531: if (this == obj)
0532: return true;
0533: DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
0534: return (zeroDigit == other.zeroDigit
0535: && groupingSeparator == other.groupingSeparator
0536: && decimalSeparator == other.decimalSeparator
0537: && percent == other.percent && perMill == other.perMill
0538: && digit == other.digit && minusSign == other.minusSign
0539: && patternSeparator == other.patternSeparator
0540: && infinity.equals(other.infinity)
0541: && NaN.equals(other.NaN)
0542: && currencySymbol.equals(other.currencySymbol)
0543: && intlCurrencySymbol.equals(other.intlCurrencySymbol)
0544: && padEscape == other.padEscape && // [NEW]
0545: plusSign == other.plusSign && // [NEW]
0546: exponentSeparator.equals(other.exponentSeparator) && // [NEW]
0547: monetarySeparator == other.monetarySeparator);
0548: }
0549:
0550: /**
0551: * Override hashCode
0552: * @stable ICU 2.0
0553: */
0554: public int hashCode() {
0555: int result = zeroDigit;
0556: result = result * 37 + groupingSeparator;
0557: result = result * 37 + decimalSeparator;
0558: return result;
0559: }
0560:
0561: /**
0562: * Initializes the symbols from the LocaleElements resource bundle.
0563: * Note: The organization of LocaleElements badly needs to be
0564: * cleaned up.
0565: */
0566: private void initialize(ULocale locale) {
0567: this .locale = locale.toLocale();
0568: this .ulocale = locale;
0569:
0570: /* try the cache first */
0571: String[][] data = (String[][]) cachedLocaleData.get(locale);
0572: String[] numberElements;
0573: if (data == null) { /* cache miss */
0574: data = new String[1][];
0575: ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle
0576: .getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
0577: locale);
0578: data[0] = rb.getStringArray("NumberElements");
0579: /* update cache */
0580: cachedLocaleData.put(locale, data);
0581: }
0582: numberElements = data[0];
0583:
0584: ICUResourceBundle r = (ICUResourceBundle) UResourceBundle
0585: .getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,
0586: locale);
0587:
0588: // TODO: Determine actual and valid locale correctly.
0589: ULocale uloc = r.getULocale();
0590: setLocale(uloc, uloc);
0591:
0592: // {dlf} clean up below now that we have our own resource data
0593: decimalSeparator = numberElements[0].charAt(0);
0594: groupingSeparator = numberElements[1].charAt(0);
0595: // Temporary hack to support old JDK 1.1 resources
0596: // patternSeparator = numberElements[2].length() > 0 ?
0597: // numberElements[2].charAt(0) : ';';
0598: patternSeparator = numberElements[2].charAt(0);
0599: percent = numberElements[3].charAt(0);
0600: zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
0601: digit = numberElements[5].charAt(0);
0602: minusSign = numberElements[6].charAt(0);
0603:
0604: // Temporary hack to support JDK versions before 1.1.6 (?)
0605: // exponentSeparator = numberElements.length >= 9 ?
0606: // numberElements[7] : DecimalFormat.PATTERN_EXPONENT;
0607: // perMill = numberElements.length >= 9 ?
0608: // numberElements[8].charAt(0) : '\u2030';
0609: // infinity = numberElements.length >= 10 ?
0610: // numberElements[9] : "\u221e";
0611: // NaN = numberElements.length >= 11 ?
0612: // numberElements[10] : "\ufffd";
0613: exponentSeparator = numberElements[7];
0614: perMill = numberElements[8].charAt(0);
0615: infinity = numberElements[9];
0616: NaN = numberElements[10];
0617:
0618: plusSign = numberElements[11].charAt(0);
0619: padEscape = DecimalFormat.PATTERN_PAD_ESCAPE;
0620: sigDigit = DecimalFormat.PATTERN_SIGNIFICANT_DIGIT;
0621:
0622: // Obtain currency data from the currency API. This is strictly
0623: // for backward compatibility; we don't use DecimalFormatSymbols
0624: // for currency data anymore.
0625: String currname = null;
0626: currency = Currency.getInstance(locale);
0627: if (currency != null) {
0628: intlCurrencySymbol = currency.getCurrencyCode();
0629: boolean[] isChoiceFormat = new boolean[1];
0630: currname = currency.getName(locale, Currency.SYMBOL_NAME,
0631: isChoiceFormat);
0632: // If this is a ChoiceFormat currency, then format an
0633: // arbitrary value; pick something != 1; more common.
0634: currencySymbol = isChoiceFormat[0] ? new ChoiceFormat(
0635: currname).format(2.0) : currname;
0636: } else {
0637: intlCurrencySymbol = "XXX";
0638: currencySymbol = "\u00A4"; // 'OX' currency symbol
0639: }
0640: // If there is a currency decimal, use it.
0641: monetarySeparator = decimalSeparator;
0642: monetaryGroupingSeparator = groupingSeparator;
0643: Currency curr = Currency.getInstance(locale);
0644: if (curr != null) {
0645: String currencyCode = curr.getCurrencyCode();
0646: if (currencyCode != null) {
0647: /* An explicit currency was requested */
0648: ICUResourceBundle resource = (ICUResourceBundle) UResourceBundle
0649: .getBundleInstance(
0650: ICUResourceBundle.ICU_BASE_NAME, locale);
0651: ICUResourceBundle currency = resource
0652: .getWithFallback("Currencies");
0653: try {
0654: currency = currency.getWithFallback(currencyCode);
0655: if (currency.getSize() > 2) {
0656: currency = currency.get(2);
0657: currencyPattern = currency.getString(0);
0658: monetarySeparator = currency.getString(1)
0659: .charAt(0);
0660: monetaryGroupingSeparator = currency.getString(
0661: 2).charAt(0);
0662: }
0663: } catch (MissingResourceException ex) {
0664: /* else An explicit currency was requested and is unknown or locale data is malformed. */
0665: /* decimal format API will get the correct value later on. */
0666: }
0667: }
0668: /* else no currency keyword used. */
0669: }
0670: //monetarySeparator = numberElements[11].charAt(0);
0671: }
0672:
0673: /**
0674: * Read the default serializable fields, then if <code>serialVersionOnStream</code>
0675: * is less than 1, initialize <code>monetarySeparator</code> to be
0676: * the same as <code>decimalSeparator</code> and <code>exponential</code>
0677: * to be 'E'.
0678: * Finally, set serialVersionOnStream back to the maximum allowed value so that
0679: * default serialization will work properly if this object is streamed out again.
0680: */
0681: private void readObject(ObjectInputStream stream)
0682: throws IOException, ClassNotFoundException {
0683:
0684: // TODO: it looks to me {dlf} that the serialization code was never updated
0685: // to handle the actual/valid ulocale fields.
0686:
0687: stream.defaultReadObject();
0688: ///CLOVER:OFF
0689: // we don't have data for these old serialized forms any more
0690: if (serialVersionOnStream < 1) {
0691: // Didn't have monetarySeparator or exponential field;
0692: // use defaults.
0693: monetarySeparator = decimalSeparator;
0694: exponential = 'E';
0695: }
0696: if (serialVersionOnStream < 2) {
0697: padEscape = DecimalFormat.PATTERN_PAD_ESCAPE;
0698: plusSign = DecimalFormat.PATTERN_PLUS_SIGN;
0699: exponentSeparator = String.valueOf(exponential);
0700: // Although we read the exponential field on stream to create the
0701: // exponentSeparator, we don't do the reverse, since scientific
0702: // notation isn't supported by the old classes, even though the
0703: // symbol is there.
0704: }
0705: ///CLOVER:ON
0706: if (serialVersionOnStream < 3) {
0707: // Resurrected objects from old streams will have no
0708: // locale. There is no 100% fix for this. A
0709: // 90% fix is to construct a mapping of data back to
0710: // locale, perhaps a hash of all our members. This is
0711: // expensive and doesn't seem worth it.
0712: locale = Locale.getDefault();
0713: }
0714: if (serialVersionOnStream < 4) {
0715: // use same default behavior as for versions with no Locale
0716: ulocale = ULocale.forLocale(locale);
0717: }
0718: if (serialVersionOnStream < 5) {
0719: // use the same one for groupingSeparator
0720: monetaryGroupingSeparator = groupingSeparator;
0721: }
0722: serialVersionOnStream = currentSerialVersion;
0723:
0724: // recreate
0725: currency = Currency.getInstance(intlCurrencySymbol);
0726: }
0727:
0728: /**
0729: * Character used for zero.
0730: *
0731: * @serial
0732: * @see #getZeroDigit
0733: */
0734: private char zeroDigit;
0735:
0736: /**
0737: * Character used for thousands separator.
0738: *
0739: * @serial
0740: * @see #getGroupingSeparator
0741: */
0742: private char groupingSeparator;
0743:
0744: /**
0745: * Character used for decimal sign.
0746: *
0747: * @serial
0748: * @see #getDecimalSeparator
0749: */
0750: private char decimalSeparator;
0751:
0752: /**
0753: * Character used for mille percent sign.
0754: *
0755: * @serial
0756: * @see #getPerMill
0757: */
0758: private char perMill;
0759:
0760: /**
0761: * Character used for percent sign.
0762: * @serial
0763: * @see #getPercent
0764: */
0765: private char percent;
0766:
0767: /**
0768: * Character used for a digit in a pattern.
0769: *
0770: * @serial
0771: * @see #getDigit
0772: */
0773: private char digit;
0774:
0775: /**
0776: * Character used for a significant digit in a pattern.
0777: *
0778: * @serial
0779: * @see #getSignificantDigit
0780: */
0781: private char sigDigit;
0782:
0783: /**
0784: * Character used to separate positive and negative subpatterns
0785: * in a pattern.
0786: *
0787: * @serial
0788: * @see #getPatternSeparator
0789: */
0790: private char patternSeparator;
0791:
0792: /**
0793: * Character used to represent infinity.
0794: * @serial
0795: * @see #getInfinity
0796: */
0797: private String infinity;
0798:
0799: /**
0800: * Character used to represent NaN.
0801: * @serial
0802: * @see #getNaN
0803: */
0804: private String NaN;
0805:
0806: /**
0807: * Character used to represent minus sign.
0808: * @serial
0809: * @see #getMinusSign
0810: */
0811: private char minusSign;
0812:
0813: /**
0814: * String denoting the local currency, e.g. "$".
0815: * @serial
0816: * @see #getCurrencySymbol
0817: */
0818: private String currencySymbol;
0819:
0820: /**
0821: * International string denoting the local currency, e.g. "USD".
0822: * @serial
0823: * @see #getInternationalCurrencySymbol
0824: */
0825: private String intlCurrencySymbol;
0826:
0827: /**
0828: * The decimal separator used when formatting currency values.
0829: * @serial
0830: * @see #getMonetaryDecimalSeparator
0831: */
0832: private char monetarySeparator; // Field new in JDK 1.1.6
0833:
0834: /**
0835: * The decimal separator used when formatting currency values.
0836: * @serial
0837: * @see #getMonetaryGroupingSeparator
0838: */
0839: private char monetaryGroupingSeparator; // Field new in JDK 1.1.6
0840:
0841: /**
0842: * The character used to distinguish the exponent in a number formatted
0843: * in exponential notation, e.g. 'E' for a number such as "1.23E45".
0844: * <p>
0845: * Note that this field has been superseded by <code>exponentSeparator</code>.
0846: * It is retained for backward compatibility.
0847: *
0848: * @serial
0849: */
0850: private char exponential; // Field new in JDK 1.1.6
0851:
0852: /**
0853: * The string used to separate the mantissa from the exponent.
0854: * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
0855: * <p>
0856: * Note that this supersedes the <code>exponential</code> field.
0857: *
0858: * @serial
0859: * @since AlphaWorks
0860: */
0861: private String exponentSeparator;
0862:
0863: /**
0864: * <strong><font face=helvetica color=red>NEW</font></strong>
0865: * The character used to indicate a padding character in a format,
0866: * e.g., '*' in a pattern such as "$*_#,##0.00".
0867: * @serial
0868: * @since AlphaWorks
0869: */
0870: private char padEscape;
0871:
0872: /**
0873: * <strong><font face=helvetica color=red>NEW</font></strong>
0874: * The character used to indicate a plus sign.
0875: * @serial
0876: * @since AlphaWorks
0877: */
0878: private char plusSign;
0879:
0880: /**
0881: * The locale for which this object was constructed. Set to the
0882: * default locale for objects resurrected from old streams.
0883: * @since ICU 2.2
0884: */
0885: private Locale locale;
0886:
0887: /**
0888: * The requested ULocale. We keep the old locale for serialization compatibility.
0889: * @since IDU 3.2
0890: */
0891: private ULocale ulocale;
0892:
0893: // Proclaim JDK 1.1 FCS compatibility
0894: private static final long serialVersionUID = 5772796243397350300L;
0895:
0896: // The internal serial version which says which version was written
0897: // - 0 (default) for version up to JDK 1.1.5
0898: // - 1 for version from JDK 1.1.6, which includes two new fields:
0899: // monetarySeparator and exponential.
0900: // - 2 for version from AlphaWorks, which includes 3 new fields:
0901: // padEscape, exponentSeparator, and plusSign.
0902: // - 3 for ICU 2.2, which includes the locale field
0903: // - 4 for ICU 3.2, which includes the ULocale field
0904: // - 5 for ICU 3.6, which includes the monetaryGroupingSeparator field
0905: private static final int currentSerialVersion = 5;
0906:
0907: /**
0908: * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
0909: * Possible values are:
0910: * <ul>
0911: * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
0912: *
0913: * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which includes
0914: * two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
0915: * <li><b>2</b>: Version for AlphaWorks. Adds padEscape, exponentSeparator,
0916: * and plusSign.
0917: * </ul>
0918: * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
0919: * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
0920: * is always written.
0921: *
0922: * @serial
0923: */
0924: private int serialVersionOnStream = currentSerialVersion;
0925:
0926: /**
0927: * cache to hold the NumberElements of a Locale.
0928: */
0929: private static final Hashtable cachedLocaleData = new Hashtable(3);
0930:
0931: /**
0932: *
0933: */
0934: private String currencyPattern = null;
0935:
0936: // -------- BEGIN ULocale boilerplate --------
0937:
0938: /**
0939: * Return the locale that was used to create this object, or null.
0940: * This may may differ from the locale requested at the time of
0941: * this object's creation. For example, if an object is created
0942: * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be
0943: * drawn from <tt>en</tt> (the <i>actual</i> locale), and
0944: * <tt>en_US</tt> may be the most specific locale that exists (the
0945: * <i>valid</i> locale).
0946: *
0947: * <p>Note: This method will be implemented in ICU 3.0; ICU 2.8
0948: * contains a partial preview implementation. The * <i>actual</i>
0949: * locale is returned correctly, but the <i>valid</i> locale is
0950: * not, in most cases.
0951: * @param type type of information requested, either {@link
0952: * com.ibm.icu.util.ULocale#VALID_LOCALE} or {@link
0953: * com.ibm.icu.util.ULocale#ACTUAL_LOCALE}.
0954: * @return the information specified by <i>type</i>, or null if
0955: * this object was not constructed from locale data.
0956: * @see com.ibm.icu.util.ULocale
0957: * @see com.ibm.icu.util.ULocale#VALID_LOCALE
0958: * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
0959: * @draft ICU 2.8 (retain)
0960: * @provisional This API might change or be removed in a future release.
0961: */
0962: public final ULocale getLocale(ULocale.Type type) {
0963: return type == ULocale.ACTUAL_LOCALE ? this .actualLocale
0964: : this .validLocale;
0965: }
0966:
0967: /**
0968: * Set information about the locales that were used to create this
0969: * object. If the object was not constructed from locale data,
0970: * both arguments should be set to null. Otherwise, neither
0971: * should be null. The actual locale must be at the same level or
0972: * less specific than the valid locale. This method is intended
0973: * for use by factories or other entities that create objects of
0974: * this class.
0975: * @param valid the most specific locale containing any resource
0976: * data, or null
0977: * @param actual the locale containing data used to construct this
0978: * object, or null
0979: * @see com.ibm.icu.util.ULocale
0980: * @see com.ibm.icu.util.ULocale#VALID_LOCALE
0981: * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
0982: * @internal
0983: */
0984: final void setLocale(ULocale valid, ULocale actual) {
0985: // Change the following to an assertion later
0986: if ((valid == null) != (actual == null)) {
0987: ///CLOVER:OFF
0988: throw new IllegalArgumentException();
0989: ///CLOVER:ON
0990: }
0991: // Another check we could do is that the actual locale is at
0992: // the same level or less specific than the valid locale.
0993: this .validLocale = valid;
0994: this .actualLocale = actual;
0995: }
0996:
0997: /**
0998: * The most specific locale containing any resource data, or null.
0999: * @see com.ibm.icu.util.ULocale
1000: * @internal
1001: */
1002: private ULocale validLocale;
1003:
1004: /**
1005: * The locale containing data used to construct this object, or
1006: * null.
1007: * @see com.ibm.icu.util.ULocale
1008: * @internal
1009: */
1010: private ULocale actualLocale;
1011:
1012: // not serialized, reconstructed from intlCurrencyCode
1013: private transient Currency currency;
1014:
1015: // -------- END ULocale boilerplate --------
1016: }
|