1/*
2 *******************************************************************************
3 * Copyright (C) 2008-2011, International Business Machines Corporation and    *
4 * others. All Rights Reserved.                                                *
5 *******************************************************************************
6 */
7package com.ibm.icu.impl.jdkadapter;
8
9import java.math.RoundingMode;
10import java.text.AttributedCharacterIterator;
11import java.text.AttributedString;
12import java.text.CharacterIterator;
13import java.text.DecimalFormatSymbols;
14import java.text.FieldPosition;
15import java.text.ParsePosition;
16import java.util.Currency;
17import java.util.HashMap;
18import java.util.Map;
19import java.util.Map.Entry;
20
21import com.ibm.icu.text.DecimalFormat;
22import com.ibm.icu.text.NumberFormat;
23
24/**
25 * DecimalFormatICU is an adapter class which wraps ICU4J DecimalFormat and
26 * implements java.text.DecimalFormat APIs.
27 */
28public class DecimalFormatICU extends java.text.DecimalFormat {
29
30    private static final long serialVersionUID = 6441573352964019403L;
31
32    private DecimalFormat fIcuDecfmt;
33
34    private DecimalFormatICU(DecimalFormat icuDecfmt) {
35        fIcuDecfmt = icuDecfmt;
36    }
37
38    public static java.text.DecimalFormat wrap(DecimalFormat icuDecfmt) {
39        return new DecimalFormatICU(icuDecfmt);
40    }
41
42    public DecimalFormat unwrap() {
43        return fIcuDecfmt;
44    }
45
46    // Methods overriding java.text.DecimalFormat
47    @Override
48    public void applyLocalizedPattern(String pattern) {
49        fIcuDecfmt.applyLocalizedPattern(pattern);
50    }
51
52    @Override
53    public void applyPattern(String pattern) {
54        fIcuDecfmt.applyPattern(pattern);
55    }
56
57    @Override
58    public Object clone() {
59        DecimalFormatICU other = (DecimalFormatICU)super.clone();
60        other.fIcuDecfmt = (DecimalFormat)fIcuDecfmt.clone();
61        return other;
62    }
63
64    @Override
65    public boolean equals(Object obj) {
66        if (obj instanceof DecimalFormatICU) {
67            return ((DecimalFormatICU)obj).fIcuDecfmt.equals(fIcuDecfmt);
68        }
69        return false;
70    }
71
72    @Override
73    public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
74        return fIcuDecfmt.format(number, result, fieldPosition);
75    }
76
77    @Override
78    public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) {
79        return fIcuDecfmt.format(number, result, fieldPosition);
80    }
81
82    @Override
83    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
84        AttributedCharacterIterator aci = fIcuDecfmt.formatToCharacterIterator(obj);
85
86        // Create a new AttributedString
87        StringBuilder sb = new StringBuilder(aci.getEndIndex() - aci.getBeginIndex());
88        char c = aci.first();
89        while (true) {
90            sb.append(c);
91            c = aci.next();
92            if (c == CharacterIterator.DONE) {
93                break;
94            }
95        }
96        AttributedString resstr = new AttributedString(sb.toString());
97
98        // Mapping attributes
99        Map<AttributedCharacterIterator.Attribute,Object> attributes = null;
100        int index = aci.getBeginIndex();
101        int residx = 0;
102        while (true) {
103            if (aci.setIndex(index) == CharacterIterator.DONE) {
104                break;
105            }
106            attributes = aci.getAttributes();
107            if (attributes != null) {
108                int end = aci.getRunLimit();
109                Map<AttributedCharacterIterator.Attribute,Object> jdkAttributes =
110                    new HashMap<AttributedCharacterIterator.Attribute,Object>();
111                for (Entry<AttributedCharacterIterator.Attribute, Object> entry
112                        : attributes.entrySet()) {
113                    AttributedCharacterIterator.Attribute key = entry.getKey();
114                    AttributedCharacterIterator.Attribute jdkKey = mapAttribute(key);
115                    Object jdkVal = entry.getValue();
116                    if (jdkVal instanceof AttributedCharacterIterator.Attribute) {
117                        jdkVal = mapAttribute((AttributedCharacterIterator.Attribute)jdkVal);
118                    }
119                    jdkAttributes.put(jdkKey, jdkVal);
120                }
121                int resend = residx + (end - index);
122                resstr.addAttributes(jdkAttributes, residx, resend);
123
124                index = end;
125                residx = resend;
126            }
127        }
128        return resstr.getIterator();
129    }
130
131    @Override
132    public Currency getCurrency() {
133        com.ibm.icu.util.Currency icuCurrency = fIcuDecfmt.getCurrency();
134        if (icuCurrency == null) {
135            return null;
136        }
137        return Currency.getInstance(icuCurrency.getCurrencyCode());
138    }
139
140    @Override
141    public DecimalFormatSymbols getDecimalFormatSymbols() {
142        return DecimalFormatSymbolsICU.wrap(fIcuDecfmt.getDecimalFormatSymbols());
143    }
144
145    @Override
146    public int getGroupingSize() {
147        return fIcuDecfmt.getGroupingSize();
148    }
149
150    @Override
151    public int getMaximumFractionDigits() {
152        return fIcuDecfmt.getMaximumFractionDigits();
153    }
154
155    @Override
156    public int getMaximumIntegerDigits() {
157        return fIcuDecfmt.getMaximumIntegerDigits();
158    }
159
160    @Override
161    public int getMinimumFractionDigits() {
162        return fIcuDecfmt.getMinimumFractionDigits();
163    }
164
165    @Override
166    public int getMinimumIntegerDigits() {
167        return fIcuDecfmt.getMinimumIntegerDigits();
168    }
169
170    @Override
171    public int getMultiplier() {
172        return fIcuDecfmt.getMultiplier();
173    }
174
175    @Override
176    public String getNegativePrefix() {
177        return fIcuDecfmt.getNegativePrefix();
178    }
179
180    @Override
181    public String getNegativeSuffix() {
182        return fIcuDecfmt.getNegativeSuffix();
183    }
184
185    @Override
186    public String getPositivePrefix() {
187        return fIcuDecfmt.getPositivePrefix();
188    }
189
190    @Override
191    public String getPositiveSuffix() {
192        return fIcuDecfmt.getPositiveSuffix();
193    }
194
195    @Override
196    public RoundingMode getRoundingMode() {
197        int icuMode = fIcuDecfmt.getRoundingMode();
198        RoundingMode mode = RoundingMode.UP;
199        switch (icuMode) {
200        case com.ibm.icu.math.BigDecimal.ROUND_CEILING:
201            mode = RoundingMode.CEILING;
202            break;
203        case com.ibm.icu.math.BigDecimal.ROUND_DOWN:
204            mode = RoundingMode.DOWN;
205            break;
206        case com.ibm.icu.math.BigDecimal.ROUND_FLOOR:
207            mode = RoundingMode.FLOOR;
208            break;
209        case com.ibm.icu.math.BigDecimal.ROUND_HALF_DOWN:
210            mode = RoundingMode.HALF_DOWN;
211            break;
212        case com.ibm.icu.math.BigDecimal.ROUND_HALF_EVEN:
213            mode = RoundingMode.HALF_EVEN;
214            break;
215        case com.ibm.icu.math.BigDecimal.ROUND_HALF_UP:
216            mode = RoundingMode.HALF_UP;
217            break;
218        case com.ibm.icu.math.BigDecimal.ROUND_UNNECESSARY:
219            mode = RoundingMode.UNNECESSARY;
220            break;
221        case com.ibm.icu.math.BigDecimal.ROUND_UP:
222            mode = RoundingMode.UP;
223            break;
224        }
225        return mode;
226    }
227
228    @Override
229    public int hashCode() {
230        return fIcuDecfmt.hashCode();
231    }
232
233    @Override
234    public boolean isDecimalSeparatorAlwaysShown() {
235        return fIcuDecfmt.isDecimalSeparatorAlwaysShown();
236    }
237
238    @Override
239    public boolean isParseBigDecimal() {
240        return fIcuDecfmt.isParseBigDecimal();
241    }
242
243    @Override
244    public Number parse(String text, ParsePosition pos) {
245        return fIcuDecfmt.parse(text, pos);
246    }
247
248    @Override
249    public void setCurrency(Currency currency) {
250        if (currency == null) {
251            fIcuDecfmt.setCurrency(null);
252        } else {
253            fIcuDecfmt.setCurrency(com.ibm.icu.util.Currency.getInstance(currency.getCurrencyCode()));
254        }
255    }
256
257    @Override
258    public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
259        com.ibm.icu.text.DecimalFormatSymbols icuDecfs = null;
260        if (newSymbols instanceof DecimalFormatSymbolsICU) {
261            icuDecfs = ((DecimalFormatSymbolsICU)newSymbols).unwrap();
262        } else {
263            icuDecfs = fIcuDecfmt.getDecimalFormatSymbols();
264
265            Currency currency = newSymbols.getCurrency();
266            if (currency == null) {
267                icuDecfs.setCurrency(null);
268            } else {
269                icuDecfs.setCurrency(com.ibm.icu.util.Currency.getInstance(currency.getCurrencyCode()));
270            }
271
272            // Copy symbols
273            icuDecfs.setCurrencySymbol(newSymbols.getCurrencySymbol());
274            icuDecfs.setDecimalSeparator(newSymbols.getDecimalSeparator());
275            icuDecfs.setDigit(newSymbols.getDigit());
276            icuDecfs.setExponentSeparator(newSymbols.getExponentSeparator());
277            icuDecfs.setGroupingSeparator(newSymbols.getGroupingSeparator());
278            icuDecfs.setInfinity(newSymbols.getInfinity());
279            icuDecfs.setInternationalCurrencySymbol(newSymbols.getInternationalCurrencySymbol());
280            icuDecfs.setMinusSign(newSymbols.getMinusSign());
281            icuDecfs.setMonetaryDecimalSeparator(newSymbols.getMonetaryDecimalSeparator());
282            icuDecfs.setNaN(newSymbols.getNaN());
283            icuDecfs.setPatternSeparator(newSymbols.getPatternSeparator());
284            icuDecfs.setPercent(newSymbols.getPercent());
285            icuDecfs.setPerMill(newSymbols.getPerMill());
286            icuDecfs.setZeroDigit(newSymbols.getZeroDigit());
287        }
288        fIcuDecfmt.setDecimalFormatSymbols(icuDecfs);
289    }
290
291    @Override
292    public void setDecimalSeparatorAlwaysShown(boolean newValue) {
293        if (fIcuDecfmt != null) {
294            fIcuDecfmt.setDecimalSeparatorAlwaysShown(newValue);
295        }
296    }
297
298    @Override
299    public void setGroupingSize(int newValue) {
300        if (fIcuDecfmt != null) {
301            fIcuDecfmt.setGroupingSize(newValue);
302        }
303    }
304
305    @Override
306    public void setMaximumFractionDigits(int newValue) {
307        if (fIcuDecfmt != null) {
308            fIcuDecfmt.setMaximumFractionDigits(newValue);
309        }
310    }
311
312    @Override
313    public void setMaximumIntegerDigits(int newValue) {
314        if (fIcuDecfmt != null) {
315            fIcuDecfmt.setMaximumIntegerDigits(newValue);
316        }
317    }
318
319    @Override
320    public void setMinimumFractionDigits(int newValue) {
321        if (fIcuDecfmt != null) {
322            fIcuDecfmt.setMinimumFractionDigits(newValue);
323        }
324    }
325
326    @Override
327    public void setMinimumIntegerDigits(int newValue) {
328        if (fIcuDecfmt != null) {
329            fIcuDecfmt.setMinimumIntegerDigits(newValue);
330        }
331    }
332
333    @Override
334    public void setMultiplier(int newValue) {
335        fIcuDecfmt.setMultiplier(newValue);
336    }
337
338    @Override
339    public void setNegativePrefix(String newValue) {
340        fIcuDecfmt.setNegativePrefix(newValue);
341    }
342
343    @Override
344    public void setNegativeSuffix(String newValue) {
345        fIcuDecfmt.setNegativeSuffix(newValue);
346    }
347
348    @Override
349    public void setParseBigDecimal(boolean newValue) {
350        fIcuDecfmt.setParseBigDecimal(newValue);
351    }
352
353    @Override
354    public void setPositivePrefix(String newValue) {
355        fIcuDecfmt.setPositivePrefix(newValue);
356    }
357
358    @Override
359    public void setPositiveSuffix(String newValue) {
360        fIcuDecfmt.setPositiveSuffix(newValue);
361    }
362
363    @Override
364    public void setRoundingMode(RoundingMode roundingMode) {
365        if (roundingMode.equals(RoundingMode.CEILING)) {
366            fIcuDecfmt.setRoundingMode(com.ibm.icu.math.BigDecimal.ROUND_CEILING);
367        } else if (roundingMode.equals(RoundingMode.DOWN)) {
368            fIcuDecfmt.setRoundingMode(com.ibm.icu.math.BigDecimal.ROUND_DOWN);
369        } else if (roundingMode.equals(RoundingMode.FLOOR)) {
370            fIcuDecfmt.setRoundingMode(com.ibm.icu.math.BigDecimal.ROUND_FLOOR);
371        } else if (roundingMode.equals(RoundingMode.HALF_DOWN)) {
372            fIcuDecfmt.setRoundingMode(com.ibm.icu.math.BigDecimal.ROUND_HALF_DOWN);
373        } else if (roundingMode.equals(RoundingMode.HALF_EVEN)) {
374            fIcuDecfmt.setRoundingMode(com.ibm.icu.math.BigDecimal.ROUND_HALF_EVEN);
375        } else if (roundingMode.equals(RoundingMode.HALF_UP)) {
376            fIcuDecfmt.setRoundingMode(com.ibm.icu.math.BigDecimal.ROUND_HALF_UP);
377        } else if (roundingMode.equals(RoundingMode.UNNECESSARY)) {
378            fIcuDecfmt.setRoundingMode(com.ibm.icu.math.BigDecimal.ROUND_UNNECESSARY);
379        } else if (roundingMode.equals(RoundingMode.UP)) {
380            fIcuDecfmt.setRoundingMode(com.ibm.icu.math.BigDecimal.ROUND_UP);
381        } else {
382            throw new IllegalArgumentException("Invalid rounding mode was specified.");
383        }
384    }
385
386    @Override
387    public String toLocalizedPattern() {
388        return fIcuDecfmt.toLocalizedPattern();
389    }
390
391    @Override
392    public String toPattern() {
393        return fIcuDecfmt.toPattern();
394    }
395
396    // Methods overriding java.text.NumberFormat
397
398    @Override
399    public boolean isGroupingUsed() {
400        return fIcuDecfmt.isGroupingUsed();
401    }
402
403    @Override
404    public boolean isParseIntegerOnly() {
405        return fIcuDecfmt.isParseIntegerOnly();
406    }
407
408    @Override
409    public void setGroupingUsed(boolean newValue) {
410        if (fIcuDecfmt != null) {
411            fIcuDecfmt.setGroupingUsed(newValue);
412        }
413    }
414
415    @Override
416    public void setParseIntegerOnly(boolean value) {
417        fIcuDecfmt.setParseIntegerOnly(value);
418    }
419
420    private static AttributedCharacterIterator.Attribute mapAttribute(AttributedCharacterIterator.Attribute icuAttribute) {
421        AttributedCharacterIterator.Attribute jdkAttribute = icuAttribute;
422
423        if (icuAttribute == NumberFormat.Field.CURRENCY) {
424            jdkAttribute = java.text.NumberFormat.Field.CURRENCY;
425        } else if (icuAttribute == NumberFormat.Field.DECIMAL_SEPARATOR) {
426            jdkAttribute = java.text.NumberFormat.Field.DECIMAL_SEPARATOR;
427        } else if (icuAttribute == NumberFormat.Field.EXPONENT) {
428            jdkAttribute = java.text.NumberFormat.Field.EXPONENT;
429        } else if (icuAttribute == NumberFormat.Field.EXPONENT_SIGN) {
430            jdkAttribute = java.text.NumberFormat.Field.EXPONENT_SIGN;
431        } else if (icuAttribute == NumberFormat.Field.EXPONENT_SYMBOL) {
432            jdkAttribute = java.text.NumberFormat.Field.EXPONENT_SYMBOL;
433        } else if (icuAttribute == NumberFormat.Field.FRACTION) {
434            jdkAttribute = java.text.NumberFormat.Field.FRACTION;
435        } else if (icuAttribute == NumberFormat.Field.GROUPING_SEPARATOR) {
436            jdkAttribute = java.text.NumberFormat.Field.GROUPING_SEPARATOR;
437        } else if (icuAttribute == NumberFormat.Field.INTEGER) {
438            jdkAttribute = java.text.NumberFormat.Field.INTEGER;
439        } else if (icuAttribute == NumberFormat.Field.PERCENT) {
440            jdkAttribute = java.text.NumberFormat.Field.PERCENT;
441        } else if (icuAttribute == NumberFormat.Field.PERMILLE) {
442            jdkAttribute = java.text.NumberFormat.Field.PERMILLE;
443        } else if (icuAttribute == NumberFormat.Field.SIGN) {
444            jdkAttribute = java.text.NumberFormat.Field.SIGN;
445        }
446
447        return jdkAttribute;
448    }
449
450}
451