package org.aperteworkflow.util.vaadin.text;
import com.vaadin.data.Property;
import com.vaadin.data.util.PropertyFormatter;
import com.vaadin.data.validator.DoubleValidator;
import com.vaadin.data.validator.IntegerValidator;
import com.vaadin.event.FieldEvents.*;
import com.vaadin.ui.TextField;
import pl.net.bluesoft.util.lang.Strings;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
public class NumberTextField extends TextField {
private DecimalFormat decimalFormat;
private boolean allowsNegative;
public boolean isAllowsNegative() {
return allowsNegative;
}
public void setAllowsNegative(boolean allowsNegative) {
this.allowsNegative = allowsNegative;
}
public NumberTextField() {
alignRight();
attachListeners();
}
public NumberTextField(String caption) {
super(caption);
alignRight();
attachListeners();
}
private void attachListeners() {
addListener((TextChangeListener) new ValueHandler());
addListener((FocusListener) new ValueHandler());
addListener((ValueChangeListener) new ValueHandler());
addListener((BlurListener) new ValueHandler());
}
public NumberTextField(Property dataSource) {
super(dataSource);
alignRight();
}
public NumberTextField(String caption, Property dataSource) {
super(caption, dataSource);
alignRight();
}
public NumberTextField(String caption, String value) {
super(caption, value);
alignRight();
}
private void alignRight() {
addStyleName("align-right");
}
public void addDoubleValidator(String errorMessage) {
addValidator(new LocalizedDoubleValidator(errorMessage));
}
public void addIntegerValidator(String errorMessage) {
addValidator(new LocalizedIntegerValidator(errorMessage));
}
@Override
public void setPropertyDataSource(final Property newDataSource) {
super.setPropertyDataSource(getPropertyFormatter(newDataSource));
}
protected PropertyFormatter getPropertyFormatter(Property newDataSource) {
return new PropertyFormatter(newDataSource) {
@Override
public String format(Object value) {
if (value == null) {
return getNullRepresentation();
}
if (value instanceof Number) {
DecimalFormat decFormat = getDecimalFormat();
return decFormat.format(((Number) value).doubleValue());
}
return removeAlphaCharacters(value.toString().replace(',', '.'));
}
@Override
public Object parse(String formattedValue) throws Exception {
return removeAlphaCharacters(formattedValue.replace(',', '.'));
}
};
}
protected String removeAlphaCharacters(String value) {
StringBuilder sb = new StringBuilder();
boolean containsDigits = false;
for (int i = 0; i < value.length(); ++i) {
char c = value.charAt(i);
if (allowsNegative && sb.length() == 0 && c == '-'){
sb.append('-');
containsDigits = true; //no, moze nie do końca zawiera cyfry, ale traktujemy to jako poprawne
}
if (Character.isDigit(c) || c == '.' || c == ',') {
sb.append(c);
if (Character.isDigit(c)) {
containsDigits = true;
}
}
}
return containsDigits ? sb.toString() : getNullRepresentation();
}
private class ValueHandler implements ValueChangeListener, FocusListener, BlurListener, TextChangeListener {
@Override
public void textChange(TextChangeEvent event) {
if (getStringValue() != null)
checkValue(event.getText());
}
protected Object getStringValue() {
return getValue();
}
@Override
public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
if (getStringValue() != null)
checkValue(getStringValue().toString());
}
@Override
public void focus(FocusEvent event) {
if (getStringValue() != null)
checkValue(getStringValue().toString());
}
@Override
public void blur(BlurEvent event) {
if (getStringValue() != null)
checkValue(getStringValue().toString());
}
private void checkValue(String propValue) {
if (Strings.hasText(propValue)) {
String value = removeAlphaCharacters(propValue);
if (!value.equals(propValue)) {
setValue(value);
}
}
}
}
protected String getDecimalFormatString() {
return "0.##";
}
protected DecimalFormat getDecimalFormat() {
if(decimalFormat == null)
decimalFormat = getLocale() != null ? new DecimalFormat(getDecimalFormatString(), new DecimalFormatSymbols(getLocale())) : new DecimalFormat(getDecimalFormatString());
return decimalFormat;
}
public void setDecimalFormat(DecimalFormat decimalFormat) {
this.decimalFormat = decimalFormat;
}
public static final class LocalizedDoubleValidator extends DoubleValidator {
public LocalizedDoubleValidator(String errorMessage) {
super(errorMessage);
}
@Override
protected boolean isValidString(String value) {
return super.isValidString(value == null ? null : value.replace(",", "."));
}
}
public static final class LocalizedIntegerValidator extends IntegerValidator {
public LocalizedIntegerValidator(String errorMessage) {
super(errorMessage);
}
@Override
protected boolean isValidString(String value) {
return super.isValidString(value == null ? null : value.replace(",", "."));
}
}
}