package org.korsakow.ide.ui.interfacebuilder.panel; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.korsakow.ide.lang.LanguageBundle; import org.korsakow.ide.ui.constraints.NumberRangeTextFieldConstraint; import org.korsakow.ide.util.OrderedEventListenerList; import org.korsakow.ide.util.UIUtil; public class InfoPanel extends JPanel { private JTextField xField; private JTextField yField; private JTextField widthField; private JTextField heightField; private NumberRangeTextFieldConstraint numberConstraint; private JLabel xLabel; private JLabel yLabel; private JLabel wLabel; private JLabel hLabel; public InfoPanel() { initUI(); initListeners(); } private void initUI() { Dimension fieldPreferredSize = new Dimension(50, 20); setLayout(new GridLayout(2, 2, 0, 10)); JPanel xPanel = new JPanel(); add(xPanel); xLabel = new JLabel(LanguageBundle.getString("interfacebuilder.infopanel.x.label"), JLabel.RIGHT); xPanel.add(xLabel); xPanel.add(xField = new JTextField()); xField.setPreferredSize(fieldPreferredSize); JPanel yPanel = new JPanel(); add(yPanel); yLabel = new JLabel(LanguageBundle.getString("interfacebuilder.infopanel.y.label"), JLabel.RIGHT); yPanel.add(yLabel); yPanel.add(yField = new JTextField()); yField.setPreferredSize(fieldPreferredSize); JPanel widthPanel = new JPanel(); add(widthPanel); wLabel = new JLabel(LanguageBundle.getString("interfacebuilder.infopanel.width.label"), JLabel.RIGHT); widthPanel.add(wLabel); widthPanel.add(widthField = new JTextField()); widthField.setPreferredSize(fieldPreferredSize); JPanel heightPanel = new JPanel(); add(heightPanel); hLabel = new JLabel(LanguageBundle.getString("interfacebuilder.infopanel.height.label"), JLabel.RIGHT); heightPanel.add(hLabel); heightPanel.add(heightField = new JTextField()); heightField.setPreferredSize(fieldPreferredSize); setPreferredSize(new Dimension(Short.MAX_VALUE, 100)); } @Override public void doLayout() { UIUtil.runUITaskLater(new Runnable() { public void run() { Dimension d = new Dimension(Integer.MIN_VALUE, Integer.MIN_VALUE); d.width = Math.max(d.width, xLabel.getWidth()); d.width = Math.max(d.width, yLabel.getWidth()); d.width = Math.max(d.width, wLabel.getWidth()); d.width = Math.max(d.width, hLabel.getWidth()); d.height = Math.max(d.height, xLabel.getHeight()); d.height = Math.max(d.height, yLabel.getHeight()); d.height = Math.max(d.height, wLabel.getHeight()); d.height = Math.max(d.height, hLabel.getHeight()); if (d.equals(xLabel.getPreferredSize())) return; xLabel.revalidate(); yLabel.revalidate(); wLabel.revalidate(); hLabel.revalidate(); xLabel.setPreferredSize(d); yLabel.setPreferredSize(d); wLabel.setPreferredSize(d); hLabel.setPreferredSize(d); } }); super.doLayout(); } private void initListeners() { numberConstraint = new NumberRangeTextFieldConstraint(Integer.class, null, null); numberConstraint.addAsListenerTo(xField); numberConstraint.addAsListenerTo(yField); numberConstraint.addAsListenerTo(widthField); numberConstraint.addAsListenerTo(heightField); } @Override public void setEnabled(boolean enabled) { xField.setEnabled(enabled); yField.setEnabled(enabled); widthField.setEnabled(enabled); heightField.setEnabled(enabled); if (!enabled) { xField.setText(LanguageBundle.getString("interfacebuilder.infopanel.novalue")); yField.setText(LanguageBundle.getString("interfacebuilder.infopanel.novalue")); widthField.setText(LanguageBundle.getString("interfacebuilder.infopanel.novalue")); heightField.setText(LanguageBundle.getString("interfacebuilder.infopanel.novalue")); } } public void addXChangeListener(ChangeListener listener) { TextFieldUpdateListener textFieldUpdater = new TextFieldUpdateListener(); textFieldUpdater.addAsListenerTo(xField); textFieldUpdater.addChangeListener(listener); } public void addYChangeListener(ChangeListener listener) { TextFieldUpdateListener textFieldUpdater = new TextFieldUpdateListener(); textFieldUpdater.addAsListenerTo(yField); textFieldUpdater.addChangeListener(listener); } public void addWidthChangeListener(ChangeListener listener) { TextFieldUpdateListener textFieldUpdater = new TextFieldUpdateListener(); textFieldUpdater.addAsListenerTo(widthField); textFieldUpdater.addChangeListener(listener); } public void addHeightChangeListener(ChangeListener listener) { TextFieldUpdateListener textFieldUpdater = new TextFieldUpdateListener(); textFieldUpdater.addAsListenerTo(heightField); textFieldUpdater.addChangeListener(listener); } public void setXValue(int x) { xField.setText(""+x); } public int getXValue() { return Integer.parseInt(xField.getText()); } public void setYValue(int y) { yField.setText(""+y); } public int getYValue() { return Integer.parseInt(yField.getText()); } public void setWidthValue(int width) { widthField.setText(""+width); } public int getWidthValue() { return Integer.parseInt(widthField.getText()); } public void setHeightValue(int height) { heightField.setText(""+height); } public int getHeightValue() { return Integer.parseInt(heightField.getText()); } /** * Aggregates "update" events for a text field, in the sense that the UI should update itself to reflect the current value of the textfield. * In some sense, the user has finished editing the text field's value. * These are different from swing "change" events which are updates while the user is still editing. * For example pressing enter or losing focus. * @author d * */ public static class TextFieldUpdateListener implements ActionListener, FocusListener { private final OrderedEventListenerList listeners = new OrderedEventListenerList(); public void addChangeListener(ChangeListener listener) { listeners.add(ChangeListener.class, listener); } /** * The updater may listen on any number of events, so we hide the implementation from the caller in this method. * This is the intended way to use the class. * @param textField */ public void addAsListenerTo(JTextField textField) { textField.addActionListener(this); textField.addFocusListener(this); } public void notifyChange(final JTextField textField) { if (!textField.isEnabled()) // it seems we can still lose focus if the comp is disabled while focused return; // this is a hack. EventListeners are notified in arbitrary order. But we have to ensure that the info panel's validator listeners are run first... UIUtil.runUITaskLater(new Runnable() { public void run() { ChangeEvent event = new ChangeEvent(textField); for (ChangeListener listener : listeners.getListeners(ChangeListener.class)) listener.stateChanged(event); } }); } public void actionPerformed(ActionEvent e) { JTextField textField = (JTextField)e.getSource(); notifyChange(textField); } public void focusLost(FocusEvent e) { JTextField textField = (JTextField)e.getSource(); notifyChange(textField); } public void focusGained(FocusEvent e) { } } }