/** | |
* 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.impl.system.SI.CUBIC_METRE; | |
import static org.eclipse.uomo.units.impl.system.SI.GRAM; | |
import static org.eclipse.uomo.units.impl.system.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.AbstractUnitFormat; | |
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 javax.measure.Unit; | |
import javax.measure.UnitConverter; | |
import java.util.Locale; | |
/** | |
* <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 LocalUnitFormat extends AbstractUnitFormat { | |
// //////////////////////////////////////////////////// | |
// Class variables // | |
// //////////////////////////////////////////////////// | |
/** | |
* serialVersionUID | |
*/ | |
private static final long serialVersionUID = -2046025264383639924L; | |
/** | |
* Name of the resource bundle | |
*/ | |
private static final String BUNDLE_NAME = LocalUnitFormat.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 LocalUnitFormat DEFAULT_INSTANCE = new LocalUnitFormat( | |
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 Locale uLocale; | |
// ///////////////// | |
// Class methods // | |
// ///////////////// | |
/** | |
* Returns the instance for the current default locale (non-ascii characters | |
* are allowed) | |
*/ | |
public static LocalUnitFormat getInstance() { | |
return DEFAULT_INSTANCE; | |
} | |
/** | |
* Returns an instance for the given locale. | |
* | |
* @param locale | |
*/ | |
public static LocalUnitFormat getInstance(Locale locale) { | |
return new LocalUnitFormat(new SymbolMapImpl(ResourceBundle.getBundle( | |
BUNDLE_NAME, locale)), locale); | |
} | |
/** Returns an instance for the given symbol map. */ | |
protected static LocalUnitFormat getInstance(SymbolMapImpl symbols, Locale locale) { | |
return new LocalUnitFormat(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 LocalUnitFormat() { | |
this(new SymbolMapImpl(ResourceBundle.getBundle( | |
BUNDLE_NAME, Locale.getDefault())), Locale.getDefault()); | |
} | |
/** | |
* Private constructor. | |
* | |
* @param symbols | |
* the symbol mapping. | |
*/ | |
private LocalUnitFormat(SymbolMapImpl symbols, Locale loc) { | |
symbolMap = symbols; | |
uLocale = 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()); | |
} | |
} | |
public Unit<?> parse(CharSequence csq) { | |
return parse(csq, new ParsePosition(0)); | |
} | |
/** | |
* 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.getBaseUnits() != null) { | |
Map<Unit<?>, Integer> productUnits = (Map<Unit<?>, Integer>) unit.getBaseUnits(); | |
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 Locale getLocale() { | |
return uLocale; | |
} | |
@Override | |
public boolean isLocaleSensitive() { | |
return true; | |
} | |
@Override | |
public void label(Unit<?> arg0, String arg1) { | |
// TODO Auto-generated method stub | |
} | |
} |