/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.eas.client.forms.components.rt;
import com.eas.script.Scripts;
import java.awt.event.FocusEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.swing.JFormattedTextField;
import javax.swing.text.DefaultFormatterFactory;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.JSType;
/**
*
* @author mg
*/
public abstract class VFormattedField extends JFormattedTextField implements HasValue<Object>, HasEmptyText, HasEditable {
public static final int NUMBER = 0;
public static final int DATE = 1;
public static final int TIME = 2;
public static final int PERCENT = 3;
public static final int CURRENCY = 4;
public static final int MASK = 5;
public static final int REGEXP = 6;
public class PolymorphFormatter extends AbstractFormatter {
private String pattern;
private final OptimisticMaskFormatter maskFormatter = new OptimisticMaskFormatter();
private final SimpleDateFormat dateFormat = new SimpleDateFormat();
private final DecimalFormat numberFormat = new DecimalFormat();
private Pattern regexp;
public PolymorphFormatter() {
super();
maskFormatter.setValueContainsLiteralCharacters(true);
}
public String getPattern() {
return pattern;
}
public void setPattern(String aValue) {
if (pattern == null ? aValue != null : !pattern.equals(aValue)) {
pattern = aValue;
try {
maskFormatter.setMask(pattern);
} catch (ParseException ex) {
Logger.getLogger(VFormattedField.class.getName()).log(Level.WARNING, ex.getMessage());
}
try {
dateFormat.applyPattern(pattern);
} catch (Exception ex) {
Logger.getLogger(VFormattedField.class.getName()).log(Level.WARNING, ex.getMessage());
}
try {
numberFormat.applyPattern(pattern);
} catch (Exception ex) {
Logger.getLogger(VFormattedField.class.getName()).log(Level.WARNING, ex.getMessage());
}
try {
regexp = aValue != null && !aValue.isEmpty() ? Pattern.compile(aValue) : null;
} catch (Exception ex) {
Logger.getLogger(VFormattedField.class.getName()).log(Level.WARNING, ex.getMessage());
}
}
}
@Override
public Object stringToValue(String text) throws ParseException {
if (onParse != null) {
JSObject jsEvent = Scripts.getSpace().makeObj();
jsEvent.setMember("source", getPublished());
jsEvent.setMember("text", text);
try {
return Scripts.getSpace().toJava(onParse.call(getPublished(), new Object[]{jsEvent}));
} catch (Throwable t) {
throw new ParseException(text, 0);
}
} else {
switch (valueType) {
case DATE:
return dateFormat.parse(text);
case TIME:
return dateFormat.parse(text);
case NUMBER:
return numberFormat.parse(text);
case PERCENT:
return numberFormat.parse(text);
case CURRENCY:
return numberFormat.parse(text);
case MASK:
return maskFormatter.stringToValue(text);
case REGEXP:
boolean matches = regexp != null ? regexp.matcher(text).matches() : true;
if (matches) {
return text;
} else {
throw new ParseException(text, 0);
}
default:
return text;
}
}
}
@Override
public String valueToString(Object value) throws ParseException {
if (onFormat != null) {
JSObject jsEvent = Scripts.getSpace().makeObj();
jsEvent.setMember("source", getPublished());
jsEvent.setMember("value", Scripts.getSpace().toJs(value));
try {
return JSType.toString(onFormat.call(getPublished(), new Object[]{jsEvent}));
} catch (Throwable t) {
throw new ParseException(t.getMessage(), 0);
}
} else {
try {
switch (valueType) {
case DATE:
return dateFormat.format(value);
case TIME:
return dateFormat.format(value);
case NUMBER:
return numberFormat.format(value);
case PERCENT:
return numberFormat.format(value);
case CURRENCY:
return numberFormat.format(value);
case MASK:
return maskFormatter.valueToString(value);
case REGEXP:
return value != null ? value.toString() : "";
default:
return value != null ? value.toString() : "";
}
} catch (IllegalArgumentException ex) {
throw new ParseException(ex.getMessage(), 0);
}
}
}
}
protected PolymorphFormatter formatter = new PolymorphFormatter();
protected int valueType = REGEXP;
protected JSObject onFormat;
protected JSObject onParse;
protected boolean valueIsNull = true;
protected PropertyChangeListener valueIsNullClearer = (PropertyChangeEvent pce) -> {
valueIsNull = false;
};
public VFormattedField(Object aValue) {
super();
setFormatterFactory(new DefaultFormatterFactory(formatter));
setValue(aValue);
}
public VFormattedField() {
this(null);
}
protected abstract JSObject getPublished();
public int getValueType() {
return valueType;
}
public void setValueType(int aValue) {
if (valueType != aValue) {
valueType = aValue;
}
}
public String getFormat() {
return formatter.getPattern();
}
public void setFormat(String aValue) {
formatter.setPattern(aValue);
}
public JSObject getOnFormat() {
return onFormat;
}
public void setOnFormat(JSObject aValue) {
onFormat = aValue;
}
public JSObject getOnParse() {
return onParse;
}
public void setOnParse(JSObject aValue) {
onParse = aValue;
}
@Override
public String getText() {
return super.getText() != null ? super.getText() : "";
}
@Override
public void setText(String aValue) {
try {
super.setText(aValue != null ? aValue : "");
super.commitEdit();
} catch (ParseException ex) {
Logger.getLogger(VFormattedField.class.getName()).log(Level.WARNING, ex.getMessage());
}
}
@Override
public Object getValue() {
return valueIsNull ? null : super.getValue();
}
@Override
public void setValue(Object aValue) {
if (aValue instanceof Number) {
aValue = ((Number) aValue).doubleValue();
}
removeValueChangeListener(valueIsNullClearer);
try {
valueIsNull = aValue == null;
super.setValue(aValue);
} finally {
addValueChangeListener(valueIsNullClearer);
}
}
@Override
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
// Crazy Swing JFormattedField issues a value change while focus gaining
if (!VALUE_PROP_NAME.equals(propertyName) || processedFocusEvent == null || processedFocusEvent.getID() == FocusEvent.FOCUS_LOST) {
super.firePropertyChange(propertyName, oldValue, newValue);
}
}
private FocusEvent processedFocusEvent;
@Override
protected void processFocusEvent(FocusEvent e) {
// Crazy Swing JFormattedField issues a value change while focus gaining
processedFocusEvent = e;
try {
super.processFocusEvent(e);
} finally {
processedFocusEvent = null;
}
}
@Override
public void addValueChangeListener(PropertyChangeListener listener) {
super.addPropertyChangeListener(VALUE_PROP_NAME, listener);
}
@Override
public void removeValueChangeListener(PropertyChangeListener listener) {
super.removePropertyChangeListener(VALUE_PROP_NAME, listener);
}
protected String emptyText;
@Override
public String getEmptyText() {
return emptyText;
}
@Override
public void setEmptyText(String aValue) {
emptyText = aValue;
}
@Override
public boolean getEditable() {
return super.isEditable();
}
}