There is another YesNoDialog property value that requires a property editor. The message property of YesNoDialog can specify a multi-line message to be displayed in the dialog. This property requires a property editor because the beanbox program does not distinguish between single-line and multi-line string types and the TextField objects it uses for text input do not allow the user to enter multiple lines of text. For this reason, we define the YesNoDialogMessageEditor class and register it with the PropertyDescriptor for the message property, as shown in Example 10.5.
Example 10.7 shows the definition of this property editor. This is a more complex editor that supports the creation of a custom editor component and graphical display of the value. Note that this example implements PropertyEditor directly. getCustomEditor() returns an editor component for multi-line strings. Figure 10.2 shows this custom editor placed within a dialog box created by the beanbox program. Note that the Done button in this figure is part of the beanbox dialog, not part of the property editor itself.
The paintValue() method is responsible for displaying the value of the message property. This multi-line value does not typically fit in the small rectangle of screen space allowed for the property, so paintValue() displays instructions for popping up the custom editor, which allows the user to inspect and edit the property value. (This example relies on the click-to-edit behavior of the beanbox program; this paintValue() method may not make sense when the bean is used in other beanbox tools.)
package oreilly.beans.yesno; import java.beans.*; import java.awt.*; import java.awt.event.*; /** * This class is a custom editor for the message property of the * YesNoDialog bean. It is necessary because the default editor for * properties of type String does not allow multi-line strings to be entered. */ public class YesNoDialogMessageEditor implements PropertyEditor { protected String value; // The value we will be editing. public void setValue(Object o) { value = (String) o; } public Object getValue() { return value; } public void setAsText(String s) { value = s; } public String getAsText() { return value; } public String[] getTags() { return null; } // not enumerated; no tags // Say that we allow custom editing. public boolean supportsCustomEditor() { return true; } // Return the custom editor. This just creates and returns a TextArea // to edit the multi-line text. But it also registers a listener on the // text area to update the value as the user types and to fire the // property change events that property editors are required to fire. public Component getCustomEditor() { final TextArea t = new TextArea(value); t.setSize(300, 150); // TextArea doesn't have a preferred size, so set one. t.addTextListener(new TextListener() { public void textValueChanged(TextEvent e) { value = t.getText(); listeners.firePropertyChange(null, null, null); } }); return t; } // Visual display of the value, for use with the custom editor. // Just print some instructions and hope they fit in the box. // This could be more sophisticated. public boolean isPaintable() { return true; } public void paintValue(Graphics g, Rectangle r) { g.setClip(r); g.drawString("Click to edit...", r.x+5, r.y+15); } // Important method for code generators. Note that it // ought to add any necessary escape sequences. public String getJavaInitializationString() { return "\"" + value + "\""; } // This code uses the PropertyChangeSupport class to maintain a list of // listeners interested in the edits we make to the value. protected PropertyChangeSupport listeners = new PropertyChangeSupport(this); public void addPropertyChangeListener(PropertyChangeListener l) { listeners.addPropertyChangeListener(l); } public void removePropertyChangeListener(PropertyChangeListener l) { listeners.removePropertyChangeListener(l); } }