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: