    001: import java.awt.*;
    002: import java.awt.event.*;
    003: import java.beans.*;
    004: import java.lang.reflect.*;
    005: import java.util.*;
    006: import javax.swing.*;
    007: import javax.swing.event.*;
    008:
    009:
    010: /**
    011:    A component filled with editors for all editable properties
    012:    of an object.
    013: */
    014: public class PropertySheet extends JPanel
    015: {
    016:    /**
    017:       Constructs a property sheet that shows the editable
    018:       properties of a given object.
    019:       @param object the object whose properties are being edited
    020:    */
    021:    public PropertySheet(Object bean)
    022:    {
    023:       try
    024:       {
    025:          BeanInfo info
    026:             = Introspector.getBeanInfo(bean.getClass());
    027:          PropertyDescriptor[] descriptors
    028:             = (PropertyDescriptor[])info.getPropertyDescriptors().clone();
    029:          setLayout(new FormLayout());
    030:          for (int i = 0; i < descriptors.length; i++)
    031:          {
    032:             PropertyEditor editor
    033:                = getEditor(bean, descriptors[i]);
    034:             if (editor != null)
    035:             {
    036:                add(new JLabel(descriptors[i].getName()));
    037:                add(getEditorComponent(editor));
    038:             }
    039:          }
    040:       }
    041:       catch (IntrospectionException exception)
    042:       {
    043:          exception.printStackTrace();
    044:       }
    045:    }
    046:
    047:    /**
    048:       Gets the property editor for a given property,
    049:       and wires it so that it updates the given object.
    050:       @param bean the object whose properties are being edited
    051:       @param descriptor the descriptor of the property to
    052:       be edited
    053:       @return a property editor that edits the property
    054:       with the given descriptor and updates the given object
    055:    */
    056:    public PropertyEditor getEditor(final Object bean,
    057:       PropertyDescriptor descriptor)
    058:    {
    059:       try
    060:       {
    061:          Method getter = descriptor.getReadMethod();
    062:          if (getter == null) return null;
    063:          final Method setter = descriptor.getWriteMethod();
    064:          if (setter == null) return null;
    065:          Class type = descriptor.getPropertyType();
    066:          PropertyEditor ed = null;
    067:          Class editorClass = descriptor.getPropertyEditorClass();
    068:          if (editorClass != null)
    069:             ed = (PropertyEditor) editorClass.newInstance();
    070:          else
    071:             ed = PropertyEditorManager.findEditor(type);
    072:          if (ed == null && Enum.class.isAssignableFrom(type))
    073:             ed = new EnumEditor(type);
    074:          if (ed == null) return null;
    075:
    076:          final PropertyEditor editor = ed;
    077:
    078:          Object value = getter.invoke(bean, new Object[] {});
    079:          editor.setValue(value);
    080:          editor.addPropertyChangeListener(new
    081:             PropertyChangeListener()
    082:             {
    083:                public void propertyChange(PropertyChangeEvent event)
    084:                {
    085:                   try
    086:                   {
    087:                      setter.invoke(bean,
    088:                         new Object[] { editor.getValue() });
    089:                      fireStateChanged(null);
    090:                   }
    091:                   catch (IllegalAccessException exception)
    092:                   {
    093:                      exception.printStackTrace();
    094:                   }
    095:                   catch (InvocationTargetException exception)
    096:                   {
    097:                      exception.printStackTrace();
    098:                   }
    099:                }
    100:             });
    101:          return editor;
    102:       }
    103:       catch (InstantiationException exception)
    104:       {
    105:          exception.printStackTrace();
    106:          return null;
    107:       }
    108:       catch (IllegalAccessException exception)
    109:       {
    110:          exception.printStackTrace();
    111:          return null;
    112:       }
    113:       catch (InvocationTargetException exception)
    114:       {
    115:          exception.printStackTrace();
    116:          return null;
    117:       }
    118:    }
    119:
    120:    /**
    121:       Wraps a property editor into a component.
    122:       @param editor the editor to wrap
    123:       @return a button (if there is a custom editor),
    124:       combo box (if the editor has tags), or text field (otherwise)
    125:    */
    126:    public Component getEditorComponent(final PropertyEditor editor)
    127:    {
    128:       String[] tags = editor.getTags();
    129:       String text = editor.getAsText();
    130:       if (editor.supportsCustomEditor())
    131:          return editor.getCustomEditor();
    132:       else if (tags != null)
    133:       {
    134:          // make a combo box that shows all tags
    135:          final JComboBox comboBox = new JComboBox(tags);
    136:          comboBox.setSelectedItem(text);
    137:          comboBox.addItemListener(new
    138:             ItemListener()
    139:             {
    140:                public void itemStateChanged(ItemEvent event)
    141:                {
    142:                   if (event.getStateChange() == ItemEvent.SELECTED)
    143:                      editor.setAsText(
    144:                         (String)comboBox.getSelectedItem());
    145:                }
    146:             });
    147:          return comboBox;
    148:       }
    149:       else
    150:       {
    151:          final JTextField textField = new JTextField(text, 10);
    152:          textField.getDocument().addDocumentListener(new
    153:             DocumentListener()
    154:             {
    155:                public void insertUpdate(DocumentEvent e)
    156:                {
    157:                   try
    158:                   {
    159:                      editor.setAsText(textField.getText());
    160:                   }
    161:                   catch (IllegalArgumentException exception)
    162:                   {
    163:                   }
    164:                }
    165:                public void removeUpdate(DocumentEvent e)
    166:                {
    167:                   try
    168:                   {
    169:                      editor.setAsText(textField.getText());
    170:                   }
    171:                   catch (IllegalArgumentException exception)
    172:                   {
    173:                   }
    174:                }
    175:                public void changedUpdate(DocumentEvent e)
    176:                {
    177:                }
    178:             });
    179:          return textField;
    180:       }
    181:    }
    182:
    183:    /**
    184:       Adds a change listener to the list of listeners.
    185:       @param listener the listener to add
    186:    */
    187:    public void addChangeListener(ChangeListener listener)
    188:    {
    189:       changeListeners.add(listener);
    190:    }
    191:
    192:    /**
    193:       Notifies all listeners of a state change.
    194:       @param event the event to propagate
    195:    */
    196:    private void fireStateChanged(ChangeEvent event)
    197:    {
    198:       for (ChangeListener listener : changeListeners)
    199:          listener.stateChanged(event);
    200:    }
    201:
    202:    private ArrayList<ChangeListener> changeListeners
    203:          = new ArrayList<ChangeListener>();
    204: }
    205: