package DisplayProject;
import java.text.ParseException;
import java.text.ParsePosition;
import javax.swing.JFormattedTextField;
import javax.swing.text.DocumentFilter;
import javax.swing.text.NavigationFilter;
import javax.swing.text.NumberFormatter;
import Framework.DataValue;
import Framework.DecimalData;
import Framework.NullAwareNumberFormat;
import Framework.NumericData;
/**
* This class can be used to format numeric data in much the same way that forte formatted numeric data,
* allowing for positive, negative, zero and null templates, with similar insert and removal rules.
*/
@SuppressWarnings("serial")
public class NumericFormatter extends NumberFormatter {
private FormattedNumericDocumentFilter docFilter;
private FormattedNumericNavigationFilter navFilter;
private NullAwareNumberFormat formatter;
private String originalFormat;
public NumericFormatter(JFormattedTextField field, String pFormat, Class<?> valueClass) {
super();
this.originalFormat = pFormat;
this.formatter = new NullAwareNumberFormat(pFormat);
this.docFilter = new FormattedNumericDocumentFilter(formatter, field);
this.navFilter = new FormattedNumericNavigationFilter(field);
this.setValueClass(valueClass);
}
@Override
protected NavigationFilter getNavigationFilter() {
return navFilter;
}
@Override
protected DocumentFilter getDocumentFilter() {
return docFilter;
}
public String getOriginalFormat() {
return originalFormat;
}
@Override
public Object stringToValue(String text) throws ParseException {
Object result;
// It is possible to have a blank mask in forte, allowing "" instead of 0 for instance. Thus
// we need to cater for this case.
if ("".equals(text)) {
ParsePosition parsePosition = new ParsePosition(0);
result = formatter.parse(text, parsePosition);
if (parsePosition.getErrorIndex() >= 0) {
throw new ParseException("Unparseable number: \"\"",
parsePosition.getErrorIndex());
}
}
else {
result = formatter.parse(text);
}
return convertValueToValueClass(result);
}
@Override
public String valueToString(Object value) throws ParseException {
return formatter.format(value);
}
/**
* Convert the passed value to a value that is compatible with the value class
* associated with this type
* @param value
* @return
*/
@SuppressWarnings("unchecked")
private Object convertValueToValueClass(Object value) {
Class<?> valueClass = getValueClass();
if (value == null) {
return null;
}
if (valueClass != null && value.getClass().equals(valueClass)) {
return value;
}
if (valueClass != null && (value instanceof Number)) {
if (valueClass == Integer.class) {
return Integer.valueOf(((Number)value).intValue());
}
else if (valueClass == Long.class) {
return Long.valueOf(((Number)value).longValue());
}
else if (valueClass == Float.class) {
return new Float(((Number)value).floatValue());
}
else if (valueClass == Double.class) {
return new Double(((Number)value).doubleValue());
}
else if (valueClass == Byte.class) {
return Byte.valueOf(((Number)value).byteValue());
}
else if (valueClass == Short.class) {
return new Short(((Number)value).shortValue());
}
else if (NumericData.class.isAssignableFrom(valueClass)) {
Class<? extends NumericData>numericValueClass = (Class<? extends NumericData>)valueClass;
try {
// TF:10/4/08:Added in the scale of decimaldatas if necessary
Object currentValue = this.docFilter.field.getValue();
DataValue dataValue = FormatterUtils.createDataValueInstance(numericValueClass);
if (currentValue instanceof DecimalData) {
DecimalData originalValue = (DecimalData)currentValue;
if (!originalValue.isNull() && dataValue instanceof DecimalData) {
((DecimalData)dataValue).setScale(originalValue.getScale());
}
}
// TF:29 sept. 2008:Changed this to use the generic method to prevent numerics being
// converted to strings, and hence losing international formatting characters
FormatterUtils.setDataValue(dataValue, value);
return dataValue;
}
catch (ParseException e) {
// This shouldn't happen. Just return the original object
return value;
}
}
}
return value;
}
}