Index: icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java |
=================================================================== |
--- icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java (revision 40724) |
+++ icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java (working copy) |
@@ -5,9 +5,8 @@ |
import java.math.BigDecimal; |
import java.math.MathContext; |
-import com.ibm.icu.impl.StandardPlural; |
import com.ibm.icu.impl.number.AffixPatternProvider; |
-import com.ibm.icu.impl.number.AffixUtils; |
+import com.ibm.icu.impl.number.CurrencyPluralInfoAffixProvider; |
import com.ibm.icu.impl.number.CustomSymbolCurrency; |
import com.ibm.icu.impl.number.DecimalFormatProperties; |
import com.ibm.icu.impl.number.MacroProps; |
@@ -14,7 +13,7 @@ |
import com.ibm.icu.impl.number.MultiplierImpl; |
import com.ibm.icu.impl.number.Padder; |
import com.ibm.icu.impl.number.PatternStringParser; |
-import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo; |
+import com.ibm.icu.impl.number.PropertiesAffixPatternProvider; |
import com.ibm.icu.impl.number.RoundingUtils; |
import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay; |
import com.ibm.icu.number.NumberFormatter.SignDisplay; |
@@ -22,7 +21,6 @@ |
import com.ibm.icu.number.Rounder.IncrementRounderImpl; |
import com.ibm.icu.number.Rounder.SignificantRounderImpl; |
import com.ibm.icu.text.CompactDecimalFormat.CompactStyle; |
-import com.ibm.icu.text.CurrencyPluralInfo; |
import com.ibm.icu.text.DecimalFormatSymbols; |
import com.ibm.icu.util.Currency; |
import com.ibm.icu.util.Currency.CurrencyUsage; |
@@ -30,20 +28,22 @@ |
/** |
* <p> |
- * This class, as well as NumberFormatterImpl, could go into the impl package, but they depend on too many |
- * package-private members of the public APIs. |
+ * This class, as well as NumberFormatterImpl, could go into the impl package, but they depend on too |
+ * many package-private members of the public APIs. |
*/ |
final class NumberPropertyMapper { |
/** Convenience method to create a NumberFormatter directly from Properties. */ |
- public static UnlocalizedNumberFormatter create(DecimalFormatProperties properties, DecimalFormatSymbols symbols) { |
+ public static UnlocalizedNumberFormatter create( |
+ DecimalFormatProperties properties, |
+ DecimalFormatSymbols symbols) { |
MacroProps macros = oldToNew(properties, symbols, null); |
return NumberFormatter.with().macros(macros); |
} |
/** |
- * Convenience method to create a NumberFormatter directly from a pattern string. Something like this could become |
- * public API if there is demand. |
+ * Convenience method to create a NumberFormatter directly from a pattern string. Something like this |
+ * could become public API if there is demand. |
*/ |
public static UnlocalizedNumberFormatter create(String pattern, DecimalFormatSymbols symbols) { |
DecimalFormatProperties properties = PatternStringParser.parseToProperties(pattern); |
@@ -51,9 +51,9 @@ |
} |
/** |
- * Creates a new {@link MacroProps} object based on the content of a {@link DecimalFormatProperties} object. In |
- * other words, maps Properties to MacroProps. This function is used by the JDK-compatibility API to call into the |
- * ICU 60 fluent number formatting pipeline. |
+ * Creates a new {@link MacroProps} object based on the content of a {@link DecimalFormatProperties} |
+ * object. In other words, maps Properties to MacroProps. This function is used by the |
+ * JDK-compatibility API to call into the ICU 60 fluent number formatting pipeline. |
* |
* @param properties |
* The property bag to be mapped. |
@@ -60,10 +60,13 @@ |
* @param symbols |
* The symbols associated with the property bag. |
* @param exportedProperties |
- * A property bag in which to store validated properties. |
+ * A property bag in which to store validated properties. Used by some DecimalFormat |
+ * getters. |
* @return A new MacroProps containing all of the information in the Properties. |
*/ |
- public static MacroProps oldToNew(DecimalFormatProperties properties, DecimalFormatSymbols symbols, |
+ public static MacroProps oldToNew( |
+ DecimalFormatProperties properties, |
+ DecimalFormatSymbols symbols, |
DecimalFormatProperties exportedProperties) { |
MacroProps macros = new MacroProps(); |
ULocale locale = symbols.getULocale(); |
@@ -96,8 +99,10 @@ |
// UNITS // |
/////////// |
- boolean useCurrency = ((properties.getCurrency() != null) || properties.getCurrencyPluralInfo() != null |
- || properties.getCurrencyUsage() != null || affixProvider.hasCurrencySign()); |
+ boolean useCurrency = ((properties.getCurrency() != null) |
+ || properties.getCurrencyPluralInfo() != null |
+ || properties.getCurrencyUsage() != null |
+ || affixProvider.hasCurrencySign()); |
Currency currency = CustomSymbolCurrency.resolve(properties.getCurrency(), locale, symbols); |
CurrencyUsage currencyUsage = properties.getCurrencyUsage(); |
boolean explicitCurrencyUsage = currencyUsage != null; |
@@ -122,7 +127,8 @@ |
MathContext mathContext = RoundingUtils.getMathContextOrUnlimited(properties); |
boolean explicitMinMaxFrac = minFrac != -1 || maxFrac != -1; |
boolean explicitMinMaxSig = minSig != -1 || maxSig != -1; |
- // Resolve min/max frac for currencies, required for the validation logic and for when minFrac or maxFrac was |
+ // Resolve min/max frac for currencies, required for the validation logic and for when minFrac or |
+ // maxFrac was |
// set (but not both) on a currency instance. |
// NOTE: Increments are handled in "Rounder.constructCurrency()". |
if (useCurrency) { |
@@ -151,7 +157,8 @@ |
minFrac = minFrac < 0 ? 0 : minFrac; |
maxFrac = maxFrac < 0 ? Integer.MAX_VALUE : maxFrac < minFrac ? minFrac : maxFrac; |
minInt = minInt <= 0 ? 1 : minInt > RoundingUtils.MAX_INT_FRAC_SIG ? 1 : minInt; |
- maxInt = maxInt < 0 ? -1 : maxInt < minInt ? minInt : maxInt > RoundingUtils.MAX_INT_FRAC_SIG ? -1 : maxInt; |
+ maxInt = maxInt < 0 ? -1 |
+ : maxInt < minInt ? minInt : maxInt > RoundingUtils.MAX_INT_FRAC_SIG ? -1 : maxInt; |
} |
Rounder rounding = null; |
if (explicitCurrencyUsage) { |
@@ -159,10 +166,12 @@ |
} else if (roundingIncrement != null) { |
rounding = Rounder.constructIncrement(roundingIncrement); |
} else if (explicitMinMaxSig) { |
- minSig = minSig < 1 ? 1 : minSig > RoundingUtils.MAX_INT_FRAC_SIG ? RoundingUtils.MAX_INT_FRAC_SIG : minSig; |
+ minSig = minSig < 1 ? 1 |
+ : minSig > RoundingUtils.MAX_INT_FRAC_SIG ? RoundingUtils.MAX_INT_FRAC_SIG : minSig; |
maxSig = maxSig < 0 ? RoundingUtils.MAX_INT_FRAC_SIG |
: maxSig < minSig ? minSig |
- : maxSig > RoundingUtils.MAX_INT_FRAC_SIG ? RoundingUtils.MAX_INT_FRAC_SIG : maxSig; |
+ : maxSig > RoundingUtils.MAX_INT_FRAC_SIG ? RoundingUtils.MAX_INT_FRAC_SIG |
+ : maxSig; |
rounding = Rounder.constructSignificant(minSig, maxSig); |
} else if (explicitMinMaxFrac) { |
rounding = Rounder.constructFraction(minFrac, maxFrac); |
@@ -184,14 +193,7 @@ |
// GROUPING STRATEGY // |
/////////////////////// |
- int grouping1 = properties.getGroupingSize(); |
- int grouping2 = properties.getSecondaryGroupingSize(); |
- int minGrouping = properties.getMinimumGroupingDigits(); |
- assert grouping1 >= -2; // value of -2 means to forward no grouping information |
- grouping1 = grouping1 > 0 ? grouping1 : grouping2 > 0 ? grouping2 : grouping1; |
- grouping2 = grouping2 > 0 ? grouping2 : grouping1; |
- // TODO: Is it important to handle minGrouping > 2? |
- macros.grouper = Grouper.getInstance((byte) grouping1, (byte) grouping2, minGrouping == 2); |
+ macros.grouper = Grouper.defaults().withProperties(properties); |
///////////// |
// PADDING // |
@@ -198,7 +200,8 @@ |
///////////// |
if (properties.getFormatWidth() != -1) { |
- macros.padder = new Padder(properties.getPadString(), properties.getFormatWidth(), |
+ macros.padder = new Padder(properties.getPadString(), |
+ properties.getFormatWidth(), |
properties.getPadPosition()); |
} |
@@ -246,7 +249,8 @@ |
// Scientific notation also involves overriding the rounding mode. |
// TODO: Overriding here is a bit of a hack. Should this logic go earlier? |
if (macros.rounder instanceof FractionRounder) { |
- // For the purposes of rounding, get the original min/max int/frac, since the local variables |
+ // For the purposes of rounding, get the original min/max int/frac, since the local |
+ // variables |
// have been manipulated for display purposes. |
int minInt_ = properties.getMinimumIntegerDigits(); |
int minFrac_ = properties.getMinimumFractionDigits(); |
@@ -334,178 +338,4 @@ |
return macros; |
} |
- |
- private static class PropertiesAffixPatternProvider implements AffixPatternProvider { |
- private final String posPrefix; |
- private final String posSuffix; |
- private final String negPrefix; |
- private final String negSuffix; |
- |
- public PropertiesAffixPatternProvider(DecimalFormatProperties properties) { |
- // There are two ways to set affixes in DecimalFormat: via the pattern string (applyPattern), and via the |
- // explicit setters (setPositivePrefix and friends). The way to resolve the settings is as follows: |
- // |
- // 1) If the explicit setting is present for the field, use it. |
- // 2) Otherwise, follows UTS 35 rules based on the pattern string. |
- // |
- // Importantly, the explicit setters affect only the one field they override. If you set the positive |
- // prefix, that should not affect the negative prefix. Since it is impossible for the user of this class |
- // to know whether the origin for a string was the override or the pattern, we have to say that we always |
- // have a negative subpattern and perform all resolution logic here. |
- |
- // Convenience: Extract the properties into local variables. |
- // Variables are named with three chars: [p/n][p/s][o/p] |
- // [p/n] => p for positive, n for negative |
- // [p/s] => p for prefix, s for suffix |
- // [o/p] => o for escaped custom override string, p for pattern string |
- String ppo = AffixUtils.escape(properties.getPositivePrefix()); |
- String pso = AffixUtils.escape(properties.getPositiveSuffix()); |
- String npo = AffixUtils.escape(properties.getNegativePrefix()); |
- String nso = AffixUtils.escape(properties.getNegativeSuffix()); |
- String ppp = properties.getPositivePrefixPattern(); |
- String psp = properties.getPositiveSuffixPattern(); |
- String npp = properties.getNegativePrefixPattern(); |
- String nsp = properties.getNegativeSuffixPattern(); |
- |
- if (ppo != null) { |
- posPrefix = ppo; |
- } else if (ppp != null) { |
- posPrefix = ppp; |
- } else { |
- // UTS 35: Default positive prefix is empty string. |
- posPrefix = ""; |
- } |
- |
- if (pso != null) { |
- posSuffix = pso; |
- } else if (psp != null) { |
- posSuffix = psp; |
- } else { |
- // UTS 35: Default positive suffix is empty string. |
- posSuffix = ""; |
- } |
- |
- if (npo != null) { |
- negPrefix = npo; |
- } else if (npp != null) { |
- negPrefix = npp; |
- } else { |
- // UTS 35: Default negative prefix is "-" with positive prefix. |
- // Important: We prepend the "-" to the pattern, not the override! |
- negPrefix = ppp == null ? "-" : "-" + ppp; |
- } |
- |
- if (nso != null) { |
- negSuffix = nso; |
- } else if (nsp != null) { |
- negSuffix = nsp; |
- } else { |
- // UTS 35: Default negative prefix is the positive prefix. |
- negSuffix = psp == null ? "" : psp; |
- } |
- } |
- |
- @Override |
- public char charAt(int flags, int i) { |
- return getStringForFlags(flags).charAt(i); |
- } |
- |
- @Override |
- public int length(int flags) { |
- return getStringForFlags(flags).length(); |
- } |
- |
- private String getStringForFlags(int flags) { |
- boolean prefix = (flags & Flags.PREFIX) != 0; |
- boolean negative = (flags & Flags.NEGATIVE_SUBPATTERN) != 0; |
- if (prefix && negative) { |
- return negPrefix; |
- } else if (prefix) { |
- return posPrefix; |
- } else if (negative) { |
- return negSuffix; |
- } else { |
- return posSuffix; |
- } |
- } |
- |
- @Override |
- public boolean positiveHasPlusSign() { |
- return AffixUtils.containsType(posPrefix, AffixUtils.TYPE_PLUS_SIGN) |
- || AffixUtils.containsType(posSuffix, AffixUtils.TYPE_PLUS_SIGN); |
- } |
- |
- @Override |
- public boolean hasNegativeSubpattern() { |
- // See comments in the constructor for more information on why this is always true. |
- return true; |
- } |
- |
- @Override |
- public boolean negativeHasMinusSign() { |
- return AffixUtils.containsType(negPrefix, AffixUtils.TYPE_MINUS_SIGN) |
- || AffixUtils.containsType(negSuffix, AffixUtils.TYPE_MINUS_SIGN); |
- } |
- |
- @Override |
- public boolean hasCurrencySign() { |
- return AffixUtils.hasCurrencySymbols(posPrefix) || AffixUtils.hasCurrencySymbols(posSuffix) |
- || AffixUtils.hasCurrencySymbols(negPrefix) || AffixUtils.hasCurrencySymbols(negSuffix); |
- } |
- |
- @Override |
- public boolean containsSymbolType(int type) { |
- return AffixUtils.containsType(posPrefix, type) || AffixUtils.containsType(posSuffix, type) |
- || AffixUtils.containsType(negPrefix, type) || AffixUtils.containsType(negSuffix, type); |
- } |
- } |
- |
- private static class CurrencyPluralInfoAffixProvider implements AffixPatternProvider { |
- private final AffixPatternProvider[] affixesByPlural; |
- |
- public CurrencyPluralInfoAffixProvider(CurrencyPluralInfo cpi) { |
- affixesByPlural = new ParsedPatternInfo[StandardPlural.COUNT]; |
- for (StandardPlural plural : StandardPlural.VALUES) { |
- affixesByPlural[plural.ordinal()] = PatternStringParser |
- .parseToPatternInfo(cpi.getCurrencyPluralPattern(plural.getKeyword())); |
- } |
- } |
- |
- @Override |
- public char charAt(int flags, int i) { |
- int pluralOrdinal = (flags & Flags.PLURAL_MASK); |
- return affixesByPlural[pluralOrdinal].charAt(flags, i); |
- } |
- |
- @Override |
- public int length(int flags) { |
- int pluralOrdinal = (flags & Flags.PLURAL_MASK); |
- return affixesByPlural[pluralOrdinal].length(flags); |
- } |
- |
- @Override |
- public boolean positiveHasPlusSign() { |
- return affixesByPlural[StandardPlural.OTHER.ordinal()].positiveHasPlusSign(); |
- } |
- |
- @Override |
- public boolean hasNegativeSubpattern() { |
- return affixesByPlural[StandardPlural.OTHER.ordinal()].hasNegativeSubpattern(); |
- } |
- |
- @Override |
- public boolean negativeHasMinusSign() { |
- return affixesByPlural[StandardPlural.OTHER.ordinal()].negativeHasMinusSign(); |
- } |
- |
- @Override |
- public boolean hasCurrencySign() { |
- return affixesByPlural[StandardPlural.OTHER.ordinal()].hasCurrencySign(); |
- } |
- |
- @Override |
- public boolean containsSymbolType(int type) { |
- return affixesByPlural[StandardPlural.OTHER.ordinal()].containsSymbolType(type); |
- } |
- } |
} |