package games.strategy.ui; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import javax.swing.JTextField; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; import games.strategy.util.ListenerList; /** * Text field for entering int values. * Ensures valid integers are entered, and can limit the range of * values user can enter. */ public class IntTextField extends JTextField { private static final long serialVersionUID = -7993942326354823887L; private int m_max = Integer.MAX_VALUE; private int m_min = Integer.MIN_VALUE; private String m_terr = null; private final ListenerList<IntTextFieldChangeListener> m_listeners = new ListenerList<>(); /** Creates new IntTextField. */ public IntTextField() { super(3); initTextField(); } public IntTextField(final int min) { this(); setMin(min); } public IntTextField(final int min, final int max) { this(); setMin(min); setMax(max); } public IntTextField(final int min, final int max, final int current) { this(); setMin(min); setMax(max); setValue(current); } public IntTextField(final int min, final int max, final int current, final int columns) { super(columns); initTextField(); setMin(min); setMax(max); setValue(current); } private void initTextField() { setDocument(new IntegerDocument()); setText(String.valueOf(m_min)); addFocusListener(new LostFocus()); } public int getValue() { return Integer.parseInt(getText()); } private void checkValue() { if (getText().trim().equals("-")) { setText(String.valueOf(m_min)); } try { Integer.parseInt(getText()); } catch (final NumberFormatException e) { setText(String.valueOf(m_min)); } if (getValue() > m_max) { setText(String.valueOf(m_max)); } if (getValue() < m_min) { setText(String.valueOf(m_min)); } } public void setValue(final int value) { if (isGood(value)) { setText(String.valueOf(value)); } } public void setMax(final int max) { if (max < m_min) { throw new IllegalArgumentException( "Max cant be less than min. Current Min: " + m_min + ", Current Max: " + m_max + ", New Max: " + max); } m_max = max; if (getValue() > m_max) { setText(String.valueOf(max)); } } public void setTerr(final String terr) { m_terr = terr; } public void setMin(final int min) { if (min > m_max) { throw new IllegalArgumentException( "Min cant be greater than max. Current Max: " + m_max + ", Current Min: " + m_min + ", New Min: " + min); } m_min = min; if (getValue() < m_min) { setText(String.valueOf(min)); } } public int getMax() { return m_max; } public String getTerr() { return m_terr; } public int getMin() { return m_min; } private boolean isGood(final int value) { return value <= m_max && value >= m_min; } /** * Make sure that no non numeric data is typed. */ private class IntegerDocument extends PlainDocument { private static final long serialVersionUID = 135871239193051281L; @Override public void insertString(final int offs, final String str, final AttributeSet a) throws BadLocationException { final String currentText = this.getText(0, getLength()); final String beforeOffset = currentText.substring(0, offs); final String afterOffset = currentText.substring(offs, currentText.length()); final String proposedResult = beforeOffset + str + afterOffset; // allow start of negative try { Integer.parseInt(proposedResult); super.insertString(offs, str, a); checkValue(); notifyListeners(); } catch (final NumberFormatException e) { // if an error dont insert // allow start of negative numbers if (offs == 0) { if (m_min < 0) { if (str.equals("-")) { super.insertString(offs, str, a); } } } } } @Override public void remove(final int offs, final int len) throws BadLocationException { super.remove(offs, len); // if its a valid number weve changed try { Integer.parseInt(IntTextField.this.getText()); notifyListeners(); } catch (final NumberFormatException e) { // ignore malformed input } } } public void addChangeListener(final IntTextFieldChangeListener listener) { m_listeners.add(listener); } public void removeChangeListener(final IntTextFieldChangeListener listener) { m_listeners.remove(listener); } private void notifyListeners() { for (final IntTextFieldChangeListener listener : m_listeners) { listener.changedValue(this); } } private class LostFocus extends FocusAdapter { @Override public void focusLost(final FocusEvent e) { // make sure the value is valid checkValue(); } } }