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: