OSDN Git Service

libjava/
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / UIManager.java
1 /* UIManager.java -- 
2    Copyright (C) 2002, 2003, 2004, 2005, 2006,  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing;
40
41 import java.awt.Color;
42 import java.awt.Dimension;
43 import java.awt.Font;
44 import java.awt.Insets;
45 import java.beans.PropertyChangeListener;
46 import java.beans.PropertyChangeSupport;
47 import java.io.Serializable;
48 import java.util.Enumeration;
49 import java.util.Locale;
50
51 import javax.swing.border.Border;
52 import javax.swing.plaf.ComponentUI;
53 import javax.swing.plaf.metal.MetalLookAndFeel;
54
55 /**
56  * Manages the current {@link LookAndFeel} and any auxiliary {@link LookAndFeel}
57  * instances.
58  */
59 public class UIManager implements Serializable
60 {
61   /**
62    * Represents the basic information about a {@link LookAndFeel} (LAF), so 
63    * that a list of installed LAFs can be presented without actually loading 
64    * the LAF class(es).
65    */
66   public static class LookAndFeelInfo
67   {
68     String name, clazz;
69         
70     /**
71      * Creates a new instance.
72      * 
73      * @param name  the look and feel name.
74      * @param clazz  the look and feel class name.
75      */
76     public LookAndFeelInfo(String name, 
77                            String clazz)
78     {
79       this.name  = name;
80       this.clazz = clazz;
81     }
82
83     /**
84      * Returns the name of the look and feel.
85      * 
86      * @return The name of the look and feel.
87      */
88     public String getName()
89     {
90       return name;
91     }
92     
93     /**
94      * Returns the fully qualified class name for the {@link LookAndFeel}.
95      * 
96      * @return The fully qualified class name for the {@link LookAndFeel}.
97      */
98     public String getClassName()
99     {
100       return clazz;
101     }
102
103     /**
104      * Returns a String representation of the LookAndFeelInfo object.
105      *
106      * @return a String representation of the LookAndFeelInfo object
107      */
108     public String toString()
109     {
110       StringBuffer s = new StringBuffer();
111       s.append(getClass().getName());
112       s.append('[');
113       s.append(getName());
114       s.append(' ');
115       s.append(getClassName());
116       s.append(']');
117       return s.toString();
118     }
119   }
120
121   /**
122    * A UIDefaults subclass that multiplexes between itself and a 'fallback'
123    * UIDefaults instance. This is used to protect the L&F UIDefaults from beeing
124    * overwritten by applications.
125    */
126   private static class MultiplexUIDefaults
127     extends UIDefaults
128   {
129     private class MultiplexEnumeration
130       implements Enumeration
131     {
132       Enumeration[] enums;
133       int i;
134       MultiplexEnumeration(Enumeration e1, Enumeration e2)
135       {
136         enums = new Enumeration[]{ e1, e2 };
137         i = 0;
138       }
139
140       public boolean hasMoreElements()
141       {
142         return enums[i].hasMoreElements() || i < enums.length - 1;
143       }
144
145       public Object nextElement()
146       {
147         Object val = enums[i].nextElement();
148         if (! enums[i].hasMoreElements() && i < enums.length - 1)
149           i++;
150         return val;
151       }
152         
153     }
154
155     UIDefaults fallback;
156
157     /**
158      * Creates a new <code>MultiplexUIDefaults</code> instance with 
159      * <code>d</code> as the fallback defaults.
160      * 
161      * @param d  the fallback defaults (<code>null</code> not permitted).
162      */
163     MultiplexUIDefaults(UIDefaults d)
164     {
165       if (d == null) 
166         throw new NullPointerException();
167       fallback = d;
168     }
169
170     public Object get(Object key)
171     {
172       Object val = super.get(key);
173       if (val == null)
174         val = fallback.get(key);
175       return val;
176     }
177
178     public Object get(Object key, Locale l)
179     {
180       Object val = super.get(key, l);
181       if (val == null)
182         val = fallback.get(key, l);
183       return val;
184     }
185
186     public Object remove(Object key)
187     {
188       Object val = super.remove(key);
189       if (val == null)
190         val = fallback.remove(key);
191       return val;
192     }
193
194     public int size()
195     {
196       return super.size() + fallback.size();
197     }
198
199     public Enumeration keys()
200     {
201       return new MultiplexEnumeration(super.keys(), fallback.keys());
202     }
203
204     public Enumeration elements()
205     {
206       return new MultiplexEnumeration(super.elements(), fallback.elements());
207     }
208   }
209
210   private static final long serialVersionUID = -5547433830339189365L;
211
212   /** The installed look and feel(s). */
213   static LookAndFeelInfo [] installed = {
214     new LookAndFeelInfo("Metal", "javax.swing.plaf.metal.MetalLookAndFeel"),
215     new LookAndFeelInfo("GNU", "gnu.javax.swing.plaf.gnu.GNULookAndFeel")
216   };
217
218   /** The installed auxiliary look and feels. */
219   static LookAndFeel[] auxLookAndFeels;
220   
221   /** The current look and feel. */
222   static LookAndFeel currentLookAndFeel;
223   
224   static MultiplexUIDefaults currentUIDefaults;
225
226   static UIDefaults lookAndFeelDefaults;
227
228   /** Property change listener mechanism. */
229   static PropertyChangeSupport listeners
230       = new PropertyChangeSupport(UIManager.class);
231
232   static
233   {
234     String defaultlaf = System.getProperty("swing.defaultlaf");
235     try 
236       {
237         if (defaultlaf != null)
238           {
239             setLookAndFeel(defaultlaf);
240           }
241         else
242           {
243             setLookAndFeel(new MetalLookAndFeel());
244           }
245       }
246     catch (Exception ex)
247       {
248         System.err.println("cannot initialize Look and Feel: " + defaultlaf);
249         System.err.println("error: " + ex.toString());
250         ex.printStackTrace();
251         System.err.println("falling back to Metal Look and Feel");
252         try
253           {
254             setLookAndFeel(new MetalLookAndFeel());
255           }
256         catch (Exception ex2)
257         {
258           throw (Error) new AssertionError("There must be no problem installing"
259                                            + " the MetalLookAndFeel.")
260                                            .initCause(ex2);
261         }
262       }
263   }
264
265   /**
266    * Creates a new instance of the <code>UIManager</code>.  There is no need
267    * to construct an instance of this class, since all methods are static.
268    */
269   public UIManager()
270   {
271     // Do nothing here.
272   }
273
274   /**
275    * Add a <code>PropertyChangeListener</code> to the listener list.
276    *
277    * @param listener the listener to add
278    */
279   public static void addPropertyChangeListener(PropertyChangeListener listener)
280   {
281     listeners.addPropertyChangeListener(listener);
282   }
283
284   /**
285    * Remove a <code>PropertyChangeListener</code> from the listener list.
286    *
287    * @param listener the listener to remove
288    */
289   public static void removePropertyChangeListener(PropertyChangeListener 
290           listener)
291   {
292     listeners.removePropertyChangeListener(listener);
293   }
294
295   /**
296    * Returns an array of all added <code>PropertyChangeListener</code> objects.
297    *
298    * @return an array of listeners
299    *
300    * @since 1.4
301    */
302   public static PropertyChangeListener[] getPropertyChangeListeners()
303   {
304     return listeners.getPropertyChangeListeners();
305   }
306
307   /**
308    * Add a {@link LookAndFeel} to the list of auxiliary look and feels.
309    * 
310    * @param laf  the auxiliary look and feel (<code>null</code> not permitted).
311    * 
312    * @throws NullPointerException if <code>laf</code> is <code>null</code>.
313    * 
314    * @see #getAuxiliaryLookAndFeels()
315    */
316   public static void addAuxiliaryLookAndFeel(LookAndFeel laf)
317   {
318     if (laf == null)
319       throw new NullPointerException("Null 'laf' argument.");
320     if (auxLookAndFeels == null)
321       {
322         auxLookAndFeels = new LookAndFeel[1];
323         auxLookAndFeels[0] = laf;
324         return;
325       }
326         
327     LookAndFeel[] temp = new LookAndFeel[auxLookAndFeels.length + 1];
328     System.arraycopy(auxLookAndFeels, 0, temp, 0, auxLookAndFeels.length);                       
329     auxLookAndFeels = temp;
330     auxLookAndFeels[auxLookAndFeels.length - 1] = laf;
331   }
332     
333   /**
334    * Removes a {@link LookAndFeel} (LAF) from the list of auxiliary LAFs.
335    * 
336    * @param laf  the LAF to remove.
337    * 
338    * @return <code>true</code> if the LAF was removed, and <code>false</code>
339    *         otherwise.
340    */
341   public static boolean removeAuxiliaryLookAndFeel(LookAndFeel laf)
342   {
343     if (auxLookAndFeels == null)
344       return false;
345     int count = auxLookAndFeels.length;
346     if (count == 1 && auxLookAndFeels[0] == laf)
347       {
348         auxLookAndFeels = null;
349         return true;
350       }
351     for (int i = 0; i < count; i++)
352       {
353         if (auxLookAndFeels[i] == laf)
354           {
355             LookAndFeel[] temp = new LookAndFeel[auxLookAndFeels.length - 1];
356             if (i == 0)
357               {
358                 System.arraycopy(auxLookAndFeels, 1, temp, 0, count - 1);  
359               }
360             else if (i == count - 1)
361               {
362                 System.arraycopy(auxLookAndFeels, 0, temp, 0, count - 1);
363               }
364             else 
365               {
366                 System.arraycopy(auxLookAndFeels, 0, temp, 0, i);
367                 System.arraycopy(auxLookAndFeels, i + 1, temp, i, 
368                         count - i - 1);
369               }
370             auxLookAndFeels = temp;
371             return true;
372           }             
373       }
374     return false;
375   }
376
377   /**
378    * Returns an array (possibly <code>null</code>) containing the auxiliary
379    * {@link LookAndFeel}s that are in use.  These are used by the 
380    * {@link javax.swing.plaf.multi.MultiLookAndFeel} class.
381    * 
382    * @return The auxiliary look and feels (possibly <code>null</code>).
383    * 
384    * @see #addAuxiliaryLookAndFeel(LookAndFeel)
385    */
386   public static LookAndFeel[] getAuxiliaryLookAndFeels()
387   {
388     return auxLookAndFeels;
389   }
390
391   /**
392    * Returns an object from the {@link UIDefaults} table for the current
393    * {@link LookAndFeel}.
394    * 
395    * @param key  the key.
396    * 
397    * @return The object.
398    */
399   public static Object get(Object key)
400   {
401     return getDefaults().get(key);
402   }
403
404   /**
405    * Returns an object from the {@link UIDefaults} table for the current
406    * {@link LookAndFeel}.
407    * 
408    * @param key  the key.
409    * 
410    * @return The object.
411    * 
412    * @since 1.4
413    */
414   public static Object get(Object key, Locale locale)
415   {
416     return getDefaults().get(key, locale);
417   }
418
419   /**
420    * Returns a boolean value from the defaults table.  If there is no value
421    * for the specified key, or the value is not an instance of {@link Boolean},
422    * this method returns <code>false</code>.
423    * 
424    * @param key  the key (<code>null</code> not permitted).
425    *
426    * @return The boolean value associated with the specified key.
427    * 
428    * @throws NullPointerException if <code>key</code> is <code>null</code>.
429    * 
430    * @since 1.4
431    */
432   public static boolean getBoolean(Object key)
433   {
434     Object value = get(key);
435     if (value instanceof Boolean) 
436       return ((Boolean) value).booleanValue();
437     return false;
438   }
439   
440   /**
441    * Returns a boolean value from the defaults table.  If there is no value
442    * for the specified key, or the value is not an instance of {@link Boolean},
443    * this method returns <code>false</code>.
444    * 
445    * @param key  the key (<code>null</code> not permitted).
446    * @param locale  the locale.
447    *
448    * @return The boolean value associated with the specified key.
449    * 
450    * @throws NullPointerException if <code>key</code> is <code>null</code>.
451    * 
452    * @since 1.4
453    */
454   public static boolean getBoolean(Object key, Locale locale)
455   {
456     Object value = get(key, locale);
457     if (value instanceof Boolean) 
458       return ((Boolean) value).booleanValue();
459     return false;
460   }
461     
462   /**
463    * Returns a border from the defaults table. 
464    * 
465    * @param key  the key (<code>null</code> not permitted).
466    * 
467    * @return The border associated with the given key, or <code>null</code>.
468    * 
469    * @throws NullPointerException if <code>key</code> is <code>null</code>.
470    */
471   public static Border getBorder(Object key)
472   {
473     Object value = get(key);
474     if (value instanceof Border) 
475       return (Border) value;
476     return null;
477   }
478     
479   /**
480    * Returns a border from the defaults table. 
481    * 
482    * @param key  the key (<code>null</code> not permitted).
483    * @param locale  the locale.
484    * 
485    * @return The border associated with the given key, or <code>null</code>.
486    * 
487    * @throws NullPointerException if <code>key</code> is <code>null</code>.
488    *
489    * @since 1.4
490    */
491   public static Border getBorder(Object key, Locale locale)
492   {
493     Object value = get(key, locale);
494     if (value instanceof Border) 
495       return (Border) value;
496     return null;
497   }
498     
499   /**
500    * Returns a drawing color from the defaults table. 
501    * 
502    * @param key  the key (<code>null</code> not permitted).
503    * 
504    * @return The color associated with the given key, or <code>null</code>.
505    * 
506    * @throws NullPointerException if <code>key</code> is <code>null</code>.
507    */
508   public static Color getColor(Object key)
509   {
510     Object value = get(key);
511     if (value instanceof Color) 
512       return (Color) value;
513     return null;
514   }
515
516   /**
517    * Returns a drawing color from the defaults table. 
518    * 
519    * @param key  the key (<code>null</code> not permitted).
520    * @param locale  the locale.
521    * 
522    * @return The color associated with the given key, or <code>null</code>.
523    * 
524    * @throws NullPointerException if <code>key</code> is <code>null</code>.
525    * 
526    * @since 1.4
527    */
528   public static Color getColor(Object key, Locale locale)
529   {
530     Object value = get(key, locale);
531     if (value instanceof Color) 
532       return (Color) value;
533     return null;
534   }
535
536   /**
537    * The fully qualified class name of the cross platform (Metal) look and feel.
538    * This string can be passed to Class.forName()
539    * 
540    * @return <code>"javax.swing.plaf.metal.MetalLookAndFeel"</code>
541    */
542   public static String getCrossPlatformLookAndFeelClassName()
543   {     
544     return "javax.swing.plaf.metal.MetalLookAndFeel";
545   }
546
547   /**
548    * Returns the default values for this look and feel. 
549    * 
550    * @return The {@link UIDefaults} for the current {@link LookAndFeel}.
551    */
552   public static UIDefaults getDefaults()
553   {
554     if (currentUIDefaults == null)
555       currentUIDefaults = new MultiplexUIDefaults(new UIDefaults());
556     return currentUIDefaults;
557   }
558
559   /**
560    * Returns a dimension from the defaults table. 
561    * 
562    * @param key  the key (<code>null</code> not permitted).
563    * 
564    * @return The color associated with the given key, or <code>null</code>.
565    * 
566    * @throws NullPointerException if <code>key</code> is <code>null</code>.
567    */
568   public static Dimension getDimension(Object key)
569   {
570     Object value = get(key);
571     if (value instanceof Dimension) 
572       return (Dimension) value;
573     return null;
574   }
575
576   /**
577    * Returns a dimension from the defaults table. 
578    * 
579    * @param key  the key (<code>null</code> not permitted).
580    * @param locale  the locale.
581    * 
582    * @return The color associated with the given key, or <code>null</code>.
583    * 
584    * @throws NullPointerException if <code>key</code> is <code>null</code>.
585    * @since 1.4
586    */
587   public static Dimension getDimension(Object key, Locale locale)
588   {
589     Object value = get(key, locale);
590     if (value instanceof Dimension) 
591       return (Dimension) value;
592     return null;
593   }
594
595   /**
596    * Retrieves a font from the defaults table of the current
597    * LookAndFeel.
598    *
599    * @param key an Object that specifies the font. Typically,
600    *        this is a String such as
601    *        <code>TitledBorder.font</code>.
602    *        
603    * @return The font associated with the given key, or <code>null</code>.
604    * 
605    * @throws NullPointerException if <code>key</code> is <code>null</code>.
606    */
607   public static Font getFont(Object key)
608   {
609     Object value = get(key);
610     if (value instanceof Font) 
611       return (Font) value;
612     return null;
613   }
614
615   /**
616    * Retrieves a font from the defaults table of the current
617    * LookAndFeel.
618    *
619    * @param key an Object that specifies the font. Typically,
620    *        this is a String such as
621    *        <code>TitledBorder.font</code>.
622    * @param locale  the locale.
623    *        
624    * @return The font associated with the given key, or <code>null</code>.
625    * 
626    * @throws NullPointerException if <code>key</code> is <code>null</code>.
627    *        
628    * @since 1.4
629    */
630   public static Font getFont(Object key, Locale locale)
631   {
632     Object value = get(key, locale);
633     if (value instanceof Font) 
634       return (Font) value;
635     return null;
636   }
637
638   /**
639    * Returns an icon from the defaults table. 
640    * 
641    * @param key  the key (<code>null</code> not permitted).
642    * 
643    * @return The icon associated with the given key, or <code>null</code>.
644    * 
645    * @throws NullPointerException if <code>key</code> is <code>null</code>.
646    */
647   public static Icon getIcon(Object key)
648   {
649     Object value = get(key);
650     if (value instanceof Icon) 
651       return (Icon) value;
652     return null;
653   }
654   
655   /**
656    * Returns an icon from the defaults table. 
657    * 
658    * @param key  the key (<code>null</code> not permitted).
659    * @param locale  the locale.
660    * 
661    * @return The icon associated with the given key, or <code>null</code>.
662    * 
663    * @throws NullPointerException if <code>key</code> is <code>null</code>.
664    * @since 1.4
665    */
666   public static Icon getIcon(Object key, Locale locale)
667   {
668     Object value = get(key, locale);
669     if (value instanceof Icon) 
670       return (Icon) value;
671     return null;
672   }
673   
674   /**
675    * Returns an Insets object from the defaults table.
676    * 
677    * @param key  the key (<code>null</code> not permitted).
678    * 
679    * @return The insets associated with the given key, or <code>null</code>.
680    * 
681    * @throws NullPointerException if <code>key</code> is <code>null</code>.   
682    */
683   public static Insets getInsets(Object key)
684   {
685     Object o = get(key);
686     if (o instanceof Insets)
687       return (Insets) o;
688     else
689       return null;
690   }
691
692   /**
693    * Returns an Insets object from the defaults table.
694    * 
695    * @param key  the key (<code>null</code> not permitted).
696    * @param locale  the locale.
697    * 
698    * @return The insets associated with the given key, or <code>null</code>.
699    * 
700    * @throws NullPointerException if <code>key</code> is <code>null</code>.   
701    * @since 1.4
702    */
703   public static Insets getInsets(Object key, Locale locale)
704   {
705     Object o = get(key, locale);
706     if (o instanceof Insets)
707       return (Insets) o;
708     else
709       return null;
710   }
711
712   /**
713    * Returns an array containing information about the {@link LookAndFeel}s
714    * that are installed.
715    * 
716    * @return A list of the look and feels that are available (installed).
717    */
718   public static LookAndFeelInfo[] getInstalledLookAndFeels()
719   {
720     return installed;
721   }
722
723   /**
724    * Returns the integer value of the {@link Integer} associated with the
725    * given key.  If there is no value, or the value is not an instance of
726    * {@link Integer}, this method returns 0.
727    * 
728    * @param key  the key (<code>null</code> not permitted).
729    * 
730    * @return The integer value associated with the given key, or 0.
731    */
732   public static int getInt(Object key)
733   {
734     Object x = get(key);
735     if (x instanceof Integer)
736       return ((Integer) x).intValue();
737     return 0;
738   }
739
740   /**
741    * Returns the integer value of the {@link Integer} associated with the
742    * given key.  If there is no value, or the value is not an instance of
743    * {@link Integer}, this method returns 0.
744    * 
745    * @param key  the key (<code>null</code> not permitted).
746    * @param locale  the locale.
747    * 
748    * @return The integer value associated with the given key, or 0.
749    * 
750    * @since 1.4
751    */
752   public static int getInt(Object key, Locale locale)
753   {
754     Object x = get(key, locale);
755     if (x instanceof Integer)
756       return ((Integer) x).intValue();
757     return 0;
758   }
759
760   /**
761    * Returns the current look and feel (which may be <code>null</code>).
762    * 
763    * @return The current look and feel.
764    * 
765    * @see #setLookAndFeel(LookAndFeel)
766    */
767   public static LookAndFeel getLookAndFeel()
768   {
769     return currentLookAndFeel;
770   }
771
772   /**
773    * Returns the <code>UIDefaults</code> table of the currently active
774    * look and feel.
775    * 
776    * @return The {@link UIDefaults} for the current {@link LookAndFeel}.
777    */
778   public static UIDefaults getLookAndFeelDefaults()
779   {
780     return lookAndFeelDefaults;
781   }
782
783   /**
784    * Returns the {@link String} associated with the given key.  If the value 
785    * is not a {@link String}, this method returns <code>null</code>.
786    * 
787    * @param key  the key (<code>null</code> not permitted).
788    * 
789    * @return The string associated with the given key, or <code>null</code>.
790    */
791   public static String getString(Object key)
792   {
793     Object s = get(key);
794     if (s instanceof String)
795       return (String) s;
796     return null;
797   }
798   
799   /**
800    * Returns the {@link String} associated with the given key.  If the value 
801    * is not a {@link String}, this method returns <code>null</code>.
802    * 
803    * @param key  the key (<code>null</code> not permitted).
804    * @param locale  the locale.
805    * 
806    * @return The string associated with the given key, or <code>null</code>.
807    * 
808    * @since 1.4
809    */
810   public static String getString(Object key, Locale locale)
811   {
812     Object s = get(key, locale);
813     if (s instanceof String)
814       return (String) s;
815     return null;
816   }
817   
818   /**
819    * Returns the name of the {@link LookAndFeel} class that implements the
820    * native systems look and feel if there is one, otherwise the name
821    * of the default cross platform LookAndFeel class.
822    * 
823    * @return The fully qualified class name for the system look and feel.
824    * 
825    * @see #getCrossPlatformLookAndFeelClassName()
826    */
827   public static String getSystemLookAndFeelClassName()
828   {
829     return getCrossPlatformLookAndFeelClassName();
830   }
831
832   /**
833    * Returns UI delegate from the current {@link LookAndFeel} that renders the 
834    * target component.
835    * 
836    * @param target  the target component.
837    */
838   public static ComponentUI getUI(JComponent target)
839   {
840     return getDefaults().getUI(target);
841   }
842
843   /**
844    * Creates a new look and feel and adds it to the current array.
845    * 
846    * @param name  the look and feel name.
847    * @param className  the fully qualified name of the class that implements the
848    *                   look and feel.
849    */
850   public static void installLookAndFeel(String name, String className)
851   {
852     installLookAndFeel(new LookAndFeelInfo(name, className));
853   }
854
855   /**
856    * Adds the specified look and feel to the current array and then calls
857    * setInstalledLookAndFeels(javax.swing.UIManager.LookAndFeelInfo[]).
858    */
859   public static void installLookAndFeel(LookAndFeelInfo info)
860   {
861     LookAndFeelInfo[] newInstalled = new LookAndFeelInfo[installed.length + 1];
862     System.arraycopy(installed, 0, newInstalled, 0, installed.length);
863     newInstalled[newInstalled.length - 1] = info;
864     setInstalledLookAndFeels(newInstalled);
865   }
866
867   /**
868    * Stores an object in the defaults table.
869    * 
870    * @param key  the key.
871    * @param value  the value.
872    */
873   public static Object put(Object key, Object value)
874   {
875     return getDefaults().put(key, value);
876   }
877
878   /**
879    * Replaces the current array of installed LookAndFeelInfos.
880    */
881   public static void setInstalledLookAndFeels(UIManager.LookAndFeelInfo[] infos)
882   {
883     installed = infos;
884   }
885   
886   /**
887    * Sets the current {@link LookAndFeel}.
888    * 
889    * @param newLookAndFeel  the new look and feel (<code>null</code> permitted).
890    * 
891    * @throws UnsupportedLookAndFeelException if the look and feel is not 
892    *         supported on the current platform.
893    * 
894    * @see LookAndFeel#isSupportedLookAndFeel()
895    */
896   public static void setLookAndFeel(LookAndFeel newLookAndFeel)
897     throws UnsupportedLookAndFeelException
898   {
899     if (newLookAndFeel != null && ! newLookAndFeel.isSupportedLookAndFeel())
900       throw new UnsupportedLookAndFeelException(newLookAndFeel.getName()
901                                          + " not supported on this platform");
902     LookAndFeel oldLookAndFeel = currentLookAndFeel;
903     if (oldLookAndFeel != null)
904       oldLookAndFeel.uninitialize();
905
906     // Set the current default look and feel using a LookAndFeel object. 
907     currentLookAndFeel = newLookAndFeel;
908     if (newLookAndFeel != null)
909       {
910         newLookAndFeel.initialize();
911         lookAndFeelDefaults = newLookAndFeel.getDefaults();
912         if (currentUIDefaults == null)
913           currentUIDefaults =
914             new MultiplexUIDefaults(lookAndFeelDefaults);
915         else
916           currentUIDefaults.fallback = lookAndFeelDefaults;
917       }
918     else
919       {
920         currentUIDefaults = null;    
921       }
922     listeners.firePropertyChange("lookAndFeel", oldLookAndFeel, newLookAndFeel);
923     //revalidate();
924     //repaint();
925   }
926
927   /**
928    * Set the current default look and feel using a class name.
929    * 
930    * @param className  the look and feel class name.
931    * 
932    * @throws UnsupportedLookAndFeelException if the look and feel is not 
933    *         supported on the current platform.
934    * 
935    * @see LookAndFeel#isSupportedLookAndFeel()
936    */
937   public static void setLookAndFeel(String className)
938     throws ClassNotFoundException, InstantiationException, IllegalAccessException,
939     UnsupportedLookAndFeelException
940   {
941     Class c = Class.forName(className, true,
942                             Thread.currentThread().getContextClassLoader());
943     LookAndFeel a = (LookAndFeel) c.newInstance(); // throws class-cast-exception
944     setLookAndFeel(a);
945   }
946 }