Revision: 7294 Author: [email protected] Date: Thu Dec 10 15:31:32 2009 Log: Abstract out a CurrencyData interface and make it available to NumberFormat, in addition to just supplying a currency code. This allows applications to use exactly the same currency data as used on the server for consistent formatting. Also makes CurrencyList a public API as it is the primary way to get CurrencyData instances.
Patch by: jat Review by: andreasst http://code.google.com/p/google-web-toolkit/source/detail?r=7294 Added: /trunk/user/src/com/google/gwt/i18n/client/CurrencyData.java /trunk/user/src/com/google/gwt/i18n/client/CurrencyList.java /trunk/user/src/com/google/gwt/i18n/client/DefaultCurrencyData.java /trunk/user/src/com/google/gwt/i18n/client/impl/CurrencyDataImpl.java /trunk/user/test/com/google/gwt/i18n/client/CurrencyTest.java Deleted: /trunk/user/src/com/google/gwt/i18n/client/impl/CurrencyData.java /trunk/user/src/com/google/gwt/i18n/client/impl/CurrencyList.java /trunk/user/test/com/google/gwt/i18n/client/impl/CurrencyTest.java Modified: /trunk/user/src/com/google/gwt/i18n/I18N.gwt.xml /trunk/user/src/com/google/gwt/i18n/client/NumberFormat.java /trunk/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java /trunk/user/test/com/google/gwt/i18n/I18NSuite.java /trunk/user/test/com/google/gwt/i18n/client/I18N_es_AR_RuntimeTest.java /trunk/user/test/com/google/gwt/i18n/client/I18N_es_MX_RuntimeTest.java /trunk/user/test/com/google/gwt/i18n/client/I18N_nb_Test.java ======================================= --- /dev/null +++ /trunk/user/src/com/google/gwt/i18n/client/CurrencyData.java Thu Dec 10 15:31:32 2009 @@ -0,0 +1,78 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.i18n.client; + +/** + * Information about a currency. + */ +public interface CurrencyData { + + /** + * @return the ISO4217 code for this currency + */ + String getCurrencyCode(); + + /** + * @return the default symbol to use for this currency + */ + String getCurrencySymbol(); + + /** + * @return the default number of decimal positions for this currency + */ + int getDefaultFractionDigits(); + + /** + * @return the default symbol to use for this currency, intended to be + * recognizable in most locales. If such a symbol is not available, it is + * acceptable to return the same value as {...@link #getCurrencySymbol()}. + */ + String getPortableCurrencySymbol(); + + /** + * @return true if this currency is deprecated and should not be returned by + * default in currency lists. + */ + boolean isDeprecated(); + + /** + * @return true if there should always be a space between the currency symbol + * and the number, false if there should be no space. Ignored unless + * {...@link #isSpacingFixed()} returns true. + */ + boolean isSpaceForced(); + + /** + * @return true if the spacing between the currency symbol and the number is + * fixed regardless of locale defaults. In this case, spacing will be + * determined by {...@link #isSpaceForced()}. + */ + boolean isSpacingFixed(); + + /** + * @return true if the position of the currency symbol relative to the number + * is fixed regardless of locale defaults. In this case, the position will be + * determined by {...@link #isSymbolPrefix()}. + */ + boolean isSymbolPositionFixed(); + + /** + * @return true if the currency symbol should go before the number, false if + * it should go after the number. This is ignored unless + * {...@link #isSymbolPositionFixed()} is true. + */ + boolean isSymbolPrefix(); +} ======================================= --- /dev/null +++ /trunk/user/src/com/google/gwt/i18n/client/CurrencyList.java Thu Dec 10 15:31:32 2009 @@ -0,0 +1,247 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.gwt.i18n.client; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * Generated class containing all the CurrencyImpl instances. This is just + * the fallback in case the I18N module is not included. + */ +public class CurrencyList implements Iterable<CurrencyData> { + + /** + * Inner class to avoid CurrencyList.clinit calls and allow this to be + * completely removed from the generated code if instance isn't referenced + * (such as when all you call is CurrencyList.get().getDefault() ). + */ + private static class CurrencyListInstance { + private static CurrencyList instance = GWT.create(CurrencyList.class); + } + + /** + * Return the singleton instance of CurrencyList. + */ + public static CurrencyList get() { + return CurrencyListInstance.instance; + } + + // This helper method exists because we can't call JSO instance methods + // directly from JSNI. + protected static boolean isDeprecated(CurrencyData currencyData) { + return currencyData.isDeprecated(); + } + + /** + * JS Object which contains a map of currency codes to CurrencyDataImpl + * objects. Each currency code is assumed to be a valid JS object key. + */ + protected JavaScriptObject dataMap; + + /** + * JS Object which contains a map of currency codes to localized currency + * names. This is kept separate from {...@link #dataMap} above so that the names + * can be completely removed by the compiler if they are not used. Each + * currency code is assumed to be a valid JS object key. + */ + protected JavaScriptObject namesMap; + + /** + * Return the default currency data for this locale. + * + * Generated implementations override this method. + */ + public native CurrencyData getDefault() /*-{ + return [ "USD", "$", 2, "US$" ]; + }-*/; + + /** + * Returns an iterator for the list of currencies. + * + * Deprecated currencies will not be included. + */ + public final Iterator<CurrencyData> iterator() { + return iterator(false); + } + + /** + * Returns an iterator for the list of currencies, optionally including + * deprecated ones. + * + * @param includeDeprecated true if deprecated currencies should be included + */ + public final Iterator<CurrencyData> iterator(boolean includeDeprecated) { + ensureCurrencyMap(); + ArrayList<String> keys = new ArrayList<String>(); + loadCurrencyKeys(keys, includeDeprecated); + final Iterator<String> it = keys.iterator(); + return new Iterator<CurrencyData>() { + + public boolean hasNext() { + return it.hasNext(); + } + + public CurrencyData next() { + return getEntry(it.next()); + } + + public void remove() { + throw new UnsupportedOperationException("Remove not supported"); + } + }; + } + + /** + * Lookup a currency based on the ISO4217 currency code. + * + * @param currencyCode ISO4217 currency code + * @return currency data, or null if code not found + */ + public final CurrencyData lookup(String currencyCode) { + ensureCurrencyMap(); + return getEntry(currencyCode); + } + + /** + * Lookup a currency name based on the ISO4217 currency code. + * + * @param currencyCode ISO4217 currency code + * @return name of the currency, or null if code not found + */ + public final String lookupName(String currencyCode) { + ensureNamesMap(); + return getNamesEntry(currencyCode); + } + + /** + * Ensure that the map of currency data has been initialized. + */ + protected final void ensureCurrencyMap() { + if (dataMap == null) { + loadCurrencyMap(); + } + } + + /** + * Ensure that the map of currency data has been initialized. + */ + protected final void ensureNamesMap() { + if (namesMap == null) { + loadNamesMap(); + } + } + + /** + * Directly reference an entry in the currency map JSO. + * + * @param code ISO4217 currency code + * @return currency data + */ + protected final native CurrencyData getEntry(String code) /*-{ + return [email protected]::dataMap[code]; + }-*/; + + /** + * Directly reference an entry in the currency names map JSO. + * + * @param code ISO4217 currency code + * @return currency name, or the currency code if not known + */ + protected final native String getNamesEntry(String code) /*-{ + return [email protected]::namesMap[code] | | code; + }-*/; + + /** + * Loads the currency map from a JS object literal. + * + * Generated implementations override this method. + */ + protected native void loadCurrencyMap() /*-{ + [email protected]::dataMap = { + "USD": [ "USD", "$", 2 ], + "EUR": [ "EUR", "€", 2 ], + "GBP": [ "GBP", "UK£", 2 ], + "JPY": [ "JPY", "¥", 0 ], + }; + }-*/; + + /** + * Loads the currency names map from a JS object literal. + * + * Generated implementations override this method. + */ + protected native void loadNamesMap() /*-{ + [email protected]::namesMap = { + "USD": "US Dollar", + "EUR": "Euro", + "GBP": "British Pound Sterling", + "JPY": "Japanese Yen", + }; + }-*/; + + /** + * Add all entries in {...@code override} to the currency data map, replacing + * any existing entries. This is used by subclasses that need to slightly + * alter the data used by the parent locale. + * + * @param override JS object with currency code -> CurrencyData pairs + */ + protected final native void overrideCurrencyMap(JavaScriptObject override) /*-{ + var map = [email protected]::dataMap; + for (var key in override) { + if (override.hasOwnProperty(key)) { + map[key] = override[key]; + } + } + }-*/; + + /** + * Add all entries in {...@code override} to the currency name map, replacing + * any existing entries. This is used by subclasses that need to slightly + * alter the data used by the parent locale. + * + * @param override JS object with currency code -> name pairs + */ + protected final native void overrideNamesMap(JavaScriptObject override) /*-{ + var map = [email protected]::namesMap; + for (var key in override) { + if (override.hasOwnProperty(key)) { + map[key] = override[key]; + } + } + }-*/; + + /** + * Add currency codes contained in the map to an ArrayList. + */ + private native void loadCurrencyKeys(ArrayList<String> keys, + boolean includeDeprecated) /*-{ + var map = [email protected]::dataMap; + for (var key in map) { + if (map.hasOwnProperty(key)) { + if (includeDeprecated + | | [email protected]::isDeprecated(Lcom/google/gwt/i18n/client/CurrencyData;)(map[key])) { + [email protected]::add(Ljava/lang/Object;)(key); + } + } + } + }-*/; +} ======================================= --- /dev/null +++ /trunk/user/src/com/google/gwt/i18n/client/DefaultCurrencyData.java Thu Dec 10 15:31:32 2009 @@ -0,0 +1,92 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.i18n.client; + +/** + * A default {...@link CurrencyData} implementation, so new methods can be added + * to the interface without breaking implementors if a reasonable default is + * available. + */ +public class DefaultCurrencyData implements CurrencyData { + + private final String currencyCode; + private final String currencySymbol; + private final int fractionDigits; + + /** + * Create a default default {...@link CurrencyData} instance, returning {...@code + * false} for all {...@code isFoo} methods, having 2 fractional digits by + * default, and using the standard symbol for the portable symbol. + * + * @param currencyCode ISO 4217 currency code + * @param currencySymbol symbol to use for this currency + */ + public DefaultCurrencyData(String currencyCode, String currencySymbol) { + this(currencyCode, currencySymbol, 2); + } + + /** + * Create a default default {...@link CurrencyData} instance, returning {...@code + * false} for all {...@code isFoo} methods and using the standard symbol for the + * portable symbol. + * + * @param currencyCode ISO 4217 currency code + * @param currencySymbol symbol to use for this currency + * @param fractionDigits default number of fraction digits + */ + public DefaultCurrencyData(String currencyCode, String currencySymbol, + int fractionDigits) { + this.currencyCode = currencyCode; + this.currencySymbol = currencySymbol; + this.fractionDigits = fractionDigits; + } + + public String getCurrencyCode() { + return currencyCode; + } + + public String getCurrencySymbol() { + return currencySymbol; + } + + public int getDefaultFractionDigits() { + return fractionDigits; + } + + public String getPortableCurrencySymbol() { + return getCurrencySymbol(); + } + + public boolean isDeprecated() { + return false; + } + + public boolean isSpaceForced() { + return false; + } + + public boolean isSpacingFixed() { + return false; + } + + public boolean isSymbolPositionFixed() { + return false; + } + + public boolean isSymbolPrefix() { + return false; + } +} ======================================= --- /dev/null +++ /trunk/user/src/com/google/gwt/i18n/client/impl/CurrencyDataImpl.java Thu Dec 10 15:31:32 2009 @@ -0,0 +1,91 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.i18n.client.impl; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.i18n.client.CurrencyData; + +/** + * JSO Overlay type that wraps currency data. + * + * The JSO is an array with three elements: + * 0 - ISO4217 currency code + * 1 - currency symbol to use for this locale + * 2 - flags and # of decimal digits: + * d0-d2: # of decimal digits for this currency, 0-7 + * d3: currency symbol goes after number, 0=before + * d4: currency symbol position is based on d3 + * d5: space is forced, 0=no space present + * d6: spacing around currency symbol is based on d5 + * 3 - portable currency symbol (optional) + */ +public final class CurrencyDataImpl extends JavaScriptObject + implements CurrencyData { + + /** + * Public so CurrencyListGenerator can get to them. As usual with an impl + * package, external code should not rely on these values. + */ + public static final int POS_FIXED_FLAG = 16; + public static final int POS_SUFFIX_FLAG = 8; + public static final int PRECISION_MASK = 7; + public static final int SPACE_FORCED_FLAG = 32; + public static final int SPACING_FIXED_FLAG = 64; + public static final int DEPRECATED_FLAG = 128; + + protected CurrencyDataImpl() { + } + + public native String getCurrencyCode() /*-{ + return this[0]; + }-*/; + + public native String getCurrencySymbol() /*-{ + return this[1]; + }-*/; + + public int getDefaultFractionDigits() { + return getFlagsAndPrecision() & PRECISION_MASK; + } + + public native String getPortableCurrencySymbol() /*-{ + return this[3] || this[1]; + }-*/; + + public boolean isDeprecated() { + return (getFlagsAndPrecision() & DEPRECATED_FLAG) != 0; + } + + public boolean isSpaceForced() { + return (getFlagsAndPrecision() & SPACE_FORCED_FLAG) != 0; + } + + public boolean isSpacingFixed() { + return (getFlagsAndPrecision() & SPACING_FIXED_FLAG) != 0; + } + + public boolean isSymbolPositionFixed() { + return (getFlagsAndPrecision() & POS_FIXED_FLAG) != 0; + } + + public boolean isSymbolPrefix() { + return (getFlagsAndPrecision() & POS_SUFFIX_FLAG) != 0; + } + + private native int getFlagsAndPrecision() /*-{ + return this[2]; + }-*/; +} ======================================= --- /dev/null +++ /trunk/user/test/com/google/gwt/i18n/client/CurrencyTest.java Thu Dec 10 15:31:32 2009 @@ -0,0 +1,76 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.i18n.client; + +import com.google.gwt.i18n.client.CurrencyData; +import com.google.gwt.i18n.client.CurrencyList; +import com.google.gwt.junit.client.GWTTestCase; + +import java.util.Iterator; + +/** + * Tests for CurrencyList and CurrencyData (in addition to locale-specific + * tests in I18N_*Test). + */ +public class CurrencyTest extends GWTTestCase { + + @Override + public String getModuleName() { + return "com.google.gwt.i18n.I18NTest_es_MX"; + } + + public void testCustom() { + CurrencyData currencyData = new DefaultCurrencyData("CAD", "/", 3); + NumberFormat format = NumberFormat.getCurrencyFormat(currencyData); + String formatted = format.format(1.23); + assertEquals("/\u00A01.230", formatted); + format = NumberFormat.getFormat("#0.0000\u00A4", currencyData); + formatted = format.format(1234.23); + assertEquals("1234.2300/", formatted); + } + + public void testIterator() { + CurrencyList list = CurrencyList.get(); + boolean found = false; + for (CurrencyData data : list) { + String code = data.getCurrencyCode(); + if ("USD".equals(code)) { + found = true; + } else if ("ITL".equals(code)) { + fail("ITL in undeprecated list"); + } + } + assertTrue("USD not found in currency list", found); + Iterator<CurrencyData> it = list.iterator(true); + found = false; + while (it.hasNext()) { + CurrencyData data = it.next(); + String code = data.getCurrencyCode(); + if ("ITL".equals(code)) { + found = true; + } + } + assertTrue("ITL not found in deprecated currency list", found); + } + + public void testLookup() { + CurrencyList list = CurrencyList.get(); + assertNotNull("USD lookup failed", list.lookup("USD")); + assertNotNull("ITL lookup failed", list.lookup("ITL")); + assertEquals("dólar estadounidense", list.lookupName("USD")); + assertEquals("lira italiana", list.lookupName("ITL")); + } +} ======================================= --- /trunk/user/src/com/google/gwt/i18n/client/impl/CurrencyData.java Tue Jun 23 20:13:51 2009 +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.gwt.i18n.client.impl; - -import com.google.gwt.core.client.JavaScriptObject; - -/** - * JSO Overlay type that wraps currency data. - * - * The JSO is an array with three elements: - * 0 - ISO4217 currency code - * 1 - currency symbol to use for this locale - * 2 - flags and # of decimal digits: - * d0-d2: # of decimal digits for this currency, 0-7 - * d3: currency symbol goes after number, 0=before - * d4: currency symbol position is based on d3 - * d5: space is forced, 0=no space present - * d6: spacing around currency symbol is based on d5 - * 3 - portable currency symbol (optional) - */ -public final class CurrencyData extends JavaScriptObject { - - /** - * Public so CurrencyListGenerator can get to them. As usual with an impl - * package, external code should not rely on these values. - */ - public static final int POS_FIXED_FLAG = 16; - public static final int POS_SUFFIX_FLAG = 8; - public static final int PRECISION_MASK = 7; - public static final int SPACE_FORCED_FLAG = 32; - public static final int SPACING_FIXED_FLAG = 64; - public static final int DEPRECATED_FLAG = 128; - - protected CurrencyData() { - } - - /** - * @return the ISO4217 code for this currency - */ - public native String getCurrencyCode() /*-{ - return this[0]; - }-*/; - - /** - * @return the default symbol to use for this currency - */ - public native String getCurrencySymbol() /*-{ - return this[1]; - }-*/; - - /** - * @return the default number of decimal positions for this currency - */ - public int getDefaultFractionDigits() { - return getFlagsAndPrecision() & PRECISION_MASK; - } - - /** - * @return the default symbol to use for this currency - */ - public native String getPortableCurrencySymbol() /*-{ - return this[3] || this[1]; - }-*/; - - public boolean isDeprecated() { - return (getFlagsAndPrecision() & DEPRECATED_FLAG) != 0; - } - - public boolean isSpaceForced() { - return (getFlagsAndPrecision() & SPACE_FORCED_FLAG) != 0; - } - - public boolean isSpacingFixed() { - return (getFlagsAndPrecision() & SPACING_FIXED_FLAG) != 0; - } - - public boolean isSymbolPositionFixed() { - return (getFlagsAndPrecision() & POS_FIXED_FLAG) != 0; - } - - public boolean isSymbolPrefix() { - return (getFlagsAndPrecision() & POS_SUFFIX_FLAG) != 0; - } - - private native int getFlagsAndPrecision() /*-{ - return this[2]; - }-*/; -} ======================================= --- /trunk/user/src/com/google/gwt/i18n/client/impl/CurrencyList.java Tue Jun 23 20:13:51 2009 +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.gwt.i18n.client.impl; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.core.client.JavaScriptObject; - -import java.util.ArrayList; -import java.util.Iterator; - -/** - * Generated class containing all the CurrencyImpl instances. This is just - * the fallback in case the I18N module is not included. - */ -public class CurrencyList implements Iterable<CurrencyData> { - - /** - * Inner class to avoid CurrencyList.clinit calls and allow this to be - * completely removed from the generated code if instance isn't referenced - * (such as when all you call is CurrencyList.get().getDefault() ). - */ - private static class CurrencyListInstance { - private static CurrencyList instance = GWT.create(CurrencyList.class); - } - - /** - * Return the singleton instance of CurrencyList. - */ - public static CurrencyList get() { - return CurrencyListInstance.instance; - } - - // This helper method exists because we can't call JSO instance methods - // directly from JSNI. - protected static boolean isDeprecated(CurrencyData currencyData) { - return currencyData.isDeprecated(); - } - - /** - * JS Object which contains a map of currency codes to CurrencyData - * objects. Each currency code is prefixed with a ':' to allow - * enumeration to find only the values we added, and not values - * which various JSVMs add to objects. - */ - protected JavaScriptObject dataMap; - - /** - * JS Object which contains a map of currency codes to localized - * currency names. This is kept separate from the CurrencyData - * map above so that the names can be completely removed by the - * compiler if they are not used. As iteration is not required, - * no prefix is added to currency codes in this map. - */ - protected JavaScriptObject namesMap; - - /** - * Return the default currency data for this locale. - * - * Generated implementations override this method. - */ - public native CurrencyData getDefault() /*-{ - return [ "USD", "$", 2, "US$" ]; - }-*/; - - /** - * Returns an iterator for the list of currencies. - * - * Deprecated currencies will not be included. - */ - public final Iterator<CurrencyData> iterator() { - return iterator(false); - } - - /** - * Returns an iterator for the list of currencies, optionally including - * deprecated ones. - * - * @param includeDeprecated true if deprecated currencies should be included - */ - public final Iterator<CurrencyData> iterator(boolean includeDeprecated) { - ensureCurrencyMap(); - ArrayList<String> keys = new ArrayList<String>(); - loadCurrencyKeys(keys, includeDeprecated); - final Iterator<String> it = keys.iterator(); - return new Iterator<CurrencyData>() { - - public boolean hasNext() { - return it.hasNext(); - } - - public CurrencyData next() { - return getEntry(it.next()); - } - - public void remove() { - throw new UnsupportedOperationException("Remove not supported"); - } - }; - } - - /** - * Lookup a currency based on the ISO4217 currency code. - * - * @param currencyCode ISO4217 currency code - * @return currency data, or null if code not found - */ - public final CurrencyData lookup(String currencyCode) { - ensureCurrencyMap(); - return getEntry(currencyCode); - } - - /** - * Lookup a currency name based on the ISO4217 currency code. - * - * @param currencyCode ISO4217 currency code - * @return name of the currency, or null if code not found - */ - public final String lookupName(String currencyCode) { - ensureNamesMap(); - return getNamesEntry(currencyCode); - } - - /** - * Ensure that the map of currency data has been initialized. - */ - protected final void ensureCurrencyMap() { - if (dataMap == null) { - loadCurrencyMap(); - } - } - - /** - * Ensure that the map of currency data has been initialized. - */ - protected final void ensureNamesMap() { - if (namesMap == null) { - loadNamesMap(); - } - } - - /** - * Directly reference an entry in the currency map JSO. - * - * @param code ISO4217 currency code - * @return currency data - */ - protected final native CurrencyData getEntry(String code) /*-{ - return [email protected]::dataMap[code]; - }-*/; - - /** - * Directly reference an entry in the currency names map JSO. - * - * @param code ISO4217 currency code - * @return currency name, or the currency code if not known - */ - protected final native String getNamesEntry(String code) /*-{ - return [email protected]::namesMap[code] || code; - }-*/; - - /** - * Loads the currency map from a JS object literal. - * - * Generated implementations override this method. - */ - protected native void loadCurrencyMap() /*-{ - [email protected]::dataMap = { - "USD": [ "USD", "$", 2 ], - "EUR": [ "EUR", "€", 2 ], - "GBP": [ "GBP", "UK£", 2 ], - "JPY": [ "JPY", "¥", 0 ], - }; - }-*/; - - /** - * Loads the currency names map from a JS object literal. - * - * Generated implementations override this method. - */ - protected native void loadNamesMap() /*-{ - [email protected]::namesMap = { - "USD": "US Dollar", - "EUR": "Euro", - "GBP": "British Pound Sterling", - "JPY": "Japanese Yen", - }; - }-*/; - - /** - * Add all entries in {...@code override} to the currency data map, replacing - * any existing entries. This is used by subclasses that need to slightly - * alter the data used by the parent locale. - * - * @param override JS object with currency code -> CurrencyData pairs - */ - protected final native void overrideCurrencyMap(JavaScriptObject override) /*-{ - var map = [email protected]::dataMap; - for (var key in override) { - if (override.hasOwnProperty(key)) { - map[key] = override[key]; - } - } - }-*/; - - /** - * Add all entries in {...@code override} to the currency name map, replacing - * any existing entries. This is used by subclasses that need to slightly - * alter the data used by the parent locale. - * - * @param override JS object with currency code -> name pairs - */ - protected final native void overrideNamesMap(JavaScriptObject override) /*-{ - var map = [email protected]::namesMap; - for (var key in override) { - if (override.hasOwnProperty(key)) { - map[key] = override[key]; - } - } - }-*/; - - /** - * Add currency codes contained in the map to an ArrayList. - */ - private native void loadCurrencyKeys(ArrayList<String> keys, - boolean includeDeprecated) /*-{ - var map = [email protected]::dataMap; - for (var key in map) { - if (map.hasOwnProperty(key)) { - if (includeDeprecated - | | [email protected]::isDeprecated(Lcom/google/gwt/i18n/client/impl/CurrencyData;)(map[key])) { - [email protected]::add(Ljava/lang/Object;)(key); - } - } - } - }-*/; -} ======================================= --- /trunk/user/test/com/google/gwt/i18n/client/impl/CurrencyTest.java Tue Jun 23 22:55:33 2009 +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.i18n.client.impl; - -import com.google.gwt.junit.client.GWTTestCase; - -import java.util.Iterator; - -/** - * Tests for CurrencyList and CurrencyData (in addition to locale-specific - * tests in I18N_*Test). - */ -public class CurrencyTest extends GWTTestCase { - - @Override - public String getModuleName() { - return "com.google.gwt.i18n.I18NTest_es_MX"; - } - - public void testIterator() { - CurrencyList list = CurrencyList.get(); - boolean found = false; - for (CurrencyData data : list) { - String code = data.getCurrencyCode(); - if ("USD".equals(code)) { - found = true; - } else if ("ITL".equals(code)) { - fail("ITL in undeprecated list"); - } - } - assertTrue("USD not found in currency list", found); - Iterator<CurrencyData> it = list.iterator(true); - found = false; - while (it.hasNext()) { - CurrencyData data = it.next(); - String code = data.getCurrencyCode(); - if ("ITL".equals(code)) { - found = true; - } - } - assertTrue("ITL not found in deprecated currency list", found); - } - - public void testLookup() { - CurrencyList list = CurrencyList.get(); - assertNotNull("USD lookup failed", list.lookup("USD")); - assertNotNull("ITL lookup failed", list.lookup("ITL")); - assertEquals("dólar estadounidense", list.lookupName("USD")); - assertEquals("lira italiana", list.lookupName("ITL")); - } -} ======================================= --- /trunk/user/src/com/google/gwt/i18n/I18N.gwt.xml Tue Jun 16 14:20:27 2009 +++ /trunk/user/src/com/google/gwt/i18n/I18N.gwt.xml Thu Dec 10 15:31:32 2009 @@ -81,7 +81,7 @@ <when-type-is class="com.google.gwt.i18n.client.impl.LocaleInfoImpl" /> </generate-with> <generate-with class="com.google.gwt.i18n.rebind.CurrencyListGenerator"> - <when-type-is class="com.google.gwt.i18n.client.impl.CurrencyList" /> + <when-type-is class="com.google.gwt.i18n.client.CurrencyList" /> </generate-with> <!-- ======================================= --- /trunk/user/src/com/google/gwt/i18n/client/NumberFormat.java Thu Dec 3 08:05:34 2009 +++ /trunk/user/src/com/google/gwt/i18n/client/NumberFormat.java Thu Dec 10 15:31:32 2009 @@ -17,8 +17,6 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.constants.NumberConstants; -import com.google.gwt.i18n.client.impl.CurrencyData; -import com.google.gwt.i18n.client.impl.CurrencyList; /** * Formats and parses numbers using locale-sensitive patterns. @@ -365,6 +363,19 @@ } return cachedCurrencyFormat; } + + /** + * Provides the standard currency format for the default locale using a + * specified currency. + * + * @param currencyData currency data to use + * @return a <code>NumberFormat</code> capable of producing and consuming + * currency format for the default locale + */ + public static NumberFormat getCurrencyFormat(CurrencyData currencyData) { + return new NumberFormat(defaultNumberConstants.currencyPattern(), + currencyData, false); + } /** * Provides the standard currency format for the default locale using a @@ -374,11 +385,12 @@ * com.google.gwt.i18n.client.constants.CurrencyCodeMapConstants.properties * @return a <code>NumberFormat</code> capable of producing and consuming * currency format for the default locale + * @throws IllegalArgumentException if the currency code is unknown */ public static NumberFormat getCurrencyFormat(String currencyCode) { // TODO(jat): consider caching values per currency code. return new NumberFormat(defaultNumberConstants.currencyPattern(), - CurrencyList.get().lookup(currencyCode), false); + lookupCurrency(currencyCode), false); } /** @@ -407,6 +419,20 @@ public static NumberFormat getFormat(String pattern) { return new NumberFormat(pattern, CurrencyList.get().getDefault(), true); } + + /** + * Gets a custom <code>NumberFormat</code> instance for the default locale + * using the specified pattern and currency code. + * + * @param pattern pattern for this formatter + * @param currencyData currency data + * @return a NumberFormat instance + * @throws IllegalArgumentException if the specified pattern is invalid + */ + public static NumberFormat getFormat(String pattern, + CurrencyData currencyData) { + return new NumberFormat(pattern, currencyData, true); + } /** * Gets a custom <code>NumberFormat</code> instance for the default locale @@ -416,9 +442,10 @@ * @param currencyCode international currency code * @return a NumberFormat instance * @throws IllegalArgumentException if the specified pattern is invalid + * or the currency code is unknown */ public static NumberFormat getFormat(String pattern, String currencyCode) { - return new NumberFormat(pattern, CurrencyList.get().lookup(currencyCode), true); + return new NumberFormat(pattern, lookupCurrency(currencyCode), true); } /** @@ -483,7 +510,8 @@ * @param orig localized NumberConstants instance * @return NumberConstants instance using latin digits/etc */ - protected static NumberConstants createLatinNumberConstants(final NumberConstants orig) { + protected static NumberConstants createLatinNumberConstants( + final NumberConstants orig) { final String groupingSeparator = remapSeparator( orig.groupingSeparator()); final String decimalSeparator = remapSeparator( @@ -579,6 +607,23 @@ } return "\u00A0"; } + + /** + * Lookup a currency code. + * + * @param currencyCode ISO4217 currency code + * @return a CurrencyData instance + * @throws IllegalArgumentException if the currency code is unknown + */ + private static CurrencyData lookupCurrency(String currencyCode) { + CurrencyData currencyData = CurrencyList.get().lookup(currencyCode); + if (currencyData == null) { + throw new IllegalArgumentException("Currency code " + currencyCode + + " is unkown in locale " + + LocaleInfo.getCurrentLocale().getLocaleName()); + } + return currencyData; + } private static native String toFixed(double d, int digits) /*-{ return d.toFixed(digits); ======================================= --- /trunk/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java Mon Nov 16 13:28:11 2009 +++ /trunk/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java Thu Dec 10 15:31:32 2009 @@ -23,8 +23,8 @@ import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; -import com.google.gwt.i18n.client.impl.CurrencyData; -import com.google.gwt.i18n.client.impl.CurrencyList; +import com.google.gwt.i18n.client.CurrencyList; +import com.google.gwt.i18n.client.impl.CurrencyDataImpl; import com.google.gwt.i18n.shared.GwtLocale; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; @@ -135,7 +135,7 @@ } int currencyFlags = currencyFractionDigits; if (currencyObsolete) { - currencyFlags |= CurrencyData.DEPRECATED_FLAG; + currencyFlags |= CurrencyDataImpl.DEPRECATED_FLAG; } String currencyPortableSymbol = ""; if (extraData != null) { @@ -148,16 +148,16 @@ currencyPortableSymbol = extraSplit[0]; if (extraSplit.length > 1) { if (extraSplit[1].contains("SymPrefix")) { - currencyFlags |= CurrencyData.POS_FIXED_FLAG; + currencyFlags |= CurrencyDataImpl.POS_FIXED_FLAG; } else if (extraSplit[1].contains("SymSuffix")) { - currencyFlags |= CurrencyData.POS_FIXED_FLAG - | CurrencyData.POS_SUFFIX_FLAG; + currencyFlags |= CurrencyDataImpl.POS_FIXED_FLAG + | CurrencyDataImpl.POS_SUFFIX_FLAG; } if (extraSplit[1].contains("ForceSpace")) { - currencyFlags |= CurrencyData.SPACING_FIXED_FLAG - | CurrencyData.SPACE_FORCED_FLAG; + currencyFlags |= CurrencyDataImpl.SPACING_FIXED_FLAG + | CurrencyDataImpl.SPACE_FORCED_FLAG; } else if (extraSplit[1].contains("ForceNoSpace")) { - currencyFlags |= CurrencyData.SPACING_FIXED_FLAG; + currencyFlags |= CurrencyDataImpl.SPACING_FIXED_FLAG; } } // If a non-empty override is supplied, use it for the currency @@ -209,19 +209,21 @@ } } - private static final String CURRENCY_DATA = CurrencyData.class.getCanonicalName(); + private static final String CURRENCY_DATA = CurrencyDataImpl.class.getCanonicalName(); /** * Prefix for properties files containing CLDR-derived currency data for each * locale. */ - private static final String CURRENCY_DATA_PREFIX = "com/google/gwt/i18n/client/impl/cldr/CurrencyData"; + private static final String CURRENCY_DATA_PREFIX = + "com/google/gwt/i18n/client/impl/cldr/CurrencyData"; /** * Prefix for properties files containing additional flags about currencies * each locale, which are not present in CLDR. */ - private static final String CURRENCY_EXTRA_PREFIX = "com/google/gwt/i18n/client/constants/CurrencyExtra"; + private static final String CURRENCY_EXTRA_PREFIX = + "com/google/gwt/i18n/client/constants/CurrencyExtra"; private static final String CURRENCY_LIST = CurrencyList.class.getCanonicalName(); @@ -230,7 +232,8 @@ * locale. We use this only to get the default currency for our current * locale. */ - private static final String NUMBER_CONSTANTS_PREFIX = "com/google/gwt/i18n/client/constants/NumberConstantsImpl"; + private static final String NUMBER_CONSTANTS_PREFIX = + "com/google/gwt/i18n/client/constants/NumberConstantsImpl"; /** * Backslash-escape any double quotes in the supplied string. @@ -288,8 +291,8 @@ * @param locale * @return generated class name for the requested locale */ - private String generateLocaleTree(TreeLogger logger, - GeneratorContext context, JClassType targetClass, GwtLocale locale) { + private String generateLocaleTree(TreeLogger logger, GeneratorContext context, + JClassType targetClass, GwtLocale locale) { String superClassName = CURRENCY_LIST; List<GwtLocale> searchList = locale.getCompleteSearchList(); @@ -334,9 +337,9 @@ defCurrencyCode = lastDefaultCurrencyCode; } if (!currencyData.isEmpty() || defCurrencyCode != null) { - String newClass = generateOneLocale(logger, context, targetClass, - search, superClassName, currencies, allCurrencyData, - defCurrencyCode); + String newClass = + generateOneLocale(logger, context, targetClass, search, + superClassName, currencies, allCurrencyData, defCurrencyCode); superClassName = newClass; lastDefaultCurrencyCode = defCurrencyCode; } @@ -355,7 +358,7 @@ * @param superClassName * @param currencies the set of currencies defined in this locale * @param allCurrencyData map of currency code -> unparsed CurrencyInfo for - * that code + * that code * @param defCurrencyCode default currency code for this locale * @return fully-qualified class name generated */ @@ -363,14 +366,13 @@ JClassType targetClass, GwtLocale locale, String superClassName, String[] currencies, Map<String, CurrencyInfo> allCurrencyData, String defCurrencyCode) { - String packageName = targetClass.getPackage().getName(); String className = targetClass.getName().replace('.', '_') + "_" + locale.getAsString(); PrintWriter pw = context.tryCreate(logger, packageName, className); if (pw != null) { - ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory( - packageName, className); + ClassSourceFileComposerFactory factory = + new ClassSourceFileComposerFactory(packageName, className); factory.setSuperclass(superClassName); factory.addImport(CURRENCY_LIST); factory.addImport(CURRENCY_DATA); @@ -409,15 +411,16 @@ * @return fully-qualified class name that was generated */ private String generateRuntimeSelection(TreeLogger logger, - GeneratorContext context, JClassType targetClass, - GwtLocale compileLocale, Set<GwtLocale> locales) { + GeneratorContext context, JClassType targetClass, GwtLocale compileLocale, + Set<GwtLocale> locales) { String packageName = targetClass.getPackage().getName(); - String className = targetClass.getName().replace('.', '_') + "_" - + compileLocale.getAsString() + "_runtimeSelection"; + String className = + targetClass.getName().replace('.', '_') + "_" + + compileLocale.getAsString() + "_runtimeSelection"; PrintWriter pw = context.tryCreate(logger, packageName, className); if (pw != null) { - ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory( - packageName, className); + ClassSourceFileComposerFactory factory = + new ClassSourceFileComposerFactory(packageName, className); factory.setSuperclass(targetClass.getQualifiedSourceName()); factory.addImport(CURRENCY_LIST); factory.addImport(CURRENCY_DATA); @@ -451,9 +454,11 @@ writer.println(" return;"); writer.println("}"); boolean fetchedLocale = false; - Map<String, Set<GwtLocale>> localeMap = new TreeMap<String, Set<GwtLocale>>(); - String compileLocaleClass = processChildLocale(logger, context, - targetClass, localeMap, compileLocale); + Map<String, Set<GwtLocale>> localeMap = new TreeMap<String, + Set<GwtLocale>>(); + String compileLocaleClass = + processChildLocale(logger, context, targetClass, localeMap, + compileLocale); if (compileLocaleClass == null) { // already gave warning, just use default implementation return null; @@ -499,7 +504,7 @@ /** * Return a map of currency data for the requested locale, or null if there is * not one (not that inheritance is not handled here). - * + * <p/> * The keys are ISO4217 currency codes. The format of the map values is: * * <pre> @@ -531,8 +536,7 @@ */ private String getDefaultCurrency(GwtLocale locale) { String defCurrencyCode = null; - LocalizedProperties numberConstants = getProperties( - NUMBER_CONSTANTS_PREFIX, locale); + LocalizedProperties numberConstants = getProperties(NUMBER_CONSTANTS_PREFIX, locale); if (numberConstants != null) { defCurrencyCode = numberConstants.getProperty("defCurrencyCode"); } @@ -593,9 +597,9 @@ * @param locale * @return class name of the generated class, or null if failed */ - private String processChildLocale(TreeLogger logger, - GeneratorContext context, JClassType targetClass, - Map<String, Set<GwtLocale>> localeMap, GwtLocale locale) { + private String processChildLocale(TreeLogger logger, GeneratorContext context, + JClassType targetClass, Map<String, Set<GwtLocale>> localeMap, + GwtLocale locale) { String generatedClass = generateLocaleTree(logger, context, targetClass, locale); if (generatedClass == null) { @@ -623,11 +627,11 @@ * method is omitted entirely. * * @param allCurrencyData map of currency codes to currency data for the - * current locale, including all inherited currencies data + * current locale, including all inherited currencies data * @param className name of the class we are generating * @param writer SourceWriter instance to use for writing the class * @param currencies array of valid currency names in the order they should be - * listed + * listed */ private void writeCurrencyMethod(String className, SourceWriter writer, String[] currencies, Map<String, CurrencyInfo> allCurrencyData) { @@ -644,9 +648,9 @@ writer.println("@Override"); writer.println("protected native void loadCurrencyMap() /*-{"); writer.indent(); - writer.println("[email protected]." + className + writer.println("[email protected]." + className + "::loadSuperCurrencyMap()();"); - writer.println("[email protected]." + className + writer.println("[email protected]." + className + "::overrideCurrencyMap(Lcom/google/gwt/core/client/" + "JavaScriptObject;)({"); writer.indent(); @@ -673,7 +677,7 @@ * @param className name of the class we are generating * @param writer SourceWriter instance to use for writing the class * @param currencies array of valid currency names in the order they should be - * listed + * listed */ private void writeNamesMethod(String className, SourceWriter writer, String[] currencies, Map<String, CurrencyInfo> allCurrencyData) { @@ -692,9 +696,9 @@ writer.println("@Override"); writer.println("protected native void loadNamesMap() /*-{"); writer.indent(); - writer.println("[email protected]." + className + writer.println("[email protected]." + className + "::loadSuperNamesMap()();"); - writer.println("[email protected]." + className + writer.println("[email protected]." + className + "::overrideNamesMap(Lcom/google/gwt/core/" + "client/JavaScriptObject;)({"); writer.indent(); ======================================= --- /trunk/user/test/com/google/gwt/i18n/I18NSuite.java Mon Nov 30 20:39:13 2009 +++ /trunk/user/test/com/google/gwt/i18n/I18NSuite.java Thu Dec 10 15:31:32 2009 @@ -17,6 +17,7 @@ import com.google.gwt.i18n.client.AnnotationsTest; import com.google.gwt.i18n.client.ArabicPluralsTest; +import com.google.gwt.i18n.client.CurrencyTest; import com.google.gwt.i18n.client.CustomPluralsTest; import com.google.gwt.i18n.client.DateTimeFormat_de_Test; import com.google.gwt.i18n.client.DateTimeFormat_en_Test; @@ -40,7 +41,6 @@ import com.google.gwt.i18n.client.RuntimeLocalesTest; import com.google.gwt.i18n.client.TimeZoneInfoTest; import com.google.gwt.i18n.client.TimeZoneTest; -import com.google.gwt.i18n.client.impl.CurrencyTest; import com.google.gwt.i18n.rebind.MessageFormatParserTest; import com.google.gwt.i18n.server.GwtLocaleTest; import com.google.gwt.i18n.server.RegionInheritanceTest; ======================================= --- /trunk/user/test/com/google/gwt/i18n/client/I18N_es_AR_RuntimeTest.java Mon Apr 20 16:10:15 2009 +++ /trunk/user/test/com/google/gwt/i18n/client/I18N_es_AR_RuntimeTest.java Thu Dec 10 15:31:32 2009 @@ -18,8 +18,6 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.I18N_es_MX_Test.MyConstants; import com.google.gwt.i18n.client.I18N_es_MX_Test.MyMessages; -import com.google.gwt.i18n.client.impl.CurrencyData; -import com.google.gwt.i18n.client.impl.CurrencyList; import com.google.gwt.junit.client.GWTTestCase; import java.util.Arrays; ======================================= --- /trunk/user/test/com/google/gwt/i18n/client/I18N_es_MX_RuntimeTest.java Mon Apr 20 16:10:15 2009 +++ /trunk/user/test/com/google/gwt/i18n/client/I18N_es_MX_RuntimeTest.java Thu Dec 10 15:31:32 2009 @@ -18,8 +18,6 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.I18N_es_MX_Test.MyConstants; import com.google.gwt.i18n.client.I18N_es_MX_Test.MyMessages; -import com.google.gwt.i18n.client.impl.CurrencyData; -import com.google.gwt.i18n.client.impl.CurrencyList; import com.google.gwt.junit.client.GWTTestCase; import java.util.Arrays; ======================================= --- /trunk/user/test/com/google/gwt/i18n/client/I18N_nb_Test.java Wed Jun 3 20:45:12 2009 +++ /trunk/user/test/com/google/gwt/i18n/client/I18N_nb_Test.java Thu Dec 10 15:31:32 2009 @@ -16,8 +16,6 @@ package com.google.gwt.i18n.client; import com.google.gwt.core.client.GWT; -import com.google.gwt.i18n.client.impl.CurrencyData; -import com.google.gwt.i18n.client.impl.CurrencyList; import com.google.gwt.junit.client.GWTTestCase; /** -- http://groups.google.com/group/Google-Web-Toolkit-Contributors
