package games.strategy.engine.framework.startup.ui.editors; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagLayout; import java.beans.PropertyChangeListener; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import games.strategy.engine.framework.startup.ui.editors.validators.IValidator; import games.strategy.engine.framework.startup.ui.editors.validators.NonEmptyValidator; /** * Base class for editors. * Editors fire property Events in response when changed, so other editors or GUI can be notified */ public abstract class EditorPanel extends JPanel { private static final long serialVersionUID = 8156959717037201321L; public static final String EDITOR_CHANGE = "EditorChange"; protected final Color m_labelColor; public EditorPanel() { super(new GridBagLayout()); m_labelColor = new JLabel().getForeground(); } /** * registers a listener for editor changes * * @param listener * the listener. be aware that the oldValue and newValue properties of the PropertyChangeEvent * will both be null */ @Override public void addPropertyChangeListener(final PropertyChangeListener listener) { super.addPropertyChangeListener(EDITOR_CHANGE, listener); } /** * Validates that a text field is not empty. if the content is not valid the associated label is marked in red * * @param field * the field to validate * @param label * the associated label (or null) * @return true if text field content is valid */ protected boolean validateTextFieldNotEmpty(final JTextField field, final JLabel label) { return validateTextField(field, label, new NonEmptyValidator()); } /** * Validates a the contents of a text field using a specified validator. if the content is not valid the associated * label is marked in red * * @param field * the field to validate * @param label * the associated label (or null) * @param IValidator * the validator * @return true if text field content is valid */ protected boolean validateTextField(final JTextField field, final JLabel label, final IValidator IValidator) { return validateText(field.getText(), label, IValidator); } /** * Validates a the contents of textusing a specified validator. if the content is not valid the associated label is * marked in red * * @param text * the text to validate * @param label * the associated label (or null) * @param IValidator * the validator * @return true if text field content is valid */ protected boolean validateText(final String text, final JLabel label, final IValidator IValidator) { boolean valid = true; Color color = m_labelColor; if (!IValidator.isValid(text)) { valid = false; color = Color.RED; label.setForeground(color); } if (label != null) { label.setForeground(color); } return valid; } /** * called to see if the bean that is edited is in a valid state. * This is typically called by editor listeners in response to a change in the editor * * @return true if valid */ public abstract boolean isBeanValid(); /** * Get the bean that is being edited. You should only call this when #isBeanValid return true * * @return the bean modified by the editor */ public abstract IBean getBean(); /** * Returns the Label width, this can be used by wrapping editors to try to align label sizes. * * @return the size of the largest label in the first column */ public int getLabelWidth() { int width = 0; final GridBagLayout layout = (GridBagLayout) getLayout(); final Component[] components = getComponents(); for (final Component component : components) { // label in first column if (component instanceof JLabel && layout.getConstraints(component).gridx == 0) { if (component.getPreferredSize().width > width) { width = component.getPreferredSize().width; } } } return width; } /** * Sets the label with for labels in the first column of the gridBagLayout. * This can be used to align components in a GUI, so all editors (or nested editors) have same label width * * @param width * the new width of the labels */ public void setLabelWidth(final int width) { final GridBagLayout layout = (GridBagLayout) getLayout(); final Component[] components = getComponents(); for (final Component component : components) { // label in first column if (component instanceof JLabel && layout.getConstraints(component).gridx == 0) { final int height = component.getPreferredSize().height; final Dimension dimension = new Dimension(width, height); component.setPreferredSize(dimension); component.setSize(dimension); } } } /** * Fires the EDITOR_CHANGE property change, to notify propertyChangeListeners which have registered to be * notified when the editor modifies the bean. */ protected void fireEditorChanged() { firePropertyChange(EDITOR_CHANGE, null, null); } /** * Document listener which calls fireEditorChanged in response to any document change. */ protected class EditorChangedFiringDocumentListener implements DocumentListener { @Override public void changedUpdate(final DocumentEvent e) { fireEditorChanged(); } @Override public void insertUpdate(final DocumentEvent e) { fireEditorChanged(); } @Override public void removeUpdate(final DocumentEvent e) { fireEditorChanged(); } } }