KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > UIDefaults


1 /*
2  * @(#)UIDefaults.java 1.58 04/05/05
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing;
9
10
11 import javax.swing.plaf.ComponentUI JavaDoc;
12 import javax.swing.border.*;
13 import javax.swing.event.SwingPropertyChangeSupport JavaDoc;
14
15 import java.lang.reflect.*;
16 import java.util.HashMap JavaDoc;
17 import java.util.Map JavaDoc;
18 import java.util.Enumeration JavaDoc;
19 import java.util.Hashtable JavaDoc;
20 import java.util.ResourceBundle JavaDoc;
21 import java.util.Locale JavaDoc;
22 import java.util.Vector JavaDoc;
23 import java.util.MissingResourceException JavaDoc;
24 import java.awt.Font JavaDoc;
25 import java.awt.Color JavaDoc;
26 import java.awt.Insets JavaDoc;
27 import java.awt.Dimension JavaDoc;
28 import java.lang.reflect.Method JavaDoc;
29 import java.beans.PropertyChangeListener JavaDoc;
30 import java.beans.PropertyChangeEvent JavaDoc;
31 import java.security.AccessController JavaDoc;
32 import java.security.AccessControlContext JavaDoc;
33 import java.security.PrivilegedAction JavaDoc;
34
35 import sun.reflect.misc.MethodUtil;
36
37 /**
38  * A table of defaults for Swing components. Applications can set/get
39  * default values via the <code>UIManager</code>.
40  * <p>
41  * <strong>Warning:</strong>
42  * Serialized objects of this class will not be compatible with
43  * future Swing releases. The current serialization support is
44  * appropriate for short term storage or RMI between applications running
45  * the same version of Swing. As of 1.4, support for long term storage
46  * of all JavaBeans<sup><font size="-2">TM</font></sup>
47  * has been added to the <code>java.beans</code> package.
48  * Please see {@link java.beans.XMLEncoder}.
49  *
50  * @see UIManager
51  * @version 1.58 05/05/04
52  * @author Hans Muller
53  */

54 public class UIDefaults extends Hashtable JavaDoc<Object JavaDoc,Object JavaDoc>
55 {
56     private static final Object JavaDoc PENDING = new String JavaDoc("Pending");
57
58     private SwingPropertyChangeSupport JavaDoc changeSupport;
59
60     private Vector JavaDoc resourceBundles;
61
62     private Locale JavaDoc defaultLocale = Locale.getDefault();
63
64     /**
65      * Maps from a Locale to a cached Map of the ResourceBundle. This is done
66      * so as to avoid an exception being thrown when a value is asked for.
67      * Access to this should be done while holding a lock on the
68      * UIDefaults, eg synchronized(this).
69      */

70     private Map JavaDoc resourceCache;
71
72     /**
73      * Create an empty defaults table.
74      */

75     public UIDefaults() {
76         super(700, .75f);
77         resourceCache = new HashMap JavaDoc();
78     }
79
80
81     /**
82      * Create a defaults table initialized with the specified
83      * key/value pairs. For example:
84      * <pre>
85         Object[] uiDefaults = {
86              "Font", new Font("Dialog", Font.BOLD, 12),
87             "Color", Color.red,
88              "five", new Integer(5)
89         }
90         UIDefaults myDefaults = new UIDefaults(uiDefaults);
91      * </pre>
92      * @param keyValueList an array of objects containing the key/value
93      * pairs
94      */

95     public UIDefaults(Object JavaDoc[] keyValueList) {
96         super(keyValueList.length / 2);
97         for(int i = 0; i < keyValueList.length; i += 2) {
98             super.put(keyValueList[i], keyValueList[i + 1]);
99         }
100     }
101
102
103     /**
104      * Returns the value for key. If the value is a
105      * <code>UIDefaults.LazyValue</code> then the real
106      * value is computed with <code>LazyValue.createValue()</code>,
107      * the table entry is replaced, and the real value is returned.
108      * If the value is an <code>UIDefaults.ActiveValue</code>
109      * the table entry is not replaced - the value is computed
110      * with <code>ActiveValue.createValue()</code> for each
111      * <code>get()</code> call.
112      *
113      * If the key is not found in the table then it is searched for in the list
114      * of resource bundles maintained by this object. The resource bundles are
115      * searched most recently added first using the locale returned by
116      * <code>getDefaultLocale</code>. <code>LazyValues</code> and
117      * <code>ActiveValues</code> are not supported in the resource bundles.
118
119      *
120      * @param key the desired key
121      * @return the value for <code>key</code>
122      * @see LazyValue
123      * @see ActiveValue
124      * @see java.util.Hashtable#get
125      * @see #getDefaultLocale
126      * @see #addResourceBundle
127      * @since 1.4
128      */

129     public Object JavaDoc get(Object JavaDoc key) {
130         Object JavaDoc value = getFromHashtable( key );
131         return (value != null) ? value : getFromResourceBundle(key, null);
132     }
133
134     /**
135      * Looks up up the given key in our Hashtable and resolves LazyValues
136      * or ActiveValues.
137      */

138     private Object JavaDoc getFromHashtable(Object JavaDoc key) {
139         /* Quickly handle the common case, without grabbing
140          * a lock.
141          */

142         Object JavaDoc value = super.get(key);
143         if ((value != PENDING) &&
144             !(value instanceof ActiveValue) &&
145             !(value instanceof LazyValue)) {
146             return value;
147         }
148
149         /* If the LazyValue for key is being constructed by another
150          * thread then wait and then return the new value, otherwise drop
151          * the lock and construct the ActiveValue or the LazyValue.
152          * We use the special value PENDING to mark LazyValues that
153          * are being constructed.
154          */

155         synchronized(this) {
156             value = super.get(key);
157             if (value == PENDING) {
158                 do {
159                     try {
160                         this.wait();
161                     }
162                     catch (InterruptedException JavaDoc e) {
163                     }
164                     value = super.get(key);
165                 }
166                 while(value == PENDING);
167                 return value;
168             }
169             else if (value instanceof LazyValue) {
170                 super.put(key, PENDING);
171             }
172             else if (!(value instanceof ActiveValue)) {
173                 return value;
174             }
175         }
176
177         /* At this point we know that the value of key was
178          * a LazyValue or an ActiveValue.
179          */

180         if (value instanceof LazyValue) {
181             try {
182                 /* If an exception is thrown we'll just put the LazyValue
183                  * back in the table.
184                  */

185                 value = ((LazyValue)value).createValue(this);
186             }
187             finally {
188                 synchronized(this) {
189                     if (value == null) {
190                         super.remove(key);
191                     }
192                     else {
193                         super.put(key, value);
194                     }
195                     this.notifyAll();
196                 }
197             }
198         }
199         else {
200             value = ((ActiveValue)value).createValue(this);
201         }
202
203         return value;
204     }
205
206
207     /**
208      * Returns the value for key associated with the given locale.
209      * If the value is a <code>UIDefaults.LazyValue</code> then the real
210      * value is computed with <code>LazyValue.createValue()</code>,
211      * the table entry is replaced, and the real value is returned.
212      * If the value is an <code>UIDefaults.ActiveValue</code>
213      * the table entry is not replaced - the value is computed
214      * with <code>ActiveValue.createValue()</code> for each
215      * <code>get()</code> call.
216      *
217      * If the key is not found in the table then it is searched for in the list
218      * of resource bundles maintained by this object. The resource bundles are
219      * searched most recently added first using the given locale.
220      * <code>LazyValues</code> and <code>ActiveValues</code> are not supported
221      * in the resource bundles.
222      *
223      * @param key the desired key
224      * @param l the desired <code>locale</code>
225      * @return the value for <code>key</code>
226      * @see LazyValue
227      * @see ActiveValue
228      * @see java.util.Hashtable#get
229      * @see #addResourceBundle
230      * @since 1.4
231      */

232     public Object JavaDoc get(Object JavaDoc key, Locale JavaDoc l) {
233         Object JavaDoc value = getFromHashtable( key );
234         return (value != null) ? value : getFromResourceBundle(key, l);
235     }
236
237     /**
238      * Looks up given key in our resource bundles.
239      */

240     private Object JavaDoc getFromResourceBundle(Object JavaDoc key, Locale JavaDoc l) {
241
242         if( resourceBundles == null ||
243             resourceBundles.isEmpty() ||
244             !(key instanceof String JavaDoc) ) {
245             return null;
246         }
247
248         // A null locale means use the default locale.
249
if( l == null ) {
250             if( defaultLocale == null )
251                 return null;
252             else
253                 l = (Locale JavaDoc)defaultLocale;
254         }
255
256         synchronized(this) {
257             return getResourceCache(l).get((String JavaDoc)key);
258         }
259     }
260
261     /**
262      * Returns a Map of the known resources for the given locale.
263      */

264     private Map JavaDoc getResourceCache(Locale JavaDoc l) {
265         Map JavaDoc values = (Map JavaDoc)resourceCache.get(l);
266
267         if (values == null) {
268             values = new HashMap JavaDoc();
269             for (int i=resourceBundles.size()-1; i >= 0; i--) {
270                 String JavaDoc bundleName = (String JavaDoc)resourceBundles.get(i);
271                 try {
272                     ResourceBundle JavaDoc b = ResourceBundle.getBundle(bundleName, l);
273                     Enumeration JavaDoc keys = b.getKeys();
274
275                     while (keys.hasMoreElements()) {
276                         String JavaDoc key = (String JavaDoc)keys.nextElement();
277
278                         if (values.get(key) == null) {
279                             Object JavaDoc value = b.getObject(key);
280
281                             values.put(key, value);
282                         }
283                     }
284                 } catch( MissingResourceException JavaDoc mre ) {
285                     // Keep looking
286
}
287             }
288             resourceCache.put(l, values);
289         }
290         return values;
291     }
292
293     /**
294      * Sets the value of <code>key</code> to <code>value</code> for all locales.
295      * If <code>key</code> is a string and the new value isn't
296      * equal to the old one, fire a <code>PropertyChangeEvent</code>.
297      * If value is <code>null</code>, the key is removed from the table.
298      *
299      * @param key the unique <code>Object</code> who's value will be used
300      * to retrieve the data value associated with it
301      * @param value the new <code>Object</code> to store as data under
302      * that key
303      * @return the previous <code>Object</code> value, or <code>null</code>
304      * @see #putDefaults
305      * @see java.util.Hashtable#put
306      */

307     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
308         Object JavaDoc oldValue = (value == null) ? super.remove(key) : super.put(key, value);
309         if (key instanceof String JavaDoc) {
310             firePropertyChange((String JavaDoc)key, oldValue, value);
311         }
312         return oldValue;
313     }
314
315
316     /**
317      * Puts all of the key/value pairs in the database and
318      * unconditionally generates one <code>PropertyChangeEvent</code>.
319      * The events oldValue and newValue will be <code>null</code> and its
320      * <code>propertyName</code> will be "UIDefaults". The key/value pairs are
321      * added for all locales.
322      *
323      * @param keyValueList an array of key/value pairs
324      * @see #put
325      * @see java.util.Hashtable#put
326      */

327     public void putDefaults(Object JavaDoc[] keyValueList) {
328         for(int i = 0, max = keyValueList.length; i < max; i += 2) {
329             Object JavaDoc value = keyValueList[i + 1];
330             if (value == null) {
331                 super.remove(keyValueList[i]);
332             }
333             else {
334                 super.put(keyValueList[i], value);
335             }
336         }
337         firePropertyChange("UIDefaults", null, null);
338     }
339
340
341     /**
342      * If the value of <code>key</code> is a <code>Font</code> return it,
343      * otherwise return <code>null</code>.
344      * @param key the desired key
345      * @return if the value for <code>key</code> is a <code>Font</code>,
346      * return the <code>Font</code> object; otherwise return
347      * <code>null</code>
348      */

349     public Font JavaDoc getFont(Object JavaDoc key) {
350         Object JavaDoc value = get(key);
351         return (value instanceof Font JavaDoc) ? (Font JavaDoc)value : null;
352     }
353
354
355     /**
356      * If the value of <code>key</code> for the given <code>Locale</code>
357      * is a <code>Font</code> return it, otherwise return <code>null</code>.
358      * @param key the desired key
359      * @param l the desired locale
360      * @return if the value for <code>key</code> and <code>Locale</code>
361      * is a <code>Font</code>,
362      * return the <code>Font</code> object; otherwise return
363      * <code>null</code>
364      * @since 1.4
365      */

366     public Font JavaDoc getFont(Object JavaDoc key, Locale JavaDoc l) {
367         Object JavaDoc value = get(key,l);
368         return (value instanceof Font JavaDoc) ? (Font JavaDoc)value : null;
369     }
370
371     /**
372      * If the value of <code>key</code> is a <code>Color</code> return it,
373      * otherwise return <code>null</code>.
374      * @param key the desired key
375      * @return if the value for <code>key</code> is a <code>Color</code>,
376      * return the <code>Color</code> object; otherwise return
377      * <code>null</code>
378      */

379     public Color JavaDoc getColor(Object JavaDoc key) {
380         Object JavaDoc value = get(key);
381         return (value instanceof Color JavaDoc) ? (Color JavaDoc)value : null;
382     }
383
384
385     /**
386      * If the value of <code>key</code> for the given <code>Locale</code>
387      * is a <code>Color</code> return it, otherwise return <code>null</code>.
388      * @param key the desired key
389      * @param l the desired locale
390      * @return if the value for <code>key</code> and <code>Locale</code>
391      * is a <code>Color</code>,
392      * return the <code>Color</code> object; otherwise return
393      * <code>null</code>
394      * @since 1.4
395      */

396     public Color JavaDoc getColor(Object JavaDoc key, Locale JavaDoc l) {
397         Object JavaDoc value = get(key,l);
398         return (value instanceof Color JavaDoc) ? (Color JavaDoc)value : null;
399     }
400
401
402     /**
403      * If the value of <code>key</code> is an <code>Icon</code> return it,
404      * otherwise return <code>null</code>.
405      * @param key the desired key
406      * @return if the value for <code>key</code> is an <code>Icon</code>,
407      * return the <code>Icon</code> object; otherwise return
408      * <code>null</code>
409      */

410     public Icon JavaDoc getIcon(Object JavaDoc key) {
411         Object JavaDoc value = get(key);
412         return (value instanceof Icon JavaDoc) ? (Icon JavaDoc)value : null;
413     }
414
415
416     /**
417      * If the value of <code>key</code> for the given <code>Locale</code>
418      * is an <code>Icon</code> return it, otherwise return <code>null</code>.
419      * @param key the desired key
420      * @param l the desired locale
421      * @return if the value for <code>key</code> and <code>Locale</code>
422      * is an <code>Icon</code>,
423      * return the <code>Icon</code> object; otherwise return
424      * <code>null</code>
425      * @since 1.4
426      */

427     public Icon JavaDoc getIcon(Object JavaDoc key, Locale JavaDoc l) {
428         Object JavaDoc value = get(key,l);
429         return (value instanceof Icon JavaDoc) ? (Icon JavaDoc)value : null;
430     }
431
432
433     /**
434      * If the value of <code>key</code> is a <code>Border</code> return it,
435      * otherwise return <code>null</code>.
436      * @param key the desired key
437      * @return if the value for <code>key</code> is a <code>Border</code>,
438      * return the <code>Border</code> object; otherwise return
439      * <code>null</code>
440      */

441     public Border getBorder(Object JavaDoc key) {
442         Object JavaDoc value = get(key);
443         return (value instanceof Border) ? (Border)value : null;
444     }
445
446
447     /**
448      * If the value of <code>key</code> for the given <code>Locale</code>
449      * is a <code>Border</code> return it, otherwise return <code>null</code>.
450      * @param key the desired key
451      * @param l the desired locale
452      * @return if the value for <code>key</code> and <code>Locale</code>
453      * is a <code>Border</code>,
454      * return the <code>Border</code> object; otherwise return
455      * <code>null</code>
456      * @since 1.4
457      */

458     public Border getBorder(Object JavaDoc key, Locale JavaDoc l) {
459         Object JavaDoc value = get(key,l);
460         return (value instanceof Border) ? (Border)value : null;
461     }
462
463
464     /**
465      * If the value of <code>key</code> is a <code>String</code> return it,
466      * otherwise return <code>null</code>.
467      * @param key the desired key
468      * @return if the value for <code>key</code> is a <code>String</code>,
469      * return the <code>String</code> object; otherwise return
470      * <code>null</code>
471      */

472     public String JavaDoc getString(Object JavaDoc key) {
473         Object JavaDoc value = get(key);
474         return (value instanceof String JavaDoc) ? (String JavaDoc)value : null;
475     }
476
477     /**
478      * If the value of <code>key</code> for the given <code>Locale</code>
479      * is a <code>String</code> return it, otherwise return <code>null</code>.
480      * @param key the desired key
481      * @param l the desired <code>Locale</code>
482      * @return if the value for <code>key</code> for the given
483      * <code>Locale</code> is a <code>String</code>,
484      * return the <code>String</code> object; otherwise return
485      * <code>null</code>
486      * @since 1.4
487      */

488     public String JavaDoc getString(Object JavaDoc key, Locale JavaDoc l) {
489         Object JavaDoc value = get(key,l);
490         return (value instanceof String JavaDoc) ? (String JavaDoc)value : null;
491     }
492
493     /**
494      * If the value of <code>key</code> is an <code>Integer</code> return its
495      * integer value, otherwise return 0.
496      * @param key the desired key
497      * @return if the value for <code>key</code> is an <code>Integer</code>,
498      * return its value, otherwise return 0
499      */

500     public int getInt(Object JavaDoc key) {
501         Object JavaDoc value = get(key);
502         return (value instanceof Integer JavaDoc) ? ((Integer JavaDoc)value).intValue() : 0;
503     }
504
505
506     /**
507      * If the value of <code>key</code> for the given <code>Locale</code>
508      * is an <code>Integer</code> return its integer value, otherwise return 0.
509      * @param key the desired key
510      * @param l the desired locale
511      * @return if the value for <code>key</code> and <code>Locale</code>
512      * is an <code>Integer</code>,
513      * return its value, otherwise return 0
514      * @since 1.4
515      */

516     public int getInt(Object JavaDoc key, Locale JavaDoc l) {
517         Object JavaDoc value = get(key,l);
518         return (value instanceof Integer JavaDoc) ? ((Integer JavaDoc)value).intValue() : 0;
519     }
520
521
522     /**
523      * If the value of <code>key</code> is boolean, return the
524      * boolean value, otherwise return false.
525      *
526      * @param key an <code>Object</code> specifying the key for the desired boolean value
527      * @return if the value of <code>key</code> is boolean, return the
528      * boolean value, otherwise return false.
529      * @since 1.4
530      */

531     public boolean getBoolean(Object JavaDoc key) {
532         Object JavaDoc value = get(key);
533         return (value instanceof Boolean JavaDoc) ? ((Boolean JavaDoc)value).booleanValue() : false;
534     }
535
536
537     /**
538      * If the value of <code>key</code> for the given <code>Locale</code>
539      * is boolean, return the boolean value, otherwise return false.
540      *
541      * @param key an <code>Object</code> specifying the key for the desired boolean value
542      * @param l the desired locale
543      * @return if the value for <code>key</code> and <code>Locale</code>
544      * is boolean, return the
545      * boolean value, otherwise return false.
546      * @since 1.4
547      */

548     public boolean getBoolean(Object JavaDoc key, Locale JavaDoc l) {
549         Object JavaDoc value = get(key,l);
550         return (value instanceof Boolean JavaDoc) ? ((Boolean JavaDoc)value).booleanValue() : false;
551     }
552
553
554     /**
555      * If the value of <code>key</code> is an <code>Insets</code> return it,
556      * otherwise return <code>null</code>.
557      * @param key the desired key
558      * @return if the value for <code>key</code> is an <code>Insets</code>,
559      * return the <code>Insets</code> object; otherwise return
560      * <code>null</code>
561      */

562     public Insets JavaDoc getInsets(Object JavaDoc key) {
563         Object JavaDoc value = get(key);
564         return (value instanceof Insets JavaDoc) ? (Insets JavaDoc)value : null;
565     }
566
567
568     /**
569      * If the value of <code>key</code> for the given <code>Locale</code>
570      * is an <code>Insets</code> return it, otherwise return <code>null</code>.
571      * @param key the desired key
572      * @param l the desired locale
573      * @return if the value for <code>key</code> and <code>Locale</code>
574      * is an <code>Insets</code>,
575      * return the <code>Insets</code> object; otherwise return
576      * <code>null</code>
577      * @since 1.4
578      */

579     public Insets JavaDoc getInsets(Object JavaDoc key, Locale JavaDoc l) {
580         Object JavaDoc value = get(key,l);
581         return (value instanceof Insets JavaDoc) ? (Insets JavaDoc)value : null;
582     }
583
584
585     /**
586      * If the value of <code>key</code> is a <code>Dimension</code> return it,
587      * otherwise return <code>null</code>.
588      * @param key the desired key
589      * @return if the value for <code>key</code> is a <code>Dimension</code>,
590      * return the <code>Dimension</code> object; otherwise return
591      * <code>null</code>
592      */

593     public Dimension JavaDoc getDimension(Object JavaDoc key) {
594         Object JavaDoc value = get(key);
595         return (value instanceof Dimension JavaDoc) ? (Dimension JavaDoc)value : null;
596     }
597
598
599     /**
600      * If the value of <code>key</code> for the given <code>Locale</code>
601      * is a <code>Dimension</code> return it, otherwise return <code>null</code>.
602      * @param key the desired key
603      * @param l the desired locale
604      * @return if the value for <code>key</code> and <code>Locale</code>
605      * is a <code>Dimension</code>,
606      * return the <code>Dimension</code> object; otherwise return
607      * <code>null</code>
608      * @since 1.4
609      */

610     public Dimension JavaDoc getDimension(Object JavaDoc key, Locale JavaDoc l) {
611         Object JavaDoc value = get(key,l);
612         return (value instanceof Dimension JavaDoc) ? (Dimension JavaDoc)value : null;
613     }
614
615
616     /**
617      * The value of <code>get(uidClassID)</code> must be the
618      * <code>String</code> name of a
619      * class that implements the corresponding <code>ComponentUI</code>
620      * class. If the class hasn't been loaded before, this method looks
621      * up the class with <code>uiClassLoader.loadClass()</code> if a non
622      * <code>null</code>
623      * class loader is provided, <code>classForName()</code> otherwise.
624      * <p>
625      * If a mapping for <code>uiClassID</code> exists or if the specified
626      * class can't be found, return <code>null</code>.
627      * <p>
628      * This method is used by <code>getUI</code>, it's usually
629      * not necessary to call it directly.
630      *
631      * @param uiClassID a string containing the class ID
632      * @param uiClassLoader the object which will load the class
633      * @return the value of <code>Class.forName(get(uidClassID))</code>
634      * @see #getUI
635      */

636     public Class JavaDoc<? extends ComponentUI JavaDoc>
637     getUIClass(String JavaDoc uiClassID, ClassLoader JavaDoc uiClassLoader)
638     {
639         try {
640             String JavaDoc className = (String JavaDoc)get(uiClassID);
641             if (className != null) {
642                 Class JavaDoc cls = (Class JavaDoc)get(className);
643                 if (cls == null) {
644                     if (uiClassLoader == null) {
645                         cls = SwingUtilities.loadSystemClass(className);
646                     }
647                     else {
648                         cls = uiClassLoader.loadClass(className);
649                     }
650                     if (cls != null) {
651                         // Save lookup for future use, as forName is slow.
652
put(className, cls);
653                     }
654                 }
655                 return cls;
656             }
657         }
658     catch (ClassNotFoundException JavaDoc e) {
659             return null;
660         }
661     catch (ClassCastException JavaDoc e) {
662             return null;
663         }
664         return null;
665     }
666
667
668     /**
669      * Returns the L&F class that renders this component.
670      *
671      * @param uiClassID a string containing the class ID
672      * @return the Class object returned by
673      * <code>getUIClass(uiClassID, null)</code>
674      */

675     public Class JavaDoc<? extends ComponentUI JavaDoc> getUIClass(String JavaDoc uiClassID) {
676     return getUIClass(uiClassID, null);
677     }
678
679
680     /**
681      * If <code>getUI()</code> fails for any reason,
682      * it calls this method before returning <code>null</code>.
683      * Subclasses may choose to do more or less here.
684      *
685      * @param msg message string to print
686      * @see #getUI
687      */

688     protected void getUIError(String JavaDoc msg) {
689         System.err.println("UIDefaults.getUI() failed: " + msg);
690         try {
691             throw new Error JavaDoc();
692         }
693         catch (Throwable JavaDoc e) {
694             e.printStackTrace();
695         }
696     }
697
698     /**
699      * Creates an <code>ComponentUI</code> implementation for the
700      * specified component. In other words create the look
701      * and feel specific delegate object for <code>target</code>.
702      * This is done in two steps:
703      * <ul>
704      * <li> Look up the name of the <code>ComponentUI</code> implementation
705      * class under the value returned by <code>target.getUIClassID()</code>.
706      * <li> Use the implementation classes static <code>createUI()</code>
707      * method to construct a look and feel delegate.
708      * </ul>
709      * @param target the <code>JComponent</code> which needs a UI
710      * @return the <code>ComponentUI</code> object
711      */

712     public ComponentUI JavaDoc getUI(JComponent JavaDoc target) {
713
714         Object JavaDoc cl = get("ClassLoader");
715     ClassLoader JavaDoc uiClassLoader =
716         (cl != null) ? (ClassLoader JavaDoc)cl : target.getClass().getClassLoader();
717         Class JavaDoc uiClass = getUIClass(target.getUIClassID(), uiClassLoader);
718         Object JavaDoc uiObject = null;
719
720         if (uiClass == null) {
721             getUIError("no ComponentUI class for: " + target);
722         }
723         else {
724             try {
725         Method JavaDoc m = (Method JavaDoc)get(uiClass);
726         if (m == null) {
727             Class JavaDoc acClass = javax.swing.JComponent JavaDoc.class;
728             m = uiClass.getMethod("createUI", new Class JavaDoc[]{acClass});
729             put(uiClass, m);
730         }
731         uiObject = MethodUtil.invoke(m, null, new Object JavaDoc[]{target});
732             }
733             catch (NoSuchMethodException JavaDoc e) {
734                 getUIError("static createUI() method not found in " + uiClass);
735             }
736             catch (Exception JavaDoc e) {
737                 getUIError("createUI() failed for " + target + " " + e);
738             }
739         }
740
741         return (ComponentUI JavaDoc)uiObject;
742     }
743
744     /**
745      * Adds a <code>PropertyChangeListener</code> to the listener list.
746      * The listener is registered for all properties.
747      * <p>
748      * A <code>PropertyChangeEvent</code> will get fired whenever a default
749      * is changed.
750      *
751      * @param listener the <code>PropertyChangeListener</code> to be added
752      * @see java.beans.PropertyChangeSupport
753      */

754     public synchronized void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
755         if (changeSupport == null) {
756             changeSupport = new SwingPropertyChangeSupport JavaDoc(this);
757         }
758         changeSupport.addPropertyChangeListener(listener);
759     }
760
761
762     /**
763      * Removes a <code>PropertyChangeListener</code> from the listener list.
764      * This removes a <code>PropertyChangeListener</code> that was registered
765      * for all properties.
766      *
767      * @param listener the <code>PropertyChangeListener</code> to be removed
768      * @see java.beans.PropertyChangeSupport
769      */

770     public synchronized void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
771         if (changeSupport != null) {
772             changeSupport.removePropertyChangeListener(listener);
773         }
774     }
775
776
777     /**
778      * Returns an array of all the <code>PropertyChangeListener</code>s added
779      * to this UIDefaults with addPropertyChangeListener().
780      *
781      * @return all of the <code>PropertyChangeListener</code>s added or an empty
782      * array if no listeners have been added
783      * @since 1.4
784      */

785     public synchronized PropertyChangeListener JavaDoc[] getPropertyChangeListeners() {
786         if (changeSupport == null) {
787             return new PropertyChangeListener JavaDoc[0];
788         }
789         return changeSupport.getPropertyChangeListeners();
790     }
791
792
793     /**
794      * Support for reporting bound property changes. If oldValue and
795      * newValue are not equal and the <code>PropertyChangeEvent</code>x
796      * listener list isn't empty, then fire a
797      * <code>PropertyChange</code> event to each listener.
798      *
799      * @param propertyName the programmatic name of the property
800      * that was changed
801      * @param oldValue the old value of the property
802      * @param newValue the new value of the property
803      * @see java.beans.PropertyChangeSupport
804      */

805     protected void firePropertyChange(String JavaDoc propertyName, Object JavaDoc oldValue, Object JavaDoc newValue) {
806         if (changeSupport != null) {
807             changeSupport.firePropertyChange(propertyName, oldValue, newValue);
808         }
809     }
810
811
812     /**
813      * Adds a resource bundle to the list of resource bundles that are
814      * searched for localized values. Resource bundles are searched in the
815      * reverse order they were added. In other words, the most recently added
816      * bundle is searched first.
817      *
818      * @param bundleName the base name of the resource bundle to be added
819      * @see java.util.ResourceBundle
820      * @see #removeResourceBundle
821      * @since 1.4
822      */

823     public synchronized void addResourceBundle( String JavaDoc bundleName ) {
824         if( bundleName == null ) {
825             return;
826         }
827         if( resourceBundles == null ) {
828             resourceBundles = new Vector JavaDoc(5);
829         }
830         if (!resourceBundles.contains(bundleName)) {
831             resourceBundles.add( bundleName );
832             resourceCache.clear();
833         }
834     }
835
836
837     /**
838      * Removes a resource bundle from the list of resource bundles that are
839      * searched for localized defaults.
840      *
841      * @param bundleName the base name of the resource bundle to be removed
842      * @see java.util.ResourceBundle
843      * @see #addResourceBundle
844      * @since 1.4
845      */

846     public synchronized void removeResourceBundle( String JavaDoc bundleName ) {
847         if( resourceBundles != null ) {
848             resourceBundles.remove( bundleName );
849         }
850         resourceCache.clear();
851     }
852
853     /**
854      * Sets the default locale. The default locale is used in retrieving
855      * localized values via <code>get</code> methods that do not take a
856      * locale argument. As of release 1.4, Swing UI objects should retrieve
857      * localized values using the locale of their component rather than the
858      * default locale. The default locale exists to provide compatibility with
859      * pre 1.4 behaviour.
860      *
861      * @param l the new default locale
862      * @see #getDefaultLocale
863      * @see #get(Object)
864      * @see #get(Object,Locale)
865      * @since 1.4
866      */

867     public void setDefaultLocale( Locale JavaDoc l ) {
868         defaultLocale = l;
869     }
870
871     /**
872      * Returns the default locale. The default locale is used in retrieving
873      * localized values via <code>get</code> methods that do not take a
874      * locale argument. As of release 1.4, Swing UI objects should retrieve
875      * localized values using the locale of their component rather than the
876      * default locale. The default locale exists to provide compatibility with
877      * pre 1.4 behaviour.
878      *
879      * @return the default locale
880      * @see #setDefaultLocale
881      * @see #get(Object)
882      * @see #get(Object,Locale)
883      * @since 1.4
884      */

885     public Locale JavaDoc getDefaultLocale() {
886         return defaultLocale;
887     }
888
889     /**
890      * This class enables one to store an entry in the defaults
891      * table that isn't constructed until the first time it's
892      * looked up with one of the <code>getXXX(key)</code> methods.
893      * Lazy values are useful for defaults that are expensive
894      * to construct or are seldom retrieved. The first time
895      * a <code>LazyValue</code> is retrieved its "real value" is computed
896      * by calling <code>LazyValue.createValue()</code> and the real
897      * value is used to replace the <code>LazyValue</code> in the
898      * <code>UIDefaults</code>
899      * table. Subsequent lookups for the same key return
900      * the real value. Here's an example of a <code>LazyValue</code>
901      * that constructs a <code>Border</code>:
902      * <pre>
903      * Object borderLazyValue = new UIDefaults.LazyValue() {
904      * public Object createValue(UIDefaults table) {
905      * return new BorderFactory.createLoweredBevelBorder();
906      * }
907      * };
908      *
909      * uiDefaultsTable.put("MyBorder", borderLazyValue);
910      * </pre>
911      *
912      * @see UIDefaults#get
913      */

914     public interface LazyValue {
915         /**
916          * Creates the actual value retrieved from the <code>UIDefaults</code>
917          * table. When an object that implements this interface is
918          * retrieved from the table, this method is used to create
919          * the real value, which is then stored in the table and
920          * returned to the calling method.
921          *
922          * @param table a <code>UIDefaults</code> table
923          * @return the created <code>Object</code>
924          */

925         Object JavaDoc createValue(UIDefaults JavaDoc table);
926     }
927
928
929     /**
930      * This class enables one to store an entry in the defaults
931      * table that's constructed each time it's looked up with one of
932      * the <code>getXXX(key)</code> methods. Here's an example of
933      * an <code>ActiveValue</code> that constructs a
934      * <code>DefaultListCellRenderer</code>:
935      * <pre>
936      * Object cellRendererActiveValue = new UIDefaults.ActiveValue() {
937      * public Object createValue(UIDefaults table) {
938      * return new DefaultListCellRenderer();
939      * }
940      * };
941      *
942      * uiDefaultsTable.put("MyRenderer", cellRendererActiveValue);
943      * </pre>
944      *
945      * @see UIDefaults#get
946      */

947     public interface ActiveValue {
948         /**
949          * Creates the value retrieved from the <code>UIDefaults</code> table.
950          * The object is created each time it is accessed.
951          *
952          * @param table a <code>UIDefaults</code> table
953          * @return the created <code>Object</code>
954          */

955         Object JavaDoc createValue(UIDefaults JavaDoc table);
956     }
957
958     /**
959      * This class provides an implementation of <code>LazyValue</code>
960      * which can be
961      * used to delay loading of the Class for the instance to be created.
962      * It also avoids creation of an anonymous inner class for the
963      * <code>LazyValue</code>
964      * subclass. Both of these improve performance at the time that a
965      * a Look and Feel is loaded, at the cost of a slight performance
966      * reduction the first time <code>createValue</code> is called
967      * (since Reflection APIs are used).
968      */

969     public static class ProxyLazyValue implements LazyValue {
970         private AccessControlContext JavaDoc acc;
971     private String JavaDoc className;
972     private String JavaDoc methodName;
973     private Object JavaDoc[] args;
974
975     /**
976      * Creates a <code>LazyValue</code> which will construct an instance
977      * when asked.
978      *
979      * @param c a <code>String</code> specifying the classname
980      * of the instance to be created on demand
981      */

982     public ProxyLazyValue(String JavaDoc c) {
983             this(c, (String JavaDoc)null);
984     }
985     /**
986      * Creates a <code>LazyValue</code> which will construct an instance
987      * when asked.
988      *
989      * @param c a <code>String</code> specifying the classname of
990          * the class
991      * containing a static method to be called for
992      * instance creation
993      * @param m a <code>String</code> specifying the static
994          * method to be called on class c
995      */

996     public ProxyLazyValue(String JavaDoc c, String JavaDoc m) {
997             this(c, m, null);
998     }
999     /**
1000     * Creates a <code>LazyValue</code> which will construct an instance
1001     * when asked.
1002     *
1003     * @param c a <code>String</code> specifying the classname
1004         * of the instance to be created on demand
1005     * @param o an array of <code>Objects</code> to be passed as
1006         * paramaters to the constructor in class c
1007     */

1008    public ProxyLazyValue(String JavaDoc c, Object JavaDoc[] o) {
1009            this(c, null, o);
1010    }
1011    /**
1012     * Creates a <code>LazyValue</code> which will construct an instance
1013     * when asked.
1014     *
1015     * @param c a <code>String</code> specifying the classname
1016         * of the class
1017     * containing a static method to be called for
1018     * instance creation.
1019     * @param m a <code>String</code> specifying the static method
1020         * to be called on class c
1021     * @param o an array of <code>Objects</code> to be passed as
1022         * paramaters to the static method in class c
1023     */

1024    public ProxyLazyValue(String JavaDoc c, String JavaDoc m, Object JavaDoc[] o) {
1025            acc = AccessController.getContext();
1026        className = c;
1027        methodName = m;
1028            if (o != null) {
1029                args = (Object JavaDoc[])o.clone();
1030            }
1031    }
1032
1033        /**
1034         * Creates the value retrieved from the <code>UIDefaults</code> table.
1035         * The object is created each time it is accessed.
1036         *
1037         * @param table a <code>UIDefaults</code> table
1038         * @return the created <code>Object</code>
1039         */

1040    public Object JavaDoc createValue(final UIDefaults JavaDoc table) {
1041            // In order to pick up the security policy in effect at the
1042
// time of creation we use a doPrivileged with the
1043
// AccessControlContext that was in place when this was created.
1044
return AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
1045                public Object JavaDoc run() {
1046                    try {
1047                        Class JavaDoc c;
1048                        Object JavaDoc cl;
1049                        // See if we should use a separate ClassLoader
1050
if (table == null || !((cl = table.get("ClassLoader"))
1051                                               instanceof ClassLoader JavaDoc)) {
1052                            cl = Thread.currentThread().
1053                                        getContextClassLoader();
1054                            if (cl == null) {
1055                                // Fallback to the system class loader.
1056
cl = ClassLoader.getSystemClassLoader();
1057                            }
1058                        }
1059                        c = Class.forName(className, true, (ClassLoader JavaDoc)cl);
1060                        if (methodName != null) {
1061                            Class JavaDoc[] types = getClassArray(args);
1062                            Method JavaDoc m = c.getMethod(methodName, types);
1063                            return MethodUtil.invoke(m, c, args);
1064                        } else {
1065                            Class JavaDoc[] types = getClassArray(args);
1066                            Constructor constructor = c.getConstructor(types);
1067                            return constructor.newInstance(args);
1068                        }
1069                    } catch(Exception JavaDoc e) {
1070                        // Ideally we would throw an exception, unfortunately
1071
// often times there are errors as an initial look and
1072
// feel is loaded before one can be switched. Perhaps a
1073
// flag should be added for debugging, so that if true
1074
// the exception would be thrown.
1075
}
1076                    return null;
1077                }
1078            }, acc);
1079    }
1080
1081    /*
1082     * Coerce the array of class types provided into one which
1083     * looks the way the Reflection APIs expect. This is done
1084     * by substituting primitive types for their Object counterparts,
1085     * and superclasses for subclasses used to add the
1086         * <code>UIResource</code> tag.
1087     */

1088    private Class JavaDoc[] getClassArray(Object JavaDoc[] args) {
1089        Class JavaDoc[] types = null;
1090        if (args!=null) {
1091        types = new Class JavaDoc[args.length];
1092        for (int i = 0; i< args.length; i++) {
1093            /* PENDING(ges): At present only the primitive types
1094               used are handled correctly; this should eventually
1095               handle all primitive types */

1096            if (args[i] instanceof java.lang.Integer JavaDoc) {
1097            types[i]=Integer.TYPE;
1098            } else if (args[i] instanceof java.lang.Boolean JavaDoc) {
1099            types[i]=Boolean.TYPE;
1100            } else if (args[i] instanceof javax.swing.plaf.ColorUIResource JavaDoc) {
1101            /* PENDING(ges) Currently the Reflection APIs do not
1102               search superclasses of parameters supplied for
1103               constructor/method lookup. Since we only have
1104               one case where this is needed, we substitute
1105               directly instead of adding a massive amount
1106               of mechanism for this. Eventually this will
1107               probably need to handle the general case as well.
1108               */

1109            types[i]=java.awt.Color JavaDoc.class;
1110            } else {
1111            types[i]=args[i].getClass();
1112            }
1113        }
1114        }
1115        return types;
1116    }
1117
1118    private String JavaDoc printArgs(Object JavaDoc[] array) {
1119        String JavaDoc s = "{";
1120        if (array !=null) {
1121        for (int i = 0 ; i < array.length-1; i++) {
1122            s = s.concat(array[i] + ",");
1123        }
1124        s = s.concat(array[array.length-1] + "}");
1125        } else {
1126        s = s.concat("}");
1127        }
1128        return s;
1129    }
1130    }
1131
1132
1133    /**
1134     * <code>LazyInputMap</code> will create a <code>InputMap</code>
1135     * in its <code>createValue</code>
1136     * method. The bindings are passed in in the constructor.
1137     * The bindings are an array with
1138     * the even number entries being string <code>KeyStrokes</code>
1139     * (eg "alt SPACE") and
1140     * the odd number entries being the value to use in the
1141     * <code>InputMap</code> (and the key in the <code>ActionMap</code>).
1142     */

1143    public static class LazyInputMap implements LazyValue {
1144    /** Key bindings are registered under. */
1145    private Object JavaDoc[] bindings;
1146
1147    public LazyInputMap(Object JavaDoc[] bindings) {
1148        this.bindings = bindings;
1149    }
1150
1151        /**
1152         * Creates an <code>InputMap</code> with the bindings that are
1153         * passed in.
1154         *
1155         * @param table a <code>UIDefaults</code> table
1156         * @return the <code>InputMap</code>
1157         */

1158        public Object JavaDoc createValue(UIDefaults JavaDoc table) {
1159        if (bindings != null) {
1160        InputMap JavaDoc km = LookAndFeel.makeInputMap(bindings);
1161        return km;
1162        }
1163        return null;
1164    }
1165    }
1166}
1167
Popular Tags