81 * </pre>
82 * The following example illustrates setting the look and feel based on
83 * class name:
84 * <pre>
85 * UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
86 * </pre>
87 * Once the look and feel has been changed it is imperative to invoke
88 * {@code updateUI} on all {@code JComponents}. The method {@link
89 * SwingUtilities#updateComponentTreeUI} makes it easy to apply {@code
90 * updateUI} to a containment hierarchy. Refer to it for
91 * details. The exact behavior of not invoking {@code
92 * updateUI} after changing the look and feel is
93 * unspecified. It is very possible to receive unexpected exceptions,
94 * painting problems, or worse.
95 *
96 * <h3>Default look and feel</h3>
97 *
98 * The class used for the default look and feel is chosen in the following
99 * manner:
100 * <ol>
101 * <li>If the system property <code>swing.defaultlaf</code> is
102 * {@code non-null}, use its value as the default look and feel class
103 * name.
104 * <li>If the {@link java.util.Properties} file <code>swing.properties</code>
105 * exists and contains the key <code>swing.defaultlaf</code>,
106 * use its value as the default look and feel class name. The location
107 * that is checked for <code>swing.properties</code> may vary depending
108 * upon the implementation of the Java platform. Typically the
109 * <code>swing.properties</code> file is located in the <code>conf</code>
110 * subdirectory of the Java installation directory.
111 * Refer to the release notes of the implementation being used for
112 * further details.
113 * <li>Otherwise use the cross platform look and feel.
114 * </ol>
115 *
116 * <h3>Defaults</h3>
117 *
118 * {@code UIManager} manages three sets of {@code UIDefaults}. In order, they
119 * are:
120 * <ol>
121 * <li>Developer defaults. With few exceptions Swing does not
122 * alter the developer defaults; these are intended to be modified
123 * and used by the developer.
124 * <li>Look and feel defaults. The look and feel defaults are
125 * supplied by the look and feel at the time it is installed as the
126 * current look and feel ({@code setLookAndFeel()} is invoked). The
127 * look and feel defaults can be obtained using the {@code
128 * getLookAndFeelDefaults()} method.
129 * <li>System defaults. The system defaults are provided by Swing.
151 * The set of defaults a particular look and feel supports is defined
152 * and documented by that look and feel. In addition, each look and
153 * feel, or {@code ComponentUI} provided by a look and feel, may
154 * access the defaults at different times in their life cycle. Some
155 * look and feels may aggressively look up defaults, so that changing a
156 * default may not have an effect after installing the look and feel.
157 * Other look and feels may lazily access defaults so that a change to
158 * the defaults may effect an existing look and feel. Finally, other look
159 * and feels might not configure themselves from the defaults table in
160 * any way. None-the-less it is usually the case that a look and feel
161 * expects certain defaults, so that in general
162 * a {@code ComponentUI} provided by one look and feel will not
163 * work with another look and feel.
164 * <p>
165 * <strong>Warning:</strong>
166 * Serialized objects of this class will not be compatible with
167 * future Swing releases. The current serialization support is
168 * appropriate for short term storage or RMI between applications running
169 * the same version of Swing. As of 1.4, support for long term storage
170 * of all JavaBeans™
171 * has been added to the <code>java.beans</code> package.
172 * Please see {@link java.beans.XMLEncoder}.
173 *
174 * @author Thomas Ball
175 * @author Hans Muller
176 * @since 1.2
177 */
178 @SuppressWarnings("serial") // Same-version serialization only
179 public class UIManager implements Serializable
180 {
181 /**
182 * This class defines the state managed by the <code>UIManager</code>. For
183 * Swing applications the fields in this class could just as well
184 * be static members of <code>UIManager</code> however we give them
185 * "AppContext"
186 * scope instead so that applets (and potentially multiple lightweight
187 * applications running in a single VM) have their own state. For example,
188 * an applet can alter its look and feel, see <code>setLookAndFeel</code>.
189 * Doing so has no affect on other applets (or the browser).
190 */
191 private static class LAFState
192 {
193 Properties swingProps;
194 private UIDefaults[] tables = new UIDefaults[2];
195
196 boolean initialized = false;
197 boolean focusPolicyInitialized = false;
198 MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables);
199 LookAndFeel lookAndFeel;
200 LookAndFeel multiLookAndFeel = null;
201 Vector<LookAndFeel> auxLookAndFeels = null;
202 SwingPropertyChangeSupport changeSupport;
203
204 LookAndFeelInfo[] installedLAFs;
205
206 UIDefaults getLookAndFeelDefaults() { return tables[0]; }
207 void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; }
208
209 UIDefaults getSystemDefaults() { return tables[1]; }
210 void setSystemDefaults(UIDefaults x) { tables[1] = x; }
211
212 /**
213 * Returns the SwingPropertyChangeSupport for the current
214 * AppContext. If <code>create</code> is a true, a non-null
215 * <code>SwingPropertyChangeSupport</code> will be returned, if
216 * <code>create</code> is false and this has not been invoked
217 * with true, null will be returned.
218 */
219 public synchronized SwingPropertyChangeSupport
220 getPropertyChangeSupport(boolean create) {
221 if (create && changeSupport == null) {
222 changeSupport = new SwingPropertyChangeSupport(
223 UIManager.class);
224 }
225 return changeSupport;
226 }
227 }
228
229
230
231
232 /* Lock object used in place of class object for synchronization. (4187686)
233 */
234 private static final Object classLock = new Object();
235
236 /**
237 * Return the <code>LAFState</code> object, lazily create one if necessary.
238 * All access to the <code>LAFState</code> fields is done via this method,
239 * for example:
240 * <pre>
241 * getLAFState().initialized = true;
242 * </pre>
243 */
244 private static LAFState getLAFState() {
245 LAFState rv = (LAFState)SwingUtilities.appContextGet(
246 SwingUtilities2.LAF_STATE_KEY);
247 if (rv == null) {
248 synchronized (classLock) {
249 rv = (LAFState)SwingUtilities.appContextGet(
250 SwingUtilities2.LAF_STATE_KEY);
251 if (rv == null) {
252 SwingUtilities.appContextPut(
253 SwingUtilities2.LAF_STATE_KEY,
254 (rv = new LAFState()));
255 }
256 }
257 }
258 return rv;
259 }
260
261
262 /* Keys used in the <code>swing.properties</code> properties file.
263 * See loadUserProperties(), initialize().
264 */
265
266 private static final String defaultLAFKey = "swing.defaultlaf";
267 private static final String auxiliaryLAFsKey = "swing.auxiliarylaf";
268 private static final String multiplexingLAFKey = "swing.plaf.multiplexinglaf";
269 private static final String installedLAFsKey = "swing.installedlafs";
270 private static final String disableMnemonicKey = "swing.disablenavaids";
271
272 /**
273 * Return a <code>swing.properties</code> file key for the attribute of specified
274 * look and feel. The attr is either "name" or "class", a typical
275 * key would be: "swing.installedlaf.windows.name"
276 */
277 private static String makeInstalledLAFKey(String laf, String attr) {
278 return "swing.installedlaf." + laf + "." + attr;
279 }
280
281 /**
282 * The location of the <code>swing.properties</code> property file is
283 * implementation-specific.
284 * It is typically located in the <code>conf</code> subdirectory of the Java
285 * installation directory. This method returns a bogus filename
286 * if <code>java.home</code> isn't defined.
287 */
288 private static String makeSwingPropertiesFilename() {
289 String sep = File.separator;
290 // No need to wrap this in a doPrivileged as it's called from
291 // a doPrivileged.
292 String javaHome = System.getProperty("java.home");
293 if (javaHome == null) {
294 javaHome = "<java.home undefined>";
295 }
296 return javaHome + sep + "conf" + sep + "swing.properties";
297 }
298
299
300 /**
301 * Provides a little information about an installed
302 * <code>LookAndFeel</code> for the sake of configuring a menu or
303 * for initial application set up.
304 *
305 * @see UIManager#getInstalledLookAndFeels
306 * @see LookAndFeel
307 */
308 public static class LookAndFeelInfo {
309 private String name;
310 private String className;
311
312 /**
313 * Constructs a <code>UIManager</code>s
314 * <code>LookAndFeelInfo</code> object.
315 *
316 * @param name a <code>String</code> specifying the name of
317 * the look and feel
318 * @param className a <code>String</code> specifying the name of
319 * the class that implements the look and feel
320 */
321 public LookAndFeelInfo(String name, String className) {
322 this.name = name;
323 this.className = className;
324 }
325
326 /**
327 * Returns the name of the look and feel in a form suitable
328 * for a menu or other presentation
329 * @return a <code>String</code> containing the name
330 * @see LookAndFeel#getName
331 */
332 public String getName() {
333 return name;
334 }
335
336 /**
337 * Returns the name of the class that implements this look and feel.
338 * @return the name of the class that implements this
339 * <code>LookAndFeel</code>
340 * @see LookAndFeel
341 */
342 public String getClassName() {
343 return className;
344 }
345
346 /**
347 * Returns a string that displays and identifies this
348 * object's properties.
349 *
350 * @return a <code>String</code> representation of this object
351 */
352 public String toString() {
353 return getClass().getName() + "[" + getName() + " " + getClassName() + "]";
354 }
355 }
356
357
358 /**
359 * The default value of <code>installedLAFS</code> is used when no
360 * <code>swing.properties</code>
361 * file is available or if the file doesn't contain a "swing.installedlafs"
362 * property.
363 *
364 * @see #initializeInstalledLAFs
365 */
366 private static LookAndFeelInfo[] installedLAFs;
367
368 static {
369 ArrayList<LookAndFeelInfo> iLAFs = new ArrayList<LookAndFeelInfo>(4);
370 iLAFs.add(new LookAndFeelInfo(
371 "Metal", "javax.swing.plaf.metal.MetalLookAndFeel"));
372 iLAFs.add(new LookAndFeelInfo(
373 "Nimbus", "javax.swing.plaf.nimbus.NimbusLookAndFeel"));
374 iLAFs.add(new LookAndFeelInfo("CDE/Motif",
375 "com.sun.java.swing.plaf.motif.MotifLookAndFeel"));
376
377 // Only include windows on Windows boxs.
378 OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
379 if (osType == OSInfo.OSType.WINDOWS) {
380 iLAFs.add(new LookAndFeelInfo("Windows",
383 "win.xpstyle.themeActive") != null) {
384 iLAFs.add(new LookAndFeelInfo("Windows Classic",
385 "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel"));
386 }
387 }
388 else if (osType == OSInfo.OSType.MACOSX) {
389 iLAFs.add(new LookAndFeelInfo("Mac OS X", "com.apple.laf.AquaLookAndFeel"));
390 }
391 else {
392 // GTK is not shipped on Windows.
393 iLAFs.add(new LookAndFeelInfo("GTK+",
394 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"));
395 }
396 installedLAFs = iLAFs.toArray(new LookAndFeelInfo[iLAFs.size()]);
397 }
398
399
400 /**
401 * Returns an array of {@code LookAndFeelInfo}s representing the
402 * {@code LookAndFeel} implementations currently available. The
403 * <code>LookAndFeelInfo</code> objects can be used by an
404 * application to construct a menu of look and feel options for
405 * the user, or to determine which look and feel to set at startup
406 * time. To avoid the penalty of creating numerous {@code
407 * LookAndFeel} objects, {@code LookAndFeelInfo} maintains the
408 * class name of the {@code LookAndFeel} class, not the actual
409 * {@code LookAndFeel} instance.
410 * <p>
411 * The following example illustrates setting the current look and feel
412 * from an instance of {@code LookAndFeelInfo}:
413 * <pre>
414 * UIManager.setLookAndFeel(info.getClassName());
415 * </pre>
416 *
417 * @return an array of <code>LookAndFeelInfo</code> objects
418 * @see #setLookAndFeel
419 */
420 public static LookAndFeelInfo[] getInstalledLookAndFeels() {
421 maybeInitialize();
422 LookAndFeelInfo[] ilafs = getLAFState().installedLAFs;
423 if (ilafs == null) {
424 ilafs = installedLAFs;
425 }
426 LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length];
427 System.arraycopy(ilafs, 0, rv, 0, ilafs.length);
428 return rv;
429 }
430
431
432 /**
433 * Sets the set of available look and feels. While this method does
434 * not check to ensure all of the {@code LookAndFeelInfos} are
435 * {@code non-null}, it is strongly recommended that only {@code non-null}
436 * values are supplied in the {@code infos} array.
437 *
438 * @param infos set of <code>LookAndFeelInfo</code> objects specifying
439 * the available look and feels
440 *
441 * @see #getInstalledLookAndFeels
442 * @throws NullPointerException if {@code infos} is {@code null}
443 */
444 public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos)
445 throws SecurityException
446 {
447 maybeInitialize();
448 LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length];
449 System.arraycopy(infos, 0, newInfos, 0, infos.length);
450 getLAFState().installedLAFs = newInfos;
451 }
452
453
454 /**
455 * Adds the specified look and feel to the set of available look
456 * and feels. While this method allows a {@code null} {@code info},
457 * it is strongly recommended that a {@code non-null} value be used.
458 *
459 * @param info a <code>LookAndFeelInfo</code> object that names the
460 * look and feel and identifies the class that implements it
461 * @see #setInstalledLookAndFeels
462 */
463 public static void installLookAndFeel(LookAndFeelInfo info) {
464 LookAndFeelInfo[] infos = getInstalledLookAndFeels();
465 LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length + 1];
466 System.arraycopy(infos, 0, newInfos, 0, infos.length);
467 newInfos[infos.length] = info;
468 setInstalledLookAndFeels(newInfos);
469 }
470
471
472 /**
473 * Adds the specified look and feel to the set of available look
474 * and feels. While this method does not check the
475 * arguments in any way, it is strongly recommended that {@code
476 * non-null} values be supplied.
477 *
478 * @param name descriptive name of the look and feel
479 * @param className name of the class that implements the look and feel
480 * @see #setInstalledLookAndFeels
481 */
482 public static void installLookAndFeel(String name, String className) {
483 installLookAndFeel(new LookAndFeelInfo(name, className));
484 }
485
486
487 /**
488 * Returns the current look and feel or <code>null</code>.
489 *
490 * @return current look and feel, or <code>null</code>
491 * @see #setLookAndFeel
492 */
493 public static LookAndFeel getLookAndFeel() {
494 maybeInitialize();
495 return getLAFState().lookAndFeel;
496 }
497
498
499 /**
500 * Sets the current look and feel to {@code newLookAndFeel}.
501 * If the current look and feel is {@code non-null} {@code
502 * uninitialize} is invoked on it. If {@code newLookAndFeel} is
503 * {@code non-null}, {@code initialize} is invoked on it followed
504 * by {@code getDefaults}. The defaults returned from {@code
505 * newLookAndFeel.getDefaults()} replace those of the defaults
506 * from the previous look and feel. If the {@code newLookAndFeel} is
507 * {@code null}, the look and feel defaults are set to {@code null}.
508 * <p>
509 * A value of {@code null} can be used to set the look and feel
510 * to {@code null}. As the {@code LookAndFeel} is required for
511 * most of Swing to function, setting the {@code LookAndFeel} to
512 * {@code null} is strongly discouraged.
513 * <p>
514 * This is a JavaBeans bound property.
515 *
516 * @param newLookAndFeel {@code LookAndFeel} to install
517 * @throws UnsupportedLookAndFeelException if
518 * {@code newLookAndFeel} is {@code non-null} and
519 * {@code newLookAndFeel.isSupportedLookAndFeel()} returns
520 * {@code false}
521 * @see #getLookAndFeel
543 else {
544 lafState.setLookAndFeelDefaults(null);
545 }
546
547 SwingPropertyChangeSupport changeSupport = lafState.
548 getPropertyChangeSupport(false);
549 if (changeSupport != null) {
550 changeSupport.firePropertyChange("lookAndFeel", oldLookAndFeel,
551 newLookAndFeel);
552 }
553 }
554
555
556 /**
557 * Loads the {@code LookAndFeel} specified by the given class
558 * name, using the current thread's context class loader, and
559 * passes it to {@code setLookAndFeel(LookAndFeel)}.
560 *
561 * @param className a string specifying the name of the class that implements
562 * the look and feel
563 * @exception ClassNotFoundException if the <code>LookAndFeel</code>
564 * class could not be found
565 * @exception InstantiationException if a new instance of the class
566 * couldn't be created
567 * @exception IllegalAccessException if the class or initializer isn't accessible
568 * @exception UnsupportedLookAndFeelException if
569 * <code>lnf.isSupportedLookAndFeel()</code> is false
570 * @throws ClassCastException if {@code className} does not identify
571 * a class that extends {@code LookAndFeel}
572 */
573 public static void setLookAndFeel(String className)
574 throws ClassNotFoundException,
575 InstantiationException,
576 IllegalAccessException,
577 UnsupportedLookAndFeelException
578 {
579 if ("javax.swing.plaf.metal.MetalLookAndFeel".equals(className)) {
580 // Avoid reflection for the common case of metal.
581 setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
582 }
583 else {
584 Class<?> lnfClass = SwingUtilities.loadSystemClass(className);
585 setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
586 }
587 }
588
589 /**
590 * Returns the name of the <code>LookAndFeel</code> class that implements
591 * the native system look and feel if there is one, otherwise
592 * the name of the default cross platform <code>LookAndFeel</code>
593 * class. This value can be overriden by setting the
594 * <code>swing.systemlaf</code> system property.
595 *
596 * @return the <code>String</code> of the <code>LookAndFeel</code>
597 * class
598 *
599 * @see #setLookAndFeel
600 * @see #getCrossPlatformLookAndFeelClassName
601 */
602 public static String getSystemLookAndFeelClassName() {
603 String systemLAF = AccessController.doPrivileged(
604 new GetPropertyAction("swing.systemlaf"));
605 if (systemLAF != null) {
606 return systemLAF;
607 }
608 OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
609 if (osType == OSInfo.OSType.WINDOWS) {
610 return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
611 } else {
612 String desktop = AccessController.doPrivileged(new GetPropertyAction("sun.desktop"));
613 Toolkit toolkit = Toolkit.getDefaultToolkit();
614 if ("gnome".equals(desktop) &&
615 toolkit instanceof SunToolkit &&
616 ((SunToolkit) toolkit).isNativeGTKAvailable()) {
617 // May be set on Linux and Solaris boxs.
618 return "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
619 }
620 if (osType == OSInfo.OSType.MACOSX) {
621 if (toolkit.getClass() .getName()
622 .equals("sun.lwawt.macosx.LWCToolkit")) {
623 return "com.apple.laf.AquaLookAndFeel";
624 }
625 }
626 if (osType == OSInfo.OSType.SOLARIS) {
627 return "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
628 }
629 }
630 return getCrossPlatformLookAndFeelClassName();
631 }
632
633
634 /**
635 * Returns the name of the <code>LookAndFeel</code> class that implements
636 * the default cross platform look and feel -- the Java
637 * Look and Feel (JLF). This value can be overriden by setting the
638 * <code>swing.crossplatformlaf</code> system property.
639 *
640 * @return a string with the JLF implementation-class
641 * @see #setLookAndFeel
642 * @see #getSystemLookAndFeelClassName
643 */
644 public static String getCrossPlatformLookAndFeelClassName() {
645 String laf = AccessController.doPrivileged(
646 new GetPropertyAction("swing.crossplatformlaf"));
647 if (laf != null) {
648 return laf;
649 }
650 return "javax.swing.plaf.metal.MetalLookAndFeel";
651 }
652
653
654 /**
655 * Returns the defaults. The returned defaults resolve using the
656 * logic specified in the class documentation.
657 *
658 * @return a <code>UIDefaults</code> object containing the default values
659 */
660 public static UIDefaults getDefaults() {
661 maybeInitialize();
662 return getLAFState().multiUIDefaults;
663 }
664
665 /**
666 * Returns a font from the defaults. If the value for {@code key} is
667 * not a {@code Font}, {@code null} is returned.
668 *
669 * @param key an <code>Object</code> specifying the font
670 * @return the <code>Font</code> object
671 * @throws NullPointerException if {@code key} is {@code null}
672 */
673 public static Font getFont(Object key) {
674 return getDefaults().getFont(key);
675 }
676
677 /**
678 * Returns a font from the defaults that is appropriate
679 * for the given locale. If the value for {@code key} is
680 * not a {@code Font}, {@code null} is returned.
681 *
682 * @param key an <code>Object</code> specifying the font
683 * @param l the <code>Locale</code> for which the font is desired; refer
684 * to {@code UIDefaults} for details on how a {@code null}
685 * {@code Locale} is handled
686 * @return the <code>Font</code> object
687 * @throws NullPointerException if {@code key} is {@code null}
688 * @since 1.4
689 */
690 public static Font getFont(Object key, Locale l) {
691 return getDefaults().getFont(key,l);
692 }
693
694 /**
695 * Returns a color from the defaults. If the value for {@code key} is
696 * not a {@code Color}, {@code null} is returned.
697 *
698 * @param key an <code>Object</code> specifying the color
699 * @return the <code>Color</code> object
700 * @throws NullPointerException if {@code key} is {@code null}
701 */
702 public static Color getColor(Object key) {
703 return getDefaults().getColor(key);
704 }
705
706 /**
707 * Returns a color from the defaults that is appropriate
708 * for the given locale. If the value for {@code key} is
709 * not a {@code Color}, {@code null} is returned.
710 *
711 * @param key an <code>Object</code> specifying the color
712 * @param l the <code>Locale</code> for which the color is desired; refer
713 * to {@code UIDefaults} for details on how a {@code null}
714 * {@code Locale} is handled
715 * @return the <code>Color</code> object
716 * @throws NullPointerException if {@code key} is {@code null}
717 * @since 1.4
718 */
719 public static Color getColor(Object key, Locale l) {
720 return getDefaults().getColor(key,l);
721 }
722
723 /**
724 * Returns an <code>Icon</code> from the defaults. If the value for
725 * {@code key} is not an {@code Icon}, {@code null} is returned.
726 *
727 * @param key an <code>Object</code> specifying the icon
728 * @return the <code>Icon</code> object
729 * @throws NullPointerException if {@code key} is {@code null}
730 */
731 public static Icon getIcon(Object key) {
732 return getDefaults().getIcon(key);
733 }
734
735 /**
736 * Returns an <code>Icon</code> from the defaults that is appropriate
737 * for the given locale. If the value for
738 * {@code key} is not an {@code Icon}, {@code null} is returned.
739 *
740 * @param key an <code>Object</code> specifying the icon
741 * @param l the <code>Locale</code> for which the icon is desired; refer
742 * to {@code UIDefaults} for details on how a {@code null}
743 * {@code Locale} is handled
744 * @return the <code>Icon</code> object
745 * @throws NullPointerException if {@code key} is {@code null}
746 * @since 1.4
747 */
748 public static Icon getIcon(Object key, Locale l) {
749 return getDefaults().getIcon(key,l);
750 }
751
752 /**
753 * Returns a border from the defaults. If the value for
754 * {@code key} is not a {@code Border}, {@code null} is returned.
755 *
756 * @param key an <code>Object</code> specifying the border
757 * @return the <code>Border</code> object
758 * @throws NullPointerException if {@code key} is {@code null}
759 */
760 public static Border getBorder(Object key) {
761 return getDefaults().getBorder(key);
762 }
763
764 /**
765 * Returns a border from the defaults that is appropriate
766 * for the given locale. If the value for
767 * {@code key} is not a {@code Border}, {@code null} is returned.
768 *
769 * @param key an <code>Object</code> specifying the border
770 * @param l the <code>Locale</code> for which the border is desired; refer
771 * to {@code UIDefaults} for details on how a {@code null}
772 * {@code Locale} is handled
773 * @return the <code>Border</code> object
774 * @throws NullPointerException if {@code key} is {@code null}
775 * @since 1.4
776 */
777 public static Border getBorder(Object key, Locale l) {
778 return getDefaults().getBorder(key,l);
779 }
780
781 /**
782 * Returns a string from the defaults. If the value for
783 * {@code key} is not a {@code String}, {@code null} is returned.
784 *
785 * @param key an <code>Object</code> specifying the string
786 * @return the <code>String</code>
787 * @throws NullPointerException if {@code key} is {@code null}
788 */
789 public static String getString(Object key) {
790 return getDefaults().getString(key);
791 }
792
793 /**
794 * Returns a string from the defaults that is appropriate for the
795 * given locale. If the value for
796 * {@code key} is not a {@code String}, {@code null} is returned.
797 *
798 * @param key an <code>Object</code> specifying the string
799 * @param l the <code>Locale</code> for which the string is desired; refer
800 * to {@code UIDefaults} for details on how a {@code null}
801 * {@code Locale} is handled
802 * @return the <code>String</code>
803 * @since 1.4
804 * @throws NullPointerException if {@code key} is {@code null}
805 */
806 public static String getString(Object key, Locale l) {
807 return getDefaults().getString(key,l);
808 }
809
810 /**
811 * Returns a string from the defaults that is appropriate for the
812 * given locale. If the value for
813 * {@code key} is not a {@code String}, {@code null} is returned.
814 *
815 * @param key an <code>Object</code> specifying the string
816 * @param c {@code Component} used to determine the locale;
817 * {@code null} implies the default locale as
818 * returned by {@code Locale.getDefault()}
819 * @return the <code>String</code>
820 * @throws NullPointerException if {@code key} is {@code null}
821 */
822 static String getString(Object key, Component c) {
823 Locale l = (c == null) ? Locale.getDefault() : c.getLocale();
824 return getString(key, l);
825 }
826
827 /**
828 * Returns an integer from the defaults. If the value for
829 * {@code key} is not an {@code Integer}, or does not exist,
830 * {@code 0} is returned.
831 *
832 * @param key an <code>Object</code> specifying the int
833 * @return the int
834 * @throws NullPointerException if {@code key} is {@code null}
835 */
836 public static int getInt(Object key) {
837 return getDefaults().getInt(key);
838 }
839
840 /**
841 * Returns an integer from the defaults that is appropriate
842 * for the given locale. If the value for
843 * {@code key} is not an {@code Integer}, or does not exist,
844 * {@code 0} is returned.
845 *
846 * @param key an <code>Object</code> specifying the int
847 * @param l the <code>Locale</code> for which the int is desired; refer
848 * to {@code UIDefaults} for details on how a {@code null}
849 * {@code Locale} is handled
850 * @return the int
851 * @throws NullPointerException if {@code key} is {@code null}
852 * @since 1.4
853 */
854 public static int getInt(Object key, Locale l) {
855 return getDefaults().getInt(key,l);
856 }
857
858 /**
859 * Returns a boolean from the defaults which is associated with
860 * the key value. If the key is not found or the key doesn't represent
861 * a boolean value then {@code false} is returned.
862 *
863 * @param key an <code>Object</code> specifying the key for the desired boolean value
864 * @return the boolean value corresponding to the key
865 * @throws NullPointerException if {@code key} is {@code null}
866 * @since 1.4
867 */
868 public static boolean getBoolean(Object key) {
869 return getDefaults().getBoolean(key);
870 }
871
872 /**
873 * Returns a boolean from the defaults which is associated with
874 * the key value and the given <code>Locale</code>. If the key is not
875 * found or the key doesn't represent
876 * a boolean value then {@code false} will be returned.
877 *
878 * @param key an <code>Object</code> specifying the key for the desired
879 * boolean value
880 * @param l the <code>Locale</code> for which the boolean is desired; refer
881 * to {@code UIDefaults} for details on how a {@code null}
882 * {@code Locale} is handled
883 * @return the boolean value corresponding to the key
884 * @throws NullPointerException if {@code key} is {@code null}
885 * @since 1.4
886 */
887 public static boolean getBoolean(Object key, Locale l) {
888 return getDefaults().getBoolean(key,l);
889 }
890
891 /**
892 * Returns an <code>Insets</code> object from the defaults. If the value
893 * for {@code key} is not an {@code Insets}, {@code null} is returned.
894 *
895 * @param key an <code>Object</code> specifying the <code>Insets</code> object
896 * @return the <code>Insets</code> object
897 * @throws NullPointerException if {@code key} is {@code null}
898 */
899 public static Insets getInsets(Object key) {
900 return getDefaults().getInsets(key);
901 }
902
903 /**
904 * Returns an <code>Insets</code> object from the defaults that is
905 * appropriate for the given locale. If the value
906 * for {@code key} is not an {@code Insets}, {@code null} is returned.
907 *
908 * @param key an <code>Object</code> specifying the <code>Insets</code> object
909 * @param l the <code>Locale</code> for which the object is desired; refer
910 * to {@code UIDefaults} for details on how a {@code null}
911 * {@code Locale} is handled
912 * @return the <code>Insets</code> object
913 * @throws NullPointerException if {@code key} is {@code null}
914 * @since 1.4
915 */
916 public static Insets getInsets(Object key, Locale l) {
917 return getDefaults().getInsets(key,l);
918 }
919
920 /**
921 * Returns a dimension from the defaults. If the value
922 * for {@code key} is not a {@code Dimension}, {@code null} is returned.
923 *
924 * @param key an <code>Object</code> specifying the dimension object
925 * @return the <code>Dimension</code> object
926 * @throws NullPointerException if {@code key} is {@code null}
927 */
928 public static Dimension getDimension(Object key) {
929 return getDefaults().getDimension(key);
930 }
931
932 /**
933 * Returns a dimension from the defaults that is appropriate
934 * for the given locale. If the value
935 * for {@code key} is not a {@code Dimension}, {@code null} is returned.
936 *
937 * @param key an <code>Object</code> specifying the dimension object
938 * @param l the <code>Locale</code> for which the object is desired; refer
939 * to {@code UIDefaults} for details on how a {@code null}
940 * {@code Locale} is handled
941 * @return the <code>Dimension</code> object
942 * @throws NullPointerException if {@code key} is {@code null}
943 * @since 1.4
944 */
945 public static Dimension getDimension(Object key, Locale l) {
946 return getDefaults().getDimension(key,l);
947 }
948
949 /**
950 * Returns an object from the defaults.
951 *
952 * @param key an <code>Object</code> specifying the desired object
953 * @return the <code>Object</code>
954 * @throws NullPointerException if {@code key} is {@code null}
955 */
956 public static Object get(Object key) {
957 return getDefaults().get(key);
958 }
959
960 /**
961 * Returns an object from the defaults that is appropriate for
962 * the given locale.
963 *
964 * @param key an <code>Object</code> specifying the desired object
965 * @param l the <code>Locale</code> for which the object is desired; refer
966 * to {@code UIDefaults} for details on how a {@code null}
967 * {@code Locale} is handled
968 * @return the <code>Object</code>
969 * @throws NullPointerException if {@code key} is {@code null}
970 * @since 1.4
971 */
972 public static Object get(Object key, Locale l) {
973 return getDefaults().get(key,l);
974 }
975
976 /**
977 * Stores an object in the developer defaults. This is a cover method
978 * for {@code getDefaults().put(key, value)}. This only effects the
979 * developer defaults, not the system or look and feel defaults.
980 *
981 * @param key an <code>Object</code> specifying the retrieval key
982 * @param value the <code>Object</code> to store; refer to
983 * {@code UIDefaults} for details on how {@code null} is
984 * handled
985 * @return the <code>Object</code> returned by {@link UIDefaults#put}
986 * @throws NullPointerException if {@code key} is {@code null}
987 * @see UIDefaults#put
988 */
989 public static Object put(Object key, Object value) {
990 return getDefaults().put(key, value);
991 }
992
993 /**
994 * Returns the appropriate {@code ComponentUI} implementation for
995 * {@code target}. Typically, this is a cover for
996 * {@code getDefaults().getUI(target)}. However, if an auxiliary
997 * look and feel has been installed, this first invokes
998 * {@code getUI(target)} on the multiplexing look and feel's
999 * defaults, and returns that value if it is {@code non-null}.
1000 *
1001 * @param target the <code>JComponent</code> to return the
1002 * {@code ComponentUI} for
1003 * @return the <code>ComponentUI</code> object for {@code target}
1004 * @throws NullPointerException if {@code target} is {@code null}
1005 * @see UIDefaults#getUI
1006 */
1007 public static ComponentUI getUI(JComponent target) {
1008 maybeInitialize();
1009 maybeInitializeFocusPolicy(target);
1010 ComponentUI ui = null;
1011 LookAndFeel multiLAF = getLAFState().multiLookAndFeel;
1012 if (multiLAF != null) {
1013 // This can return null if the multiplexing look and feel
1014 // doesn't support a particular UI.
1015 ui = multiLAF.getDefaults().getUI(target);
1016 }
1017 if (ui == null) {
1018 ui = getDefaults().getUI(target);
1019 }
1020 return ui;
1021 }
1022
1023
1024 /**
1025 * Returns the {@code UIDefaults} from the current look and feel,
1026 * that were obtained at the time the look and feel was installed.
1027 * <p>
1028 * In general, developers should use the {@code UIDefaults} returned from
1029 * {@code getDefaults()}. As the current look and feel may expect
1030 * certain values to exist, altering the {@code UIDefaults} returned
1031 * from this method could have unexpected results.
1032 *
1033 * @return <code>UIDefaults</code> from the current look and feel
1034 * @see #getDefaults
1035 * @see #setLookAndFeel(LookAndFeel)
1036 * @see LookAndFeel#getDefaults
1037 */
1038 public static UIDefaults getLookAndFeelDefaults() {
1039 maybeInitialize();
1040 return getLAFState().getLookAndFeelDefaults();
1041 }
1042
1043 /**
1044 * Finds the Multiplexing <code>LookAndFeel</code>.
1045 */
1046 private static LookAndFeel getMultiLookAndFeel() {
1047 LookAndFeel multiLookAndFeel = getLAFState().multiLookAndFeel;
1048 if (multiLookAndFeel == null) {
1049 String defaultName = "javax.swing.plaf.multi.MultiLookAndFeel";
1050 String className = getLAFState().swingProps.getProperty(multiplexingLAFKey, defaultName);
1051 try {
1052 Class<?> lnfClass = SwingUtilities.loadSystemClass(className);
1053 multiLookAndFeel = (LookAndFeel)lnfClass.newInstance();
1054 } catch (Exception exc) {
1055 System.err.println("UIManager: failed loading " + className);
1056 }
1057 }
1058 return multiLookAndFeel;
1059 }
1060
1061 /**
1062 * Adds a <code>LookAndFeel</code> to the list of auxiliary look and feels.
1063 * The auxiliary look and feels tell the multiplexing look and feel what
1064 * other <code>LookAndFeel</code> classes for a component instance are to be used
1065 * in addition to the default <code>LookAndFeel</code> class when creating a
1066 * multiplexing UI. The change will only take effect when a new
1067 * UI class is created or when the default look and feel is changed
1068 * on a component instance.
1069 * <p>Note these are not the same as the installed look and feels.
1070 *
1071 * @param laf the <code>LookAndFeel</code> object
1072 * @see #removeAuxiliaryLookAndFeel
1073 * @see #setLookAndFeel
1074 * @see #getAuxiliaryLookAndFeels
1075 * @see #getInstalledLookAndFeels
1076 */
1077 public static void addAuxiliaryLookAndFeel(LookAndFeel laf) {
1078 maybeInitialize();
1079
1080 if (!laf.isSupportedLookAndFeel()) {
1081 // Ideally we would throw an exception here, but it's too late
1082 // for that.
1083 return;
1084 }
1085 Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
1086 if (v == null) {
1087 v = new Vector<LookAndFeel>();
1088 }
1089
1090 if (!v.contains(laf)) {
1091 v.addElement(laf);
1092 laf.initialize();
1093 getLAFState().auxLookAndFeels = v;
1094
1095 if (getLAFState().multiLookAndFeel == null) {
1096 getLAFState().multiLookAndFeel = getMultiLookAndFeel();
1097 }
1098 }
1099 }
1100
1101 /**
1102 * Removes a <code>LookAndFeel</code> from the list of auxiliary look and feels.
1103 * The auxiliary look and feels tell the multiplexing look and feel what
1104 * other <code>LookAndFeel</code> classes for a component instance are to be used
1105 * in addition to the default <code>LookAndFeel</code> class when creating a
1106 * multiplexing UI. The change will only take effect when a new
1107 * UI class is created or when the default look and feel is changed
1108 * on a component instance.
1109 * <p>Note these are not the same as the installed look and feels.
1110 *
1111 * @param laf the {@code LookAndFeel} to be removed
1112 * @return true if the <code>LookAndFeel</code> was removed from the list
1113 * @see #removeAuxiliaryLookAndFeel
1114 * @see #getAuxiliaryLookAndFeels
1115 * @see #setLookAndFeel
1116 * @see #getInstalledLookAndFeels
1117 */
1118 public static boolean removeAuxiliaryLookAndFeel(LookAndFeel laf) {
1119 maybeInitialize();
1120
1121 boolean result;
1122
1123 Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
1124 if ((v == null) || (v.size() == 0)) {
1125 return false;
1126 }
1127
1128 result = v.removeElement(laf);
1129 if (result) {
1130 if (v.size() == 0) {
1131 getLAFState().auxLookAndFeels = null;
1132 getLAFState().multiLookAndFeel = null;
1133 } else {
1134 getLAFState().auxLookAndFeels = v;
1135 }
1136 }
1137 laf.uninitialize();
1138
1139 return result;
1140 }
1141
1142 /**
1143 * Returns the list of auxiliary look and feels (can be <code>null</code>).
1144 * The auxiliary look and feels tell the multiplexing look and feel what
1145 * other <code>LookAndFeel</code> classes for a component instance are
1146 * to be used in addition to the default LookAndFeel class when creating a
1147 * multiplexing UI.
1148 * <p>Note these are not the same as the installed look and feels.
1149 *
1150 * @return list of auxiliary <code>LookAndFeel</code>s or <code>null</code>
1151 * @see #addAuxiliaryLookAndFeel
1152 * @see #removeAuxiliaryLookAndFeel
1153 * @see #setLookAndFeel
1154 * @see #getInstalledLookAndFeels
1155 */
1156 public static LookAndFeel[] getAuxiliaryLookAndFeels() {
1157 maybeInitialize();
1158
1159 Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
1160 if ((v == null) || (v.size() == 0)) {
1161 return null;
1162 }
1163 else {
1164 LookAndFeel[] rv = new LookAndFeel[v.size()];
1165 for (int i = 0; i < rv.length; i++) {
1166 rv[i] = v.elementAt(i);
1167 }
1168 return rv;
1169 }
1170 }
1171
1172
1173 /**
1174 * Adds a <code>PropertyChangeListener</code> to the listener list.
1175 * The listener is registered for all properties.
1176 *
1177 * @param listener the <code>PropertyChangeListener</code> to be added
1178 * @see java.beans.PropertyChangeSupport
1179 */
1180 public static void addPropertyChangeListener(PropertyChangeListener listener)
1181 {
1182 synchronized (classLock) {
1183 getLAFState().getPropertyChangeSupport(true).
1184 addPropertyChangeListener(listener);
1185 }
1186 }
1187
1188
1189 /**
1190 * Removes a <code>PropertyChangeListener</code> from the listener list.
1191 * This removes a <code>PropertyChangeListener</code> that was registered
1192 * for all properties.
1193 *
1194 * @param listener the <code>PropertyChangeListener</code> to be removed
1195 * @see java.beans.PropertyChangeSupport
1196 */
1197 public static void removePropertyChangeListener(PropertyChangeListener listener)
1198 {
1199 synchronized (classLock) {
1200 getLAFState().getPropertyChangeSupport(true).
1201 removePropertyChangeListener(listener);
1202 }
1203 }
1204
1205
1206 /**
1207 * Returns an array of all the <code>PropertyChangeListener</code>s added
1208 * to this UIManager with addPropertyChangeListener().
1209 *
1210 * @return all of the <code>PropertyChangeListener</code>s added or an empty
1211 * array if no listeners have been added
1212 * @since 1.4
1213 */
1214 public static PropertyChangeListener[] getPropertyChangeListeners() {
1215 synchronized(classLock) {
1216 return getLAFState().getPropertyChangeSupport(true).
1217 getPropertyChangeListeners();
1218 }
1219 }
1220
1221 private static Properties loadSwingProperties()
1222 {
1223 /* Don't bother checking for Swing properties if untrusted, as
1224 * there's no way to look them up without triggering SecurityExceptions.
1225 */
1226 if (UIManager.class.getClassLoader() != null) {
1227 return new Properties();
1228 }
1229 else {
1230 final Properties props = new Properties();
1261 checkProperty(props, disableMnemonicKey);
1262 // Don't care about return value.
1263 return null;
1264 }
1265 });
1266 return props;
1267 }
1268 }
1269
1270 private static void checkProperty(Properties props, String key) {
1271 // No need to do catch the SecurityException here, this runs
1272 // in a doPrivileged.
1273 String value = System.getProperty(key);
1274 if (value != null) {
1275 props.put(key, value);
1276 }
1277 }
1278
1279
1280 /**
1281 * If a <code>swing.properties</code> file exist and it has a
1282 * <code>swing.installedlafs</code> property
1283 * then initialize the <code>installedLAFs</code> field.
1284 *
1285 * @see #getInstalledLookAndFeels
1286 */
1287 private static void initializeInstalledLAFs(Properties swingProps)
1288 {
1289 String ilafsString = swingProps.getProperty(installedLAFsKey);
1290 if (ilafsString == null) {
1291 return;
1292 }
1293
1294 /* Create a vector that contains the value of the swing.installedlafs
1295 * property. For example given "swing.installedlafs=motif,windows"
1296 * lafs = {"motif", "windows"}.
1297 */
1298 Vector<String> lafs = new Vector<String>();
1299 StringTokenizer st = new StringTokenizer(ilafsString, ",", false);
1300 while (st.hasMoreTokens()) {
1301 lafs.addElement(st.nextToken());
1302 }
1303
1402 auxLookAndFeels = null;
1403 }
1404 else {
1405 getLAFState().multiLookAndFeel = getMultiLookAndFeel();
1406 if (getLAFState().multiLookAndFeel == null) {
1407 auxLookAndFeels = null;
1408 }
1409 }
1410
1411 getLAFState().auxLookAndFeels = auxLookAndFeels;
1412 }
1413
1414
1415 private static void initializeSystemDefaults(Properties swingProps) {
1416 getLAFState().swingProps = swingProps;
1417 }
1418
1419
1420 /*
1421 * This method is called before any code that depends on the
1422 * <code>AppContext</code> specific LAFState object runs. When the AppContext
1423 * corresponds to a set of applets it's possible for this method
1424 * to be re-entered, which is why we grab a lock before calling
1425 * initialize().
1426 */
1427 private static void maybeInitialize() {
1428 synchronized (classLock) {
1429 if (!getLAFState().initialized) {
1430 getLAFState().initialized = true;
1431 initialize();
1432 }
1433 }
1434 }
1435
1436 /*
1437 * Sets default swing focus traversal policy.
1438 */
1439 @SuppressWarnings("deprecation")
1440 private static void maybeInitializeFocusPolicy(JComponent comp) {
1441 // Check for JRootPane which indicates that a swing toplevel
1442 // is coming, in which case a swing default focus policy
|
81 * </pre>
82 * The following example illustrates setting the look and feel based on
83 * class name:
84 * <pre>
85 * UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
86 * </pre>
87 * Once the look and feel has been changed it is imperative to invoke
88 * {@code updateUI} on all {@code JComponents}. The method {@link
89 * SwingUtilities#updateComponentTreeUI} makes it easy to apply {@code
90 * updateUI} to a containment hierarchy. Refer to it for
91 * details. The exact behavior of not invoking {@code
92 * updateUI} after changing the look and feel is
93 * unspecified. It is very possible to receive unexpected exceptions,
94 * painting problems, or worse.
95 *
96 * <h3>Default look and feel</h3>
97 *
98 * The class used for the default look and feel is chosen in the following
99 * manner:
100 * <ol>
101 * <li>If the system property {@code swing.defaultlaf} is
102 * {@code non-null}, use its value as the default look and feel class
103 * name.
104 * <li>If the {@link java.util.Properties} file {@code swing.properties}
105 * exists and contains the key {@code swing.defaultlaf},
106 * use its value as the default look and feel class name. The location
107 * that is checked for {@code swing.properties} may vary depending
108 * upon the implementation of the Java platform. Typically the
109 * {@code swing.properties} file is located in the {@code conf}
110 * subdirectory of the Java installation directory.
111 * Refer to the release notes of the implementation being used for
112 * further details.
113 * <li>Otherwise use the cross platform look and feel.
114 * </ol>
115 *
116 * <h3>Defaults</h3>
117 *
118 * {@code UIManager} manages three sets of {@code UIDefaults}. In order, they
119 * are:
120 * <ol>
121 * <li>Developer defaults. With few exceptions Swing does not
122 * alter the developer defaults; these are intended to be modified
123 * and used by the developer.
124 * <li>Look and feel defaults. The look and feel defaults are
125 * supplied by the look and feel at the time it is installed as the
126 * current look and feel ({@code setLookAndFeel()} is invoked). The
127 * look and feel defaults can be obtained using the {@code
128 * getLookAndFeelDefaults()} method.
129 * <li>System defaults. The system defaults are provided by Swing.
151 * The set of defaults a particular look and feel supports is defined
152 * and documented by that look and feel. In addition, each look and
153 * feel, or {@code ComponentUI} provided by a look and feel, may
154 * access the defaults at different times in their life cycle. Some
155 * look and feels may aggressively look up defaults, so that changing a
156 * default may not have an effect after installing the look and feel.
157 * Other look and feels may lazily access defaults so that a change to
158 * the defaults may effect an existing look and feel. Finally, other look
159 * and feels might not configure themselves from the defaults table in
160 * any way. None-the-less it is usually the case that a look and feel
161 * expects certain defaults, so that in general
162 * a {@code ComponentUI} provided by one look and feel will not
163 * work with another look and feel.
164 * <p>
165 * <strong>Warning:</strong>
166 * Serialized objects of this class will not be compatible with
167 * future Swing releases. The current serialization support is
168 * appropriate for short term storage or RMI between applications running
169 * the same version of Swing. As of 1.4, support for long term storage
170 * of all JavaBeans™
171 * has been added to the {@code java.beans} package.
172 * Please see {@link java.beans.XMLEncoder}.
173 *
174 * @author Thomas Ball
175 * @author Hans Muller
176 * @since 1.2
177 */
178 @SuppressWarnings("serial") // Same-version serialization only
179 public class UIManager implements Serializable
180 {
181 /**
182 * This class defines the state managed by the {@code UIManager}. For
183 * Swing applications the fields in this class could just as well
184 * be static members of {@code UIManager} however we give them
185 * "AppContext"
186 * scope instead so that applets (and potentially multiple lightweight
187 * applications running in a single VM) have their own state. For example,
188 * an applet can alter its look and feel, see {@code setLookAndFeel}.
189 * Doing so has no affect on other applets (or the browser).
190 */
191 private static class LAFState
192 {
193 Properties swingProps;
194 private UIDefaults[] tables = new UIDefaults[2];
195
196 boolean initialized = false;
197 boolean focusPolicyInitialized = false;
198 MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables);
199 LookAndFeel lookAndFeel;
200 LookAndFeel multiLookAndFeel = null;
201 Vector<LookAndFeel> auxLookAndFeels = null;
202 SwingPropertyChangeSupport changeSupport;
203
204 LookAndFeelInfo[] installedLAFs;
205
206 UIDefaults getLookAndFeelDefaults() { return tables[0]; }
207 void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; }
208
209 UIDefaults getSystemDefaults() { return tables[1]; }
210 void setSystemDefaults(UIDefaults x) { tables[1] = x; }
211
212 /**
213 * Returns the SwingPropertyChangeSupport for the current
214 * AppContext. If {@code create} is a true, a non-null
215 * {@code SwingPropertyChangeSupport} will be returned, if
216 * {@code create} is false and this has not been invoked
217 * with true, null will be returned.
218 */
219 public synchronized SwingPropertyChangeSupport
220 getPropertyChangeSupport(boolean create) {
221 if (create && changeSupport == null) {
222 changeSupport = new SwingPropertyChangeSupport(
223 UIManager.class);
224 }
225 return changeSupport;
226 }
227 }
228
229
230
231
232 /* Lock object used in place of class object for synchronization. (4187686)
233 */
234 private static final Object classLock = new Object();
235
236 /**
237 * Return the {@code LAFState} object, lazily create one if necessary.
238 * All access to the {@code LAFState} fields is done via this method,
239 * for example:
240 * <pre>
241 * getLAFState().initialized = true;
242 * </pre>
243 */
244 private static LAFState getLAFState() {
245 LAFState rv = (LAFState)SwingUtilities.appContextGet(
246 SwingUtilities2.LAF_STATE_KEY);
247 if (rv == null) {
248 synchronized (classLock) {
249 rv = (LAFState)SwingUtilities.appContextGet(
250 SwingUtilities2.LAF_STATE_KEY);
251 if (rv == null) {
252 SwingUtilities.appContextPut(
253 SwingUtilities2.LAF_STATE_KEY,
254 (rv = new LAFState()));
255 }
256 }
257 }
258 return rv;
259 }
260
261
262 /* Keys used in the {@code swing.properties} properties file.
263 * See loadUserProperties(), initialize().
264 */
265
266 private static final String defaultLAFKey = "swing.defaultlaf";
267 private static final String auxiliaryLAFsKey = "swing.auxiliarylaf";
268 private static final String multiplexingLAFKey = "swing.plaf.multiplexinglaf";
269 private static final String installedLAFsKey = "swing.installedlafs";
270 private static final String disableMnemonicKey = "swing.disablenavaids";
271
272 /**
273 * Return a {@code swing.properties} file key for the attribute of specified
274 * look and feel. The attr is either "name" or "class", a typical
275 * key would be: "swing.installedlaf.windows.name"
276 */
277 private static String makeInstalledLAFKey(String laf, String attr) {
278 return "swing.installedlaf." + laf + "." + attr;
279 }
280
281 /**
282 * The location of the {@code swing.properties} property file is
283 * implementation-specific.
284 * It is typically located in the {@code conf} subdirectory of the Java
285 * installation directory. This method returns a bogus filename
286 * if {@code java.home} isn't defined.
287 */
288 private static String makeSwingPropertiesFilename() {
289 String sep = File.separator;
290 // No need to wrap this in a doPrivileged as it's called from
291 // a doPrivileged.
292 String javaHome = System.getProperty("java.home");
293 if (javaHome == null) {
294 javaHome = "<java.home undefined>";
295 }
296 return javaHome + sep + "conf" + sep + "swing.properties";
297 }
298
299
300 /**
301 * Provides a little information about an installed
302 * {@code LookAndFeel} for the sake of configuring a menu or
303 * for initial application set up.
304 *
305 * @see UIManager#getInstalledLookAndFeels
306 * @see LookAndFeel
307 */
308 public static class LookAndFeelInfo {
309 private String name;
310 private String className;
311
312 /**
313 * Constructs a {@code UIManager}s
314 * {@code LookAndFeelInfo} object.
315 *
316 * @param name a {@code String} specifying the name of
317 * the look and feel
318 * @param className a {@code String} specifying the name of
319 * the class that implements the look and feel
320 */
321 public LookAndFeelInfo(String name, String className) {
322 this.name = name;
323 this.className = className;
324 }
325
326 /**
327 * Returns the name of the look and feel in a form suitable
328 * for a menu or other presentation
329 * @return a {@code String} containing the name
330 * @see LookAndFeel#getName
331 */
332 public String getName() {
333 return name;
334 }
335
336 /**
337 * Returns the name of the class that implements this look and feel.
338 * @return the name of the class that implements this
339 * {@code LookAndFeel}
340 * @see LookAndFeel
341 */
342 public String getClassName() {
343 return className;
344 }
345
346 /**
347 * Returns a string that displays and identifies this
348 * object's properties.
349 *
350 * @return a {@code String} representation of this object
351 */
352 public String toString() {
353 return getClass().getName() + "[" + getName() + " " + getClassName() + "]";
354 }
355 }
356
357
358 /**
359 * The default value of {@code installedLAFS} is used when no
360 * {@code swing.properties}
361 * file is available or if the file doesn't contain a "swing.installedlafs"
362 * property.
363 *
364 * @see #initializeInstalledLAFs
365 */
366 private static LookAndFeelInfo[] installedLAFs;
367
368 static {
369 ArrayList<LookAndFeelInfo> iLAFs = new ArrayList<LookAndFeelInfo>(4);
370 iLAFs.add(new LookAndFeelInfo(
371 "Metal", "javax.swing.plaf.metal.MetalLookAndFeel"));
372 iLAFs.add(new LookAndFeelInfo(
373 "Nimbus", "javax.swing.plaf.nimbus.NimbusLookAndFeel"));
374 iLAFs.add(new LookAndFeelInfo("CDE/Motif",
375 "com.sun.java.swing.plaf.motif.MotifLookAndFeel"));
376
377 // Only include windows on Windows boxs.
378 OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
379 if (osType == OSInfo.OSType.WINDOWS) {
380 iLAFs.add(new LookAndFeelInfo("Windows",
383 "win.xpstyle.themeActive") != null) {
384 iLAFs.add(new LookAndFeelInfo("Windows Classic",
385 "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel"));
386 }
387 }
388 else if (osType == OSInfo.OSType.MACOSX) {
389 iLAFs.add(new LookAndFeelInfo("Mac OS X", "com.apple.laf.AquaLookAndFeel"));
390 }
391 else {
392 // GTK is not shipped on Windows.
393 iLAFs.add(new LookAndFeelInfo("GTK+",
394 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"));
395 }
396 installedLAFs = iLAFs.toArray(new LookAndFeelInfo[iLAFs.size()]);
397 }
398
399
400 /**
401 * Returns an array of {@code LookAndFeelInfo}s representing the
402 * {@code LookAndFeel} implementations currently available. The
403 * {@code LookAndFeelInfo} objects can be used by an
404 * application to construct a menu of look and feel options for
405 * the user, or to determine which look and feel to set at startup
406 * time. To avoid the penalty of creating numerous {@code
407 * LookAndFeel} objects, {@code LookAndFeelInfo} maintains the
408 * class name of the {@code LookAndFeel} class, not the actual
409 * {@code LookAndFeel} instance.
410 * <p>
411 * The following example illustrates setting the current look and feel
412 * from an instance of {@code LookAndFeelInfo}:
413 * <pre>
414 * UIManager.setLookAndFeel(info.getClassName());
415 * </pre>
416 *
417 * @return an array of {@code LookAndFeelInfo} objects
418 * @see #setLookAndFeel
419 */
420 public static LookAndFeelInfo[] getInstalledLookAndFeels() {
421 maybeInitialize();
422 LookAndFeelInfo[] ilafs = getLAFState().installedLAFs;
423 if (ilafs == null) {
424 ilafs = installedLAFs;
425 }
426 LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length];
427 System.arraycopy(ilafs, 0, rv, 0, ilafs.length);
428 return rv;
429 }
430
431
432 /**
433 * Sets the set of available look and feels. While this method does
434 * not check to ensure all of the {@code LookAndFeelInfos} are
435 * {@code non-null}, it is strongly recommended that only {@code non-null}
436 * values are supplied in the {@code infos} array.
437 *
438 * @param infos set of {@code LookAndFeelInfo} objects specifying
439 * the available look and feels
440 *
441 * @see #getInstalledLookAndFeels
442 * @throws NullPointerException if {@code infos} is {@code null}
443 */
444 public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos)
445 throws SecurityException
446 {
447 maybeInitialize();
448 LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length];
449 System.arraycopy(infos, 0, newInfos, 0, infos.length);
450 getLAFState().installedLAFs = newInfos;
451 }
452
453
454 /**
455 * Adds the specified look and feel to the set of available look
456 * and feels. While this method allows a {@code null info},
457 * it is strongly recommended that a {@code non-null} value be used.
458 *
459 * @param info a {@code LookAndFeelInfo} object that names the
460 * look and feel and identifies the class that implements it
461 * @see #setInstalledLookAndFeels
462 */
463 public static void installLookAndFeel(LookAndFeelInfo info) {
464 LookAndFeelInfo[] infos = getInstalledLookAndFeels();
465 LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length + 1];
466 System.arraycopy(infos, 0, newInfos, 0, infos.length);
467 newInfos[infos.length] = info;
468 setInstalledLookAndFeels(newInfos);
469 }
470
471
472 /**
473 * Adds the specified look and feel to the set of available look
474 * and feels. While this method does not check the
475 * arguments in any way, it is strongly recommended that {@code
476 * non-null} values be supplied.
477 *
478 * @param name descriptive name of the look and feel
479 * @param className name of the class that implements the look and feel
480 * @see #setInstalledLookAndFeels
481 */
482 public static void installLookAndFeel(String name, String className) {
483 installLookAndFeel(new LookAndFeelInfo(name, className));
484 }
485
486
487 /**
488 * Returns the current look and feel or {@code null}.
489 *
490 * @return current look and feel, or {@code null}
491 * @see #setLookAndFeel
492 */
493 public static LookAndFeel getLookAndFeel() {
494 maybeInitialize();
495 return getLAFState().lookAndFeel;
496 }
497
498
499 /**
500 * Sets the current look and feel to {@code newLookAndFeel}.
501 * If the current look and feel is {@code non-null
502 * uninitialize} is invoked on it. If {@code newLookAndFeel} is
503 * {@code non-null}, {@code initialize} is invoked on it followed
504 * by {@code getDefaults}. The defaults returned from {@code
505 * newLookAndFeel.getDefaults()} replace those of the defaults
506 * from the previous look and feel. If the {@code newLookAndFeel} is
507 * {@code null}, the look and feel defaults are set to {@code null}.
508 * <p>
509 * A value of {@code null} can be used to set the look and feel
510 * to {@code null}. As the {@code LookAndFeel} is required for
511 * most of Swing to function, setting the {@code LookAndFeel} to
512 * {@code null} is strongly discouraged.
513 * <p>
514 * This is a JavaBeans bound property.
515 *
516 * @param newLookAndFeel {@code LookAndFeel} to install
517 * @throws UnsupportedLookAndFeelException if
518 * {@code newLookAndFeel} is {@code non-null} and
519 * {@code newLookAndFeel.isSupportedLookAndFeel()} returns
520 * {@code false}
521 * @see #getLookAndFeel
543 else {
544 lafState.setLookAndFeelDefaults(null);
545 }
546
547 SwingPropertyChangeSupport changeSupport = lafState.
548 getPropertyChangeSupport(false);
549 if (changeSupport != null) {
550 changeSupport.firePropertyChange("lookAndFeel", oldLookAndFeel,
551 newLookAndFeel);
552 }
553 }
554
555
556 /**
557 * Loads the {@code LookAndFeel} specified by the given class
558 * name, using the current thread's context class loader, and
559 * passes it to {@code setLookAndFeel(LookAndFeel)}.
560 *
561 * @param className a string specifying the name of the class that implements
562 * the look and feel
563 * @exception ClassNotFoundException if the {@code LookAndFeel}
564 * class could not be found
565 * @exception InstantiationException if a new instance of the class
566 * couldn't be created
567 * @exception IllegalAccessException if the class or initializer isn't accessible
568 * @exception UnsupportedLookAndFeelException if
569 * {@code lnf.isSupportedLookAndFeel()} is false
570 * @throws ClassCastException if {@code className} does not identify
571 * a class that extends {@code LookAndFeel}
572 */
573 public static void setLookAndFeel(String className)
574 throws ClassNotFoundException,
575 InstantiationException,
576 IllegalAccessException,
577 UnsupportedLookAndFeelException
578 {
579 if ("javax.swing.plaf.metal.MetalLookAndFeel".equals(className)) {
580 // Avoid reflection for the common case of metal.
581 setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
582 }
583 else {
584 Class<?> lnfClass = SwingUtilities.loadSystemClass(className);
585 setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
586 }
587 }
588
589 /**
590 * Returns the name of the {@code LookAndFeel} class that implements
591 * the native system look and feel if there is one, otherwise
592 * the name of the default cross platform {@code LookAndFeel}
593 * class. This value can be overriden by setting the
594 * {@code swing.systemlaf} system property.
595 *
596 * @return the {@code String} of the {@code LookAndFeel}
597 * class
598 *
599 * @see #setLookAndFeel
600 * @see #getCrossPlatformLookAndFeelClassName
601 */
602 public static String getSystemLookAndFeelClassName() {
603 String systemLAF = AccessController.doPrivileged(
604 new GetPropertyAction("swing.systemlaf"));
605 if (systemLAF != null) {
606 return systemLAF;
607 }
608 OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
609 if (osType == OSInfo.OSType.WINDOWS) {
610 return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
611 } else {
612 String desktop = AccessController.doPrivileged(new GetPropertyAction("sun.desktop"));
613 Toolkit toolkit = Toolkit.getDefaultToolkit();
614 if ("gnome".equals(desktop) &&
615 toolkit instanceof SunToolkit &&
616 ((SunToolkit) toolkit).isNativeGTKAvailable()) {
617 // May be set on Linux and Solaris boxs.
618 return "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
619 }
620 if (osType == OSInfo.OSType.MACOSX) {
621 if (toolkit.getClass() .getName()
622 .equals("sun.lwawt.macosx.LWCToolkit")) {
623 return "com.apple.laf.AquaLookAndFeel";
624 }
625 }
626 if (osType == OSInfo.OSType.SOLARIS) {
627 return "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
628 }
629 }
630 return getCrossPlatformLookAndFeelClassName();
631 }
632
633
634 /**
635 * Returns the name of the {@code LookAndFeel} class that implements
636 * the default cross platform look and feel -- the Java
637 * Look and Feel (JLF). This value can be overriden by setting the
638 * {@code swing.crossplatformlaf} system property.
639 *
640 * @return a string with the JLF implementation-class
641 * @see #setLookAndFeel
642 * @see #getSystemLookAndFeelClassName
643 */
644 public static String getCrossPlatformLookAndFeelClassName() {
645 String laf = AccessController.doPrivileged(
646 new GetPropertyAction("swing.crossplatformlaf"));
647 if (laf != null) {
648 return laf;
649 }
650 return "javax.swing.plaf.metal.MetalLookAndFeel";
651 }
652
653
654 /**
655 * Returns the defaults. The returned defaults resolve using the
656 * logic specified in the class documentation.
657 *
658 * @return a {@code UIDefaults} object containing the default values
659 */
660 public static UIDefaults getDefaults() {
661 maybeInitialize();
662 return getLAFState().multiUIDefaults;
663 }
664
665 /**
666 * Returns a font from the defaults. If the value for {@code key} is
667 * not a {@code Font}, {@code null} is returned.
668 *
669 * @param key an {@code Object} specifying the font
670 * @return the {@code Font} object
671 * @throws NullPointerException if {@code key} is {@code null}
672 */
673 public static Font getFont(Object key) {
674 return getDefaults().getFont(key);
675 }
676
677 /**
678 * Returns a font from the defaults that is appropriate
679 * for the given locale. If the value for {@code key} is
680 * not a {@code Font}, {@code null} is returned.
681 *
682 * @param key an {@code Object} specifying the font
683 * @param l the {@code Locale} for which the font is desired; refer
684 * to {@code UIDefaults} for details on how a {@code null}
685 * {@code Locale} is handled
686 * @return the {@code Font} object
687 * @throws NullPointerException if {@code key} is {@code null}
688 * @since 1.4
689 */
690 public static Font getFont(Object key, Locale l) {
691 return getDefaults().getFont(key,l);
692 }
693
694 /**
695 * Returns a color from the defaults. If the value for {@code key} is
696 * not a {@code Color}, {@code null} is returned.
697 *
698 * @param key an {@code Object} specifying the color
699 * @return the {@code Color} object
700 * @throws NullPointerException if {@code key} is {@code null}
701 */
702 public static Color getColor(Object key) {
703 return getDefaults().getColor(key);
704 }
705
706 /**
707 * Returns a color from the defaults that is appropriate
708 * for the given locale. If the value for {@code key} is
709 * not a {@code Color}, {@code null} is returned.
710 *
711 * @param key an {@code Object} specifying the color
712 * @param l the {@code Locale} for which the color is desired; refer
713 * to {@code UIDefaults} for details on how a {@code null}
714 * {@code Locale} is handled
715 * @return the {@code Color} object
716 * @throws NullPointerException if {@code key} is {@code null}
717 * @since 1.4
718 */
719 public static Color getColor(Object key, Locale l) {
720 return getDefaults().getColor(key,l);
721 }
722
723 /**
724 * Returns an {@code Icon} from the defaults. If the value for
725 * {@code key} is not an {@code Icon}, {@code null} is returned.
726 *
727 * @param key an {@code Object} specifying the icon
728 * @return the {@code Icon} object
729 * @throws NullPointerException if {@code key} is {@code null}
730 */
731 public static Icon getIcon(Object key) {
732 return getDefaults().getIcon(key);
733 }
734
735 /**
736 * Returns an {@code Icon} from the defaults that is appropriate
737 * for the given locale. If the value for
738 * {@code key} is not an {@code Icon}, {@code null} is returned.
739 *
740 * @param key an {@code Object} specifying the icon
741 * @param l the {@code Locale} for which the icon is desired; refer
742 * to {@code UIDefaults} for details on how a {@code null}
743 * {@code Locale} is handled
744 * @return the {@code Icon} object
745 * @throws NullPointerException if {@code key} is {@code null}
746 * @since 1.4
747 */
748 public static Icon getIcon(Object key, Locale l) {
749 return getDefaults().getIcon(key,l);
750 }
751
752 /**
753 * Returns a border from the defaults. If the value for
754 * {@code key} is not a {@code Border}, {@code null} is returned.
755 *
756 * @param key an {@code Object} specifying the border
757 * @return the {@code Border} object
758 * @throws NullPointerException if {@code key} is {@code null}
759 */
760 public static Border getBorder(Object key) {
761 return getDefaults().getBorder(key);
762 }
763
764 /**
765 * Returns a border from the defaults that is appropriate
766 * for the given locale. If the value for
767 * {@code key} is not a {@code Border}, {@code null} is returned.
768 *
769 * @param key an {@code Object} specifying the border
770 * @param l the {@code Locale} for which the border is desired; refer
771 * to {@code UIDefaults} for details on how a {@code null}
772 * {@code Locale} is handled
773 * @return the {@code Border} object
774 * @throws NullPointerException if {@code key} is {@code null}
775 * @since 1.4
776 */
777 public static Border getBorder(Object key, Locale l) {
778 return getDefaults().getBorder(key,l);
779 }
780
781 /**
782 * Returns a string from the defaults. If the value for
783 * {@code key} is not a {@code String}, {@code null} is returned.
784 *
785 * @param key an {@code Object} specifying the string
786 * @return the {@code String}
787 * @throws NullPointerException if {@code key} is {@code null}
788 */
789 public static String getString(Object key) {
790 return getDefaults().getString(key);
791 }
792
793 /**
794 * Returns a string from the defaults that is appropriate for the
795 * given locale. If the value for
796 * {@code key} is not a {@code String}, {@code null} is returned.
797 *
798 * @param key an {@code Object} specifying the string
799 * @param l the {@code Locale} for which the string is desired; refer
800 * to {@code UIDefaults} for details on how a {@code null}
801 * {@code Locale} is handled
802 * @return the {@code String}
803 * @since 1.4
804 * @throws NullPointerException if {@code key} is {@code null}
805 */
806 public static String getString(Object key, Locale l) {
807 return getDefaults().getString(key,l);
808 }
809
810 /**
811 * Returns a string from the defaults that is appropriate for the
812 * given locale. If the value for
813 * {@code key} is not a {@code String}, {@code null} is returned.
814 *
815 * @param key an {@code Object} specifying the string
816 * @param c {@code Component} used to determine the locale;
817 * {@code null} implies the default locale as
818 * returned by {@code Locale.getDefault()}
819 * @return the {@code String}
820 * @throws NullPointerException if {@code key} is {@code null}
821 */
822 static String getString(Object key, Component c) {
823 Locale l = (c == null) ? Locale.getDefault() : c.getLocale();
824 return getString(key, l);
825 }
826
827 /**
828 * Returns an integer from the defaults. If the value for
829 * {@code key} is not an {@code Integer}, or does not exist,
830 * {@code 0} is returned.
831 *
832 * @param key an {@code Object} specifying the int
833 * @return the int
834 * @throws NullPointerException if {@code key} is {@code null}
835 */
836 public static int getInt(Object key) {
837 return getDefaults().getInt(key);
838 }
839
840 /**
841 * Returns an integer from the defaults that is appropriate
842 * for the given locale. If the value for
843 * {@code key} is not an {@code Integer}, or does not exist,
844 * {@code 0} is returned.
845 *
846 * @param key an {@code Object} specifying the int
847 * @param l the {@code Locale} for which the int is desired; refer
848 * to {@code UIDefaults} for details on how a {@code null}
849 * {@code Locale} is handled
850 * @return the int
851 * @throws NullPointerException if {@code key} is {@code null}
852 * @since 1.4
853 */
854 public static int getInt(Object key, Locale l) {
855 return getDefaults().getInt(key,l);
856 }
857
858 /**
859 * Returns a boolean from the defaults which is associated with
860 * the key value. If the key is not found or the key doesn't represent
861 * a boolean value then {@code false} is returned.
862 *
863 * @param key an {@code Object} specifying the key for the desired boolean value
864 * @return the boolean value corresponding to the key
865 * @throws NullPointerException if {@code key} is {@code null}
866 * @since 1.4
867 */
868 public static boolean getBoolean(Object key) {
869 return getDefaults().getBoolean(key);
870 }
871
872 /**
873 * Returns a boolean from the defaults which is associated with
874 * the key value and the given {@code Locale}. If the key is not
875 * found or the key doesn't represent
876 * a boolean value then {@code false} will be returned.
877 *
878 * @param key an {@code Object} specifying the key for the desired
879 * boolean value
880 * @param l the {@code Locale} for which the boolean is desired; refer
881 * to {@code UIDefaults} for details on how a {@code null}
882 * {@code Locale} is handled
883 * @return the boolean value corresponding to the key
884 * @throws NullPointerException if {@code key} is {@code null}
885 * @since 1.4
886 */
887 public static boolean getBoolean(Object key, Locale l) {
888 return getDefaults().getBoolean(key,l);
889 }
890
891 /**
892 * Returns an {@code Insets} object from the defaults. If the value
893 * for {@code key} is not an {@code Insets}, {@code null} is returned.
894 *
895 * @param key an {@code Object} specifying the {@code Insets} object
896 * @return the {@code Insets} object
897 * @throws NullPointerException if {@code key} is {@code null}
898 */
899 public static Insets getInsets(Object key) {
900 return getDefaults().getInsets(key);
901 }
902
903 /**
904 * Returns an {@code Insets} object from the defaults that is
905 * appropriate for the given locale. If the value
906 * for {@code key} is not an {@code Insets}, {@code null} is returned.
907 *
908 * @param key an {@code Object} specifying the {@code Insets} object
909 * @param l the {@code Locale} for which the object is desired; refer
910 * to {@code UIDefaults} for details on how a {@code null}
911 * {@code Locale} is handled
912 * @return the {@code Insets} object
913 * @throws NullPointerException if {@code key} is {@code null}
914 * @since 1.4
915 */
916 public static Insets getInsets(Object key, Locale l) {
917 return getDefaults().getInsets(key,l);
918 }
919
920 /**
921 * Returns a dimension from the defaults. If the value
922 * for {@code key} is not a {@code Dimension}, {@code null} is returned.
923 *
924 * @param key an {@code Object} specifying the dimension object
925 * @return the {@code Dimension} object
926 * @throws NullPointerException if {@code key} is {@code null}
927 */
928 public static Dimension getDimension(Object key) {
929 return getDefaults().getDimension(key);
930 }
931
932 /**
933 * Returns a dimension from the defaults that is appropriate
934 * for the given locale. If the value
935 * for {@code key} is not a {@code Dimension}, {@code null} is returned.
936 *
937 * @param key an {@code Object} specifying the dimension object
938 * @param l the {@code Locale} for which the object is desired; refer
939 * to {@code UIDefaults} for details on how a {@code null}
940 * {@code Locale} is handled
941 * @return the {@code Dimension} object
942 * @throws NullPointerException if {@code key} is {@code null}
943 * @since 1.4
944 */
945 public static Dimension getDimension(Object key, Locale l) {
946 return getDefaults().getDimension(key,l);
947 }
948
949 /**
950 * Returns an object from the defaults.
951 *
952 * @param key an {@code Object} specifying the desired object
953 * @return the {@code Object}
954 * @throws NullPointerException if {@code key} is {@code null}
955 */
956 public static Object get(Object key) {
957 return getDefaults().get(key);
958 }
959
960 /**
961 * Returns an object from the defaults that is appropriate for
962 * the given locale.
963 *
964 * @param key an {@code Object} specifying the desired object
965 * @param l the {@code Locale} for which the object is desired; refer
966 * to {@code UIDefaults} for details on how a {@code null}
967 * {@code Locale} is handled
968 * @return the {@code Object}
969 * @throws NullPointerException if {@code key} is {@code null}
970 * @since 1.4
971 */
972 public static Object get(Object key, Locale l) {
973 return getDefaults().get(key,l);
974 }
975
976 /**
977 * Stores an object in the developer defaults. This is a cover method
978 * for {@code getDefaults().put(key, value)}. This only effects the
979 * developer defaults, not the system or look and feel defaults.
980 *
981 * @param key an {@code Object} specifying the retrieval key
982 * @param value the {@code Object} to store; refer to
983 * {@code UIDefaults} for details on how {@code null} is
984 * handled
985 * @return the {@code Object} returned by {@link UIDefaults#put}
986 * @throws NullPointerException if {@code key} is {@code null}
987 * @see UIDefaults#put
988 */
989 public static Object put(Object key, Object value) {
990 return getDefaults().put(key, value);
991 }
992
993 /**
994 * Returns the appropriate {@code ComponentUI} implementation for
995 * {@code target}. Typically, this is a cover for
996 * {@code getDefaults().getUI(target)}. However, if an auxiliary
997 * look and feel has been installed, this first invokes
998 * {@code getUI(target)} on the multiplexing look and feel's
999 * defaults, and returns that value if it is {@code non-null}.
1000 *
1001 * @param target the {@code JComponent} to return the
1002 * {@code ComponentUI} for
1003 * @return the {@code ComponentUI} object for {@code target}
1004 * @throws NullPointerException if {@code target} is {@code null}
1005 * @see UIDefaults#getUI
1006 */
1007 public static ComponentUI getUI(JComponent target) {
1008 maybeInitialize();
1009 maybeInitializeFocusPolicy(target);
1010 ComponentUI ui = null;
1011 LookAndFeel multiLAF = getLAFState().multiLookAndFeel;
1012 if (multiLAF != null) {
1013 // This can return null if the multiplexing look and feel
1014 // doesn't support a particular UI.
1015 ui = multiLAF.getDefaults().getUI(target);
1016 }
1017 if (ui == null) {
1018 ui = getDefaults().getUI(target);
1019 }
1020 return ui;
1021 }
1022
1023
1024 /**
1025 * Returns the {@code UIDefaults} from the current look and feel,
1026 * that were obtained at the time the look and feel was installed.
1027 * <p>
1028 * In general, developers should use the {@code UIDefaults} returned from
1029 * {@code getDefaults()}. As the current look and feel may expect
1030 * certain values to exist, altering the {@code UIDefaults} returned
1031 * from this method could have unexpected results.
1032 *
1033 * @return {@code UIDefaults} from the current look and feel
1034 * @see #getDefaults
1035 * @see #setLookAndFeel(LookAndFeel)
1036 * @see LookAndFeel#getDefaults
1037 */
1038 public static UIDefaults getLookAndFeelDefaults() {
1039 maybeInitialize();
1040 return getLAFState().getLookAndFeelDefaults();
1041 }
1042
1043 /**
1044 * Finds the Multiplexing {@code LookAndFeel}.
1045 */
1046 private static LookAndFeel getMultiLookAndFeel() {
1047 LookAndFeel multiLookAndFeel = getLAFState().multiLookAndFeel;
1048 if (multiLookAndFeel == null) {
1049 String defaultName = "javax.swing.plaf.multi.MultiLookAndFeel";
1050 String className = getLAFState().swingProps.getProperty(multiplexingLAFKey, defaultName);
1051 try {
1052 Class<?> lnfClass = SwingUtilities.loadSystemClass(className);
1053 multiLookAndFeel = (LookAndFeel)lnfClass.newInstance();
1054 } catch (Exception exc) {
1055 System.err.println("UIManager: failed loading " + className);
1056 }
1057 }
1058 return multiLookAndFeel;
1059 }
1060
1061 /**
1062 * Adds a {@code LookAndFeel} to the list of auxiliary look and feels.
1063 * The auxiliary look and feels tell the multiplexing look and feel what
1064 * other {@code LookAndFeel} classes for a component instance are to be used
1065 * in addition to the default {@code LookAndFeel} class when creating a
1066 * multiplexing UI. The change will only take effect when a new
1067 * UI class is created or when the default look and feel is changed
1068 * on a component instance.
1069 * <p>Note these are not the same as the installed look and feels.
1070 *
1071 * @param laf the {@code LookAndFeel} object
1072 * @see #removeAuxiliaryLookAndFeel
1073 * @see #setLookAndFeel
1074 * @see #getAuxiliaryLookAndFeels
1075 * @see #getInstalledLookAndFeels
1076 */
1077 public static void addAuxiliaryLookAndFeel(LookAndFeel laf) {
1078 maybeInitialize();
1079
1080 if (!laf.isSupportedLookAndFeel()) {
1081 // Ideally we would throw an exception here, but it's too late
1082 // for that.
1083 return;
1084 }
1085 Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
1086 if (v == null) {
1087 v = new Vector<LookAndFeel>();
1088 }
1089
1090 if (!v.contains(laf)) {
1091 v.addElement(laf);
1092 laf.initialize();
1093 getLAFState().auxLookAndFeels = v;
1094
1095 if (getLAFState().multiLookAndFeel == null) {
1096 getLAFState().multiLookAndFeel = getMultiLookAndFeel();
1097 }
1098 }
1099 }
1100
1101 /**
1102 * Removes a {@code LookAndFeel} from the list of auxiliary look and feels.
1103 * The auxiliary look and feels tell the multiplexing look and feel what
1104 * other {@code LookAndFeel} classes for a component instance are to be used
1105 * in addition to the default {@code LookAndFeel} class when creating a
1106 * multiplexing UI. The change will only take effect when a new
1107 * UI class is created or when the default look and feel is changed
1108 * on a component instance.
1109 * <p>Note these are not the same as the installed look and feels.
1110 *
1111 * @param laf the {@code LookAndFeel} to be removed
1112 * @return true if the {@code LookAndFeel} was removed from the list
1113 * @see #removeAuxiliaryLookAndFeel
1114 * @see #getAuxiliaryLookAndFeels
1115 * @see #setLookAndFeel
1116 * @see #getInstalledLookAndFeels
1117 */
1118 public static boolean removeAuxiliaryLookAndFeel(LookAndFeel laf) {
1119 maybeInitialize();
1120
1121 boolean result;
1122
1123 Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
1124 if ((v == null) || (v.size() == 0)) {
1125 return false;
1126 }
1127
1128 result = v.removeElement(laf);
1129 if (result) {
1130 if (v.size() == 0) {
1131 getLAFState().auxLookAndFeels = null;
1132 getLAFState().multiLookAndFeel = null;
1133 } else {
1134 getLAFState().auxLookAndFeels = v;
1135 }
1136 }
1137 laf.uninitialize();
1138
1139 return result;
1140 }
1141
1142 /**
1143 * Returns the list of auxiliary look and feels (can be {@code null}).
1144 * The auxiliary look and feels tell the multiplexing look and feel what
1145 * other {@code LookAndFeel} classes for a component instance are
1146 * to be used in addition to the default LookAndFeel class when creating a
1147 * multiplexing UI.
1148 * <p>Note these are not the same as the installed look and feels.
1149 *
1150 * @return list of auxiliary {@code LookAndFeel}s or {@code null}
1151 * @see #addAuxiliaryLookAndFeel
1152 * @see #removeAuxiliaryLookAndFeel
1153 * @see #setLookAndFeel
1154 * @see #getInstalledLookAndFeels
1155 */
1156 public static LookAndFeel[] getAuxiliaryLookAndFeels() {
1157 maybeInitialize();
1158
1159 Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
1160 if ((v == null) || (v.size() == 0)) {
1161 return null;
1162 }
1163 else {
1164 LookAndFeel[] rv = new LookAndFeel[v.size()];
1165 for (int i = 0; i < rv.length; i++) {
1166 rv[i] = v.elementAt(i);
1167 }
1168 return rv;
1169 }
1170 }
1171
1172
1173 /**
1174 * Adds a {@code PropertyChangeListener} to the listener list.
1175 * The listener is registered for all properties.
1176 *
1177 * @param listener the {@code PropertyChangeListener} to be added
1178 * @see java.beans.PropertyChangeSupport
1179 */
1180 public static void addPropertyChangeListener(PropertyChangeListener listener)
1181 {
1182 synchronized (classLock) {
1183 getLAFState().getPropertyChangeSupport(true).
1184 addPropertyChangeListener(listener);
1185 }
1186 }
1187
1188
1189 /**
1190 * Removes a {@code PropertyChangeListener} from the listener list.
1191 * This removes a {@code PropertyChangeListener} that was registered
1192 * for all properties.
1193 *
1194 * @param listener the {@code PropertyChangeListener} to be removed
1195 * @see java.beans.PropertyChangeSupport
1196 */
1197 public static void removePropertyChangeListener(PropertyChangeListener listener)
1198 {
1199 synchronized (classLock) {
1200 getLAFState().getPropertyChangeSupport(true).
1201 removePropertyChangeListener(listener);
1202 }
1203 }
1204
1205
1206 /**
1207 * Returns an array of all the {@code PropertyChangeListener}s added
1208 * to this UIManager with addPropertyChangeListener().
1209 *
1210 * @return all of the {@code PropertyChangeListener}s added or an empty
1211 * array if no listeners have been added
1212 * @since 1.4
1213 */
1214 public static PropertyChangeListener[] getPropertyChangeListeners() {
1215 synchronized(classLock) {
1216 return getLAFState().getPropertyChangeSupport(true).
1217 getPropertyChangeListeners();
1218 }
1219 }
1220
1221 private static Properties loadSwingProperties()
1222 {
1223 /* Don't bother checking for Swing properties if untrusted, as
1224 * there's no way to look them up without triggering SecurityExceptions.
1225 */
1226 if (UIManager.class.getClassLoader() != null) {
1227 return new Properties();
1228 }
1229 else {
1230 final Properties props = new Properties();
1261 checkProperty(props, disableMnemonicKey);
1262 // Don't care about return value.
1263 return null;
1264 }
1265 });
1266 return props;
1267 }
1268 }
1269
1270 private static void checkProperty(Properties props, String key) {
1271 // No need to do catch the SecurityException here, this runs
1272 // in a doPrivileged.
1273 String value = System.getProperty(key);
1274 if (value != null) {
1275 props.put(key, value);
1276 }
1277 }
1278
1279
1280 /**
1281 * If a {@code swing.properties} file exist and it has a
1282 * {@code swing.installedlafs} property
1283 * then initialize the {@code installedLAFs} field.
1284 *
1285 * @see #getInstalledLookAndFeels
1286 */
1287 private static void initializeInstalledLAFs(Properties swingProps)
1288 {
1289 String ilafsString = swingProps.getProperty(installedLAFsKey);
1290 if (ilafsString == null) {
1291 return;
1292 }
1293
1294 /* Create a vector that contains the value of the swing.installedlafs
1295 * property. For example given "swing.installedlafs=motif,windows"
1296 * lafs = {"motif", "windows"}.
1297 */
1298 Vector<String> lafs = new Vector<String>();
1299 StringTokenizer st = new StringTokenizer(ilafsString, ",", false);
1300 while (st.hasMoreTokens()) {
1301 lafs.addElement(st.nextToken());
1302 }
1303
1402 auxLookAndFeels = null;
1403 }
1404 else {
1405 getLAFState().multiLookAndFeel = getMultiLookAndFeel();
1406 if (getLAFState().multiLookAndFeel == null) {
1407 auxLookAndFeels = null;
1408 }
1409 }
1410
1411 getLAFState().auxLookAndFeels = auxLookAndFeels;
1412 }
1413
1414
1415 private static void initializeSystemDefaults(Properties swingProps) {
1416 getLAFState().swingProps = swingProps;
1417 }
1418
1419
1420 /*
1421 * This method is called before any code that depends on the
1422 * {@code AppContext} specific LAFState object runs. When the AppContext
1423 * corresponds to a set of applets it's possible for this method
1424 * to be re-entered, which is why we grab a lock before calling
1425 * initialize().
1426 */
1427 private static void maybeInitialize() {
1428 synchronized (classLock) {
1429 if (!getLAFState().initialized) {
1430 getLAFState().initialized = true;
1431 initialize();
1432 }
1433 }
1434 }
1435
1436 /*
1437 * Sets default swing focus traversal policy.
1438 */
1439 @SuppressWarnings("deprecation")
1440 private static void maybeInitializeFocusPolicy(JComponent comp) {
1441 // Check for JRootPane which indicates that a swing toplevel
1442 // is coming, in which case a swing default focus policy
|