public class PropertySheet extends JPanel
1: import java.awt.*;
2: import java.awt.event.*;
3: import java.beans.*;
4: import java.lang.reflect.*;
5: import java.util.*;
6: import javax.swing.*;
7: import javax.swing.event.*;
10: /**
11: A component filled with editors for all editable properties
12: of an object.
13: */
14: public class PropertySheet extends JPanel
15: {
16: /**
17: Constructs a property sheet that shows the editable
18: properties of a given object.
19: @param object the object whose properties are being edited
20: */
21: public PropertySheet(Object bean)
22: {
23: try
24: {
25: BeanInfo info
26: = Introspector.getBeanInfo(bean.getClass());
27: PropertyDescriptor[] descriptors
28: = (PropertyDescriptor[])info.getPropertyDescriptors().clone();
29: setLayout(new FormLayout());
30: for (int i = 0; i < descriptors.length; i++)
31: {
32: PropertyEditor editor
33: = getEditor(bean, descriptors[i]);
34: if (editor != null)
35: {
36: add(new JLabel(descriptors[i].getName()));
37: add(getEditorComponent(editor));
38: }
39: }
40: }
41: catch (IntrospectionException exception)
42: {
43: exception.printStackTrace();
44: }
45: }
47: /**
48: Gets the property editor for a given property,
49: and wires it so that it updates the given object.
50: @param bean the object whose properties are being edited
51: @param descriptor the descriptor of the property to
52: be edited
53: @return a property editor that edits the property
54: with the given descriptor and updates the given object
55: */
56: public PropertyEditor getEditor(final Object bean,
57: PropertyDescriptor descriptor)
58: {
59: try
60: {
61: Method getter = descriptor.getReadMethod();
62: if (getter == null) return null;
63: final Method setter = descriptor.getWriteMethod();
64: if (setter == null) return null;
65: Class type = descriptor.getPropertyType();
66: PropertyEditor ed = null;
67: Class editorClass = descriptor.getPropertyEditorClass();
68: if (editorClass != null)
69: ed = (PropertyEditor) editorClass.newInstance();
70: else
71: ed = PropertyEditorManager.findEditor(type);
72: if (ed == null && Enum.class.isAssignableFrom(type))
73: ed = new EnumEditor(type);
74: if (ed == null) return null;
76: final PropertyEditor editor = ed;
78: Object value = getter.invoke(bean, new Object[] {});
79: editor.setValue(value);
80: editor.addPropertyChangeListener(new
81: PropertyChangeListener()
82: {
83: public void propertyChange(PropertyChangeEvent event)
84: {
85: try
86: {
87: setter.invoke(bean,
88: new Object[] { editor.getValue() });
89: fireStateChanged(null);
90: }
91: catch (IllegalAccessException exception)
92: {
93: exception.printStackTrace();
94: }
95: catch (InvocationTargetException exception)
96: {
97: exception.printStackTrace();
98: }
99: }
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: }
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: }
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: }
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: }