1. /*
  2. * @(#)DecimalFormatSymbols.java 1.27 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * @(#)DecimalFormatSymbols.java 1.27 01/11/29
  9. *
  10. * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  11. * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  12. *
  13. * Portions copyright (c) 1996-1998 Sun Microsystems, Inc.
  14. * All Rights Reserved.
  15. *
  16. * The original version of this source code and documentation is copyrighted
  17. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  18. * materials are provided under terms of a License Agreement between Taligent
  19. * and Sun. This technology is protected by multiple US and International
  20. * patents. This notice and attribution to Taligent may not be removed.
  21. * Taligent is a registered trademark of Taligent, Inc.
  22. *
  23. * Permission to use, copy, modify, and distribute this software
  24. * and its documentation for NON-COMMERCIAL purposes and without
  25. * fee is hereby granted provided that this copyright notice
  26. * appears in all copies. Please refer to the file "copyright.html"
  27. * for further important copyright and licensing information.
  28. *
  29. * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  30. * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  31. * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  32. * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  33. * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  34. * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  35. *
  36. */
  37. package java.text;
  38. import java.io.IOException;
  39. import java.io.ObjectInputStream;
  40. import java.io.Serializable;
  41. import java.util.ResourceBundle;
  42. import java.util.Locale;
  43. import java.util.Hashtable;
  44. /**
  45. * This class represents the set of symbols (such as the decimal separator,
  46. * the grouping separator, and so on) needed by <code>DecimalFormat</code>
  47. * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
  48. * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any
  49. * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
  50. * your <code>DecimalFormat</code> and modify it.
  51. *
  52. * @see java.util.Locale
  53. * @see DecimalFormat
  54. * @version 1.12 29 Jan 1997
  55. * @author Mark Davis
  56. * @author Alan Liu
  57. */
  58. final public class DecimalFormatSymbols implements Cloneable, Serializable {
  59. /**
  60. * Create a DecimalFormatSymbols object for the default locale.
  61. */
  62. public DecimalFormatSymbols() {
  63. initialize( Locale.getDefault() );
  64. }
  65. /**
  66. * Create a DecimalFormatSymbols object for the given locale.
  67. */
  68. public DecimalFormatSymbols( Locale locale ) {
  69. initialize( locale );
  70. }
  71. /**
  72. * character used for zero. Different for Arabic, etc.
  73. */
  74. public char getZeroDigit() {
  75. return zeroDigit;
  76. }
  77. public void setZeroDigit(char zeroDigit) {
  78. this.zeroDigit = zeroDigit;
  79. }
  80. /**
  81. * character used for thousands separator. Different for French, etc.
  82. */
  83. public char getGroupingSeparator() {
  84. return groupingSeparator;
  85. }
  86. public void setGroupingSeparator(char groupingSeparator) {
  87. this.groupingSeparator = groupingSeparator;
  88. }
  89. /**
  90. * character used for decimal sign. Different for French, etc.
  91. */
  92. public char getDecimalSeparator() {
  93. return decimalSeparator;
  94. }
  95. public void setDecimalSeparator(char decimalSeparator) {
  96. this.decimalSeparator = decimalSeparator;
  97. }
  98. /**
  99. * character used for mille percent sign. Different for Arabic, etc.
  100. */
  101. public char getPerMill() {
  102. return perMill;
  103. }
  104. public void setPerMill(char perMill) {
  105. this.perMill = perMill;
  106. }
  107. /**
  108. * character used for percent sign. Different for Arabic, etc.
  109. */
  110. public char getPercent() {
  111. return percent;
  112. }
  113. public void setPercent(char percent) {
  114. this.percent = percent;
  115. }
  116. /**
  117. * character used for a digit in a pattern.
  118. */
  119. public char getDigit() {
  120. return digit;
  121. }
  122. public void setDigit(char digit) {
  123. this.digit = digit;
  124. }
  125. /**
  126. * character used to separate positive and negative subpatterns
  127. * in a pattern.
  128. */
  129. public char getPatternSeparator() {
  130. return patternSeparator;
  131. }
  132. public void setPatternSeparator(char patternSeparator) {
  133. this.patternSeparator = patternSeparator;
  134. }
  135. /**
  136. * character used to represent infinity. Almost always left
  137. * unchanged.
  138. */
  139. public String getInfinity() {
  140. return infinity;
  141. }
  142. public void setInfinity(String infinity) {
  143. this.infinity = infinity;
  144. }
  145. /**
  146. * character used to represent NaN. Almost always left
  147. * unchanged.
  148. */
  149. public String getNaN() {
  150. return NaN;
  151. }
  152. public void setNaN(String NaN) {
  153. this.NaN = NaN;
  154. }
  155. /**
  156. * character used to represent minus sign. If no explicit
  157. * negative format is specified, one is formed by prefixing
  158. * minusSign to the positive format.
  159. */
  160. public char getMinusSign() {
  161. return minusSign;
  162. }
  163. public void setMinusSign(char minusSign) {
  164. this.minusSign = minusSign;
  165. }
  166. /**
  167. * Return the string denoting the local currency.
  168. */
  169. public String getCurrencySymbol()
  170. {
  171. return currencySymbol;
  172. }
  173. /**
  174. * Set the string denoting the local currency.
  175. */
  176. public void setCurrencySymbol(String currency)
  177. {
  178. currencySymbol = currency;
  179. }
  180. /**
  181. * Return the international string denoting the local currency.
  182. */
  183. public String getInternationalCurrencySymbol()
  184. {
  185. return intlCurrencySymbol;
  186. }
  187. /**
  188. * Set the international string denoting the local currency.
  189. */
  190. public void setInternationalCurrencySymbol(String currency)
  191. {
  192. intlCurrencySymbol = currency;
  193. }
  194. /**
  195. * Return the monetary decimal separator.
  196. */
  197. public char getMonetaryDecimalSeparator()
  198. {
  199. return monetarySeparator;
  200. }
  201. /**
  202. * Set the monetary decimal separator.
  203. */
  204. public void setMonetaryDecimalSeparator(char sep)
  205. {
  206. monetarySeparator = sep;
  207. }
  208. //------------------------------------------------------------
  209. // BEGIN Package Private methods ... to be made public later
  210. //------------------------------------------------------------
  211. /**
  212. * Return the character used to separate the mantissa from the exponent.
  213. */
  214. char getExponentialSymbol()
  215. {
  216. return exponential;
  217. }
  218. /**
  219. * Set the character used to separate the mantissa from the exponent.
  220. */
  221. void setExponentialSymbol(char exp)
  222. {
  223. exponential = exp;
  224. }
  225. //------------------------------------------------------------
  226. // END Package Private methods ... to be made public later
  227. //------------------------------------------------------------
  228. /**
  229. * Standard override.
  230. */
  231. public Object clone() {
  232. try {
  233. return (DecimalFormatSymbols)super.clone();
  234. // other fields are bit-copied
  235. } catch (CloneNotSupportedException e) {
  236. throw new InternalError();
  237. }
  238. }
  239. /**
  240. * Override equals
  241. */
  242. public boolean equals(Object obj) {
  243. if (obj == null) return false;
  244. if (this == obj) return true;
  245. if (getClass() != obj.getClass()) return false;
  246. DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
  247. return (zeroDigit == other.zeroDigit &&
  248. groupingSeparator == other.groupingSeparator &&
  249. decimalSeparator == other.decimalSeparator &&
  250. percent == other.percent &&
  251. perMill == other.perMill &&
  252. digit == other.digit &&
  253. minusSign == other.minusSign &&
  254. patternSeparator == other.patternSeparator &&
  255. infinity.equals(other.infinity) &&
  256. NaN.equals(other.NaN) &&
  257. currencySymbol.equals(other.currencySymbol) &&
  258. intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
  259. monetarySeparator == other.monetarySeparator);
  260. }
  261. /**
  262. * Override hashCode
  263. */
  264. public int hashCode() {
  265. int result = zeroDigit;
  266. result = result * 37 + groupingSeparator;
  267. result = result * 37 + decimalSeparator;
  268. return result;
  269. }
  270. /**
  271. * Initializes the symbols from the LocaleElements resource bundle.
  272. * Note: The organization of LocaleElements badly needs to be
  273. * cleaned up.
  274. */
  275. private void initialize( Locale locale ) {
  276. /* try the cache first */
  277. String[][] data = (String[][]) cachedLocaleData.get(locale);
  278. String[] numberElements;
  279. String[] currencyElements;
  280. if (data == null) { /* cache miss */
  281. data = new String[2][];
  282. ResourceBundle rb = ResourceBundle.getBundle
  283. ("java.text.resources.LocaleElements", locale);
  284. data[0] = rb.getStringArray("NumberElements");
  285. data[1] = rb.getStringArray("CurrencyElements");
  286. /* update cache */
  287. cachedLocaleData.put(locale, data);
  288. }
  289. numberElements = data[0];
  290. currencyElements = data[1];
  291. decimalSeparator = numberElements[0].charAt(0);
  292. groupingSeparator = numberElements[1].charAt(0);
  293. patternSeparator = numberElements[2].charAt(0);
  294. percent = numberElements[3].charAt(0);
  295. zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
  296. digit = numberElements[5].charAt(0);
  297. minusSign = numberElements[6].charAt(0);
  298. exponential = numberElements[7].charAt(0);
  299. perMill = numberElements[8].charAt(0);
  300. infinity = numberElements[9];
  301. NaN = numberElements[10];
  302. currencySymbol = currencyElements[0];
  303. intlCurrencySymbol = currencyElements[1];
  304. // if the resource data specified the empty string as the monetary decimal
  305. // separator, that means we should just use the regular separator as the
  306. // monetary separator
  307. if (currencyElements[2].length() == 0)
  308. monetarySeparator = decimalSeparator;
  309. else
  310. monetarySeparator = currencyElements[2].charAt(0);
  311. }
  312. /**
  313. * Read the default serializable fields, then if <code>serialVersionOnStream</code>
  314. * is less than 1, initialize <code>monetarySeparator</code> to be
  315. * the same as <code>decimalSeparator</code> and <code>exponential</code>
  316. * to be 'E'.
  317. * Finally, set serialVersionOnStream back to the maximum allowed value so that
  318. * default serialization will work properly if this object is streamed out again.
  319. *
  320. * @since JDK 1.1.6
  321. */
  322. private void readObject(ObjectInputStream stream)
  323. throws IOException, ClassNotFoundException
  324. {
  325. stream.defaultReadObject();
  326. if (serialVersionOnStream < 1)
  327. {
  328. // Didn't have monetarySeparator or exponential field;
  329. // use defaults.
  330. monetarySeparator = decimalSeparator;
  331. exponential = 'E';
  332. }
  333. serialVersionOnStream = currentSerialVersion;
  334. }
  335. /**
  336. * Character used for zero.
  337. *
  338. * @serial
  339. * @see #getZeroDigit
  340. */
  341. private char zeroDigit;
  342. /**
  343. * Character used for thousands separator.
  344. *
  345. * @serial
  346. * @see #getGroupingSeparator
  347. */
  348. private char groupingSeparator;
  349. /**
  350. * Character used for decimal sign.
  351. *
  352. * @serial
  353. * @see #getDecimalSeparator
  354. */
  355. private char decimalSeparator;
  356. /**
  357. * Character used for mille percent sign.
  358. *
  359. * @serial
  360. * @see #getPerMill
  361. */
  362. private char perMill;
  363. /**
  364. * Character used for percent sign.
  365. * @serial
  366. * @see #getPercent
  367. */
  368. private char percent;
  369. /**
  370. * Character used for a digit in a pattern.
  371. *
  372. * @serial
  373. * @see #getDigit
  374. */
  375. private char digit;
  376. /**
  377. * Character used to separate positive and negative subpatterns
  378. * in a pattern.
  379. *
  380. * @serial
  381. * @see #getPatternSeparator
  382. */
  383. private char patternSeparator;
  384. /**
  385. * Character used to represent infinity.
  386. * @serial
  387. * @see #getInfinity
  388. */
  389. private String infinity;
  390. /**
  391. * Character used to represent NaN.
  392. * @serial
  393. * @see #getNaN
  394. */
  395. private String NaN;
  396. /**
  397. * Character used to represent minus sign.
  398. * @serial
  399. * @see #getMinusSign
  400. */
  401. private char minusSign;
  402. /**
  403. * String denoting the local currency, e.g. "$".
  404. * @serial
  405. * @see #getCurrencySymbol
  406. */
  407. private String currencySymbol;
  408. /**
  409. * International string denoting the local currency, e.g. "USD".
  410. * @serial
  411. * @see #getInternationalCurrencySymbol
  412. */
  413. private String intlCurrencySymbol;
  414. /**
  415. * The decimal separator used when formatting currency values.
  416. * @serial
  417. * @since JDK 1.1.6
  418. * @see #getMonetaryDecimalSeparator
  419. */
  420. private char monetarySeparator; // Field new in JDK 1.1.6
  421. /**
  422. * The character used to distinguish the exponent in a number formatted
  423. * in exponential notation, e.g. 'E' for a number such as "1.23E45".
  424. * <p>
  425. * Note that the public API provides no way to set this field,
  426. * even though it is supported by the implementation and the stream format.
  427. * The intent is that this will be added to the API in the future.
  428. *
  429. * @serial
  430. * @since JDK 1.1.6
  431. */
  432. private char exponential; // Field new in JDK 1.1.6
  433. // Proclaim JDK 1.1 FCS compatibility
  434. static final long serialVersionUID = 5772796243397350300L;
  435. // The internal serial version which says which version was written
  436. // - 0 (default) for version up to JDK 1.1.5
  437. // - 1 for version from JDK 1.1.6, which includes two new fields:
  438. // monetarySeparator and exponential.
  439. private static final int currentSerialVersion = 1;
  440. /**
  441. * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
  442. * Possible values are:
  443. * <ul>
  444. * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
  445. *
  446. * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which includes
  447. * two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
  448. * </ul>
  449. * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
  450. * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
  451. * is always written.
  452. *
  453. * @serial
  454. * @since JDK 1.1.6
  455. */
  456. private int serialVersionOnStream = currentSerialVersion;
  457. /**
  458. * cache to hold the NumberElements and the CurrencyElements
  459. * of a Locale.
  460. */
  461. private static final Hashtable cachedLocaleData = new Hashtable(3);
  462. }