blob: a84db69446da6b3eeb29579b2c7148c55ec42141 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.swing;
27
28import java.beans.*;
29import java.lang.reflect.Method;
30
31public class BeanInfoUtils
32{
33 /* The values of these createPropertyDescriptor() and
34 * createBeanDescriptor() keywords are the names of the
35 * properties they're used to set.
36 */
37 public static final String BOUND = "bound";
38 public static final String CONSTRAINED = "constrained";
39 public static final String PROPERTYEDITORCLASS = "propertyEditorClass";
40 public static final String READMETHOD = "readMethod";
41 public static final String WRITEMETHOD = "writeMethod";
42 public static final String DISPLAYNAME = "displayName";
43 public static final String EXPERT = "expert";
44 public static final String HIDDEN = "hidden";
45 public static final String PREFERRED = "preferred";
46 public static final String SHORTDESCRIPTION = "shortDescription";
47 public static final String CUSTOMIZERCLASS = "customizerClass";
48
49 static private void initFeatureDescriptor(FeatureDescriptor fd, String key, Object value)
50 {
51 if (DISPLAYNAME.equals(key)) {
52 fd.setDisplayName((String)value);
53 }
54
55 if (EXPERT.equals(key)) {
56 fd.setExpert(((Boolean)value).booleanValue());
57 }
58
59 if (HIDDEN.equals(key)) {
60 fd.setHidden(((Boolean)value).booleanValue());
61 }
62
63 if (PREFERRED.equals(key)) {
64 fd.setPreferred(((Boolean)value).booleanValue());
65 }
66
67 else if (SHORTDESCRIPTION.equals(key)) {
68 fd.setShortDescription((String)value);
69 }
70
71 /* Otherwise assume that we have an arbitrary FeatureDescriptor
72 * "attribute".
73 */
74 else {
75 fd.setValue(key, value);
76 }
77 }
78
79 /**
80 * Create a beans PropertyDescriptor given an of keyword/value
81 * arguments. The following sample call shows all of the supported
82 * keywords:
83 *<pre>
84 * createPropertyDescriptor("contentPane", new Object[] {
85 * BOUND, Boolean.TRUE,
86 * CONSTRAINED, Boolean.TRUE,
87 * PROPERTYEDITORCLASS, package.MyEditor.class,
88 * READMETHOD, "getContentPane",
89 * WRITEMETHOD, "setContentPane",
90 * DISPLAYNAME, "contentPane",
91 * EXPERT, Boolean.FALSE,
92 * HIDDEN, Boolean.FALSE,
93 * PREFERRED, Boolean.TRUE,
94 * SHORTDESCRIPTION, "A top level window with a window manager border",
95 * "random attribute","random object value"
96 * }
97 * );
98 * </pre>
99 * The keywords correspond to <code>java.beans.PropertyDescriptor</code> and
100 * <code>java.beans.FeatureDescriptor</code> properties, e.g. providing a value
101 * for displayName is comparable to <code>FeatureDescriptor.setDisplayName()</code>.
102 * Using createPropertyDescriptor instead of the PropertyDescriptor
103 * constructor and set methods is preferrable in that it regularizes
104 * the code in a <code>java.beans.BeanInfo.getPropertyDescriptors()</code>
105 * method implementation. One can use <code>createPropertyDescriptor</code>
106 * to set <code>FeatureDescriptor</code> attributes, as in "random attribute"
107 * "random object value".
108 * <p>
109 * All properties should provide a reasonable value for the
110 * <code>SHORTDESCRIPTION</code> keyword and should set <code>BOUND</code>
111 * to <code>Boolean.TRUE</code> if neccessary. The remaining keywords
112 * are optional. There's no need to provide values for keywords like
113 * READMETHOD if the correct value can be computed, i.e. if the properties
114 * get/is method follows the standard beans pattern.
115 * <p>
116 * The PREFERRED keyword is not supported by the JDK1.1 java.beans package.
117 * It's still worth setting it to true for properties that are most
118 * likely to be interested to the average developer, e.g. AbstractButton.title
119 * is a preferred property, AbstractButton.focusPainted is not.
120 *
121 * @see java.beans#BeanInfo
122 * @see java.beans#PropertyDescriptor
123 * @see java.beans#FeatureDescriptor
124 */
125 public static PropertyDescriptor createPropertyDescriptor(Class cls, String name, Object[] args)
126 {
127 PropertyDescriptor pd = null;
128 try {
129 pd = new PropertyDescriptor(name, cls);
130 } catch (IntrospectionException e) {
131 // Try creating a read-only property, in case setter isn't defined.
132 try {
133 pd = createReadOnlyPropertyDescriptor(name, cls);
134 } catch (IntrospectionException ie) {
135 throwError(ie, "Can't create PropertyDescriptor for " + name + " ");
136 }
137 }
138
139 for(int i = 0; i < args.length; i += 2) {
140 String key = (String)args[i];
141 Object value = args[i + 1];
142
143 if (BOUND.equals(key)) {
144 pd.setBound(((Boolean)value).booleanValue());
145 }
146
147 else if (CONSTRAINED.equals(key)) {
148 pd.setConstrained(((Boolean)value).booleanValue());
149 }
150
151 else if (PROPERTYEDITORCLASS.equals(key)) {
152 pd.setPropertyEditorClass((Class)value);
153 }
154
155 else if (READMETHOD.equals(key)) {
156 String methodName = (String)value;
157 Method method;
158 try {
159 method = cls.getMethod(methodName, new Class[0]);
160 pd.setReadMethod(method);
161 }
162 catch(Exception e) {
163 throwError(e, cls + " no such method as \"" + methodName + "\"");
164 }
165 }
166
167 else if (WRITEMETHOD.equals(key)) {
168 String methodName = (String)value;
169 Method method;
170 try {
171 Class type = pd.getPropertyType();
172 method = cls.getMethod(methodName, new Class[]{type});
173 pd.setWriteMethod(method);
174 }
175 catch(Exception e) {
176 throwError(e, cls + " no such method as \"" + methodName + "\"");
177 }
178 }
179
180 else {
181 initFeatureDescriptor(pd, key, value);
182 }
183 }
184
185 return pd;
186 }
187
188
189 /**
190 * Create a BeanDescriptor object given an of keyword/value
191 * arguments. The following sample call shows all of the supported
192 * keywords:
193 *<pre>
194 * createBeanDescriptor(JWindow..class, new Object[] {
195 * CUSTOMIZERCLASS, package.MyCustomizer.class,
196 * DISPLAYNAME, "JFrame",
197 * EXPERT, Boolean.FALSE,
198 * HIDDEN, Boolean.FALSE,
199 * PREFERRED, Boolean.TRUE,
200 * SHORTDESCRIPTION, "A top level window with a window manager border",
201 * "random attribute","random object value"
202 * }
203 * );
204 * </pre>
205 * The keywords correspond to <code>java.beans.BeanDescriptor</code> and
206 * <code>java.beans.FeatureDescriptor</code> properties, e.g. providing a value
207 * for displayName is comparable to <code>FeatureDescriptor.setDisplayName()</code>.
208 * Using createBeanDescriptor instead of the BeanDescriptor
209 * constructor and set methods is preferrable in that it regularizes
210 * the code in a <code>java.beans.BeanInfo.getBeanDescriptor()</code>
211 * method implementation. One can use <code>createBeanDescriptor</code>
212 * to set <code>FeatureDescriptor</code> attributes, as in "random attribute"
213 * "random object value".
214 *
215 * @see java.beans#BeanInfo
216 * @see java.beans#PropertyDescriptor
217 */
218 public static BeanDescriptor createBeanDescriptor(Class cls, Object[] args)
219 {
220 Class customizerClass = null;
221
222 /* For reasons I don't understand, customizerClass is a
223 * readOnly property. So we have to find it and pass it
224 * to the constructor here.
225 */
226 for(int i = 0; i < args.length; i += 2) {
227 if (CUSTOMIZERCLASS.equals((String)args[i])) {
228 customizerClass = (Class)args[i + 1];
229 break;
230 }
231 }
232
233 BeanDescriptor bd = new BeanDescriptor(cls, customizerClass);
234
235 for(int i = 0; i < args.length; i += 2) {
236 String key = (String)args[i];
237 Object value = args[i + 1];
238 initFeatureDescriptor(bd, key, value);
239 }
240
241 return bd;
242 }
243
244 static private PropertyDescriptor createReadOnlyPropertyDescriptor(
245 String name, Class cls) throws IntrospectionException {
246
247 Method readMethod = null;
248 String base = capitalize(name);
249 Class[] parameters = new Class[0];
250
251 // Is it a boolean?
252 try {
253 readMethod = cls.getMethod("is" + base, parameters);
254 } catch (Exception ex) {}
255 if (readMethod == null) {
256 try {
257 // Try normal accessor pattern.
258 readMethod = cls.getMethod("get" + base, parameters);
259 } catch (Exception ex2) {}
260 }
261 if (readMethod != null) {
262 return new PropertyDescriptor(name, readMethod, null);
263 }
264
265 try {
266 // Try indexed accessor pattern.
267 parameters = new Class[1];
268 parameters[0] = int.class;
269 readMethod = cls.getMethod("get" + base, parameters);
270 } catch (NoSuchMethodException nsme) {
271 throw new IntrospectionException(
272 "cannot find accessor method for " + name + " property.");
273 }
274 return new IndexedPropertyDescriptor(name, null, null, readMethod, null);
275 }
276
277 // Modified methods from java.beans.Introspector
278 private static String capitalize(String s) {
279 if (s.length() == 0) {
280 return s;
281 }
282 char chars[] = s.toCharArray();
283 chars[0] = Character.toUpperCase(chars[0]);
284 return new String(chars);
285 }
286
287 /**
288 * Fatal errors are handled by calling this method.
289 */
290 public static void throwError(Exception e, String s) {
291 throw new Error(e.toString() + " " + s);
292 }
293}