]> granicus.if.org Git - icu/commitdiff
ICU-10344 add new field & factory method for currency CASH/STANDARD Usage
authorTom Zhang <tomzhang@svn.icu-project.org>
Tue, 10 Jun 2014 18:48:49 +0000 (18:48 +0000)
committerTom Zhang <tomzhang@svn.icu-project.org>
Tue, 10 Jun 2014 18:48:49 +0000 (18:48 +0000)
X-SVN-Rev: 35853

icu4j/main/classes/core/src/com/ibm/icu/text/CurrencyMetaInfo.java
icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java
icu4j/main/classes/core/src/com/ibm/icu/text/NumberFormat.java
icu4j/main/classes/core/src/com/ibm/icu/util/Currency.java
icu4j/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyMetaInfo.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java

index bbb3b48384b808a2bcdd04dcb2998ad937c4619d..6340f8302991f5d2716fe85a589c01afef3d93f7 100644 (file)
@@ -12,6 +12,7 @@ import java.util.Date;
 import java.util.List;
 
 import com.ibm.icu.impl.Grego;
+import com.ibm.icu.util.Currency.CurrencyUsage;
 
 /**
  * Provides information about currencies that is not specific to a locale.
@@ -532,11 +533,24 @@ public class CurrencyMetaInfo {
 
     /**
      * Returns the CurrencyDigits for the currency code.
+     * This is equivalent to currencyDigits(isoCode, CurrencyUsage.STANDARD);
      * @param isoCode the currency code
      * @return the CurrencyDigits
      * @stable ICU 4.4
      */
     public CurrencyDigits currencyDigits(String isoCode) {
+        return currencyDigits(isoCode, CurrencyUsage.STANDARD);
+    }
+
+    /**
+     * Returns the CurrencyDigits for the currency code with Context Usage.
+     * @param isoCode the currency code
+     * @param currencyUsage the currency usage
+     * @return the CurrencyDigits
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release. 
+     */
+    public CurrencyDigits currencyDigits(String isoCode, CurrencyUsage currencyUsage) {
         return defaultDigits;
     }
 
index fc1ff98cc1370ccab2c6ef08c69a56149c55cab6..7abba4e40aeceb5c717429f0c6692c65f3f704e6 100644 (file)
@@ -29,6 +29,7 @@ import com.ibm.icu.math.BigDecimal;
 import com.ibm.icu.math.MathContext;
 import com.ibm.icu.text.PluralRules.FixedDecimal;
 import com.ibm.icu.util.Currency;
+import com.ibm.icu.util.Currency.CurrencyUsage;
 import com.ibm.icu.util.CurrencyAmount;
 import com.ibm.icu.util.ULocale;
 import com.ibm.icu.util.ULocale.Category;
@@ -2298,7 +2299,7 @@ public class DecimalFormat extends NumberFormat {
                 0xFB29, 0xFB29,
                 0xFE62, 0xFE62,
                 0xFF0B, 0xFF0B).freeze();
-
+    
     // equivalent grouping and decimal support
     static final boolean skipExtendedSeparatorParsing = ICUConfig.get(
         "com.ibm.icu.text.DecimalFormat.SkipExtendedSeparatorParsing", "false")
@@ -3832,6 +3833,7 @@ public class DecimalFormat extends NumberFormat {
                 other.currencyPluralInfo = (CurrencyPluralInfo) currencyPluralInfo.clone();
             }
             other.attributes = new ArrayList<FieldPosition>(); // #9240
+            other.currencyUsage = currencyUsage;
 
             // TODO: We need to figure out whether we share a single copy of DigitList by
             // multiple cloned copies.  format/subformat are designed to use a single
@@ -3873,7 +3875,8 @@ public class DecimalFormat extends NumberFormat {
                 && (!useSignificantDigits || minSignificantDigits == other.minSignificantDigits
                         && maxSignificantDigits == other.maxSignificantDigits)
                 && symbols.equals(other.symbols)
-                && Utility.objectEquals(currencyPluralInfo, other.currencyPluralInfo);
+                && Utility.objectEquals(currencyPluralInfo, other.currencyPluralInfo)
+                && currencyUsage.equals(other.currencyUsage);
     }
 
     // method to unquote the strings and compare
@@ -5030,8 +5033,8 @@ public class DecimalFormat extends NumberFormat {
             // by the currency
             Currency theCurrency = getCurrency();
             if (theCurrency != null) {
-                setRoundingIncrement(theCurrency.getRoundingIncrement());
-                int d = theCurrency.getDefaultFractionDigits();
+                setRoundingIncrement(theCurrency.getRoundingIncrement(currencyUsage));
+                int d = theCurrency.getDefaultFractionDigits(currencyUsage);
                 setMinimumFractionDigits(d);
                 _setMaximumFractionDigits(d);
             }
@@ -5194,8 +5197,8 @@ public class DecimalFormat extends NumberFormat {
 
         if (currencySignCount != CURRENCY_SIGN_COUNT_ZERO) {
             if (theCurrency != null) {
-                setRoundingIncrement(theCurrency.getRoundingIncrement());
-                int d = theCurrency.getDefaultFractionDigits();
+                setRoundingIncrement(theCurrency.getRoundingIncrement(currencyUsage));
+                int d = theCurrency.getDefaultFractionDigits(currencyUsage);
                 setMinimumFractionDigits(d);
                 setMaximumFractionDigits(d);
             }
@@ -5206,7 +5209,40 @@ public class DecimalFormat extends NumberFormat {
             }
         }
     }
+    
+    /**
+     * Sets the <tt>Currency Usage</tt> object used to display currency.
+     * This takes effect immediately, if this format is a
+     * currency format.  
+     * @param newUsage new currency context object to use.  
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release. 
+     */
+    public void setCurrencyUsage(CurrencyUsage newUsage) {
+        if (newUsage == null) {
+            throw new NullPointerException("return value is null at method AAA");
+        }
+        currencyUsage = newUsage;
+        Currency theCurrency = this.getCurrency();
+
+        // We set rounding/digit based on currency context
+        if (theCurrency != null) {
+            setRoundingIncrement(theCurrency.getRoundingIncrement(currencyUsage));
+            int d = theCurrency.getDefaultFractionDigits(currencyUsage);
+            setMinimumFractionDigits(d);
+            _setMaximumFractionDigits(d);
+        }
+    }
 
+    /**
+     * Returns the <tt>Currency Usage</tt> object used to display currency
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release. 
+     */
+    public CurrencyUsage getCurrencyUsage() {
+        return currencyUsage;
+    }
+    
     /**
      * Returns the currency in effect for this formatter. Subclasses should override this
      * method as needed. Unlike getCurrency(), this method should never return null.
@@ -5362,6 +5398,9 @@ public class DecimalFormat extends NumberFormat {
             // the DecimalFormatSymbols object.
             setCurrencyForSymbols();
         }
+        if (serialVersionOnStream < 4) {
+            currencyUsage = CurrencyUsage.STANDARD;
+        }
         serialVersionOnStream = currentSerialVersion;
         digitList = new DigitList();
 
@@ -5668,9 +5707,16 @@ public class DecimalFormat extends NumberFormat {
      */
     private boolean parseBigDecimal = false;
 
+    /**
+     * The currency usage for the NumberFormat(standard or cash usage).
+     * It is used as STANDARD by default
+     * @since ICU 54
+     */
+    private CurrencyUsage currencyUsage = CurrencyUsage.STANDARD;
+    
     // ----------------------------------------------------------------------
 
-    static final int currentSerialVersion = 3;
+    static final int currentSerialVersion = 4;
 
     /**
      * The internal serial version which says which version was written Possible values
@@ -5688,6 +5734,8 @@ public class DecimalFormat extends NumberFormat {
      *
      * <li><b>3</b>: ICU 2.2. Adds currency object.
      *
+     * <li><b>4</b>: ICU 54. Adds currency usage(standard vs cash)
+     * 
      * </ul>
      *
      * @serial
index 088d07f308d056a69d3ff23e0a270508e5a4126d..41133537f162afbd6dd294317694d93b53d7c9ae 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Set;
 
 import com.ibm.icu.impl.ICUResourceBundle;
 import com.ibm.icu.util.Currency;
+import com.ibm.icu.util.Currency.CurrencyUsage;
 import com.ibm.icu.util.CurrencyAmount;
 import com.ibm.icu.util.ULocale;
 import com.ibm.icu.util.ULocale.Category;
@@ -215,6 +216,14 @@ public abstract class NumberFormat extends UFormat {
      * @provisional This API might change or be removed in a future release.
      */
     public static final int ACCOUNTINGCURRENCYSTYLE = 7;
+    /**
+     * {@icu} Constant to specify currency cash style of format which uses currency
+     * ISO code to represent currency, for example: "NT$3" instead of "NT$3.23".
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release. 
+     */
+    public static final int CASHCURRENCYSTYLE = 8;
+    /**
 
     /**
      * Field constant used to construct a FieldPosition object. Signifies that
@@ -231,7 +240,7 @@ public abstract class NumberFormat extends UFormat {
      * @stable ICU 2.0
      */
     public static final int FRACTION_FIELD = 1;
-
+    
     /**
      * Formats a number and appends the resulting text to the given string buffer.
      * {@icunote} recognizes <code>BigInteger</code>
@@ -1240,7 +1249,7 @@ public abstract class NumberFormat extends UFormat {
     public Currency getCurrency() {
         return currency;
     }
-
+    
     /**
      * Returns the currency in effect for this formatter.  Subclasses
      * should override this method as needed.  Unlike getCurrency(),
@@ -1302,7 +1311,7 @@ public abstract class NumberFormat extends UFormat {
      * @stable ICU 4.2
      */
     public static NumberFormat getInstance(ULocale desiredLocale, int choice) {
-        if (choice < NUMBERSTYLE || choice > ACCOUNTINGCURRENCYSTYLE) {
+        if (choice < NUMBERSTYLE || choice > CASHCURRENCYSTYLE) {
             throw new IllegalArgumentException(
                 "choice should be from NUMBERSTYLE to PLURALCURRENCYSTYLE");
         }
@@ -1331,7 +1340,8 @@ public abstract class NumberFormat extends UFormat {
         // This style wont work for currency plural format.
         // For currency plural format, the pattern is get from
         // the locale (from CurrencyUnitPatterns) without override.
-        if(choice == CURRENCYSTYLE || choice == ISOCURRENCYSTYLE || choice == ACCOUNTINGCURRENCYSTYLE){
+        if (choice == CURRENCYSTYLE || choice == ISOCURRENCYSTYLE || choice == ACCOUNTINGCURRENCYSTYLE
+                || choice == CASHCURRENCYSTYLE) {
             String temp = symbols.getCurrencyPattern();
             if(temp!=null){
                 pattern = temp;
@@ -1394,6 +1404,10 @@ public abstract class NumberFormat extends UFormat {
                 f.setDecimalSeparatorAlwaysShown(false);
                 f.setParseIntegerOnly(true);
             }
+            
+            if (choice == CASHCURRENCYSTYLE) {
+                f.setCurrencyUsage(CurrencyUsage.CASH);
+            }
             format = f;
        }
         // TODO: the actual locale of the *pattern* may differ from that
@@ -1477,6 +1491,7 @@ public abstract class NumberFormat extends UFormat {
             patternKey = "decimalFormat";
             break;
         case CURRENCYSTYLE:
+        case CASHCURRENCYSTYLE:
         case ISOCURRENCYSTYLE:
         case PLURALCURRENCYSTYLE:
             patternKey = "currencyFormat";
index 2e405120bb600b792cff69c2c248407418861729..2d66bcae9a17c3856651c799c94e524493092758 100644 (file)
@@ -89,6 +89,29 @@ public class Currency extends MeasureUnit {
             .add("\u20a8", "\u20b9")
             .add("\u00a3", "\u20a4");
 
+    /**
+     * Currency Usage used for Decimal Format
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release. 
+     */
+    public enum CurrencyUsage{
+        /**
+         * a setting to specify currency usage which determines currency digit and rounding
+         * for standard usage, for example: "50.00 NT$"
+         * @draft ICU 54
+         * @provisional This API might change or be removed in a future release.
+         */
+        STANDARD,
+        
+        /**
+         * a setting to specify currency usage which determines currency digit and rounding
+         * for cash usage, for example: "50 NT$"
+         * @draft ICU 54
+         * @provisional This API might change or be removed in a future release.
+         */
+        CASH
+    }
+    
     // begin registry stuff
 
     // shim for service code
@@ -729,25 +752,52 @@ public class Currency extends MeasureUnit {
     /**
      * Returns the number of the number of fraction digits that should
      * be displayed for this currency.
+     * This is equivalent to getDefaultFractionDigits(CurrencyUsage.STANDARD);
      * @return a non-negative number of fraction digits to be
      * displayed
      * @stable ICU 2.2
      */
     public int getDefaultFractionDigits() {
+        return getDefaultFractionDigits(CurrencyUsage.STANDARD);
+    }
+
+    /**
+     * Returns the number of the number of fraction digits that should
+     * be displayed for this currency with Usage.
+     * @param Usage the usage of currency(Standard or Cash)
+     * @return a non-negative number of fraction digits to be
+     * displayed
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release. 
+     */
+    public int getDefaultFractionDigits(CurrencyUsage Usage) {
         CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
-        CurrencyDigits digits = info.currencyDigits(subType);
+        CurrencyDigits digits = info.currencyDigits(subType, Usage);
         return digits.fractionDigits;
     }
 
     /**
      * Returns the rounding increment for this currency, or 0.0 if no
      * rounding is done by this currency.
+     * This is equivalent to getRoundingIncrement(CurrencyUsage.STANDARD);
      * @return the non-negative rounding increment, or 0.0 if none
      * @stable ICU 2.2
      */
     public double getRoundingIncrement() {
+        return getRoundingIncrement(CurrencyUsage.STANDARD);
+    }
+
+    /**
+     * Returns the rounding increment for this currency, or 0.0 if no
+     * rounding is done by this currency with the Usage.
+     * @param Usage the usage of currency(Standard or Cash)
+     * @return the non-negative rounding increment, or 0.0 if none
+     * @draft ICU 54
+     * @provisional This API might change or be removed in a future release. 
+     */
+    public double getRoundingIncrement(CurrencyUsage Usage) {
         CurrencyMetaInfo info = CurrencyMetaInfo.getInstance();
-        CurrencyDigits digits = info.currencyDigits(subType);
+        CurrencyDigits digits = info.currencyDigits(subType, Usage);
 
         int data1 = digits.roundingIncrement;
 
@@ -764,7 +814,7 @@ public class Currency extends MeasureUnit {
             return 0.0;
         }
 
-        // Return data[1] / 10^(data[0]).  The only actual rounding data,
+        // Return data[1] / 10^(data[0]). The only actual rounding data,
         // as of this writing, is CHF { 2, 25 }.
         return (double) data1 / POW10[data0];
     }
index 82245ba61f9ccd0b85b1c9f46cfb2e9b6219dc62..b2329bd221e75bb3d5cdca4cbf2b6a25bb7ab234 100644 (file)
@@ -13,6 +13,7 @@ import java.util.List;
 import java.util.Set;
 
 import com.ibm.icu.text.CurrencyMetaInfo;
+import com.ibm.icu.util.Currency.CurrencyUsage;
 
 /**
  * ICU's currency meta info data.
@@ -46,14 +47,25 @@ public class ICUCurrencyMetaInfo extends CurrencyMetaInfo {
 
     @Override
     public CurrencyDigits currencyDigits(String isoCode) {
+        return currencyDigits(isoCode, CurrencyUsage.STANDARD);
+    }
+
+    @Override
+    public CurrencyDigits currencyDigits(String isoCode, CurrencyUsage currencyPurpose) {
         ICUResourceBundle b = digitInfo.findWithFallback(isoCode);
         if (b == null) {
             b = digitInfo.findWithFallback("DEFAULT");
         }
         int[] data = b.getIntVector();
-        return new CurrencyDigits(data[0], data[1]);
+        if (currencyPurpose == CurrencyUsage.CASH) {
+            return new CurrencyDigits(data[2], data[3]);
+        } else if (currencyPurpose == CurrencyUsage.STANDARD) {
+            return new CurrencyDigits(data[0], data[1]);
+        } else {
+            return new CurrencyDigits(data[0], data[1]);
+        }
     }
-
+    
     private <T> List<T> collect(Collector<T> collector, CurrencyFilter filter) {
         // We rely on the fact that the data lists the regions in order, and the
         // priorities in order within region.  This means we don't need
index 4f9bccc2cac00126880d2efa506f2c470a4dcd84..df67d0499b617520d7988f10a370545111f3b24a 100644 (file)
@@ -2735,7 +2735,7 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
      */
     public void TestGetInstance() {
         // Tests "public final static NumberFormat getInstance(int style)"
-        int maxStyle = NumberFormat.ACCOUNTINGCURRENCYSTYLE;
+        int maxStyle = NumberFormat.CASHCURRENCYSTYLE;
 
         int[] invalid_cases = { NumberFormat.NUMBERSTYLE - 1, NumberFormat.NUMBERSTYLE - 2,
                 maxStyle + 1, maxStyle + 2 };
@@ -3608,4 +3608,78 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
             expect(acfmt, num, fmt, rt);
         }
     }
+    
+    public void TestCurrencyUsage() {
+        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
+        // compare the Currency and Currency Cash Digits
+        for (int i = 0; i < 2; i++) {
+            String original_expected = "NT$123.57";
+            DecimalFormat custom = null;
+            if (i == 0) {
+                custom = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=TWD"),
+                        DecimalFormat.CURRENCYSTYLE);
+
+                String original = custom.format(123.567);
+                assertEquals("Test Currency Context", original_expected, original);
+
+                // test the getter
+                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(),
+                        Currency.CurrencyUsage.STANDARD);
+                custom.setCurrencyUsage(Currency.CurrencyUsage.CASH);
+                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(), Currency.CurrencyUsage.CASH);
+            } else {
+                custom = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=TWD"),
+                        DecimalFormat.CASHCURRENCYSTYLE);
+
+                // test the getter
+                assertEquals("Test Currency Context Purpose", custom.getCurrencyUsage(), Currency.CurrencyUsage.CASH);
+            }
+
+            String cash_currency = custom.format(123.567);
+            String cash_currency_expected = "NT$124";
+            assertEquals("Test Currency Context", cash_currency_expected, cash_currency);
+        }
+
+        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
+        // compare the Currency and Currency Cash Rounding
+        for (int i = 0; i < 2; i++) {
+            String original_rounding_expected = "CA$123.57";
+            DecimalFormat fmt = null;
+            if (i == 0) {
+                fmt = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=CAD"),
+                        DecimalFormat.CURRENCYSTYLE);
+
+                String original_rounding = fmt.format(123.566);
+                assertEquals("Test Currency Context", original_rounding_expected, original_rounding);
+
+                fmt.setCurrencyUsage(Currency.CurrencyUsage.CASH);
+            } else {
+                fmt = (DecimalFormat) DecimalFormat.getInstance(new ULocale("en_US@currency=CAD"),
+                        DecimalFormat.CASHCURRENCYSTYLE);
+            }
+
+            String cash_rounding_currency = fmt.format(123.567);
+            String cash__rounding_currency_expected = "CA$123.55";
+            assertEquals("Test Currency Context", cash__rounding_currency_expected, cash_rounding_currency);
+        }
+
+        // the 1st one is checking setter/getter, while the 2nd one checks for getInstance
+        // Test the currency change
+        for (int i = 0; i < 2; i++) {
+            DecimalFormat fmt2 = null;
+            if (i == 1) {
+                fmt2 = (DecimalFormat) NumberFormat.getInstance(new ULocale("en_US@currency=JPY"),
+                        NumberFormat.CURRENCYSTYLE);
+                fmt2.setCurrencyUsage(Currency.CurrencyUsage.CASH);
+            } else {
+                fmt2 = (DecimalFormat) NumberFormat.getInstance(new ULocale("en_US@currency=JPY"),
+                        NumberFormat.CASHCURRENCYSTYLE);
+            }
+
+            fmt2.setCurrency(Currency.getInstance("TWD"));
+            String TWD_changed = fmt2.format(123.567);
+            String TWD_changed_expected = "NT$124";
+            assertEquals("Test Currency Context", TWD_changed_expected, TWD_changed);
+        }
+    }
 }