    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:    A component filled with editors for all editable properties
    011:    of an object.
    012: */
    013: public class PropertySheet extends JPanel
    014: {
    015:    /**
    016:       Constructs a property sheet that shows the editable
    017:       properties of a given object.
    018:       @param object the object whose properties are being edited
    019:    */
    020:    public PropertySheet(Object bean)
    021:    {
    022:       try
    023:       {
    024:          BeanInfo info
    025:             = Introspector.getBeanInfo(bean.getClass());
    026:          PropertyDescriptor[] descriptors
    027:             = info.getPropertyDescriptors();
    028:          setLayout(new FormLayout());
    029:          for (int i = 0; i < descriptors.length; i++)
    030:          {
    031:             PropertyEditor editor
    032:                = getEditor(bean, descriptors[i]);
    033:             if (editor != null)
    034:             {
    035:                add(new JLabel(descriptors[i].getName()));
    036:                add(getEditorComponent(editor));
    037:             }
    038:          }
    039:       }
    040:       catch (IntrospectionException exception)
    041:       {
    042:          exception.printStackTrace();
    043:       }
    044:    }
    045:
    046:    /**
    047:       Gets the property editor for a given property,
    048:       and wires it so that it updates the given object.
    049:       @param bean the object whose properties are being edited
    050:       @param descriptor the descriptor of the property to
    051:       be edited
    052:       @return a property editor that edits the property
    053:       with the given descriptor and updates the given object
    054:    */
    055:    public PropertyEditor getEditor(final Object bean,
    056:       PropertyDescriptor descriptor)
    057:    {
    058:       try
    059:       {
    060:          Method getter = descriptor.getReadMethod();
    061:          if (getter == null) return null;
    062:          final Method setter = descriptor.getWriteMethod();
    063:          if (setter == null) return null;
    064:          final PropertyEditor editor;
    065:          Class editorClass = descriptor.getPropertyEditorClass();
    066:          if (editorClass != null)
    067:             editor = (PropertyEditor) editorClass.newInstance();
    068:          else
    069:             editor = PropertyEditorManager.findEditor(
    070:                descriptor.getPropertyType());
    071:          if (editor == null) return null;
    072:
    073:          Object value = getter.invoke(bean, new Object[] {});
    074:          editor.setValue(value);
    075:          editor.addPropertyChangeListener(new
    076:             PropertyChangeListener()
    077:             {
    078:                public void propertyChange(PropertyChangeEvent event)
    079:                {
    080:                   try
    081:                   {
    082:                      setter.invoke(bean,
    083:                         new Object[] { editor.getValue() });
    084:                   }
    085:                   catch (IllegalAccessException exception)
    086:                   {
    087:                   }
    088:                   catch (InvocationTargetException exception)
    089:                   {
    090:                   }
    091:                }
    092:             });
    093:          return editor;
    094:       }
    095:       catch (InstantiationException exception)
    096:       {
    097:          return null;
    098:       }
    099:       catch (IllegalAccessException exception)
    100:       {
    101:          return null;
    102:       }
    103:       catch (InvocationTargetException exception)
    104:       {
    105:          return null;
    106:       }
    107:    }
    108:
    109:    /**
    110:       Wraps a property editor into a component.
    111:       @param editor the editor to wrap
    112:       @return a button (if there is a custom editor),
    113:       combo box (if the editor has tags), or text field (otherwise)
    114:    */
    115:    public Component getEditorComponent(final PropertyEditor editor)
    116:    {
    117:       String[] tags = editor.getTags();
    118:       String text = editor.getAsText();
    119:       if (editor.supportsCustomEditor())
    120:       {
    121:          // Make a button that pops up the custom editor
    122:          final JButton button = new JButton();
    123:          // if the editor is paintable, have it paint an icon
    124:          if (editor.isPaintable())
    125:          {
    126:             button.setIcon(new
    127:                Icon()
    128:                {
    129:                   public int getIconWidth() { return WIDTH - 8; }
    130:                   public int getIconHeight() { return HEIGHT - 8; }
    131:
    132:                   public void paintIcon(Component c, Graphics g,
    133:                      int x, int y)
    134:                   {
    135:                      g.translate(x, y);
    136:                      Rectangle r = new Rectangle(0, 0,
    137:                         getIconWidth(), getIconHeight());
    138:                      Color oldColor = g.getColor();
    139:                      g.setColor(Color.BLACK);
    140:                      editor.paintValue(g, r);
    141:                      g.setColor(oldColor);
    142:                      g.translate(-x, -y);
    143:                   }
    144:                });
    145:          }
    146:          else
    147:             button.setText(buttonText(text));
    148:          // pop up custom editor when button is clicked
    149:          button.addActionListener(new
    150:             ActionListener()
    151:             {
    152:                public void actionPerformed(ActionEvent event)
    153:                {
    154:                   JOptionPane.showMessageDialog(null,
    155:                      editor.getCustomEditor());
    156:                   if (editor.isPaintable())
    157:                      button.repaint();
    158:                   else
    159:                      button.setText(buttonText(editor.getAsText()));
    160:                }
    161:             });
    162:          return button;
    163:       }
    164:       else if (tags != null)
    165:       {
    166:          // make a combo box that shows all tags
    167:          final JComboBox comboBox = new JComboBox(tags);
    168:          comboBox.setSelectedItem(text);
    169:          comboBox.addItemListener(new
    170:             ItemListener()
    171:             {
    172:                public void itemStateChanged(ItemEvent event)
    173:                {
    174:                   if (event.getStateChange() == ItemEvent.SELECTED)
    175:                      editor.setAsText(
    176:                         (String) comboBox.getSelectedItem());
    177:                }
    178:             });
    179:          return comboBox;
    180:       }
    181:       else
    182:       {
    183:          final JTextField textField = new JTextField(text, 10);
    184:          textField.getDocument().addDocumentListener(new
    185:             DocumentListener()
    186:             {
    187:                public void insertUpdate(DocumentEvent e)
    188:                {
    189:                   try
    190:                   {
    191:                      editor.setAsText(textField.getText());
    192:                   }
    193:                   catch (IllegalArgumentException exception)
    194:                   {
    195:                   }
    196:                }
    197:                public void removeUpdate(DocumentEvent e)
    198:                {
    199:                   try
    200:                   {
    201:                      editor.setAsText(textField.getText());
    202:                   }
    203:                   catch (IllegalArgumentException exception)
    204:                   {
    205:                   }
    206:                }
    207:                public void changedUpdate(DocumentEvent e)
    208:                {
    209:                }
    210:             });
    211:          return textField;
    212:       }
    213:    }
    214:
    215:    /**
    216:       Formats text for the button that pops up a
    217:       custom editor.
    218:       @param text the property value as text
    219:       @return the text to put on the button
    220:    */
    221:    private static String buttonText(String text)
    222:    {
    223:       if (text == null || text.equals(""))
    224:          return " ";
    225:       if (text.length() > MAX_TEXT_LENGTH)
    226:          return text.substring(0, MAX_TEXT_LENGTH) + "...";
    227:       return text;
    228:    }
    229:
    230:    private ArrayList changeListeners = new ArrayList();
    231:    private static final int WIDTH = 100;
    232:    private static final int HEIGHT = 25;
    233:    private static final int MAX_TEXT_LENGTH = 15;
    234: }
    235: