MeasureFormat.java revision bfab1e7fec36dff93fb980c546ad64a565faf9fc
12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */ 22ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 32ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ********************************************************************** 498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert * Copyright (c) 2004-2016, International Business Machines 52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Corporation and others. All Rights Reserved. 62ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ********************************************************************** 72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Author: Alan Liu 82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Created: April 20, 2004 92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Since: ICU 3.0 102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ********************************************************************** 112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.text; 132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.Externalizable; 152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.IOException; 162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.InvalidObjectException; 172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectInput; 182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectOutput; 192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectStreamException; 202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.FieldPosition; 212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.ParsePosition; 222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Arrays; 232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Collection; 242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Date; 252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.EnumMap; 262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.HashMap; 272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Locale; 282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Map; 292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.MissingResourceException; 302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.concurrent.ConcurrentHashMap; 312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.DontCareFieldPosition; 332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.ICUData; 342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.ICUResourceBundle; 352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.SimpleCache; 362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.SimplePatternFormatter; 3798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubertimport android.icu.impl.StandardPlural; 3896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubertimport android.icu.impl.UResource; 392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.math.BigDecimal; 402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.PluralRules.Factory; 412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Currency; 422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.CurrencyAmount; 4396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubertimport android.icu.util.ICUException; 442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Measure; 452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.MeasureUnit; 462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZone; 472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale; 482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale.Category; 492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.UResourceBundle; 502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller// If you update the examples in the doc, don't forget to update MesaureUnitTest.TestExamplesInDocs too. 522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/** 532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A formatter for Measure objects. 542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>To format a Measure object, first create a formatter 562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * object using a MeasureFormat factory method. Then use that 572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * object's format or formatMeasures methods. 582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Here is sample code: 602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre> 612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * MeasureFormat fmtFr = MeasureFormat.getInstance( 622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * ULocale.FRENCH, FormatWidth.SHORT); 632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Measure measure = new Measure(23, MeasureUnit.CELSIUS); 642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * // Output: 23 °C 662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * System.out.println(fmtFr.format(measure)); 672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Measure measureF = new Measure(70, MeasureUnit.FAHRENHEIT); 692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * // Output: 70 °F 712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * System.out.println(fmtFr.format(measureF)); 722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * MeasureFormat fmtFrFull = MeasureFormat.getInstance( 742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * ULocale.FRENCH, FormatWidth.WIDE); 752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * // Output: 70 pieds et 5,3 pouces 762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * System.out.println(fmtFrFull.formatMeasures( 772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * new Measure(70, MeasureUnit.FOOT), 782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * new Measure(5.3, MeasureUnit.INCH))); 792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * // Output: 1 pied et 1 pouce 812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * System.out.println(fmtFrFull.formatMeasures( 822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * new Measure(1, MeasureUnit.FOOT), 832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * new Measure(1, MeasureUnit.INCH))); 842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * MeasureFormat fmtFrNarrow = MeasureFormat.getInstance( 862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ULocale.FRENCH, FormatWidth.NARROW); 872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * // Output: 1′ 1″ 882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * System.out.println(fmtFrNarrow.formatMeasures( 892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * new Measure(1, MeasureUnit.FOOT), 902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * new Measure(1, MeasureUnit.INCH))); 912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * MeasureFormat fmtEn = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE); 942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * // Output: 1 inch, 2 feet 962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * fmtEn.formatMeasures( 972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * new Measure(1, MeasureUnit.INCH), 982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * new Measure(2, MeasureUnit.FOOT)); 992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </pre> 1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p> 1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This class does not do conversions from one unit to another. It simply formats 1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * whatever units it is given 1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p> 1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This class is immutable and thread-safe so long as its deprecated subclass, 1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * TimeUnitFormat, is never used. TimeUnitFormat is not thread-safe, and is 1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * mutable. Although this class has existing subclasses, this class does not support new 1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * sub-classes. 1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see android.icu.text.UFormat 1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @author Alan Liu 1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class MeasureFormat extends UFormat { 1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Generated by serialver from JDK 1.4.1_01 1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller static final long serialVersionUID = -7182021401701778240L; 1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert private final transient MeasureFormatData cache; 11996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final transient ImmutableNumberFormat numberFormat; 1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final transient FormatWidth formatWidth; 1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // PluralRules is documented as being immutable which implies thread-safety. 1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final transient PluralRules rules; 1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final transient NumericFormatters numericFormatters; 1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final transient ImmutableNumberFormat currencyFormat; 1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final transient ImmutableNumberFormat integerFormat; 1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final SimpleCache<ULocale, MeasureFormatData> localeMeasureFormatData 1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller = new SimpleCache<ULocale, MeasureFormatData>(); 1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final SimpleCache<ULocale, NumericFormatters> localeToNumericDurationFormatters 1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller = new SimpleCache<ULocale,NumericFormatters>(); 1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final Map<MeasureUnit, Integer> hmsTo012 = 1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller new HashMap<MeasureUnit, Integer>(); 1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller static { 1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hmsTo012.put(MeasureUnit.HOUR, 0); 1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hmsTo012.put(MeasureUnit.MINUTE, 1); 1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hmsTo012.put(MeasureUnit.SECOND, 2); 1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // For serialization: sub-class types. 1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final int MEASURE_FORMAT = 0; 1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final int TIME_UNIT_FORMAT = 1; 1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final int CURRENCY_FORMAT = 2; 1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Formatting width enum. 1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Be sure to update MeasureUnitTest.TestSerialFormatWidthEnum 1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // when adding an enum value. 1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public enum FormatWidth { 1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Spell out everything. 1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 16396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert WIDE(ListFormatter.Style.DURATION, NumberFormat.PLURALCURRENCYSTYLE), 1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Abbreviate when possible. 1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 16896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert SHORT(ListFormatter.Style.DURATION_SHORT, NumberFormat.ISOCURRENCYSTYLE), 1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Brief. Use only a symbol for the unit when possible. 1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 17396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert NARROW(ListFormatter.Style.DURATION_NARROW, NumberFormat.CURRENCYSTYLE), 1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Identical to NARROW except when formatMeasures is called with 1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * an hour and minute; minute and second; or hour, minute, and second Measures. 1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * In these cases formatMeasures formats as 5:37:23 instead of 5h, 37m, 23s. 1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 18096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert NUMERIC(ListFormatter.Style.DURATION_NARROW, NumberFormat.CURRENCYSTYLE); 1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Be sure to update the toFormatWidth and fromFormatWidth() functions 1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // when adding an enum value. 18496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert private static final int INDEX_COUNT = 3; // NARROW.ordinal() + 1 1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final ListFormatter.Style listFormatterStyle; 1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final int currencyStyle; 1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 18996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert private FormatWidth(ListFormatter.Style style, int currencyStyle) { 1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.listFormatterStyle = style; 1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.currencyStyle = currencyStyle; 1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ListFormatter.Style getListFormatterStyle() { 1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return listFormatterStyle; 1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int getCurrencyStyle() { 1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return currencyStyle; 2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Create a format from the locale, formatWidth, and format. 2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param locale the locale. 2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param formatWidth hints how long formatted strings should be. 2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return The new MeasureFormat object. 2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static MeasureFormat getInstance(ULocale locale, FormatWidth formatWidth) { 2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getInstance(locale, formatWidth, NumberFormat.getInstance(locale)); 2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2155a559d08b74c555d7f997b51acd311b7a8756d26Fredrik Roubert * Create a format from the {@link java.util.Locale} and formatWidth. 2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 2175a559d08b74c555d7f997b51acd311b7a8756d26Fredrik Roubert * @param locale the {@link java.util.Locale}. 2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param formatWidth hints how long formatted strings should be. 2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return The new MeasureFormat object. 2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static MeasureFormat getInstance(Locale locale, FormatWidth formatWidth) { 2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getInstance(ULocale.forLocale(locale), formatWidth); 2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Create a format from the locale, formatWidth, and format. 2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param locale the locale. 2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param formatWidth hints how long formatted strings should be. 2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param format This is defensively copied. 2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return The new MeasureFormat object. 2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static MeasureFormat getInstance(ULocale locale, FormatWidth formatWidth, NumberFormat format) { 2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller PluralRules rules = PluralRules.forLocale(locale); 2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NumericFormatters formatters = null; 2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MeasureFormatData data = localeMeasureFormatData.get(locale); 2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (data == null) { 2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller data = loadLocaleData(locale); 2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller localeMeasureFormatData.put(locale, data); 2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (formatWidth == FormatWidth.NUMERIC) { 2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller formatters = localeToNumericDurationFormatters.get(locale); 2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (formatters == null) { 2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller formatters = loadNumericFormatters(locale); 2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller localeToNumericDurationFormatters.put(locale, formatters); 2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NumberFormat intFormat = NumberFormat.getInstance(locale); 2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller intFormat.setMaximumFractionDigits(0); 2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller intFormat.setMinimumFractionDigits(0); 2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller intFormat.setRoundingMode(BigDecimal.ROUND_DOWN); 2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new MeasureFormat( 2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller locale, 25496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert data, 2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller formatWidth, 2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller new ImmutableNumberFormat(format), 2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller rules, 2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller formatters, 2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller new ImmutableNumberFormat(NumberFormat.getInstance(locale, formatWidth.getCurrencyStyle())), 26096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert new ImmutableNumberFormat(intFormat)); 2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2645a559d08b74c555d7f997b51acd311b7a8756d26Fredrik Roubert * Create a format from the {@link java.util.Locale}, formatWidth, and format. 2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 2665a559d08b74c555d7f997b51acd311b7a8756d26Fredrik Roubert * @param locale the {@link java.util.Locale}. 2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param formatWidth hints how long formatted strings should be. 2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param format This is defensively copied. 2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return The new MeasureFormat object. 2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static MeasureFormat getInstance(Locale locale, FormatWidth formatWidth, NumberFormat format) { 2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getInstance(ULocale.forLocale(locale), formatWidth, format); 2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Able to format Collection<? extends Measure>, Measure[], and Measure 2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * by delegating to formatMeasures. 2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the pos argument identifies a NumberFormat field, 2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * then its indices are set to the beginning and end of the first such field 2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * encountered. MeasureFormat itself does not supply any fields. 2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Calling a 2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>formatMeasures</code> method is preferred over calling 2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * this method as they give better performance. 2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 286bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * @param obj must be a Collection<? extends Measure>, Measure[], or Measure object. 2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param toAppendTo Formatted string appended here. 2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param pos Identifies a field in the formatted text. 2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition) 2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { 2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int prevLength = toAppendTo.length(); 2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FieldPosition fpos = 2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller new FieldPosition(pos.getFieldAttribute(), pos.getField()); 2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (obj instanceof Collection) { 2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Collection<?> coll = (Collection<?>) obj; 2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Measure[] measures = new Measure[coll.size()]; 2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int idx = 0; 3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (Object o : coll) { 3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!(o instanceof Measure)) { 3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException(obj.toString()); 3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller measures[idx++] = (Measure) o; 3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller toAppendTo.append(formatMeasures(new StringBuilder(), fpos, measures)); 3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (obj instanceof Measure[]) { 3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller toAppendTo.append(formatMeasures(new StringBuilder(), fpos, (Measure[]) obj)); 3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (obj instanceof Measure){ 3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller toAppendTo.append(formatMeasure((Measure) obj, numberFormat, new StringBuilder(), fpos)); 3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException(obj.toString()); 3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller pos.setBeginIndex(fpos.getBeginIndex() + prevLength); 3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller pos.setEndIndex(fpos.getEndIndex() + prevLength); 3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return toAppendTo; 3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Parses text from a string to produce a <code>Measure</code>. 3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition) 3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @throws UnsupportedOperationException Not supported. 325836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Measure parseObject(String source, ParsePosition pos) { 3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new UnsupportedOperationException(); 3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Format a sequence of measures. Uses the ListFormatter unit lists. 3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * So, for example, one could format “3 feet, 2 inches”. 3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Zero values are formatted (eg, “3 feet, 0 inches”). It is the caller’s 3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * responsibility to have the appropriate values in appropriate order, 3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and using the appropriate Number values. Typically the units should be 3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in descending order, with all but the last Measure having integer values 3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * (eg, not “3.2 feet, 2 inches”). 3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param measures a sequence of one or more measures. 3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the formatted string. 3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final String formatMeasures(Measure... measures) { 3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatMeasures( 3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller new StringBuilder(), 3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DontCareFieldPosition.INSTANCE, 3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller measures).toString(); 3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Format a range of measures, such as "3.4-5.1 meters". It is the caller’s 3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * responsibility to have the appropriate values in appropriate order, 3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and using the appropriate Number values. 3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <br>Note: If the format doesn’t have enough decimals, or lowValue ≥ highValue, 3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the result will be a degenerate range, like “5-5 meters”. 3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <br>Currency Units are not yet supported. 3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param lowValue low value in range 3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param highValue high value in range 3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the formatted string. 3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @deprecated This API is ICU internal only. 36393cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * @hide original deprecated declaration 364836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Deprecated 3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final String formatMeasureRange(Measure lowValue, Measure highValue) { 3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MeasureUnit unit = lowValue.getUnit(); 3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!unit.equals(highValue.getUnit())) { 3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("Units must match: " + unit + " ≠ " + highValue.getUnit()); 3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Number lowNumber = lowValue.getNumber(); 3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Number highNumber = highValue.getNumber(); 3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final boolean isCurrency = unit instanceof Currency; 3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller UFieldPosition lowFpos = new UFieldPosition(); 3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller UFieldPosition highFpos = new UFieldPosition(); 3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuffer lowFormatted = null; 3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuffer highFormatted = null; 3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (isCurrency) { 3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Currency currency = (Currency) unit; 3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int fracDigits = currency.getDefaultFractionDigits(); 3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int maxFrac = numberFormat.nf.getMaximumFractionDigits(); 3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int minFrac = numberFormat.nf.getMinimumFractionDigits(); 3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fracDigits != maxFrac || fracDigits != minFrac) { 3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DecimalFormat currentNumberFormat = (DecimalFormat) numberFormat.get(); 3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller currentNumberFormat.setMaximumFractionDigits(fracDigits); 3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller currentNumberFormat.setMinimumFractionDigits(fracDigits); 3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller lowFormatted = currentNumberFormat.format(lowNumber, new StringBuffer(), lowFpos); 3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller highFormatted = currentNumberFormat.format(highNumber, new StringBuffer(), highFpos); 3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (lowFormatted == null) { 3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller lowFormatted = numberFormat.format(lowNumber, new StringBuffer(), lowFpos); 3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller highFormatted = numberFormat.format(highNumber, new StringBuffer(), highFpos); 3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final double lowDouble = lowNumber.doubleValue(); 4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String keywordLow = rules.select(new PluralRules.FixedDecimal(lowDouble, 4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller lowFpos.getCountVisibleFractionDigits(), lowFpos.getFractionDigits())); 4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final double highDouble = highNumber.doubleValue(); 4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String keywordHigh = rules.select(new PluralRules.FixedDecimal(highDouble, 4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller highFpos.getCountVisibleFractionDigits(), highFpos.getFractionDigits())); 4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final PluralRanges pluralRanges = Factory.getDefaultFactory().getPluralRanges(getLocale()); 40898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert StandardPlural resolvedPlural = pluralRanges.get( 40998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert StandardPlural.fromString(keywordLow), 41098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert StandardPlural.fromString(keywordHigh)); 4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 41298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String rangeFormatter = getRangeFormat(getLocale(), formatWidth); 41398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String formattedNumber = SimplePatternFormatter.formatCompiledPattern(rangeFormatter, lowFormatted, highFormatted); 4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (isCurrency) { 4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Nasty hack 4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller currencyFormat.format(1d); // have to call this for the side effect 4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Currency currencyUnit = (Currency) unit; 4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuilder result = new StringBuilder(); 42198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert appendReplacingCurrency(currencyFormat.getPrefix(lowDouble >= 0), currencyUnit, resolvedPlural, result); 4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.append(formattedNumber); 42398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert appendReplacingCurrency(currencyFormat.getSuffix(highDouble >= 0), currencyUnit, resolvedPlural, result); 4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result.toString(); 4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // StringBuffer buffer = new StringBuffer(); 4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // CurrencyAmount currencyLow = (CurrencyAmount) lowValue; 4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // CurrencyAmount currencyHigh = (CurrencyAmount) highValue; 4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // FieldPosition pos = new FieldPosition(NumberFormat.INTEGER_FIELD); 4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // currencyFormat.format(currencyLow, buffer, pos); 4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // int startOfInteger = pos.getBeginIndex(); 4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // StringBuffer buffer2 = new StringBuffer(); 4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // FieldPosition pos2 = new FieldPosition(0); 4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // currencyFormat.format(currencyHigh, buffer2, pos2); 4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 43598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String formatter = 43698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert getPluralFormatter(lowValue.getUnit(), formatWidth, resolvedPlural.ordinal()); 43798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert return SimplePatternFormatter.formatCompiledPattern(formatter, formattedNumber); 4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 44198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert private void appendReplacingCurrency(String affix, Currency unit, StandardPlural resolvedPlural, StringBuilder result) { 4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String replacement = "¤"; 4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int pos = affix.indexOf(replacement); 4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (pos < 0) { 4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller replacement = "XXX"; 4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller pos = affix.indexOf(replacement); 4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (pos < 0) { 4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.append(affix); 4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // for now, just assume single 4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.append(affix.substring(0,pos)); 4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // we have a mismatch between the number style and the currency style, so remap 4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int currentStyle = formatWidth.getCurrencyStyle(); 4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (currentStyle == NumberFormat.ISOCURRENCYSTYLE) { 4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.append(unit.getCurrencyCode()); 4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.append(unit.getName(currencyFormat.nf.getLocale(ULocale.ACTUAL_LOCALE), 4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller currentStyle == NumberFormat.CURRENCYSTYLE ? Currency.SYMBOL_NAME : Currency.PLURAL_LONG_NAME, 46098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert resolvedPlural.getKeyword(), null)); 4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.append(affix.substring(pos+replacement.length())); 4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Formats a single measure per unit. 4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * An example of such a formatted string is "3.5 meters per second." 4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param measure the measure object. In above example, 3.5 meters. 4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param perUnit the per unit. In above example, it is MeasureUnit.SECOND 4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param appendTo formatted string appended here. 4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param pos The field position. 4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return appendTo. 476836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public StringBuilder formatMeasurePerUnit( 4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Measure measure, 4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MeasureUnit perUnit, 4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuilder appendTo, 4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FieldPosition pos) { 4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MeasureUnit resolvedUnit = MeasureUnit.resolveUnitPerUnit( 4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller measure.getUnit(), perUnit); 4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (resolvedUnit != null) { 4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Measure newMeasure = new Measure(measure.getNumber(), resolvedUnit); 4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatMeasure(newMeasure, numberFormat, appendTo, pos); 4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FieldPosition fpos = new FieldPosition( 4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller pos.getFieldAttribute(), pos.getField()); 4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int offset = withPerUnitAndAppend( 4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller formatMeasure(measure, numberFormat, new StringBuilder(), fpos), 4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller perUnit, 4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendTo); 4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller pos.setBeginIndex(fpos.getBeginIndex() + offset); 4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller pos.setEndIndex(fpos.getEndIndex() + offset); 4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return appendTo; 5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Formats a sequence of measures. 5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the fieldPosition argument identifies a NumberFormat field, 5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * then its indices are set to the beginning and end of the first such field 5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * encountered. MeasureFormat itself does not supply any fields. 5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param appendTo the formatted string appended here. 5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param fieldPosition Identifies a field in the formatted text. 5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param measures the measures to format. 5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return appendTo. 5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see MeasureFormat#formatMeasures(Measure...) 5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public StringBuilder formatMeasures( 5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuilder appendTo, FieldPosition fieldPosition, Measure... measures) { 5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // fast track for trivial cases 5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (measures.length == 0) { 5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return appendTo; 5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (measures.length == 1) { 5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatMeasure(measures[0], numberFormat, appendTo, fieldPosition); 5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (formatWidth == FormatWidth.NUMERIC) { 5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If we have just hour, minute, or second follow the numeric 5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // track. 5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Number[] hms = toHMS(measures); 5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (hms != null) { 5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatNumeric(hms, appendTo); 5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ListFormatter listFormatter = ListFormatter.getInstance( 5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getLocale(), formatWidth.getListFormatterStyle()); 5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fieldPosition != DontCareFieldPosition.INSTANCE) { 5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatMeasuresSlowTrack(listFormatter, appendTo, fieldPosition, measures); 5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Fast track: No field position. 5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String[] results = new String[measures.length]; 5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int i = 0; i < measures.length; i++) { 5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller results[i] = formatMeasure( 5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller measures[i], 5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller i == measures.length - 1 ? numberFormat : integerFormat); 5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return appendTo.append(listFormatter.format((Object[]) results)); 5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Two MeasureFormats, a and b, are equal if and only if they have the same formatWidth, 5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * locale, and equal number formats. 5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final boolean equals(Object other) { 5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (this == other) { 5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!(other instanceof MeasureFormat)) { 5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MeasureFormat rhs = (MeasureFormat) other; 5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // A very slow but safe implementation. 5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getWidth() == rhs.getWidth() 5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && getLocale().equals(rhs.getLocale()) 5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller && getNumberFormat().equals(rhs.getNumberFormat()); 5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final int hashCode() { 5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // A very slow but safe implementation. 5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return (getLocale().hashCode() * 31 5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller + getNumberFormat().hashCode()) * 31 + getWidth().hashCode(); 5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Get the format width this instance is using. 5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public MeasureFormat.FormatWidth getWidth() { 5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatWidth; 5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Get the locale of this instance. 5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public final ULocale getLocale() { 5902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getLocale(ULocale.VALID_LOCALE); 5912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 5942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Get a copy of the number format. 5952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public NumberFormat getNumberFormat() { 5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return numberFormat.get(); 5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return a formatter for CurrencyAmount objects in the given 6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * locale. 6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param locale desired locale 6042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return a formatter object 6052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static MeasureFormat getCurrencyFormat(ULocale locale) { 6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new CurrencyFormat(locale); 6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return a formatter for CurrencyAmount objects in the given 6125a559d08b74c555d7f997b51acd311b7a8756d26Fredrik Roubert * {@link java.util.Locale}. 6135a559d08b74c555d7f997b51acd311b7a8756d26Fredrik Roubert * @param locale desired {@link java.util.Locale} 6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return a formatter object 6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static MeasureFormat getCurrencyFormat(Locale locale) { 6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getCurrencyFormat(ULocale.forLocale(locale)); 6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Return a formatter for CurrencyAmount objects in the default 6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>FORMAT</code> locale. 6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return a formatter object 6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see Category#FORMAT 6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static MeasureFormat getCurrencyFormat() { 6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getCurrencyFormat(ULocale.getDefault(Category.FORMAT)); 6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // This method changes the NumberFormat object as well to match the new locale. 6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MeasureFormat withLocale(ULocale locale) { 6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return MeasureFormat.getInstance(locale, getWidth()); 6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MeasureFormat withNumberFormat(NumberFormat format) { 6362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new MeasureFormat( 6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getLocale(), 63896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert this.cache, 6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.formatWidth, 6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller new ImmutableNumberFormat(format), 6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.rules, 6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.numericFormatters, 6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.currencyFormat, 64496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert this.integerFormat); 6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private MeasureFormat( 6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ULocale locale, 64996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert MeasureFormatData data, 6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FormatWidth formatWidth, 6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ImmutableNumberFormat format, 6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller PluralRules rules, 6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NumericFormatters formatters, 6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ImmutableNumberFormat currencyFormat, 65596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert ImmutableNumberFormat integerFormat) { 6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller setLocale(locale, locale); 65796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert this.cache = data; 6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.formatWidth = formatWidth; 6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.numberFormat = format; 6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.rules = rules; 6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.numericFormatters = formatters; 6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.currencyFormat = currencyFormat; 6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.integerFormat = integerFormat; 6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller MeasureFormat() { 6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Make compiler happy by setting final fields to null. 66896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert this.cache = null; 6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.formatWidth = null; 6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.numberFormat = null; 6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.rules = null; 6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.numericFormatters = null; 6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.currencyFormat = null; 6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.integerFormat = null; 6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller static class NumericFormatters { 6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private DateFormat hourMinute; 6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private DateFormat minuteSecond; 6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private DateFormat hourMinuteSecond; 6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public NumericFormatters( 6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat hourMinute, 6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat minuteSecond, 6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat hourMinuteSecond) { 6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.hourMinute = hourMinute; 6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.minuteSecond = minuteSecond; 6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.hourMinuteSecond = hourMinuteSecond; 6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public DateFormat getHourMinute() { return hourMinute; } 6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public DateFormat getMinuteSecond() { return minuteSecond; } 6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public DateFormat getHourMinuteSecond() { return hourMinuteSecond; } 6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static NumericFormatters loadNumericFormatters( 6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ULocale locale) { 6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ICUResourceBundle r = (ICUResourceBundle)UResourceBundle. 6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getBundleInstance(ICUData.ICU_UNIT_BASE_NAME, locale); 7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new NumericFormatters( 7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller loadNumericDurationFormat(r, "hm"), 7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller loadNumericDurationFormat(r, "ms"), 7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller loadNumericDurationFormat(r, "hms")); 7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 70796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Sink for enumerating all of the measurement unit display names. 70896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Contains inner sink classes, each one corresponding to a type of resource table. 70996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * The outer sink handles the top-level units, unitsNarrow, and unitsShort tables. 71096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * 71196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root): 71296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Only store a value if it is still missing, that is, it has not been overridden. 71396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * 71496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * C++: Each inner sink class has a reference to the main outer sink. 71596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Java: Use non-static inner classes instead. 7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 71796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert private static final class UnitDataSink extends UResource.TableSink { 71896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert /** 71996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Sink for a table of display patterns. For example, 72096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * unitsShort/duration/hour contains other{"{0} hrs"}. 72196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert */ 72296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert class UnitPatternSink extends UResource.TableSink { 72398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String[] patterns; 72498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert 72598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert void setFormatterIfAbsent(int index, UResource.Value value, int minPlaceholders) { 72698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (patterns == null) { 72798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert EnumMap<FormatWidth, String[]> styleToPatterns = 72898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert cacheData.unitToStyleToPatterns.get(unit); 72998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (styleToPatterns == null) { 73098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert styleToPatterns = 73198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert new EnumMap<FormatWidth, String[]>(FormatWidth.class); 73298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert cacheData.unitToStyleToPatterns.put(unit, styleToPatterns); 73398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert } else { 73498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert patterns = styleToPatterns.get(width); 73598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert } 73698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (patterns == null) { 73798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert patterns = new String[MeasureFormatData.PATTERN_COUNT]; 73898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert styleToPatterns.put(width, patterns); 73998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert } 74098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert } 74198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (patterns[index] == null) { 74298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert patterns[index] = SimplePatternFormatter.compileToStringMinMaxPlaceholders( 74398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert value.getString(), sb, minPlaceholders, 1); 74498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert } 74598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert } 74696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 74796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert @Override 74896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert public void put(UResource.Key key, UResource.Value value) { 74996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (key.contentEquals("dnam")) { 75096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // Skip the unit display name for now. 75196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } else if (key.contentEquals("per")) { 75296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // For example, "{0}/h". 75398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert // TODO: Set minPlaceholders=1 75498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert // after http://unicode.org/cldr/trac/ticket/9129 is fixed. 75598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert setFormatterIfAbsent(MeasureFormatData.PER_UNIT_INDEX, value, 0); 75696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } else { 75796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // The key must be one of the plural form strings. For example: 75896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // one{"{0} hr"} 75996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // other{"{0} hrs"} 76098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert setFormatterIfAbsent(StandardPlural.indexFromString(key), value, 0); 76196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 76496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert UnitPatternSink patternSink = new UnitPatternSink(); 76596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 76696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert /** 76796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Sink for a table of per-unit tables. For example, 76896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * unitsShort/duration contains tables for duration-unit subtypes day & hour. 76996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert */ 77096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert class UnitSubtypeSink extends UResource.TableSink { 77196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert @Override 77296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert public UResource.TableSink getOrCreateTableSink(UResource.Key key, int initialSize) { 77396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // Should we ignore or reject unknown units? 77496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert unit = MeasureUnit.internalGetInstance(type, key.toString()); // never null 77598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert // Trigger a fresh lookup of the patterns for this unit+width. 77698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert patternSink.patterns = null; 77796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return patternSink; 7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 77996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 78096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert UnitSubtypeSink subtypeSink = new UnitSubtypeSink(); 78196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 78296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert /** 78396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Sink for compound x-per-y display pattern. For example, 78496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * unitsShort/compound/per may be "{0}/{1}". 78596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert */ 78696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert class UnitCompoundSink extends UResource.TableSink { 78796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert @Override 78896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert public void put(UResource.Key key, UResource.Value value) { 78996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (key.contentEquals("per")) { 79096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert cacheData.styleToPerPattern.put(width, 79198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert SimplePatternFormatter.compileToStringMinMaxPlaceholders( 79298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert value.getString(), sb, 2, 2)); 79396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 79596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 79696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert UnitCompoundSink compoundSink = new UnitCompoundSink(); 79796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 79896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert /** 79996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Sink for a table of unit type tables. For example, 80096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * unitsShort contains tables for area & duration. 80196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * It also contains a table for the compound/per pattern. 80296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert */ 80396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert class UnitTypeSink extends UResource.TableSink { 80496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert @Override 80596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert public UResource.TableSink getOrCreateTableSink(UResource.Key key, int initialSize) { 80696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (key.contentEquals("currency")) { 80796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // Skip. 80896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } else if (key.contentEquals("compound")) { 80996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (!cacheData.hasPerFormatter(width)) { 81096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return compoundSink; 8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 81296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } else { 81396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert type = key.toString(); 81496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return subtypeSink; 81596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 81696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return null; 81796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 81896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 81996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert UnitTypeSink typeSink = new UnitTypeSink(); 82096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 82196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert UnitDataSink(MeasureFormatData outputData) { 82296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert cacheData = outputData; 82396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 82496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert @Override 82596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert public void put(UResource.Key key, UResource.Value value) { 82696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // Handle aliases like 82796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // units:alias{"/LOCALE/unitsShort"} 82896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // which should only occur in the root bundle. 82996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (value.getType() != ICUResourceBundle.ALIAS) { return; } 83096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert FormatWidth sourceWidth = widthFromKey(key); 83196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (sourceWidth == null) { 83296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // Alias from something we don't care about. 83396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return; 83496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 83596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert FormatWidth targetWidth = widthFromAlias(value); 83696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (targetWidth == null) { 83796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // We do not recognize what to fall back to. 83896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert throw new ICUException("Units data fallback from " + key + 83996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert " to unknown " + value.getAliasString()); 84096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 84196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // Check that we do not fall back to another fallback. 84296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (cacheData.widthFallback[targetWidth.ordinal()] != null) { 84396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert throw new ICUException("Units data fallback from " + key + 84496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert " to " + value.getAliasString() + " which falls back to something else"); 84596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 84696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert cacheData.widthFallback[sourceWidth.ordinal()] = targetWidth; 84796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 84896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert @Override 84996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert public UResource.TableSink getOrCreateTableSink(UResource.Key key, int initialSize) { 85096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if ((width = widthFromKey(key)) != null) { 85196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return typeSink; 85296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 85396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return null; 85496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 85596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 85696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert static FormatWidth widthFromKey(UResource.Key key) { 85796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (key.startsWith("units")) { 85896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (key.length() == 5) { 85996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return FormatWidth.WIDE; 86096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } else if (key.regionMatches(5, "Short")) { 86196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return FormatWidth.SHORT; 86296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } else if (key.regionMatches(5, "Narrow")) { 86396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return FormatWidth.NARROW; 8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 86696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return null; 8672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 86896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 86996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert static FormatWidth widthFromAlias(UResource.Value value) { 87096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert String s = value.getAliasString(); 87196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // For example: "/LOCALE/unitsShort" 87296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (s.startsWith("/LOCALE/units")) { 87396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (s.length() == 13) { 87496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return FormatWidth.WIDE; 87596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } else if (s.length() == 18 && s.endsWith("Short")) { 87696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return FormatWidth.SHORT; 87796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } else if (s.length() == 19 && s.endsWith("Narrow")) { 87896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return FormatWidth.NARROW; 87996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 88096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 88196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return null; 88296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 88396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 88496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // Output data. 88596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert MeasureFormatData cacheData; 88696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 88796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert // Path to current data. 88896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert FormatWidth width; 88996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert String type; 89096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert MeasureUnit unit; 89198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert 89298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert // Temporary 89398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert StringBuilder sb = new StringBuilder(); 8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 89596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 89696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert /** 89796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Returns formatting data for all MeasureUnits except for currency ones. 89896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert */ 89996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert private static MeasureFormatData loadLocaleData(ULocale locale) { 90096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert ICUResourceBundle resource = 90196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME, locale); 90296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert MeasureFormatData cacheData = new MeasureFormatData(); 90396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert UnitDataSink sink = new UnitDataSink(cacheData); 90496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert resource.getAllTableItemsWithFallback("", sink); 90596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return cacheData; 90696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 90796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 90896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert private static final FormatWidth getRegularWidth(FormatWidth width) { 90996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (width == FormatWidth.NUMERIC) { 91096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return FormatWidth.NARROW; 9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 91296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return width; 91396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 91496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 91598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert private String getFormatterOrNull(MeasureUnit unit, FormatWidth width, int index) { 91696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert width = getRegularWidth(width); 91798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert Map<FormatWidth, String[]> styleToPatterns = cache.unitToStyleToPatterns.get(unit); 91898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String[] patterns = styleToPatterns.get(width); 91998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (patterns != null && patterns[index] != null) { 92098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert return patterns[index]; 9212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 92296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert FormatWidth fallbackWidth = cache.widthFallback[width.ordinal()]; 92396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (fallbackWidth != null) { 92498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert patterns = styleToPatterns.get(fallbackWidth); 92598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (patterns != null && patterns[index] != null) { 92698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert return patterns[index]; 9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 92998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert return null; 9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 93196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 93298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert private String getFormatter(MeasureUnit unit, FormatWidth width, int index) { 93398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String pattern = getFormatterOrNull(unit, width, index); 93498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (pattern == null) { 93598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert throw new MissingResourceException( 93698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert "no formatting pattern for " + unit + ", width " + width + ", index " + index, 93798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert null, null); 93896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 93998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert return pattern; 94098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert } 94198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert 94298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert private String getPluralFormatter(MeasureUnit unit, FormatWidth width, int index) { 94398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (index != StandardPlural.OTHER_INDEX) { 94498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String pattern = getFormatterOrNull(unit, width, index); 94598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (pattern != null) { 94698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert return pattern; 94796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 94896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 94998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert return getFormatter(unit, width, StandardPlural.OTHER_INDEX); 95096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 95196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 95298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert private String getPerFormatter(FormatWidth width) { 95396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert width = getRegularWidth(width); 95498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String perPattern = cache.styleToPerPattern.get(width); 95596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (perPattern != null) { 95696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return perPattern; 95796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 95896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert FormatWidth fallbackWidth = cache.widthFallback[width.ordinal()]; 95996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (fallbackWidth != null) { 96096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert perPattern = cache.styleToPerPattern.get(fallbackWidth); 96196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert if (perPattern != null) { 96296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return perPattern; 96396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 96496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 96596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert throw new MissingResourceException("no x-per-y pattern for width " + width, null, null); 96696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 96796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 9682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private int withPerUnitAndAppend( 9692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller CharSequence formatted, MeasureUnit perUnit, StringBuilder appendTo) { 9702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] offsets = new int[1]; 97198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String perUnitPattern = 97298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert getFormatterOrNull(perUnit, formatWidth, MeasureFormatData.PER_UNIT_INDEX); 9732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (perUnitPattern != null) { 97498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert SimplePatternFormatter.formatAndAppend(perUnitPattern, appendTo, offsets, formatted); 9752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return offsets[0]; 9762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 97798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String perPattern = getPerFormatter(formatWidth); 97898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String pattern = getPluralFormatter(perUnit, formatWidth, StandardPlural.ONE.ordinal()); 97998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String perUnitString = SimplePatternFormatter.getTextWithNoPlaceholders(pattern).trim(); 98098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert SimplePatternFormatter.formatAndAppend( 98198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert perPattern, appendTo, offsets, formatted, perUnitString); 9822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return offsets[0]; 9832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private String formatMeasure(Measure measure, ImmutableNumberFormat nf) { 9862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatMeasure( 9872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller measure, nf, new StringBuilder(), 9882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DontCareFieldPosition.INSTANCE).toString(); 9892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private StringBuilder formatMeasure( 9922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Measure measure, 9932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ImmutableNumberFormat nf, 9942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuilder appendTo, 9952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FieldPosition fieldPosition) { 99698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert Number n = measure.getNumber(); 99798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert MeasureUnit unit = measure.getUnit(); 99898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert if (unit instanceof Currency) { 9992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return appendTo.append( 10002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller currencyFormat.format( 100198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert new CurrencyAmount(n, (Currency) unit), 10022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller new StringBuffer(), 10032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fieldPosition)); 10042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 100698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert StringBuffer formattedNumber = new StringBuffer(); 100798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert StandardPlural pluralForm = QuantityFormatter.selectPlural( 100898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert n, nf.nf, rules, formattedNumber, fieldPosition); 100998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String formatter = getPluralFormatter(unit, formatWidth, pluralForm.ordinal()); 101098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert return QuantityFormatter.format(formatter, formattedNumber, appendTo, fieldPosition); 10112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 101298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert 101396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert /** 101496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Instances contain all MeasureFormat specific data for a particular locale. 101596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * This data is cached. It is never copied, but is shared via shared pointers. 101696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * 101796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Note: We might change the cache data to have 101896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * an array[WIDTH_INDEX_COUNT] or EnumMap<FormatWidth, ...> of 101996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * complete sets of unit & per patterns, 102096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * to correspond to the resource data and its aliases. 102196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert */ 10222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final class MeasureFormatData { 102398d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert static final int PER_UNIT_INDEX = StandardPlural.COUNT; 102498d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert static final int PATTERN_COUNT = PER_UNIT_INDEX + 1; 102598d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert 102696a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert boolean hasPerFormatter(FormatWidth width) { 102796a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert return styleToPerPattern.containsKey(width); 102896a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert } 102996a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert 103096a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert /** 103196a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * Redirection data from root-bundle, top-level sideways aliases. 103296a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * - null: initial value, just fall back to root 103396a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert * - FormatWidth.WIDE/SHORT/NARROW: sideways alias for missing data 103496a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert */ 103596a989def40de002d53d58a6bc121e0c110bd6c0Fredrik Roubert final FormatWidth widthFallback[] = new FormatWidth[FormatWidth.INDEX_COUNT]; 103698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert /** Measure unit -> format width -> array of patterns ("{0} meters") (plurals + PER_UNIT_INDEX) */ 103798d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert final Map<MeasureUnit, EnumMap<FormatWidth, String[]>> unitToStyleToPatterns = 103898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert new HashMap<MeasureUnit, EnumMap<FormatWidth, String[]>>(); 103998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert final EnumMap<FormatWidth, String> styleToPerPattern = 104098d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert new EnumMap<FormatWidth, String>(FormatWidth.class);; 10412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Wrapper around NumberFormat that provides immutability and thread-safety. 10442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final class ImmutableNumberFormat { 10452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private NumberFormat nf; 10462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public ImmutableNumberFormat(NumberFormat nf) { 10482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.nf = (NumberFormat) nf.clone(); 10492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public synchronized NumberFormat get() { 10522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return (NumberFormat) nf.clone(); 10532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public synchronized StringBuffer format( 10562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Number n, StringBuffer buffer, FieldPosition pos) { 10572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return nf.format(n, buffer, pos); 10582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public synchronized StringBuffer format( 10612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller CurrencyAmount n, StringBuffer buffer, FieldPosition pos) { 10622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return nf.format(n, buffer, pos); 10632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @SuppressWarnings("unused") 10662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public synchronized String format(Number number) { 10672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return nf.format(number); 10682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getPrefix(boolean positive) { 10712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return positive ? ((DecimalFormat)nf).getPositivePrefix() : ((DecimalFormat)nf).getNegativePrefix(); 10722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getSuffix(boolean positive) { 10742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return positive ? ((DecimalFormat)nf).getPositiveSuffix() : ((DecimalFormat)nf).getPositiveSuffix(); 10752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller static final class PatternData { 10792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final String prefix; 10802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final String suffix; 10812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public PatternData(String pattern) { 10822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int pos = pattern.indexOf("{0}"); 10832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (pos < 0) { 10842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller prefix = pattern; 10852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller suffix = null; 10862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 10872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller prefix = pattern.substring(0,pos); 10882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller suffix = pattern.substring(pos+3); 10892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String toString() { 10922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return prefix + "; " + suffix; 10932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Object toTimeUnitProxy() { 10982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new MeasureProxy(getLocale(), formatWidth, numberFormat.get(), TIME_UNIT_FORMAT); 10992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Object toCurrencyProxy() { 11022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new MeasureProxy(getLocale(), formatWidth, numberFormat.get(), CURRENCY_FORMAT); 11032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private StringBuilder formatMeasuresSlowTrack( 11062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ListFormatter listFormatter, 11072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuilder appendTo, 11082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FieldPosition fieldPosition, 11092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Measure... measures) { 11102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String[] results = new String[measures.length]; 11112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Zero out our field position so that we can tell when we find our field. 11132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FieldPosition fpos = new FieldPosition( 11142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fieldPosition.getFieldAttribute(), fieldPosition.getField()); 11152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int fieldPositionFoundIndex = -1; 11172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int i = 0; i < measures.length; ++i) { 11182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ImmutableNumberFormat nf = (i == measures.length - 1 ? numberFormat : integerFormat); 11192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fieldPositionFoundIndex == -1) { 11202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller results[i] = formatMeasure(measures[i], nf, new StringBuilder(), fpos).toString(); 11212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 11222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fieldPositionFoundIndex = i; 11232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 11252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller results[i] = formatMeasure(measures[i], nf); 11262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ListFormatter.FormattedListBuilder builder = 11292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller listFormatter.format(Arrays.asList(results), fieldPositionFoundIndex); 11302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Fix up FieldPosition indexes if our field is found. 11322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (builder.getOffset() != -1) { 11332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fieldPosition.setBeginIndex(fpos.getBeginIndex() + builder.getOffset() + appendTo.length()); 11342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fieldPosition.setEndIndex(fpos.getEndIndex() + builder.getOffset() + appendTo.length()); 11352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return appendTo.append(builder.toString()); 11372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // type is one of "hm", "ms" or "hms" 11402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static DateFormat loadNumericDurationFormat( 11412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ICUResourceBundle r, String type) { 11422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller r = r.getWithFallback(String.format("durationUnits/%s", type)); 11432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // We replace 'h' with 'H' because 'h' does not make sense in the context of durations. 11442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat result = new SimpleDateFormat(r.getString().replace("h", "H")); 11452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.setTimeZone(TimeZone.GMT_ZONE); 11462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 11472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Returns hours in [0]; minutes in [1]; seconds in [2] out of measures array. If 11502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // unsuccessful, e.g measures has other measurements besides hours, minutes, seconds; 11512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // hours, minutes, seconds are out of order; or have negative values, returns null. 11522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If hours, minutes, or seconds is missing from measures the corresponding element in 11532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // returned array will be null. 11542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static Number[] toHMS(Measure[] measures) { 11552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Number[] result = new Number[3]; 11562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int lastIdx = -1; 11572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (Measure m : measures) { 11582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (m.getNumber().doubleValue() < 0.0) { 11592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 11602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Integer idxObj = hmsTo012.get(m.getUnit()); 11622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (idxObj == null) { 11632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 11642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int idx = idxObj.intValue(); 11662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (idx <= lastIdx) { 11672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // hour before minute before second 11682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 11692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller lastIdx = idx; 11712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result[idx] = m.getNumber(); 11722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 11742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Formats numeric time duration as 5:00:47 or 3:54. In the process, it replaces any null 11772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // values in hms with 0. 11782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private StringBuilder formatNumeric(Number[] hms, StringBuilder appendable) { 11792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // find the start and end of non-nil values in hms array. We have to know if we 11812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // have hour-minute; minute-second; or hour-minute-second. 11822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int startIndex = -1; 11832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int endIndex = -1; 11842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (int i = 0; i < hms.length; i++) { 11852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (hms[i] != null) { 11862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller endIndex = i; 11872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (startIndex == -1) { 11882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller startIndex = endIndex; 11892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 11912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Replace nil value with 0. 11922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hms[i] = Integer.valueOf(0); 11932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // convert hours, minutes, seconds into milliseconds. 11962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller long millis = (long) (((Math.floor(hms[0].doubleValue()) * 60.0 11972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller + Math.floor(hms[1].doubleValue())) * 60.0 11982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller + Math.floor(hms[2].doubleValue())) * 1000.0); 11992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date d = new Date(millis); 12002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // if hour-minute-second 12012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (startIndex == 0 && endIndex == 2) { 12022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatNumeric( 12032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller d, 12042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller numericFormatters.getHourMinuteSecond(), 12052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat.Field.SECOND, 12062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hms[endIndex], 12072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendable); 12082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 12092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // if minute-second 12102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (startIndex == 1 && endIndex == 2) { 12112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatNumeric( 12122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller d, 12132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller numericFormatters.getMinuteSecond(), 12142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat.Field.SECOND, 12152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hms[endIndex], 12162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendable); 12172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 12182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // if hour-minute 12192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (startIndex == 0 && endIndex == 1) { 12202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return formatNumeric( 12212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller d, 12222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller numericFormatters.getHourMinute(), 12232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat.Field.MINUTE, 12242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hms[endIndex], 12252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendable); 12262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 12272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalStateException(); 12282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 12292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 12302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Formats a duration as 5:00:37 or 23:59. 12312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // duration is a particular duration after epoch. 12322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // formatter is a hour-minute-second, hour-minute, or minute-second formatter. 12332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // smallestField denotes what the smallest field is in duration: either 12342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // hour, minute, or second. 12352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // smallestAmount is the value of that smallest field. for 5:00:37.3, 12362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // smallestAmount is 37.3. This smallest field is formatted with this object's 12372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // NumberFormat instead of formatter. 12382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // appendTo is where the formatted string is appended. 12392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private StringBuilder formatNumeric( 12402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Date duration, 12412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat formatter, 12422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateFormat.Field smallestField, 12432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Number smallestAmount, 12442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller StringBuilder appendTo) { 12452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Format the smallest amount ahead of time. 12462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String smallestAmountFormatted; 12472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 12482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Format the smallest amount using this object's number format, but keep track 12492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // of the integer portion of this formatted amount. We have to replace just the 12502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // integer part with the corresponding value from formatting the date. Otherwise 12512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // when formatting 0 minutes 9 seconds, we may get "00:9" instead of "00:09" 12522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FieldPosition intFieldPosition = new FieldPosition(NumberFormat.INTEGER_FIELD); 12532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller smallestAmountFormatted = numberFormat.format( 12542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller smallestAmount, new StringBuffer(), intFieldPosition).toString(); 12552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Give up if there is no integer field. 12562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (intFieldPosition.getBeginIndex() == 0 && intFieldPosition.getEndIndex() == 0) { 12572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalStateException(); 12582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 12592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Format our duration as a date, but keep track of where the smallest field is 12602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // so that we can use it to replace the integer portion of the smallest value. 12612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FieldPosition smallestFieldPosition = new FieldPosition(smallestField); 12622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String draft = formatter.format( 12632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller duration, new StringBuffer(), smallestFieldPosition).toString(); 12642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 12652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If we find the smallest field 12662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (smallestFieldPosition.getBeginIndex() != 0 12672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller || smallestFieldPosition.getEndIndex() != 0) { 12682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // add everything up to the start of the smallest field in duration. 12692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendTo.append(draft, 0, smallestFieldPosition.getBeginIndex()); 12702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 12712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // add everything in the smallest field up to the integer portion 12722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendTo.append(smallestAmountFormatted, 0, intFieldPosition.getBeginIndex()); 12732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 12742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Add the smallest field in formatted duration in lieu of the integer portion 12752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // of smallest field 12762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendTo.append( 12772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller draft, 12782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller smallestFieldPosition.getBeginIndex(), 12792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller smallestFieldPosition.getEndIndex()); 12802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 12812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Add the rest of the smallest field 12822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendTo.append( 12832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller smallestAmountFormatted, 12842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller intFieldPosition.getEndIndex(), 12852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller smallestAmountFormatted.length()); 12862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendTo.append(draft, smallestFieldPosition.getEndIndex(), draft.length()); 12872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 12882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // As fallback, just use the formatted duration. 12892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller appendTo.append(draft); 12902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 12912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return appendTo; 12922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 12932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 12942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private Object writeReplace() throws ObjectStreamException { 12952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new MeasureProxy( 12962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getLocale(), formatWidth, numberFormat.get(), MEASURE_FORMAT); 12972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 12982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 12992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller static class MeasureProxy implements Externalizable { 13002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final long serialVersionUID = -6033308329886716770L; 13012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private ULocale locale; 13032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private FormatWidth formatWidth; 13042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private NumberFormat numberFormat; 13052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private int subClass; 13062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private HashMap<Object, Object> keyValues; 13072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public MeasureProxy( 13092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ULocale locale, 13102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FormatWidth width, 13112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NumberFormat numberFormat, 13122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int subClass) { 13132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.locale = locale; 13142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.formatWidth = width; 13152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.numberFormat = numberFormat; 13162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.subClass = subClass; 13172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this.keyValues = new HashMap<Object, Object>(); 13182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Must have public constructor, to enable Externalizable 13212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public MeasureProxy() { 13222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void writeExternal(ObjectOutput out) throws IOException { 13252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller out.writeByte(0); // version 13262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller out.writeUTF(locale.toLanguageTag()); 13272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller out.writeByte(formatWidth.ordinal()); 13282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller out.writeObject(numberFormat); 13292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller out.writeByte(subClass); 13302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller out.writeObject(keyValues); 13312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @SuppressWarnings("unchecked") 13342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 13352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller in.readByte(); // version. 13362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller locale = ULocale.forLanguageTag(in.readUTF()); 13372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller formatWidth = fromFormatWidthOrdinal(in.readByte() & 0xFF); 13382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller numberFormat = (NumberFormat) in.readObject(); 13392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (numberFormat == null) { 13402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new InvalidObjectException("Missing number format."); 13412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller subClass = in.readByte() & 0xFF; 13432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // This cast is safe because the serialized form of hashtable can have 13452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // any object as the key and any object as the value. 13462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller keyValues = (HashMap<Object, Object>) in.readObject(); 13472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (keyValues == null) { 13482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new InvalidObjectException("Missing optional values map."); 13492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private TimeUnitFormat createTimeUnitFormat() throws InvalidObjectException { 13532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int style; 13542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (formatWidth == FormatWidth.WIDE) { 13552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller style = TimeUnitFormat.FULL_NAME; 13562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if (formatWidth == FormatWidth.SHORT) { 13572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller style = TimeUnitFormat.ABBREVIATED_NAME; 13582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 13592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new InvalidObjectException("Bad width: " + formatWidth); 13602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller TimeUnitFormat result = new TimeUnitFormat(locale, style); 13622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.setNumberFormat(numberFormat); 13632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 13642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private Object readResolve() throws ObjectStreamException { 13672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller switch (subClass) { 13682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case MEASURE_FORMAT: 13692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return MeasureFormat.getInstance(locale, formatWidth, numberFormat); 13702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case TIME_UNIT_FORMAT: 13712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return createTimeUnitFormat(); 13722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller case CURRENCY_FORMAT: 13732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new CurrencyFormat(locale); 13742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller default: 13752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new InvalidObjectException("Unknown subclass: " + subClass); 13762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static FormatWidth fromFormatWidthOrdinal(int ordinal) { 13812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller FormatWidth[] values = FormatWidth.values(); 13822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (ordinal < 0 || ordinal >= values.length) { 13832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return FormatWidth.SHORT; 13842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return values[ordinal]; 13862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 13872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 138898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert private static final Map<ULocale, String> localeIdToRangeFormat = 138998d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert new ConcurrentHashMap<ULocale, String>(); 13902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 13912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 139298d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert * Return a formatter (compiled SimplePatternFormatter pattern) for a range, such as "{0}–{1}". 13932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param forLocale locale to get the format for 13942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param width the format width 13952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return range formatter, such as "{0}–{1}" 13962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @deprecated This API is ICU internal only. 139793cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * @hide original deprecated declaration 1398836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 13992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 14002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Deprecated 140198d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert public static String getRangeFormat(ULocale forLocale, FormatWidth width) { 14022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // TODO fix Hack for French 14032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (forLocale.getLanguage().equals("fr")) { 14042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return getRangeFormat(ULocale.ROOT, width); 14052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 140698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert String result = localeIdToRangeFormat.get(forLocale); 14072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (result == null) { 14082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle. 14092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller getBundleInstance(ICUData.ICU_BASE_NAME, forLocale); 14102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ULocale realLocale = rb.getULocale(); 14112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!forLocale.equals(realLocale)) { // if the child would inherit, then add a cache entry for it. 14122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result = localeIdToRangeFormat.get(forLocale); 14132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (result != null) { 14142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller localeIdToRangeFormat.put(forLocale, result); 14152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 14162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 14172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 14182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // At this point, both the forLocale and the realLocale don't have an item 14192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // So we have to make one. 14202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller NumberingSystem ns = NumberingSystem.getInstance(forLocale); 14212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 14222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String resultString = null; 14232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 14242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller resultString = rb.getStringWithFallback("NumberElements/" + ns.getName() + "/miscPatterns/range"); 14252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } catch ( MissingResourceException ex ) { 14262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller resultString = rb.getStringWithFallback("NumberElements/latn/patterns/range"); 14272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 142898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert result = SimplePatternFormatter.compileToStringMinMaxPlaceholders(resultString, new StringBuilder(), 2, 2); 14292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller localeIdToRangeFormat.put(forLocale, result); 14302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (!forLocale.equals(realLocale)) { 14312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller localeIdToRangeFormat.put(realLocale, result); 14322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 14332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 14342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 14352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 14362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller} 1437