1 /* UIDefaults.java -- database for all settings and interface bindings.
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
41 import java
.awt
.Color
;
42 import java
.awt
.Dimension
;
44 import java
.awt
.Insets
;
45 import java
.beans
.PropertyChangeListener
;
46 import java
.beans
.PropertyChangeSupport
;
47 import java
.lang
.reflect
.Method
;
48 import java
.util
.Hashtable
;
49 import java
.util
.LinkedList
;
50 import java
.util
.ListIterator
;
51 import java
.util
.Locale
;
52 import java
.util
.MissingResourceException
;
53 import java
.util
.ResourceBundle
;
55 import javax
.swing
.border
.Border
;
56 import javax
.swing
.plaf
.ComponentUI
;
57 import javax
.swing
.plaf
.InputMapUIResource
;
60 * UIDefaults is a database where all settings and interface bindings are
61 * stored into. A PLAF implementation fills one of these (see for example
62 * plaf/basic/BasicLookAndFeel.java) with "ButtonUI" -> new BasicButtonUI().
64 * @author Ronald Veldema (rveldema@cs.vu.nl)
66 public class UIDefaults
extends Hashtable
69 /** Our ResourceBundles. */
70 private LinkedList bundles
;
72 /** The default locale. */
73 private Locale defaultLocale
;
75 /** We use this for firing PropertyChangeEvents. */
76 private PropertyChangeSupport propertyChangeSupport
;
79 * Used for lazy instantiation of UIDefaults values so that they are not
80 * all loaded when a Swing application starts up, but only the values that
81 * are really needed. An <code>ActiveValue</code> is newly instantiated
82 * every time when the value is requested, as opposed to the normal
83 * {@link LazyValue} that is only instantiated once.
85 public static interface ActiveValue
87 Object
createValue(UIDefaults table
);
90 public static class LazyInputMap
implements LazyValue
93 public LazyInputMap(Object
[] bindings
)
97 public Object
createValue(UIDefaults table
)
99 InputMapUIResource im
= new InputMapUIResource ();
100 for (int i
= 0; 2*i
+1 < bind
.length
; ++i
)
102 Object curr
= bind
[2*i
];
103 if (curr
instanceof KeyStroke
)
104 im
.put((KeyStroke
) curr
, bind
[2*i
+1]);
106 im
.put(KeyStroke
.getKeyStroke((String
) curr
),
114 * Used for lazy instantiation of UIDefaults values so that they are not
115 * all loaded when a Swing application starts up, but only the values that
116 * are really needed. A <code>LazyValue</code> is only instantiated once,
117 * as opposed to the {@link ActiveValue} that is newly created every time
120 public static interface LazyValue
122 Object
createValue(UIDefaults table
);
125 public static class ProxyLazyValue
implements LazyValue
128 public ProxyLazyValue(String s
)
130 final String className
= s
;
131 inner
= new LazyValue ()
133 public Object
createValue (UIDefaults table
)
139 .getConstructor(new Class
[] {})
140 .newInstance(new Object
[] {});
150 public ProxyLazyValue(String c
, String m
)
152 final String className
= c
;
153 final String methodName
= m
;
154 inner
= new LazyValue ()
156 public Object
createValue (UIDefaults table
)
162 .getMethod (methodName
, new Class
[] {})
163 .invoke (null, new Object
[] {});
173 public ProxyLazyValue(String c
, Object
[] os
)
175 final String className
= c
;
176 final Object
[] objs
= os
;
177 final Class
[] clss
= new Class
[objs
.length
];
178 for (int i
= 0; i
< objs
.length
; ++i
)
180 clss
[i
] = objs
[i
].getClass();
182 inner
= new LazyValue()
184 public Object
createValue(UIDefaults table
)
190 .getConstructor(clss
)
201 public ProxyLazyValue(String c
, String m
, Object
[] os
)
203 final String className
= c
;
204 final String methodName
= m
;
205 final Object
[] objs
= os
;
206 final Class
[] clss
= new Class
[objs
.length
];
207 for (int i
= 0; i
< objs
.length
; ++i
)
209 clss
[i
] = objs
[i
].getClass();
211 inner
= new LazyValue()
213 public Object
createValue(UIDefaults table
)
219 .getMethod(methodName
, clss
)
230 public Object
createValue(UIDefaults table
)
232 return inner
.createValue(table
);
236 /** Our serialVersionUID for serialization. */
237 private static final long serialVersionUID
= 7341222528856548117L;
240 * Constructs a new empty UIDefaults instance.
244 bundles
= new LinkedList();
245 defaultLocale
= Locale
.getDefault();
246 propertyChangeSupport
= new PropertyChangeSupport(this);
250 * Constructs a new UIDefaults instance and loads the specified entries.
251 * The entries are expected to come in pairs, that means
252 * <code>entries[0]</code> is a key, <code>entries[1]</code> is a value,
253 * <code>entries[2]</code> a key and so forth.
255 * @param entries the entries to initialize the UIDefaults instance with
257 public UIDefaults(Object
[] entries
)
261 for (int i
= 0; (2 * i
+ 1) < entries
.length
; ++i
)
262 put(entries
[2 * i
], entries
[2 * i
+ 1]);
266 * Returns the entry for the specified <code>key</code> in the default
269 * @return the entry for the specified <code>key</code>
271 public Object
get(Object key
)
273 return this.get(key
, getDefaultLocale());
277 * Returns the entry for the specified <code>key</code> in the Locale
280 * @param key the key for which we return the value
281 * @param loc the locale
283 public Object
get(Object key
, Locale loc
)
287 if (super.containsKey(key
))
289 obj
= super.get(key
);
291 else if (key
instanceof String
)
293 String keyString
= (String
) key
;
294 ListIterator i
= bundles
.listIterator(0);
297 String bundle_name
= (String
) i
.next();
299 ResourceBundle
.getBundle(bundle_name
, loc
);
304 obj
= res
.getObject(keyString
);
307 catch (MissingResourceException me
)
309 // continue, this bundle has no such key
315 // now we've found the object, resolve it.
316 // nb: LazyValues aren't supported in resource bundles, so it's correct
317 // to insert their results in the locale-less hashtable.
322 if (obj
instanceof LazyValue
)
324 Object resolved
= ((LazyValue
) obj
).createValue(this);
326 super.put(key
, resolved
);
329 else if (obj
instanceof ActiveValue
)
331 return ((ActiveValue
) obj
).createValue(this);
338 * Puts a key and value into this UIDefaults object.<br>
340 * {@link java.util.Hashtable}s <code>null</code>-values are accepted
341 * here and treated like #remove(key).
343 * This fires a PropertyChangeEvent with key as name and the old and new
346 * @param key the key to put into the map
347 * @param value the value to put into the map
349 * @return the old value for key or <code>null</code> if <code>key</code>
350 * had no value assigned
352 public Object
put(Object key
, Object value
)
354 Object old
= checkAndPut(key
, value
);
356 if (key
instanceof String
&& old
!= value
)
357 firePropertyChange((String
) key
, old
, value
);
362 * Puts a set of key-value pairs into the map.
363 * The entries are expected to come in pairs, that means
364 * <code>entries[0]</code> is a key, <code>entries[1]</code> is a value,
365 * <code>entries[2]</code> a key and so forth.
367 * If a value is <code>null</code> it is treated like #remove(key).
369 * This unconditionally fires a PropertyChangeEvent with
370 * <code>'UIDefaults'</code> as name and <code>null</code> for
373 * @param entries the entries to be put into the map
375 public void putDefaults(Object
[] entries
)
377 for (int i
= 0; (2 * i
+ 1) < entries
.length
; ++i
)
379 checkAndPut(entries
[2 * i
], entries
[2 * i
+ 1]);
381 firePropertyChange("UIDefaults", null, null);
385 * Checks the value for <code>null</code> and put it into the Hashtable, if
386 * it is not <code>null</code>. If the value is <code>null</code> then
387 * remove the corresponding key.
389 * @param key the key to put into this UIDefauls table
390 * @param value the value to put into this UIDefaults table
392 * @return the old value for <code>key</code>
394 private Object
checkAndPut(Object key
, Object value
)
399 old
= super.put(key
, value
);
401 old
= super.remove(key
);
407 * Returns a font entry for the default locale.
409 * @param key the key to the requested entry
411 * @return the font entry for <code>key</code> or null if no such entry
414 public Font
getFont(Object key
)
417 return o
instanceof Font ?
(Font
) o
: null;
421 * Returns a font entry for a specic locale.
423 * @param key the key to the requested entry
424 * @param locale the locale to the requested entry
426 * @return the font entry for <code>key</code> or null if no such entry
429 public Font
getFont(Object key
, Locale locale
)
431 Object o
= get(key
, locale
);
432 return o
instanceof Font ?
(Font
) o
: null;
436 * Returns a color entry for the default locale.
438 * @param key the key to the requested entry
440 * @return the color entry for <code>key</code> or null if no such entry
443 public Color
getColor(Object key
)
446 return o
instanceof Color ?
(Color
) o
: null;
450 * Returns a color entry for a specic locale.
452 * @param key the key to the requested entry
453 * @param locale the locale to the requested entry
455 * @return the color entry for <code>key</code> or null if no such entry
458 public Color
getColor(Object key
, Locale locale
)
460 Object o
= get(key
, locale
);
461 return o
instanceof Color ?
(Color
) o
: null;
465 * Returns an icon entry for the default locale.
467 * @param key the key to the requested entry
469 * @return the icon entry for <code>key</code> or null if no such entry
472 public Icon
getIcon(Object key
)
475 return o
instanceof Icon ?
(Icon
) o
: null;
479 * Returns an icon entry for a specic locale.
481 * @param key the key to the requested entry
482 * @param locale the locale to the requested entry
484 * @return the icon entry for <code>key</code> or null if no such entry
487 public Icon
getIcon(Object key
, Locale locale
)
489 Object o
= get(key
, locale
);
490 return o
instanceof Icon ?
(Icon
) o
: null;
494 * Returns a border entry for the default locale.
496 * @param key the key to the requested entry
498 * @return the border entry for <code>key</code> or null if no such entry
501 public Border
getBorder(Object key
)
504 return o
instanceof Border ?
(Border
) o
: null;
508 * Returns a border entry for a specic locale.
510 * @param key the key to the requested entry
511 * @param locale the locale to the requested entry
513 * @return the border entry for <code>key</code> or null if no such entry
516 public Border
getBorder(Object key
, Locale locale
)
518 Object o
= get(key
, locale
);
519 return o
instanceof Border ?
(Border
) o
: null;
523 * Returns a string entry for the default locale.
525 * @param key the key to the requested entry
527 * @return the string entry for <code>key</code> or null if no such entry
530 public String
getString(Object key
)
533 return o
instanceof String ?
(String
) o
: null;
537 * Returns a string entry for a specic locale.
539 * @param key the key to the requested entry
540 * @param locale the locale to the requested entry
542 * @return the string entry for <code>key</code> or null if no such entry
545 public String
getString(Object key
, Locale locale
)
547 Object o
= get(key
, locale
);
548 return o
instanceof String ?
(String
) o
: null;
552 * Returns an integer entry for the default locale.
554 * @param key the key to the requested entry
556 * @return the integer entry for <code>key</code> or null if no such entry
559 public int getInt(Object key
)
562 return o
instanceof Integer ?
((Integer
) o
).intValue() : 0;
566 * Returns an integer entry for a specic locale.
568 * @param key the key to the requested entry
569 * @param locale the locale to the requested entry
571 * @return the integer entry for <code>key</code> or null if no such entry
574 public int getInt(Object key
, Locale locale
)
576 Object o
= get(key
, locale
);
577 return o
instanceof Integer ?
((Integer
) o
).intValue() : 0;
581 * Returns a boolean entry for the default locale.
583 * @param key the key to the requested entry
585 * @return The boolean entry for <code>key</code> or <code>false</code> if no
588 public boolean getBoolean(Object key
)
590 return Boolean
.TRUE
.equals(get(key
));
594 * Returns a boolean entry for a specic locale.
596 * @param key the key to the requested entry
597 * @param locale the locale to the requested entry
599 * @return the boolean entry for <code>key</code> or null if no such entry
602 public boolean getBoolean(Object key
, Locale locale
)
604 return Boolean
.TRUE
.equals(get(key
, locale
));
608 * Returns an insets entry for the default locale.
610 * @param key the key to the requested entry
612 * @return the insets entry for <code>key</code> or null if no such entry
615 public Insets
getInsets(Object key
)
618 return o
instanceof Insets ?
(Insets
) o
: null;
622 * Returns an insets entry for a specic locale.
624 * @param key the key to the requested entry
625 * @param locale the locale to the requested entry
627 * @return the boolean entry for <code>key</code> or null if no such entry
630 public Insets
getInsets(Object key
, Locale locale
)
632 Object o
= get(key
, locale
);
633 return o
instanceof Insets ?
(Insets
) o
: null;
637 * Returns a dimension entry for the default locale.
639 * @param key the key to the requested entry
641 * @return the dimension entry for <code>key</code> or null if no such entry
644 public Dimension
getDimension(Object key
)
647 return o
instanceof Dimension ?
(Dimension
) o
: null;
651 * Returns a dimension entry for a specic locale.
653 * @param key the key to the requested entry
654 * @param locale the locale to the requested entry
656 * @return the boolean entry for <code>key</code> or null if no such entry
659 public Dimension
getDimension(Object key
, Locale locale
)
661 Object o
= get(key
, locale
);
662 return o
instanceof Dimension ?
(Dimension
) o
: null;
666 * Returns the ComponentUI class that renders a component. <code>id</code>
667 * is the ID for which the String value of the classname is stored in
668 * this UIDefaults map.
670 * @param id the ID of the UI class
671 * @param loader the ClassLoader to use
673 * @return the UI class for <code>id</code>
675 public Class
getUIClass(String id
, ClassLoader loader
)
677 String className
= (String
) get (id
);
678 if (className
== null)
683 loader
= ClassLoader
.getSystemClassLoader();
684 return loader
.loadClass (className
);
693 * Returns the ComponentUI class that renders a component. <code>id</code>
694 * is the ID for which the String value of the classname is stored in
695 * this UIDefaults map.
697 * @param id the ID of the UI class
699 * @return the UI class for <code>id</code>
701 public Class
getUIClass(String id
)
703 return getUIClass (id
, null);
707 * If a key is requested in #get(key) that has no value, this method
708 * is called before returning <code>null</code>.
710 * @param msg the error message
712 protected void getUIError(String msg
)
714 System
.err
.println ("UIDefaults.getUIError: " + msg
);
718 * Returns the {@link ComponentUI} for the specified {@link JComponent}.
720 * @param target the component for which the ComponentUI is requested
722 * @return the {@link ComponentUI} for the specified {@link JComponent}
724 public ComponentUI
getUI(JComponent target
)
726 String classId
= target
.getUIClassID ();
727 Class cls
= getUIClass (classId
);
730 getUIError ("failed to locate UI class:" + classId
);
738 factory
= cls
.getMethod ("createUI", new Class
[] { JComponent
.class } );
740 catch (NoSuchMethodException nme
)
742 getUIError ("failed to locate createUI method on " + cls
.toString ());
748 return (ComponentUI
) factory
.invoke (null, new Object
[] { target
});
750 catch (java
.lang
.reflect
.InvocationTargetException ite
)
752 getUIError ("InvocationTargetException ("+ ite
.getTargetException()
753 +") calling createUI(...) on " + cls
.toString ());
758 getUIError ("exception calling createUI(...) on " + cls
.toString ());
764 * Adds a {@link PropertyChangeListener} to this UIDefaults map.
765 * Registered PropertyChangeListener are notified when values
766 * are beeing put into this UIDefaults map.
768 * @param listener the PropertyChangeListener to add
770 public void addPropertyChangeListener(PropertyChangeListener listener
)
772 propertyChangeSupport
.addPropertyChangeListener(listener
);
776 * Removes a PropertyChangeListener from this UIDefaults map.
778 * @param listener the PropertyChangeListener to remove
780 public void removePropertyChangeListener(PropertyChangeListener listener
)
782 propertyChangeSupport
.removePropertyChangeListener(listener
);
786 * Returns an array of all registered PropertyChangeListeners.
788 * @return all registered PropertyChangeListeners
790 public PropertyChangeListener
[] getPropertyChangeListeners()
792 return propertyChangeSupport
.getPropertyChangeListeners();
796 * Fires a PropertyChangeEvent.
798 * @param property the property name
799 * @param oldValue the old value
800 * @param newValue the new value
802 protected void firePropertyChange(String property
,
803 Object oldValue
, Object newValue
)
805 propertyChangeSupport
.firePropertyChange(property
, oldValue
, newValue
);
809 * Adds a ResourceBundle for localized values.
811 * @param name the name of the ResourceBundle to add
813 public void addResourceBundle(String name
)
815 bundles
.addFirst(name
);
819 * Removes a ResourceBundle.
821 * @param name the name of the ResourceBundle to remove
823 public void removeResourceBundle(String name
)
825 bundles
.remove(name
);
829 * Sets the current locale to <code>loc</code>.
831 * @param loc the Locale to be set
833 public void setDefaultLocale(Locale loc
)
839 * Returns the current default locale.
841 * @return the current default locale
843 public Locale
getDefaultLocale()
845 return defaultLocale
;