package com.aratana.ui.fields;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
import com.aratana.ui.InputChangeListener;
import com.aratana.ui.ValueChangeListener;
import com.aratana.ui.ViewField;
@SuppressWarnings("serial")
public abstract class BasicField<T> extends JTextField implements ViewField<T> {
private boolean obrigatory = false;
private Color originalBackground;
protected boolean allSelected = false;
private boolean autoTransferOnLimit = false;
private boolean autoTransferOnEmpty = false;
private boolean caseSensitive = true;
private final Runnable autoTransferFocusBack = new Runnable() {
public void run() {
if (getText().length() == 0) {
transferFocusBackward();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final Component component = SwingUtilities.getWindowAncestor(BasicField.this).getFocusOwner();
if (component != null && BasicField.class.isAssignableFrom(component.getClass())) {
((BasicField<?>) component).setSelectionStart(((BasicField<?>) component).getText().length());
}
}
});
}
}
};
private final List<ValueChangeListener<T>> listeners = new ArrayList<ValueChangeListener<T>>();
private final List<InputChangeListener> input = new ArrayList<InputChangeListener>();
private String valueStr = "";
private T value = null;
private final Class<T> fieldClass;
private final Constructor<T> constructor;
private final Runnable autoTransferFocus = new Runnable() {
public void run() {
if (getText().length() == getMax()) {
transferFocus();
}
}
};
private int max = -1;
private int min = -1;
@SuppressWarnings({ "unchecked" })
public BasicField() {
try {
fieldClass = (Class<T>) Class.forName(((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].toString().replaceAll("class ", ""));
constructor = fieldClass.getConstructor(String.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
setFont(TAHOMA_13);
addFocusListener(new FocusAdapter() {
@Override
public void focusGained(final FocusEvent e) {
selectAll();
}
@Override
public void focusLost(FocusEvent e) {
getValue();
}
});
setDocument(new PlainDocument() {
@Override
public void remove(int offs, int len) throws BadLocationException {
super.remove(offs, len);
fireInputChanged();
}
@Override
public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
super.replace(offset, length, text, attrs);
fireInputChanged();
}
@Override
public void insertString(final int offs, final String str, final AttributeSet a) throws BadLocationException {
String text = (getMax() > 0 && str.length() + BasicField.this.getText().length() > getMax() ? str.substring(0, getMax() - BasicField.this.getText().length()) : str);
super.insertString(offs, caseSensitive ? text : text.toUpperCase(), a);
fireInputChanged();
}
});
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DELETE) {
setText("");
e.consume();
} else if ((e.getModifiers() | InputEvent.CTRL_DOWN_MASK) != InputEvent.CTRL_DOWN_MASK) {
if (e.getKeyCode() == KeyEvent.VK_A) {
allSelected = true;
}
} else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
if (autoTransferOnEmpty) {
SwingUtilities.invokeLater(autoTransferFocusBack);
}
} else {
allSelected = false;
if (autoTransferOnLimit && Character.isLetterOrDigit(e.getKeyChar())) {
SwingUtilities.invokeLater(autoTransferFocus);
}
}
}
});
setPreferredSize(new Dimension(100, getPreferredSize().height));
}
@Override
public void addValueChangeListener(final ValueChangeListener<T> listener) {
listeners.add(listener);
}
public boolean removeValueChangeListener(final ValueChangeListener<T> listener) {
return listeners.remove(listener);
}
public void removeAllValueChangeListener() {
listeners.clear();
}
@Override
public void addInputChangeListener(InputChangeListener listener) {
input.add(listener);
}
public boolean removeInputChangeListener(final InputChangeListener listener) {
return input.remove(listener);
}
public void removeAllInputChangeListener() {
input.clear();
}
protected void fireInputChanged() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
for (InputChangeListener l : input) {
l.inputChange(BasicField.this);
}
}
});
}
protected boolean validateValue(T newValue) {
boolean valid = true;
for (ValueChangeListener<T> l : listeners) {
valid = l.validateValue(newValue);
if (!valid) {
break;
}
}
return valid;
}
protected void fireValueChanged(T newValue, T oldValue) {
for (ValueChangeListener<T> l : listeners) {
l.valueChanged(newValue, oldValue);
}
}
@Override
public int getMax() {
return max;
}
public void setMax(final int max) {
this.max = max;
}
@Override
public int getMin() {
return this.min;
}
public void setMin(int min) {
this.min = min;
}
@Override
public final T getValue() {
try {
String trim = getText().trim();
if (originalBackground != null) {
setBackground(originalBackground);
originalBackground = null;
repaint();
}
if (trim.isEmpty()) {
return setValue(null);
} else if (valueStr.equals(trim)) {
return value;
} else {
return setValue(getStringValue(trim));
}
} catch (final Exception e) {
if (originalBackground == null) {
originalBackground = getBackground();
}
setBackground(INVALID_BACKGROUND);
return setValue(null);
}
}
@Override
public final T setValue(final T value) {
if (this.value != value || (this.value != null && !this.value.equals(value))) {
if (validateValue(value)) {
String tmpStr = getValueString(value);
if (tmpStr.isEmpty() || getMin() <= 0 || tmpStr.length() >= getMin()) {
setText(valueStr = tmpStr);
T oldValue = this.value;
this.value = value;
fireValueChanged(this.value, oldValue);
} else {
setText("");
}
} else {
setText(valueStr);
}
}
return this.value;
}
@Override
public T getStringValue(String trim) throws Exception {
return (T) constructor.newInstance(trim);
}
@Override
public String getValueString(T value) {
return value == null ? "" : value.toString().trim();
}
/**
* Verifica se o campo esta transferindo o foco automaticamente.
*
* @return <code>true</code> se o componente transfere automaticamente o
* foco aps ficar vazio.
* @see #setAutoTransferOnEmpty(boolean)
*/
public boolean isAutoTransferOnEmpty() {
return autoTransferOnEmpty;
}
/**
* Verifica se o campo esta transferindo o foco automaticamente.
*
* @return <code>true</code> se o componente transfere automaticamente o
* foco aps chegar ao seu limite.
* @see #setAutoTransferOnLimit(boolean)
*/
public boolean isAutoTransferOnLimit() {
return autoTransferOnLimit;
}
public boolean isCaseSensitive() {
return caseSensitive;
}
@Override
public boolean isObrigatory() {
return obrigatory;
}
@Override
protected void processFocusEvent(final FocusEvent e) {
if (e.getID() == FocusEvent.FOCUS_GAINED && isEditable()) {
if (originalBackground == null) {
originalBackground = getBackground();
}
setBackground(SELECTED_BACKGROUND);
repaint();
} else if (originalBackground != null) {
setBackground(originalBackground);
originalBackground = null;
repaint();
}
super.processFocusEvent(e);
}
/**
* Indica se o field deve passar o foco para o prximo componente assim que
* ficar vazio.
*
* @param autoTransferOnEmpty
*/
public void setAutoTransferOnEmpty(final boolean autoTransferOnEmpty) {
this.autoTransferOnEmpty = autoTransferOnEmpty;
};
/**
* Indica se o field deve passar o foco para o prximo componente assim que
* chegar ao seu limite.
*
* @param autoTransferOnLimit
* @see #setLimit(int)
*/
public void setAutoTransferOnLimit(final boolean autoTransferOnLimit) {
this.autoTransferOnLimit = autoTransferOnLimit;
}
/**
* Indica se o field deve aceitar inputs de modo caseSensitive
*
* @param caseSensitive
*/
public void setCaseSensitive(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
public void setObrigatory(final boolean obrigatory) {
this.obrigatory = obrigatory;
}
@Override
public Class<T> getFieldClass() {
return fieldClass;
}
}
|