| /** |
| * Copyright (c) 2005, 2011, Werner Keil, Ikayzo and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Werner Keil, Eric Russell - initial API and implementation |
| */ |
| package org.eclipse.uomo.units.impl.format; |
| |
| import static org.eclipse.uomo.units.SI.CUBIC_METRE; |
| import static org.eclipse.uomo.units.SI.GRAM; |
| import static org.eclipse.uomo.units.SI.KILOGRAM; |
| import static org.eclipse.uomo.units.impl.system.USCustomary.LITER; |
| |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.math.BigInteger; |
| import java.text.FieldPosition; |
| import java.text.ParsePosition; |
| import java.util.Formattable; |
| import java.util.Formatter; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.ResourceBundle; |
| |
| import org.eclipse.uomo.units.AbstractConverter; |
| import org.eclipse.uomo.units.AbstractConverter.Compound; |
| import org.eclipse.uomo.units.AbstractFormat; |
| import org.eclipse.uomo.units.AbstractUnit; |
| import org.eclipse.uomo.units.SymbolMap; |
| import org.eclipse.uomo.units.impl.AnnotatedUnit; |
| import org.eclipse.uomo.units.impl.BaseUnit; |
| import org.eclipse.uomo.units.impl.TransformedUnit; |
| import org.eclipse.uomo.units.impl.converter.AddConverter; |
| import org.eclipse.uomo.units.impl.converter.ExpConverter; |
| import org.eclipse.uomo.units.impl.converter.LogConverter; |
| import org.eclipse.uomo.units.impl.converter.MultiplyConverter; |
| import org.eclipse.uomo.units.impl.converter.RationalConverter; |
| import org.eclipse.uomo.units.Messages; |
| import org.unitsofmeasurement.unit.Unit; |
| import org.unitsofmeasurement.unit.UnitConverter; |
| |
| import com.ibm.icu.util.ULocale; |
| |
| /** |
| * <p> |
| * This class represents the local sensitive format. |
| * </p> |
| * |
| * <h3>Here is the grammar for Units in Extended Backus-Naur Form (EBNF)</h3> |
| * <p> |
| * Note that the grammar has been left-factored to be suitable for use by a |
| * top-down parser generator such as <a |
| * href="https://javacc.dev.java.net/">JavaCC</a> |
| * </p> |
| * <table width="90%" align="center"> |
| * <tr> |
| * <th colspan="3" align="left">Lexical Entities:</th> |
| * </tr> |
| * <tr valign="top"> |
| * <td><sign></td> |
| * <td>:=</td> |
| * <td>"+" | "-"</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><digit></td> |
| * <td>:=</td> |
| * <td>"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><superscript_digit></td> |
| * <td>:=</td> |
| * <td>"⁰" | "¹" | "²" | "³" | "⁴" | "⁵" | "⁶" | "⁷" | "⁸" | "⁹"</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><integer></td> |
| * <td>:=</td> |
| * <td>(<digit>)+</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><number></td> |
| * <td>:=</td> |
| * <td>(<sign>)? (<digit>)* (".")? (<digit>)+ (("e" | "E") |
| * (<sign>)? (<digit>)+)?</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><exponent></td> |
| * <td>:=</td> |
| * <td>( "^" ( <sign> )? <integer> ) <br> |
| * | ( "^(" (<sign>)? <integer> ( "/" (<sign>)? |
| * <integer> )? ")" ) <br> |
| * | ( <superscript_digit> )+</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><initial_char></td> |
| * <td>:=</td> |
| * <td>? Any Unicode character excluding the following: ASCII control & |
| * whitespace (\u0000 - \u0020), decimal digits '0'-'9', '(' |
| * (\u0028), ')' (\u0029), '*' (\u002A), '+' (\u002B), '-' |
| * (\u002D), '.' (\u002E), '/' (\u005C), ':' (\u003A), '^' |
| * (\u005E), '²' (\u00B2), '³' (\u00B3), '·' (\u00B7), '¹' |
| * (\u00B9), '⁰' (\u2070), '⁴' (\u2074), '⁵' (\u2075), '⁶' |
| * (\u2076), '⁷' (\u2077), '⁸' (\u2078), '⁹' (\u2079) ?</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><unit_identifier></td> |
| * <td>:=</td> |
| * <td><initial_char> ( <initial_char> | <digit> )*</td> |
| * </tr> |
| * <tr> |
| * <th colspan="3" align="left">Non-Terminals:</th> |
| * </tr> |
| * <tr valign="top"> |
| * <td><unit_expr></td> |
| * <td>:=</td> |
| * <td><compound_expr></td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><compound_expr></td> |
| * <td>:=</td> |
| * <td><add_expr> ( ":" <add_expr> )*</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><add_expr></td> |
| * <td>:=</td> |
| * <td>( <number> <sign> )? <mul_expr> ( <sign> |
| * <number> )?</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><mul_expr></td> |
| * <td>:=</td> |
| * <td><exponent_expr> ( ( ( "*" | "·" ) <exponent_expr> ) | ( "/" |
| * <exponent_expr> ) )*</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><exponent_expr></td> |
| * <td>:=</td> |
| * <td>( <atomic_expr> ( <exponent> )? ) <br> |
| * | (<integer> "^" <atomic_expr>) <br> |
| * | ( ( "log" ( <integer> )? ) | "ln" ) "(" <add_expr> ")" )</td> |
| * </tr> |
| * <tr valign="top"> |
| * <td><atomic_expr></td> |
| * <td>:=</td> |
| * <td><number> <br> |
| * | <unit_identifier> <br> |
| * | ( "(" <add_expr> ")" )</td> |
| * </tr> |
| * </table> |
| * |
| * @author <a href="mailto:eric-r@northwestern.edu">Eric Russell</a> |
| * @author <a href="mailto:uomo@catmedia.us">Werner Keil</a> |
| * @version 1.4.1 ($Revision: 232 $), $Date: 2010-10-13 17:13:18 +0200 (Mi, 13 Okt 2010) $ |
| */ |
| public class LocalUnitFormatImpl extends AbstractFormat { |
| |
| // //////////////////////////////////////////////////// |
| // Class variables // |
| // //////////////////////////////////////////////////// |
| /** |
| * serialVersionUID |
| */ |
| private static final long serialVersionUID = -2046025264383639924L; |
| |
| /** |
| * Name of the resource bundle |
| */ |
| private static final String BUNDLE_NAME = LocalUnitFormatImpl.class.getPackage() |
| .getName() + ".messages"; //$NON-NLS-1$ |
| |
| /** |
| * Default locale instance. If the default locale is changed after the class |
| * is initialized, this instance will no longer be used. |
| */ |
| private static final LocalUnitFormatImpl DEFAULT_INSTANCE = new LocalUnitFormatImpl( |
| new SymbolMapImpl(ResourceBundle.getBundle(BUNDLE_NAME)), Locale.getDefault()); |
| |
| /** Multiplicand character */ |
| private static final char MIDDLE_DOT = '\u00b7'; //$NON-NLS-1$ |
| |
| /** Exponent 1 character */ |
| private static final char EXPONENT_1 = '\u00b9'; //$NON-NLS-1$ |
| |
| /** Exponent 2 character */ |
| private static final char EXPONENT_2 = '\u00b2'; //$NON-NLS-1$ |
| |
| /** Operator precedence for the addition and subtraction operations */ |
| private static final int ADDITION_PRECEDENCE = 0; |
| |
| /** Operator precedence for the multiplication and division operations */ |
| private static final int PRODUCT_PRECEDENCE = ADDITION_PRECEDENCE + 2; |
| |
| /** Operator precedence for the exponentiation and logarithm operations */ |
| private static final int EXPONENT_PRECEDENCE = PRODUCT_PRECEDENCE + 2; |
| |
| |
| |
| /** |
| * Operator precedence for a unit identifier containing no mathematical |
| * operations (i.e., consisting exclusively of an identifier and possibly a |
| * prefix). Defined to be <code>Integer.MAX_VALUE</code> so that no operator |
| * can have a higher precedence. |
| */ |
| private static final int NOOP_PRECEDENCE = Integer.MAX_VALUE; |
| |
| private final ULocale uLocale; |
| |
| // ///////////////// |
| // Class methods // |
| // ///////////////// |
| /** |
| * Returns the instance for the current default locale (non-ascii characters |
| * are allowed) |
| */ |
| public static LocalUnitFormatImpl getInstance() { |
| return DEFAULT_INSTANCE; |
| } |
| |
| /** |
| * Returns an instance for the given locale. |
| * |
| * @param locale |
| */ |
| public static LocalUnitFormatImpl getInstance(Locale locale) { |
| return new LocalUnitFormatImpl(new SymbolMapImpl(ResourceBundle.getBundle( |
| BUNDLE_NAME, locale)), locale); |
| } |
| |
| /** Returns an instance for the given symbol map. */ |
| protected static LocalUnitFormatImpl getInstance(SymbolMapImpl symbols, Locale locale) { |
| return new LocalUnitFormatImpl(symbols, locale); |
| } |
| |
| // ////////////////////// |
| // Instance variables // |
| // ////////////////////// |
| /** |
| * The symbol map used by this instance to map between |
| * {@link org.unitsofmeasure.Unit Unit}s and <code>String</code>s, etc... |
| */ |
| private transient SymbolMapImpl symbolMap; |
| |
| // //////////////// |
| // Constructors // |
| // //////////////// |
| /** |
| * Base constructor. |
| * |
| */ |
| public LocalUnitFormatImpl() { |
| this(new SymbolMapImpl(ResourceBundle.getBundle( |
| BUNDLE_NAME, Locale.getDefault())), Locale.getDefault()); |
| } |
| |
| /** |
| * Private constructor. |
| * |
| * @param symbols |
| * the symbol mapping. |
| */ |
| private LocalUnitFormatImpl(SymbolMapImpl symbols, Locale loc) { |
| symbolMap = symbols; |
| uLocale = ULocale.forLocale(loc); |
| } |
| |
| // ////////////////////// |
| // Instance methods // |
| // ////////////////////// |
| /** |
| * Get the symbol map used by this instance to map between |
| * {@link org.unitsofmeasure.Unit Unit}s and <code>String</code>s, etc... |
| * |
| * @return SymbolMap the current symbol map |
| */ |
| public SymbolMap getSymbolMap() { |
| return symbolMap; |
| } |
| |
| // ////////////// |
| // Formatting // |
| // ////////////// |
| public Appendable format(Unit<?> unit, Appendable appendable) |
| throws IOException { |
| formatInternal(unit, appendable); |
| if (unit instanceof AnnotatedUnit<?>) { |
| AnnotatedUnit<?> annotatedUnit = (AnnotatedUnit<?>) unit; |
| if (annotatedUnit.getAnnotation() != null) { |
| appendable.append('{'); |
| appendable.append(annotatedUnit.getAnnotation()); |
| appendable.append('}'); |
| } |
| } |
| return appendable; |
| } |
| |
| public Unit<?> parse(CharSequence csq, ParsePosition cursor) |
| throws IllegalArgumentException { |
| // Parsing reads the whole character sequence from the parse position. |
| int start = cursor != null ? cursor.getIndex() : 0; |
| int end = csq.length(); |
| if (end <= start) { |
| return AbstractUnit.ONE; |
| } |
| String source = csq.subSequence(start, end).toString().trim(); |
| if (source.length() == 0) { |
| return AbstractUnit.ONE; |
| } |
| try { |
| UnitParser parser = new UnitParser(symbolMap, new StringReader( |
| source)); |
| Unit<?> result = parser.parseUnit(); |
| if (cursor != null) |
| cursor.setIndex(end); |
| return result; |
| } catch (ParseException e) { |
| if (cursor != null) { |
| if (e.currentToken != null) { |
| cursor.setErrorIndex(start + e.currentToken.endColumn); |
| } else { |
| cursor.setErrorIndex(start); |
| } |
| } |
| throw new IllegalArgumentException(e.getMessage()); |
| } catch (TokenMgrError e) { |
| cursor.setErrorIndex(start); |
| throw new IllegalArgumentException(e.getMessage()); |
| } |
| } |
| |
| /** |
| * Format the given unit to the given StringBuffer, then return the operator |
| * precedence of the outermost operator in the unit expression that was |
| * formatted. See {@link ConverterFormat} for the constants that define the |
| * various precedence values. |
| * |
| * @param unit |
| * the unit to be formatted |
| * @param buffer |
| * the <code>StringBuffer</code> to be written to |
| * @return the operator precedence of the outermost operator in the unit |
| * expression that was output |
| */ |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| private int formatInternal(Unit<?> unit, Appendable buffer) |
| throws IOException { |
| if (unit instanceof AnnotatedUnit<?>) { |
| unit = ((AnnotatedUnit<?>) unit).getActualUnit(); |
| // } else if (unit instanceof ProductUnit<?>) { |
| // ProductUnit<?> p = (ProductUnit<?>)unit; |
| } |
| String symbol = symbolMap.getSymbol(unit); |
| if (symbol != null) { |
| buffer.append(symbol); |
| return NOOP_PRECEDENCE; |
| } else if (unit.getProductUnits() != null) { |
| Map<Unit<?>, Integer> productUnits = (Map<Unit<?>, Integer>) unit.getProductUnits(); |
| int negativeExponentCount = 0; |
| // Write positive exponents first... |
| boolean start = true; |
| for (Map.Entry<Unit<?>, Integer> e : productUnits.entrySet()) { |
| int pow = e.getValue(); |
| if (pow >= 0) { |
| formatExponent(e.getKey(), pow, 1, !start, buffer); |
| start = false; |
| } else { |
| negativeExponentCount += 1; |
| } |
| } |
| // ..then write negative exponents. |
| if (negativeExponentCount > 0) { |
| if (start) { |
| buffer.append('1'); |
| } |
| buffer.append('/'); |
| if (negativeExponentCount > 1) { |
| buffer.append('('); |
| } |
| start = true; |
| for (Map.Entry<Unit<?>, Integer> e : productUnits.entrySet()) { |
| int pow = e.getValue(); |
| if (pow < 0) { |
| formatExponent(e.getKey(), -pow, 1, !start, buffer); |
| start = false; |
| } |
| } |
| if (negativeExponentCount > 1) { |
| buffer.append(')'); |
| } |
| } |
| return PRODUCT_PRECEDENCE; |
| } else if (unit instanceof BaseUnit<?>) { |
| buffer.append(((BaseUnit<?>) unit).getSymbol()); |
| return NOOP_PRECEDENCE; |
| } else if (unit.getSymbol() != null) { // Alternate unit. |
| buffer.append(unit.getSymbol()); |
| return NOOP_PRECEDENCE; |
| } else { // A transformed unit or new unit type! |
| UnitConverter converter = null; |
| boolean printSeparator = false; |
| StringBuilder temp = new StringBuilder(); |
| int unitPrecedence = NOOP_PRECEDENCE; |
| Unit<?> parentUnit = unit.getSystemUnit(); |
| converter = ((AbstractUnit<?>) unit).getConverterToMetric(); |
| if (KILOGRAM.equals(parentUnit)) { |
| // More special-case hackery to work around gram/kilogram |
| // incosistency |
| if (unit.equals(GRAM)) { |
| buffer.append(symbolMap.getSymbol(GRAM)); |
| return NOOP_PRECEDENCE; |
| } |
| parentUnit = GRAM; |
| if (unit instanceof TransformedUnit<?>) { |
| converter = ((TransformedUnit<?>) unit).toParentUnit(); |
| } else { |
| converter = unit.getConverterTo((Unit) GRAM); |
| } |
| } else if (CUBIC_METRE.equals(parentUnit)) { |
| if (converter != null) { |
| parentUnit = LITER; |
| } |
| } |
| |
| if (unit instanceof TransformedUnit) { |
| TransformedUnit transUnit = (TransformedUnit) unit; |
| if (parentUnit== null) parentUnit = transUnit.getParentUnit(); |
| // String x = parentUnit.toString(); |
| converter = transUnit.toParentUnit(); |
| } |
| |
| unitPrecedence = formatInternal(parentUnit, temp); |
| printSeparator = !parentUnit.equals(AbstractUnit.ONE); |
| int result = formatConverter(converter, printSeparator, |
| unitPrecedence, temp); |
| buffer.append(temp); |
| return result; |
| } |
| } |
| |
| /** |
| * Format the given unit raised to the given fractional power to the given |
| * <code>StringBuffer</code>. |
| * |
| * @param unit |
| * Unit the unit to be formatted |
| * @param pow |
| * int the numerator of the fractional power |
| * @param root |
| * int the denominator of the fractional power |
| * @param continued |
| * boolean <code>true</code> if the converter expression should |
| * begin with an operator, otherwise <code>false</code>. This |
| * will always be true unless the unit being modified is equal to |
| * Unit.ONE. |
| * @param buffer |
| * StringBuffer the buffer to append to. No assumptions should be |
| * made about its content. |
| */ |
| private void formatExponent(Unit<?> unit, int pow, int root, |
| boolean continued, Appendable buffer) throws IOException { |
| if (continued) { |
| buffer.append(MIDDLE_DOT); |
| } |
| StringBuilder temp = new StringBuilder(); |
| int unitPrecedence = formatInternal(unit, temp); |
| |
| if (unitPrecedence < PRODUCT_PRECEDENCE) { |
| temp.insert(0, '('); //$NON-NLS-1$ |
| temp.append(')'); //$NON-NLS-1$ |
| } |
| buffer.append(temp); |
| if ((root == 1) && (pow == 1)) { |
| // do nothing |
| } else if ((root == 1) && (pow > 1)) { |
| String powStr = Integer.toString(pow); |
| for (int i = 0; i < powStr.length(); i += 1) { |
| char c = powStr.charAt(i); |
| switch (c) { |
| case '0': |
| buffer.append('\u2070'); //$NON-NLS-1$ |
| break; |
| case '1': |
| buffer.append(EXPONENT_1); //$NON-NLS-1$ |
| break; |
| case '2': |
| buffer.append(EXPONENT_2); |
| break; |
| case '3': |
| buffer.append('\u00b3'); //$NON-NLS-1$ |
| break; |
| case '4': |
| buffer.append('\u2074'); //$NON-NLS-1$ |
| break; |
| case '5': |
| buffer.append('\u2075'); //$NON-NLS-1$ |
| break; |
| case '6': |
| buffer.append('\u2076'); //$NON-NLS-1$ |
| break; |
| case '7': |
| buffer.append('\u2077'); //$NON-NLS-1$ |
| break; |
| case '8': |
| buffer.append('\u2078'); //$NON-NLS-1$ |
| break; |
| case '9': |
| buffer.append('\u2079'); //$NON-NLS-1$ |
| break; |
| } |
| } |
| } else if (root == 1) { |
| buffer.append('^'); //$NON-NLS-1$ |
| buffer.append(String.valueOf(pow)); |
| } else { |
| buffer.append("^("); //$NON-NLS-1$ |
| buffer.append(String.valueOf(pow)); |
| buffer.append('/'); //$NON-NLS-1$ |
| buffer.append(String.valueOf(root)); |
| buffer.append(')'); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Formats the given converter to the given StringBuilder and returns the |
| * operator precedence of the converter's mathematical operation. This is |
| * the default implementation, which supports all built-in UnitConverter |
| * implementations. Note that it recursively calls itself in the case of a |
| * {@link org.eclipse.uomo.units.internal.AbstractConverter.converter.UnitConverter.Compound |
| * Compound} converter. |
| * |
| * @param converter |
| * the converter to be formatted |
| * @param continued |
| * <code>true</code> if the converter expression should begin |
| * with an operator, otherwise <code>false</code>. |
| * @param unitPrecedence |
| * the operator precedence of the operation expressed by the unit |
| * being modified by the given converter. |
| * @param buffer |
| * the <code>StringBuffer</code> to append to. |
| * @return the operator precedence of the given UnitConverter |
| */ |
| private int formatConverter(UnitConverter converter, boolean continued, |
| int unitPrecedence, StringBuilder buffer) { |
| ParsePrefix prefix = symbolMap |
| .getPrefixObject((AbstractConverter) converter); |
| if ((prefix != null) && (unitPrecedence == NOOP_PRECEDENCE)) { |
| buffer.insert(0, symbolMap.getSymbol(prefix)); |
| return NOOP_PRECEDENCE; |
| } else if (converter instanceof AddConverter) { |
| if (unitPrecedence < ADDITION_PRECEDENCE) { |
| buffer.insert(0, '('); |
| buffer.append(')'); |
| } |
| double offset = ((AddConverter) converter).getOffset(); |
| if (offset < 0) { |
| buffer.append("-"); //$NON-NLS-1$ |
| offset = -offset; |
| } else if (continued) { |
| buffer.append("+"); //$NON-NLS-1$ |
| } |
| long lOffset = (long) offset; |
| if (lOffset == offset) { |
| buffer.append(lOffset); |
| } else { |
| buffer.append(offset); |
| } |
| return ADDITION_PRECEDENCE; |
| } else if (converter instanceof LogConverter) { |
| double base = ((LogConverter) converter).getBase(); |
| StringBuffer expr = new StringBuffer(); |
| if (base == StrictMath.E) { |
| expr.append("ln"); //$NON-NLS-1$ |
| } else { |
| expr.append("log"); //$NON-NLS-1$ |
| if (base != 10) { |
| expr.append((int) base); |
| } |
| } |
| expr.append("("); //$NON-NLS-1$ |
| buffer.insert(0, expr); |
| buffer.append(")"); //$NON-NLS-1$ |
| return EXPONENT_PRECEDENCE; |
| } else if (converter instanceof ExpConverter) { |
| if (unitPrecedence < EXPONENT_PRECEDENCE) { |
| buffer.insert(0, '('); |
| buffer.append(')'); |
| } |
| StringBuffer expr = new StringBuffer(); |
| double base = ((ExpConverter) converter).getBase(); |
| if (base == StrictMath.E) { |
| expr.append('e'); |
| } else { |
| expr.append((int) base); |
| } |
| expr.append('^'); |
| buffer.insert(0, expr); |
| return EXPONENT_PRECEDENCE; |
| } else if (converter instanceof MultiplyConverter) { |
| if (unitPrecedence < PRODUCT_PRECEDENCE) { |
| buffer.insert(0, '('); |
| buffer.append(')'); |
| } |
| if (continued) { |
| buffer.append(MIDDLE_DOT); |
| } |
| double factor = ((MultiplyConverter) converter).getFactor(); |
| long lFactor = (long) factor; |
| if (lFactor == factor) { |
| buffer.append(lFactor); |
| } else { |
| buffer.append(factor); |
| } |
| return PRODUCT_PRECEDENCE; |
| } else if (converter instanceof RationalConverter) { |
| if (unitPrecedence < PRODUCT_PRECEDENCE) { |
| buffer.insert(0, '('); |
| buffer.append(')'); |
| } |
| RationalConverter rationalConverter = (RationalConverter) converter; |
| if (!rationalConverter.getDividend().equals(BigInteger.ONE)) { |
| if (continued) { |
| buffer.append(MIDDLE_DOT); |
| } |
| buffer.append(rationalConverter.getDividend()); |
| } |
| if (!rationalConverter.getDivisor().equals(BigInteger.ONE)) { |
| buffer.append('/'); |
| buffer.append(rationalConverter.getDivisor()); |
| } |
| return PRODUCT_PRECEDENCE; |
| } else if (converter instanceof AbstractConverter.Compound) { |
| AbstractConverter.Compound compound = (Compound) converter; |
| if (compound.getLeft() == AbstractConverter.IDENTITY) { |
| return formatConverter(compound.getRight(), true, |
| unitPrecedence, buffer); |
| } else { |
| if (compound.getLeft() instanceof Formattable) { |
| return formatFormattable((Formattable)compound.getLeft(), unitPrecedence, buffer); |
| } else if (compound.getRight() instanceof Formattable) { |
| return formatFormattable((Formattable)compound.getRight(), unitPrecedence, buffer); |
| } else { |
| return formatConverter(compound.getLeft(), true, |
| unitPrecedence, buffer); |
| // FIXME use getRight() here, too |
| } |
| } |
| // return formatConverter(compound.getRight(), true, |
| // unitPrecedence, buffer); |
| |
| } else { |
| if (converter != null) { |
| // throw new IllegalArgumentException( |
| // "Unable to format the given UnitConverter: " + converter.getClass()); //$NON-NLS-1$ |
| buffer.replace(0, 1, converter.toString()); |
| return NOOP_PRECEDENCE; |
| } else |
| throw new IllegalArgumentException( |
| "Unable to format, no UnitConverter given"); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Formats the given <code>Formattable</code> to the given StringBuffer and returns the |
| * given precedence of the converter's mathematical operation. |
| * |
| * @param f |
| * the formattable to be formatted |
| * @param unitPrecedence |
| * the operator precedence of the operation expressed by the unit |
| * being modified by the given converter. |
| * @param buffer |
| * the <code>StringBuffer</code> to append to. |
| * @return the given operator precedence |
| */ |
| private int formatFormattable(Formattable f, int unitPrecedence, StringBuilder buffer) { |
| Formatter fmt = new Formatter(); |
| fmt.format(Messages.LocalFormat_Pattern, f); |
| buffer.replace(0, 1, fmt.toString()); |
| fmt.close(); // XXX try Java 7 with res, but for now let's leave J6 compliant |
| return unitPrecedence; |
| } |
| |
| /** |
| * Override Format.format(). |
| * |
| * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, |
| * java.text.FieldPosition) |
| */ |
| @Override |
| public StringBuffer format(Object obj, StringBuffer toAppendTo, |
| FieldPosition pos) { |
| try { |
| Unit<?> unit = (Unit<?>) obj; |
| // fmt.setCurrency(currency.getCurrency()); |
| return (StringBuffer) format(unit, toAppendTo); |
| } catch (IOException ie) { |
| throw new IllegalArgumentException( |
| "Invalid type: " + obj.getClass().getName()); //$NON-NLS-1$ |
| } catch (ClassCastException e) { |
| throw new IllegalArgumentException( |
| "Invalid type: " + obj.getClass().getName()); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Override Format.parseObject(). |
| * |
| * @see java.text.Format#parseObject(java.lang.String, |
| * java.text.ParsePosition) |
| */ |
| public Object parseObject(String source, ParsePosition pos) { |
| return parse(source, pos); |
| } |
| |
| public ULocale getLocale() { |
| return uLocale; |
| } |
| } |