001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.text;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.ObjectOutputStream;
023: import java.io.ObjectStreamField;
024: import java.io.Serializable;
025: import java.util.Arrays;
026: import java.util.Currency;
027: import java.util.Locale;
028:
029: /**
030: * DecimalFormatSymbols holds the symbols used in the formating and parsing of
031: * numbers.
032: */
033: public final class DecimalFormatSymbols implements Cloneable,
034: Serializable {
035:
036: private static final long serialVersionUID = 5772796243397350300L;
037:
038: private final int ZeroDigit = 0, Digit = 1, DecimalSeparator = 2,
039: GroupingSeparator = 3, PatternSeparator = 4, Percent = 5,
040: PerMill = 6, Exponent = 7, MonetaryDecimalSeparator = 8,
041: MinusSign = 9;
042:
043: transient char[] patternChars;
044:
045: private transient Currency currency;
046:
047: private transient Locale locale;
048:
049: private String infinity, NaN, currencySymbol, intlCurrencySymbol;
050:
051: /**
052: * Constructs a new DecimalFormatSymbols containing the symbols for the
053: * default Locale.
054: */
055: public DecimalFormatSymbols() {
056: this (Locale.getDefault());
057: }
058:
059: /**
060: * Constructs a new DecimalFormatSymbols containing the symbols for the
061: * specified Locale.
062: *
063: * @param locale
064: * the Locale
065: */
066: public DecimalFormatSymbols(Locale locale) {
067: com.ibm.icu.text.DecimalFormatSymbols icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(
068: locale);
069: infinity = icuSymbols.getInfinity();
070: NaN = icuSymbols.getNaN();
071: this .locale = locale;
072: currencySymbol = icuSymbols.getCurrencySymbol();
073: intlCurrencySymbol = icuSymbols
074: .getInternationalCurrencySymbol();
075: if (locale.getCountry().length() == 0) {
076: currency = Currency.getInstance("XXX");
077: } else {
078: currency = Currency.getInstance(locale);
079: }
080: patternChars = new char[10];
081: patternChars[ZeroDigit] = icuSymbols.getZeroDigit();
082: patternChars[Digit] = icuSymbols.getDigit();
083: patternChars[DecimalSeparator] = icuSymbols
084: .getDecimalSeparator();
085: patternChars[GroupingSeparator] = icuSymbols
086: .getGroupingSeparator();
087: patternChars[PatternSeparator] = icuSymbols
088: .getPatternSeparator();
089: patternChars[Percent] = icuSymbols.getPercent();
090: patternChars[PerMill] = icuSymbols.getPerMill();
091: patternChars[Exponent] = icuSymbols.getExponentSeparator()
092: .charAt(0);
093: patternChars[MonetaryDecimalSeparator] = icuSymbols
094: .getMonetaryDecimalSeparator();
095: patternChars[MinusSign] = icuSymbols.getMinusSign();
096:
097: }
098:
099: /**
100: * Answers a new DecimalFormatSymbols with the same symbols as this
101: * DecimalFormatSymbols.
102: *
103: * @return a shallow copy of this DecimalFormatSymbols
104: *
105: * @see java.lang.Cloneable
106: */
107: @Override
108: public Object clone() {
109: try {
110: DecimalFormatSymbols symbols = (DecimalFormatSymbols) super
111: .clone();
112: symbols.patternChars = patternChars.clone();
113: return symbols;
114: } catch (CloneNotSupportedException e) {
115: return null;
116: }
117: }
118:
119: /**
120: * Compares the specified object to this DecimalFormatSymbols and answer if
121: * they are equal. The object must be an instance of DecimalFormatSymbols
122: * with the same symbols.
123: *
124: * @param object
125: * the object to compare with this object
126: * @return true if the specified object is equal to this
127: * DecimalFormatSymbols, false otherwise
128: *
129: * @see #hashCode
130: */
131: @Override
132: public boolean equals(Object object) {
133: if (this == object) {
134: return true;
135: }
136: if (!(object instanceof DecimalFormatSymbols)) {
137: return false;
138: }
139: DecimalFormatSymbols obj = (DecimalFormatSymbols) object;
140: return Arrays.equals(patternChars, obj.patternChars)
141: && infinity.equals(obj.infinity) && NaN.equals(obj.NaN)
142: && currencySymbol.equals(obj.currencySymbol)
143: && intlCurrencySymbol.equals(obj.intlCurrencySymbol);
144: }
145:
146: /**
147: * Answers the currency.
148: * <p>
149: * <code>null<code> is returned
150: * if <code>setInternationalCurrencySymbol()</code> has been previously called
151: * with a value that is not a valid ISO 4217 currency code.
152: * <p>
153: *
154: * @return the currency that was set in the constructor, <code>setCurrency()</code>,
155: * or <code>setInternationalCurrencySymbol()</code>, or </code>null</code>
156: *
157: * @see #setCurrency(Currency)
158: * @see #setInternationalCurrencySymbol(String)
159: */
160: public Currency getCurrency() {
161: return currency;
162: }
163:
164: /**
165: * Answers the international currency symbol.
166: *
167: * @return a String
168: */
169: public String getInternationalCurrencySymbol() {
170: return intlCurrencySymbol;
171: }
172:
173: /**
174: * Answers the currency symbol.
175: *
176: * @return a String
177: */
178: public String getCurrencySymbol() {
179: return currencySymbol;
180: }
181:
182: /**
183: * Answers the character which represents the decimal point in a number.
184: *
185: * @return a char
186: */
187: public char getDecimalSeparator() {
188: return patternChars[DecimalSeparator];
189: }
190:
191: /**
192: * Answers the character which represents a single digit in a format
193: * pattern.
194: *
195: * @return a char
196: */
197: public char getDigit() {
198: return patternChars[Digit];
199: }
200:
201: /**
202: * Answers the character used as the thousands separator in a number.
203: *
204: * @return a char
205: */
206: public char getGroupingSeparator() {
207: return patternChars[GroupingSeparator];
208: }
209:
210: /**
211: * Answers the String which represents infinity.
212: *
213: * @return a String
214: */
215: public String getInfinity() {
216: return infinity;
217: }
218:
219: String getLocalPatternChars() {
220: // Don't include the MonetaryDecimalSeparator or the MinusSign
221: return new String(patternChars, 0, patternChars.length - 2);
222: }
223:
224: /**
225: * Answers the minus sign character.
226: *
227: * @return a char
228: */
229: public char getMinusSign() {
230: return patternChars[MinusSign];
231: }
232:
233: /**
234: * Answers the character which represents the decimal point in a monetary
235: * value.
236: *
237: * @return a char
238: */
239: public char getMonetaryDecimalSeparator() {
240: return patternChars[MonetaryDecimalSeparator];
241: }
242:
243: /**
244: * Answers the String which represents NaN.
245: *
246: * @return a String
247: */
248: public String getNaN() {
249: return NaN;
250: }
251:
252: /**
253: * Answers the character which separates the positive and negative patterns
254: * in a format pattern.
255: *
256: * @return a char
257: */
258: public char getPatternSeparator() {
259: return patternChars[PatternSeparator];
260: }
261:
262: /**
263: * Answers the percent character.
264: *
265: * @return a char
266: */
267: public char getPercent() {
268: return patternChars[Percent];
269: }
270:
271: /**
272: * Answers the mille percent sign character.
273: *
274: * @return a char
275: */
276: public char getPerMill() {
277: return patternChars[PerMill];
278: }
279:
280: /**
281: * Answers the character which represents zero.
282: *
283: * @return a char
284: */
285: public char getZeroDigit() {
286: return patternChars[ZeroDigit];
287: }
288:
289: char getExponential() {
290: return patternChars[Exponent];
291: }
292:
293: /**
294: * Answers an integer hash code for the receiver. Objects which are equal
295: * answer the same value for this method.
296: *
297: * @return the receiver's hash
298: *
299: * @see #equals
300: */
301: @Override
302: public int hashCode() {
303: return new String(patternChars).hashCode()
304: + infinity.hashCode() + NaN.hashCode()
305: + currencySymbol.hashCode()
306: + intlCurrencySymbol.hashCode();
307: }
308:
309: /**
310: * Sets the currency.
311: * <p>
312: * The international currency symbol and currency symbol are updated, but
313: * the min and max number of fraction digits stay the same.
314: * <p>
315: *
316: * @param currency
317: * the new currency
318: *
319: * @throws java.lang.NullPointerException
320: * if currency is null
321: */
322: public void setCurrency(Currency currency) {
323: if (currency == null) {
324: throw new NullPointerException();
325: }
326: if (currency == this .currency) {
327: return;
328: }
329: this .currency = currency;
330: intlCurrencySymbol = currency.getCurrencyCode();
331: currencySymbol = currency.getSymbol(locale);
332: }
333:
334: /**
335: * Sets the international currency symbol.
336: * <p>
337: * currency and currency symbol also are updated, if <code>value</code> is
338: * a valid ISO4217 currency code.
339: * <p>
340: * The min and max number of fraction digits stay the same.
341: *
342: * @param value
343: * currency code
344: */
345: public void setInternationalCurrencySymbol(String value) {
346: if (value == null) {
347: currency = null;
348: intlCurrencySymbol = null;
349: return;
350: }
351:
352: if (value.equals(intlCurrencySymbol)) {
353: return;
354: }
355:
356: try {
357: currency = Currency.getInstance(value);
358: currencySymbol = currency.getSymbol(locale);
359: } catch (IllegalArgumentException e) {
360: currency = null;
361: }
362: intlCurrencySymbol = value;
363: }
364:
365: /**
366: * Sets the currency symbol.
367: *
368: * @param value
369: * a String
370: */
371: public void setCurrencySymbol(String value) {
372: currencySymbol = value;
373: }
374:
375: /**
376: * Sets the character which represents the decimal point in a number.
377: *
378: * @param value
379: * the decimal separator character
380: */
381: public void setDecimalSeparator(char value) {
382: patternChars[DecimalSeparator] = value;
383: }
384:
385: /**
386: * Sets the character which represents a single digit in a format pattern.
387: *
388: * @param value
389: * the digit character
390: */
391: public void setDigit(char value) {
392: patternChars[Digit] = value;
393: }
394:
395: /**
396: * Sets the character used as the thousands separator in a number.
397: *
398: * @param value
399: * the grouping separator character
400: */
401: public void setGroupingSeparator(char value) {
402: patternChars[GroupingSeparator] = value;
403: }
404:
405: /**
406: * Sets the String which represents infinity.
407: *
408: * @param value
409: * the String
410: */
411: public void setInfinity(String value) {
412: infinity = value;
413: }
414:
415: /**
416: * Sets the minus sign character.
417: *
418: * @param value
419: * the minus sign character
420: */
421: public void setMinusSign(char value) {
422: patternChars[MinusSign] = value;
423: }
424:
425: /**
426: * Sets the character which represents the decimal point in a monetary
427: * value.
428: *
429: * @param value
430: * the monetary decimal separator character
431: */
432: public void setMonetaryDecimalSeparator(char value) {
433: patternChars[MonetaryDecimalSeparator] = value;
434: }
435:
436: /**
437: * Sets the String which represents NaN.
438: *
439: * @param value
440: * the String
441: */
442: public void setNaN(String value) {
443: NaN = value;
444: }
445:
446: /**
447: * Sets the character which separates the positive and negative patterns in
448: * a format pattern.
449: *
450: * @param value
451: * the pattern separator character
452: */
453: public void setPatternSeparator(char value) {
454: patternChars[PatternSeparator] = value;
455: }
456:
457: /**
458: * Sets the percent character.
459: *
460: * @param value
461: * the percent character
462: */
463: public void setPercent(char value) {
464: patternChars[Percent] = value;
465: }
466:
467: /**
468: * Sets the mille percent sign character.
469: *
470: * @param value
471: * the mille percent character
472: */
473: public void setPerMill(char value) {
474: patternChars[PerMill] = value;
475: }
476:
477: /**
478: * Sets the character which represents zero.
479: *
480: * @param value
481: * the zero digit character
482: */
483: public void setZeroDigit(char value) {
484: patternChars[ZeroDigit] = value;
485: }
486:
487: void setExponential(char value) {
488: patternChars[Exponent] = value;
489: }
490:
491: private static final ObjectStreamField[] serialPersistentFields = {
492: new ObjectStreamField("currencySymbol", String.class), //$NON-NLS-1$
493: new ObjectStreamField("decimalSeparator", Character.TYPE), //$NON-NLS-1$
494: new ObjectStreamField("digit", Character.TYPE), //$NON-NLS-1$
495: new ObjectStreamField("exponential", Character.TYPE), //$NON-NLS-1$
496: new ObjectStreamField("groupingSeparator", Character.TYPE), //$NON-NLS-1$
497: new ObjectStreamField("infinity", String.class), //$NON-NLS-1$
498: new ObjectStreamField("intlCurrencySymbol", String.class), //$NON-NLS-1$
499: new ObjectStreamField("minusSign", Character.TYPE), //$NON-NLS-1$
500: new ObjectStreamField("monetarySeparator", Character.TYPE), //$NON-NLS-1$
501: new ObjectStreamField("NaN", String.class), //$NON-NLS-1$
502: new ObjectStreamField("patternSeparator", Character.TYPE), //$NON-NLS-1$
503: new ObjectStreamField("percent", Character.TYPE), //$NON-NLS-1$
504: new ObjectStreamField("perMill", Character.TYPE), //$NON-NLS-1$
505: new ObjectStreamField("serialVersionOnStream", Integer.TYPE), //$NON-NLS-1$
506: new ObjectStreamField("zeroDigit", Character.TYPE), //$NON-NLS-1$
507: new ObjectStreamField("locale", Locale.class), }; //$NON-NLS-1$
508:
509: private void writeObject(ObjectOutputStream stream)
510: throws IOException {
511: ObjectOutputStream.PutField fields = stream.putFields();
512: fields.put("currencySymbol", currencySymbol); //$NON-NLS-1$
513: fields.put("decimalSeparator", getDecimalSeparator()); //$NON-NLS-1$
514: fields.put("digit", getDigit()); //$NON-NLS-1$
515: fields.put("exponential", getExponential()); //$NON-NLS-1$
516: fields.put("groupingSeparator", getGroupingSeparator()); //$NON-NLS-1$
517: fields.put("infinity", infinity); //$NON-NLS-1$
518: fields.put("intlCurrencySymbol", intlCurrencySymbol); //$NON-NLS-1$
519: fields.put("minusSign", getMinusSign()); //$NON-NLS-1$
520: fields.put("monetarySeparator", getMonetaryDecimalSeparator()); //$NON-NLS-1$
521: fields.put("NaN", NaN); //$NON-NLS-1$
522: fields.put("patternSeparator", getPatternSeparator()); //$NON-NLS-1$
523: fields.put("percent", getPercent()); //$NON-NLS-1$
524: fields.put("perMill", getPerMill()); //$NON-NLS-1$
525: fields.put("serialVersionOnStream", 1); //$NON-NLS-1$
526: fields.put("zeroDigit", getZeroDigit()); //$NON-NLS-1$
527: fields.put("locale", locale); //$NON-NLS-1$
528: stream.writeFields();
529: }
530:
531: private void readObject(ObjectInputStream stream)
532: throws IOException, ClassNotFoundException {
533: ObjectInputStream.GetField fields = stream.readFields();
534: patternChars = new char[10];
535: currencySymbol = (String) fields.get("currencySymbol", ""); //$NON-NLS-1$ //$NON-NLS-2$
536: setDecimalSeparator(fields.get("decimalSeparator", '.')); //$NON-NLS-1$
537: setDigit(fields.get("digit", '#')); //$NON-NLS-1$
538: setGroupingSeparator(fields.get("groupingSeparator", ',')); //$NON-NLS-1$
539: infinity = (String) fields.get("infinity", ""); //$NON-NLS-1$ //$NON-NLS-2$
540: intlCurrencySymbol = (String) fields.get(
541: "intlCurrencySymbol", ""); //$NON-NLS-1$ //$NON-NLS-2$
542: setMinusSign(fields.get("minusSign", '-')); //$NON-NLS-1$
543: NaN = (String) fields.get("NaN", ""); //$NON-NLS-1$ //$NON-NLS-2$
544: setPatternSeparator(fields.get("patternSeparator", ';')); //$NON-NLS-1$
545: setPercent(fields.get("percent", '%')); //$NON-NLS-1$
546: setPerMill(fields.get("perMill", '\u2030')); //$NON-NLS-1$
547: setZeroDigit(fields.get("zeroDigit", '0')); //$NON-NLS-1$
548: locale = (Locale) fields.get("locale", null); //$NON-NLS-1$
549: if (fields.get("serialVersionOnStream", 0) == 0) { //$NON-NLS-1$
550: setMonetaryDecimalSeparator(getDecimalSeparator());
551: setExponential('E');
552: } else {
553: setMonetaryDecimalSeparator(fields.get(
554: "monetarySeparator", '.')); //$NON-NLS-1$
555: setExponential(fields.get("exponential", 'E')); //$NON-NLS-1$
556:
557: }
558: try {
559: currency = Currency.getInstance(intlCurrencySymbol);
560: } catch (IllegalArgumentException e) {
561: currency = null;
562: }
563: }
564:
565: Locale getLocale() {
566: return locale;
567: }
568: }
|