BasicField.java :  » MVC » aratana » com » aratana » ui » fields » Java Open Source

Java Open Source » MVC » aratana 
aratana » com » aratana » ui » fields » BasicField.java
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;
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.