1. /*
  2. * @(#)UIManager.java 1.115 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.Component;
  9. import java.awt.Container;
  10. import java.awt.Window;
  11. import java.awt.Font;
  12. import java.awt.Color;
  13. import java.awt.Insets;
  14. import java.awt.Dimension;
  15. import java.awt.KeyboardFocusManager;
  16. import java.awt.KeyEventPostProcessor;
  17. import java.awt.Toolkit;
  18. import java.awt.event.KeyEvent;
  19. import java.security.AccessController;
  20. import javax.swing.plaf.ComponentUI;
  21. import javax.swing.border.Border;
  22. import javax.swing.event.SwingPropertyChangeSupport;
  23. import java.beans.PropertyChangeListener;
  24. import java.beans.PropertyChangeEvent;
  25. import java.io.FileOutputStream;
  26. import java.io.IOException;
  27. import java.io.ObjectOutputStream;
  28. import java.io.ObjectInputStream;
  29. import java.io.Serializable;
  30. import java.io.File;
  31. import java.io.FileInputStream;
  32. import java.io.BufferedInputStream;
  33. import java.util.ArrayList;
  34. import java.util.Enumeration;
  35. import java.util.Hashtable;
  36. import java.util.Properties;
  37. import java.util.StringTokenizer;
  38. import java.util.Vector;
  39. import java.util.Locale;
  40. import sun.security.action.GetPropertyAction;
  41. /**
  42. * This class keeps track of the current look and feel and its
  43. * defaults.
  44. * The default look and feel class is chosen in the following manner:
  45. * <ol>
  46. * <li>If the system property <code>swing.defaultlaf</code> is
  47. * non-null, use it as the default look and feel class name.
  48. * <li>If the {@link java.util.Properties} file <code>swing.properties</code>
  49. * exists and contains the key <code>swing.defaultlaf</code>,
  50. * use its value as default look and feel class name. The location of
  51. * <code>swing.properties</code> may vary depending upon the
  52. * implementation of the Java platform. In Sun's implementation
  53. * this will reside in
  54. * <code>&java.home>/lib/swing.properties</code>. Refer to
  55. * the release notes of the implementation you are using for
  56. * further details.
  57. * <li>Otherwise use the Java look and feel.
  58. * </ol>
  59. * <p>
  60. * We manage three levels of defaults: user defaults, look
  61. * and feel defaults, system defaults. A call to <code>UIManager.get</code>
  62. * checks all three levels in order and returns the first non-<code>null</code>
  63. * value for a key, if any. A call to <code>UIManager.put</code> just
  64. * affects the user defaults. Note that a call to
  65. * <code>setLookAndFeel</code> doesn't affect the user defaults, it just
  66. * replaces the middle defaults "level".
  67. * <p>
  68. * <strong>Warning:</strong>
  69. * Serialized objects of this class will not be compatible with
  70. * future Swing releases. The current serialization support is
  71. * appropriate for short term storage or RMI between applications running
  72. * the same version of Swing. As of 1.4, support for long term storage
  73. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  74. * has been added to the <code>java.beans</code> package.
  75. * Please see {@link java.beans.XMLEncoder}.
  76. *
  77. * @see javax.swing.plaf.metal
  78. *
  79. * @version 1.115 12/19/03
  80. * @author Thomas Ball
  81. * @author Hans Muller
  82. */
  83. public class UIManager implements Serializable
  84. {
  85. /**
  86. * This class defines the state managed by the <code>UIManager</code>. For
  87. * Swing applications the fields in this class could just as well
  88. * be static members of <code>UIManager</code> however we give them
  89. * "AppContext"
  90. * scope instead so that applets (and potentially multiple lightweight
  91. * applications running in a single VM) have their own state. For example,
  92. * an applet can alter its look and feel, see <code>setLookAndFeel</code>.
  93. * Doing so has no affect on other applets (or the browser).
  94. */
  95. private static class LAFState
  96. {
  97. Properties swingProps;
  98. private UIDefaults[] tables = new UIDefaults[2];
  99. boolean initialized = false;
  100. MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables);
  101. LookAndFeel lookAndFeel;
  102. LookAndFeel multiLookAndFeel = null;
  103. Vector auxLookAndFeels = null;
  104. SwingPropertyChangeSupport changeSupport;
  105. UIDefaults getLookAndFeelDefaults() { return tables[0]; }
  106. void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; }
  107. UIDefaults getSystemDefaults() { return tables[1]; }
  108. void setSystemDefaults(UIDefaults x) { tables[1] = x; }
  109. /**
  110. * Returns the SwingPropertyChangeSupport for the current
  111. * AppContext. If <code>create</code> is a true, a non-null
  112. * <code>SwingPropertyChangeSupport</code> will be returned, if
  113. * <code>create</code> is false and this has not been invoked
  114. * with true, null will be returned.
  115. */
  116. public synchronized SwingPropertyChangeSupport
  117. getPropertyChangeSupport(boolean create) {
  118. if (create && changeSupport == null) {
  119. changeSupport = new SwingPropertyChangeSupport(
  120. UIManager.class);
  121. }
  122. return changeSupport;
  123. }
  124. }
  125. /**
  126. * The <code>AppContext</code> key for our one <code>LAFState</code> instance.
  127. */
  128. private static final Object lafStateACKey = new StringBuffer("LookAndFeel State");
  129. /* Lock object used in place of class object for synchronization. (4187686)
  130. */
  131. private static final Object classLock = new Object();
  132. /* Cache the last referenced LAFState to improve performance
  133. * when accessing it. The cache is based on last thread rather
  134. * than last AppContext because of the cost of looking up the
  135. * AppContext each time. Since most Swing UI work is on the
  136. * EventDispatchThread, this hits often enough to justify the
  137. * overhead. (4193032)
  138. */
  139. private static Thread currentLAFStateThread = null;
  140. private static LAFState currentLAFState = null;
  141. /**
  142. * Return the <code>LAFState</code> object, lazily create one if necessary.
  143. * All access to the <code>LAFState</code> fields is done via this method,
  144. * for example:
  145. * <pre>
  146. * getLAFState().initialized = true;
  147. * </pre>
  148. */
  149. private static LAFState getLAFState() {
  150. // First check whether we're running on the same thread as
  151. // the last request.
  152. Thread thisThread = Thread.currentThread();
  153. if (thisThread == currentLAFStateThread) {
  154. return currentLAFState;
  155. }
  156. LAFState rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey);
  157. if (rv == null) {
  158. synchronized (classLock) {
  159. rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey);
  160. if (rv == null) {
  161. SwingUtilities.appContextPut(lafStateACKey,
  162. (rv = new LAFState()));
  163. }
  164. }
  165. }
  166. currentLAFStateThread = thisThread;
  167. currentLAFState = rv;
  168. return rv;
  169. }
  170. /* Keys used for the properties file in <java.home>/lib/swing.properties.
  171. * See loadUserProperties(), initialize().
  172. */
  173. private static final String defaultLAFKey = "swing.defaultlaf";
  174. private static final String auxiliaryLAFsKey = "swing.auxiliarylaf";
  175. private static final String multiplexingLAFKey = "swing.plaf.multiplexinglaf";
  176. private static final String installedLAFsKey = "swing.installedlafs";
  177. private static final String disableMnemonicKey = "swing.disablenavaids";
  178. /**
  179. * Return a swing.properties file key for the attribute of specified
  180. * look and feel. The attr is either "name" or "class", a typical
  181. * key would be: "swing.installedlaf.windows.name"
  182. */
  183. private static String makeInstalledLAFKey(String laf, String attr) {
  184. return "swing.installedlaf." + laf + "." + attr;
  185. }
  186. /**
  187. * The filename for swing.properties is a path like this (Unix version):
  188. * <java.home>/lib/swing.properties. This method returns a bogus
  189. * filename if java.home isn't defined.
  190. */
  191. private static String makeSwingPropertiesFilename() {
  192. String sep = File.separator;
  193. // No need to wrap this in a doPrivileged as it's called from
  194. // a doPrivileged.
  195. String javaHome = System.getProperty("java.home");
  196. if (javaHome == null) {
  197. javaHome = "<java.home undefined>";
  198. }
  199. return javaHome + sep + "lib" + sep + "swing.properties";
  200. }
  201. /**
  202. * Provides a little information about an installed
  203. * <code>LookAndFeel</code> for the sake of configuring a menu or
  204. * for initial application set up.
  205. *
  206. * @see UIManager#getInstalledLookAndFeels
  207. * @see LookAndFeel
  208. */
  209. public static class LookAndFeelInfo {
  210. private String name;
  211. private String className;
  212. /**
  213. * Constructs a <code>UIManager</code>s
  214. * <code>LookAndFeelInfo</code> object.
  215. *
  216. * @param name a <code>String</code> specifying the name of
  217. * the look and feel
  218. * @param className a <code>String</code> specifiying the name of
  219. * the class that implements the look and feel
  220. */
  221. public LookAndFeelInfo(String name, String className) {
  222. this.name = name;
  223. this.className = className;
  224. }
  225. /**
  226. * Returns the name of the look and feel in a form suitable
  227. * for a menu or other presentation
  228. * @return a <code>String</code> containing the name
  229. * @see LookAndFeel#getName
  230. */
  231. public String getName() {
  232. return name;
  233. }
  234. /**
  235. * Returns the name of the class that implements this look and feel.
  236. * @return the name of the class that implements this
  237. * <code>LookAndFeel</code>
  238. * @see LookAndFeel
  239. */
  240. public String getClassName() {
  241. return className;
  242. }
  243. /**
  244. * Returns a string that displays and identifies this
  245. * object's properties.
  246. *
  247. * @return a <code>String</code> representation of this object
  248. */
  249. public String toString() {
  250. return getClass().getName() + "[" + getName() + " " + getClassName() + "]";
  251. }
  252. }
  253. /**
  254. * The default value of <code>installedLAFS</code> is used when no
  255. * swing.properties
  256. * file is available or if the file doesn't contain a "swing.installedlafs"
  257. * property.
  258. *
  259. * @see #initializeInstalledLAFs
  260. */
  261. private static LookAndFeelInfo[] installedLAFs;
  262. static {
  263. ArrayList iLAFs = new ArrayList(4);
  264. iLAFs.add(new LookAndFeelInfo(
  265. "Metal", "javax.swing.plaf.metal.MetalLookAndFeel"));
  266. iLAFs.add(new LookAndFeelInfo("CDE/Motif",
  267. "com.sun.java.swing.plaf.motif.MotifLookAndFeel"));
  268. // Only include windows on Windows boxs.
  269. String osName = (String)AccessController.doPrivileged(
  270. new GetPropertyAction("os.name"));
  271. if (osName != null && osName.indexOf("Windows") != -1) {
  272. iLAFs.add(new LookAndFeelInfo("Windows",
  273. "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"));
  274. if (Toolkit.getDefaultToolkit().getDesktopProperty(
  275. "win.xpstyle.themeActive") != null) {
  276. iLAFs.add(new LookAndFeelInfo("Windows Classic",
  277. "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel"));
  278. }
  279. }
  280. else {
  281. // GTK is not shipped on Windows.
  282. iLAFs.add(new LookAndFeelInfo("GTK+",
  283. "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"));
  284. }
  285. installedLAFs = (LookAndFeelInfo[])iLAFs.toArray(
  286. new LookAndFeelInfo[iLAFs.size()]);
  287. }
  288. /**
  289. * Returns an array of objects that provide some information about the
  290. * <code>LookAndFeel</code> implementations that have been installed with this
  291. * software development kit. The <code>LookAndFeel</code> info objects can
  292. * used by an application to construct a menu of look and feel options for
  293. * the user or to set the look and feel at start up time. Note that
  294. * we do not return the <code>LookAndFeel</code> classes themselves here to
  295. * avoid the cost of unnecessarily loading them.
  296. * <p>
  297. * Given a <code>LookAndFeelInfo</code> object one can set the current
  298. * look and feel like this:
  299. * <pre>
  300. * UIManager.setLookAndFeel(info.getClassName());
  301. * </pre>
  302. * @return an array of <code>LookAndFeelInfo</code> objects
  303. *
  304. * @see #setLookAndFeel
  305. */
  306. public static LookAndFeelInfo[] getInstalledLookAndFeels() {
  307. maybeInitialize();
  308. LookAndFeelInfo[] ilafs = installedLAFs;
  309. LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length];
  310. System.arraycopy(ilafs, 0, rv, 0, ilafs.length);
  311. return rv;
  312. }
  313. /**
  314. * Replaces the current array of installed <code>LookAndFeelInfos</code>.
  315. * @param infos new array of <code>LookAndFeelInfo</code> objects
  316. *
  317. * @see #getInstalledLookAndFeels
  318. */
  319. public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos)
  320. throws SecurityException
  321. {
  322. LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length];
  323. System.arraycopy(infos, 0, newInfos, 0, infos.length);
  324. installedLAFs = newInfos;
  325. }
  326. /**
  327. * Adds the specified look and feel to the current array and
  328. * then calls {@link #setInstalledLookAndFeels}.
  329. * @param info a <code>LookAndFeelInfo</code> object that names the
  330. * look and feel and identifies that class that implements it
  331. */
  332. public static void installLookAndFeel(LookAndFeelInfo info) {
  333. LookAndFeelInfo[] infos = getInstalledLookAndFeels();
  334. LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length + 1];
  335. System.arraycopy(infos, 0, newInfos, 0, infos.length);
  336. newInfos[infos.length] = info;
  337. setInstalledLookAndFeels(newInfos);
  338. }
  339. /**
  340. * Creates a new look and feel and adds it to the current array.
  341. * Then calls {@link #setInstalledLookAndFeels}.
  342. *
  343. * @param name a <code>String</code> specifying the name of the
  344. * look and feel
  345. * @param className a <code>String</code> specifying the class name
  346. * that implements the look and feel
  347. */
  348. public static void installLookAndFeel(String name, String className) {
  349. installLookAndFeel(new LookAndFeelInfo(name, className));
  350. }
  351. /**
  352. * Returns the current default look and feel or <code>null</code>.
  353. *
  354. * @return the current default look and feel, or <code>null</code>
  355. * @see #setLookAndFeel
  356. */
  357. public static LookAndFeel getLookAndFeel() {
  358. maybeInitialize();
  359. return getLAFState().lookAndFeel;
  360. }
  361. /**
  362. * Sets the current default look and feel using a
  363. * <code>LookAndFeel</code> object.
  364. * <p>
  365. * This is a JavaBeans bound property.
  366. *
  367. * @param newLookAndFeel the <code>LookAndFeel</code> object
  368. * @exception UnsupportedLookAndFeelException if
  369. * <code>lnf.isSupportedLookAndFeel()</code> is false
  370. * @see #getLookAndFeel
  371. */
  372. public static void setLookAndFeel(LookAndFeel newLookAndFeel)
  373. throws UnsupportedLookAndFeelException
  374. {
  375. if ((newLookAndFeel != null) && !newLookAndFeel.isSupportedLookAndFeel()) {
  376. String s = newLookAndFeel.toString() + " not supported on this platform";
  377. throw new UnsupportedLookAndFeelException(s);
  378. }
  379. LAFState lafState = getLAFState();
  380. LookAndFeel oldLookAndFeel = lafState.lookAndFeel;
  381. if (oldLookAndFeel != null) {
  382. oldLookAndFeel.uninitialize();
  383. }
  384. lafState.lookAndFeel = newLookAndFeel;
  385. if (newLookAndFeel != null) {
  386. sun.swing.DefaultLookup.setDefaultLookup(null);
  387. newLookAndFeel.initialize();
  388. lafState.setLookAndFeelDefaults(newLookAndFeel.getDefaults());
  389. }
  390. else {
  391. lafState.setLookAndFeelDefaults(null);
  392. }
  393. SwingPropertyChangeSupport changeSupport = lafState.
  394. getPropertyChangeSupport(false);
  395. if (changeSupport != null) {
  396. changeSupport.firePropertyChange("lookAndFeel", oldLookAndFeel,
  397. newLookAndFeel);
  398. }
  399. }
  400. /**
  401. * Sets the current default look and feel using a class name.
  402. *
  403. * @param className a string specifying the name of the class that implements
  404. * the look and feel
  405. * @exception ClassNotFoundException if the <code>LookAndFeel</code>
  406. * class could not be found
  407. * @exception InstantiationException if a new instance of the class
  408. * couldn't be created
  409. * @exception IllegalAccessException if the class or initializer isn't accessible
  410. * @exception UnsupportedLookAndFeelException if
  411. * <code>lnf.isSupportedLookAndFeel()</code> is false
  412. */
  413. public static void setLookAndFeel(String className)
  414. throws ClassNotFoundException,
  415. InstantiationException,
  416. IllegalAccessException,
  417. UnsupportedLookAndFeelException
  418. {
  419. if ("javax.swing.plaf.metal.MetalLookAndFeel".equals(className)) {
  420. // Avoid reflection for the common case of metal.
  421. setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
  422. }
  423. else {
  424. Class lnfClass = SwingUtilities.loadSystemClass(className);
  425. setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
  426. }
  427. }
  428. /**
  429. * Returns the name of the <code>LookAndFeel</code> class that implements
  430. * the native systems look and feel if there is one, otherwise
  431. * the name of the default cross platform <code>LookAndFeel</code>
  432. * class. If the system property <code>swing.systemlaf</code> has been
  433. * defined, its value will be returned.
  434. *
  435. * @return the <code>String</code> of the <code>LookAndFeel</code>
  436. * class
  437. *
  438. * @see #setLookAndFeel
  439. * @see #getCrossPlatformLookAndFeelClassName
  440. */
  441. public static String getSystemLookAndFeelClassName() {
  442. String systemLAF = (String)AccessController.doPrivileged(
  443. new GetPropertyAction("swing.systemlaf"));
  444. if (systemLAF != null) {
  445. return systemLAF;
  446. }
  447. String osName = (String)AccessController.doPrivileged(
  448. new GetPropertyAction("os.name"));
  449. if (osName != null) {
  450. if (osName.indexOf("Windows") != -1) {
  451. return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
  452. }
  453. else {
  454. String desktop = (String)AccessController.doPrivileged(
  455. new GetPropertyAction("sun.desktop"));
  456. if ("gnome".equals(desktop)) {
  457. // May be set on Linux and Solaris boxs.
  458. return "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
  459. }
  460. if ((osName.indexOf("Solaris") != -1) ||
  461. (osName.indexOf("SunOS") != -1)) {
  462. return "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
  463. }
  464. }
  465. }
  466. return getCrossPlatformLookAndFeelClassName();
  467. }
  468. /**
  469. * Returns the name of the <code>LookAndFeel</code> class that implements
  470. * the default cross platform look and feel -- the Java
  471. * Look and Feel (JLF). If the system property
  472. * <code>swing.crossplatformlaf</code> has been
  473. * defined, its value will be returned.
  474. *
  475. * @return a string with the JLF implementation-class
  476. * @see #setLookAndFeel
  477. * @see #getSystemLookAndFeelClassName
  478. */
  479. public static String getCrossPlatformLookAndFeelClassName() {
  480. String laf = (String)AccessController.doPrivileged(
  481. new GetPropertyAction("swing.crossplatformlaf"));
  482. if (laf != null) {
  483. return laf;
  484. }
  485. return "javax.swing.plaf.metal.MetalLookAndFeel";
  486. }
  487. /**
  488. * Returns the default values for this look and feel.
  489. *
  490. * @return a <code>UIDefaults</code> object containing the default values
  491. */
  492. public static UIDefaults getDefaults() {
  493. maybeInitialize();
  494. return getLAFState().multiUIDefaults;
  495. }
  496. /**
  497. * Returns a drawing font from the defaults table.
  498. *
  499. * @param key an <code>Object</code> specifying the font
  500. * @return the <code>Font</code> object
  501. */
  502. public static Font getFont(Object key) {
  503. return getDefaults().getFont(key);
  504. }
  505. /**
  506. * Returns a drawing font from the defaults table that is appropriate
  507. * for the given locale.
  508. *
  509. * @param key an <code>Object</code> specifying the font
  510. * @param l the <code>Locale</code> for which the font is desired
  511. * @return the <code>Font</code> object
  512. * @since 1.4
  513. */
  514. public static Font getFont(Object key, Locale l) {
  515. return getDefaults().getFont(key,l);
  516. }
  517. /**
  518. * Returns a drawing color from the defaults table.
  519. *
  520. * @param key an <code>Object</code> specifying the color
  521. * @return the <code>Color</code> object
  522. */
  523. public static Color getColor(Object key) {
  524. return getDefaults().getColor(key);
  525. }
  526. /**
  527. * Returns a drawing color from the defaults table that is appropriate
  528. * for the given locale.
  529. *
  530. * @param key an <code>Object</code> specifying the color
  531. * @param l the <code>Locale</code> for which the color is desired
  532. * @return the <code>Color</code> object
  533. * @since 1.4
  534. */
  535. public static Color getColor(Object key, Locale l) {
  536. return getDefaults().getColor(key,l);
  537. }
  538. /**
  539. * Returns an <code>Icon</code> from the defaults table.
  540. *
  541. * @param key an <code>Object</code> specifying the icon
  542. * @return the <code>Icon</code> object
  543. */
  544. public static Icon getIcon(Object key) {
  545. return getDefaults().getIcon(key);
  546. }
  547. /**
  548. * Returns an <code>Icon</code> from the defaults table that is appropriate
  549. * for the given locale.
  550. *
  551. * @param key an <code>Object</code> specifying the icon
  552. * @param l the <code>Locale</code> for which the icon is desired
  553. * @return the <code>Icon</code> object
  554. * @since 1.4
  555. */
  556. public static Icon getIcon(Object key, Locale l) {
  557. return getDefaults().getIcon(key,l);
  558. }
  559. /**
  560. * Returns a border from the defaults table.
  561. *
  562. * @param key an <code>Object</code> specifying the border
  563. * @return the <code>Border</code> object
  564. */
  565. public static Border getBorder(Object key) {
  566. return getDefaults().getBorder(key);
  567. }
  568. /**
  569. * Returns a border from the defaults table that is appropriate
  570. * for the given locale.
  571. *
  572. * @param key an <code>Object</code> specifying the border
  573. * @param l the <code>Locale</code> for which the border is desired
  574. * @return the <code>Border</code> object
  575. * @since 1.4
  576. */
  577. public static Border getBorder(Object key, Locale l) {
  578. return getDefaults().getBorder(key,l);
  579. }
  580. /**
  581. * Returns a string from the defaults table.
  582. *
  583. * @param key an <code>Object</code> specifying the string
  584. * @return the <code>String</code>
  585. */
  586. public static String getString(Object key) {
  587. return getDefaults().getString(key);
  588. }
  589. /**
  590. * Returns a string from the defaults table that is appropriate for the
  591. * given locale.
  592. *
  593. * @param key an <code>Object</code> specifying the string
  594. * @param l the <code>Locale</code> for which the string is desired
  595. * @return the <code>String</code>
  596. */
  597. public static String getString(Object key, Locale l) {
  598. return getDefaults().getString(key,l);
  599. }
  600. /**
  601. * Returns a string from the defaults table that is appropriate for the
  602. * given locale.
  603. *
  604. * @param key an <code>Object</code> specifying the string
  605. * @param c Component used to determine Locale, null implies use the
  606. * default Locale.
  607. * @return the <code>String</code>
  608. */
  609. static String getString(Object key, Component c) {
  610. Locale l = (c == null) ? Locale.getDefault() : c.getLocale();
  611. return getString(key, l);
  612. }
  613. /**
  614. * Returns an integer from the defaults table.
  615. *
  616. * @param key an <code>Object</code> specifying the int
  617. * @return the int
  618. */
  619. public static int getInt(Object key) {
  620. return getDefaults().getInt(key);
  621. }
  622. /**
  623. * Returns an integer from the defaults table that is appropriate
  624. * for the given locale.
  625. *
  626. * @param key an <code>Object</code> specifying the int
  627. * @param l the <code>Locale</code> for which the int is desired
  628. * @return the int
  629. * @since 1.4
  630. */
  631. public static int getInt(Object key, Locale l) {
  632. return getDefaults().getInt(key,l);
  633. }
  634. /**
  635. * Returns an integer from the defaults table. If <code>key</code> does
  636. * not map to a valid <code>Integer</code>, or can not be convered from
  637. * a <code>String</code> to an integer, <code>default</code> is
  638. * returned.
  639. *
  640. * @param key an <code>Object</code> specifying the int
  641. * @param defaultValue Returned value if <code>key</code> is not available,
  642. * or is not an Integer
  643. * @return the int
  644. */
  645. static int getInt(Object key, int defaultValue) {
  646. Object value = UIManager.get(key);
  647. if (value instanceof Integer) {
  648. return ((Integer)value).intValue();
  649. }
  650. if (value instanceof String) {
  651. try {
  652. return Integer.parseInt((String)value);
  653. } catch (NumberFormatException nfe) {}
  654. }
  655. return defaultValue;
  656. }
  657. /**
  658. * Returns a boolean from the defaults table which is associated with
  659. * the key value. If the key is not found or the key doesn't represent
  660. * a boolean value then false will be returned.
  661. *
  662. * @param key an <code>Object</code> specifying the key for the desired boolean value
  663. * @return the boolean value corresponding to the key
  664. * @since 1.4
  665. */
  666. public static boolean getBoolean(Object key) {
  667. return getDefaults().getBoolean(key);
  668. }
  669. /**
  670. * Returns a boolean from the defaults table which is associated with
  671. * the key value and the given <code>Locale</code>. If the key is not
  672. * found or the key doesn't represent
  673. * a boolean value then false will be returned.
  674. *
  675. * @param key an <code>Object</code> specifying the key for the desired
  676. * boolean value
  677. * @param l the <code>Locale</code> for which the boolean is desired
  678. * @return the boolean value corresponding to the key
  679. * @since 1.4
  680. */
  681. public static boolean getBoolean(Object key, Locale l) {
  682. return getDefaults().getBoolean(key,l);
  683. }
  684. /**
  685. * Returns an <code>Insets</code> object from the defaults table.
  686. *
  687. * @param key an <code>Object</code> specifying the <code>Insets</code> object
  688. * @return the <code>Insets</code> object
  689. */
  690. public static Insets getInsets(Object key) {
  691. return getDefaults().getInsets(key);
  692. }
  693. /**
  694. * Returns an <code>Insets</code> object from the defaults table that is
  695. * appropriate for the given locale.
  696. *
  697. * @param key an <code>Object</code> specifying the <code>Insets</code> object
  698. * @param l the <code>Locale</code> for which the object is desired
  699. * @return the <code>Insets</code> object
  700. * @since 1.4
  701. */
  702. public static Insets getInsets(Object key, Locale l) {
  703. return getDefaults().getInsets(key,l);
  704. }
  705. /**
  706. * Returns a dimension from the defaults table.
  707. *
  708. * @param key an <code>Object</code> specifying the dimension object
  709. * @return the <code>Dimension</code> object
  710. */
  711. public static Dimension getDimension(Object key) {
  712. return getDefaults().getDimension(key);
  713. }
  714. /**
  715. * Returns a dimension from the defaults table that is appropriate
  716. * for the given locale.
  717. *
  718. * @param key an <code>Object</code> specifying the dimension object
  719. * @param l the <code>Locale</code> for which the object is desired
  720. * @return the <code>Dimension</code> object
  721. * @since 1.4
  722. */
  723. public static Dimension getDimension(Object key, Locale l) {
  724. return getDefaults().getDimension(key,l);
  725. }
  726. /**
  727. * Returns an object from the defaults table.
  728. *
  729. * @param key an <code>Object</code> specifying the desired object
  730. * @return the <code>Object</code>
  731. */
  732. public static Object get(Object key) {
  733. return getDefaults().get(key);
  734. }
  735. /**
  736. * Returns an object from the defaults table that is appropriate for
  737. * the given locale.
  738. *
  739. * @param key an <code>Object</code> specifying the desired object
  740. * @param l the <code>Locale</code> for which the object is desired
  741. * @return the <code>Object</code>
  742. */
  743. public static Object get(Object key, Locale l) {
  744. return getDefaults().get(key,l);
  745. }
  746. /**
  747. * Stores an object in the defaults table.
  748. *
  749. * @param key an <code>Object</code> specifying the retrieval key
  750. * @param value the <code>Object</code> to store
  751. * @return the <code>Object</code> returned by {@link UIDefaults#put}
  752. */
  753. public static Object put(Object key, Object value) {
  754. return getDefaults().put(key, value);
  755. }
  756. /**
  757. * Returns the L&F object that renders the target component.
  758. *
  759. * @param target the <code>JComponent</code> to render
  760. * @return the <code>ComponentUI</code> object that renders the target component
  761. */
  762. public static ComponentUI getUI(JComponent target) {
  763. maybeInitialize();
  764. ComponentUI ui = null;
  765. LookAndFeel multiLAF = getLAFState().multiLookAndFeel;
  766. if (multiLAF != null) {
  767. // This can return null if the multiplexing look and feel
  768. // doesn't support a particular UI.
  769. ui = multiLAF.getDefaults().getUI(target);
  770. }
  771. if (ui == null) {
  772. ui = getDefaults().getUI(target);
  773. }
  774. return ui;
  775. }
  776. /**
  777. * Returns the default values for this look and feel.
  778. *
  779. * @return an <code>UIDefaults</code> object containing the default values
  780. */
  781. public static UIDefaults getLookAndFeelDefaults() {
  782. maybeInitialize();
  783. return getLAFState().getLookAndFeelDefaults();
  784. }
  785. /**
  786. * Finds the Multiplexing <code>LookAndFeel</code>.
  787. */
  788. private static LookAndFeel getMultiLookAndFeel() {
  789. LookAndFeel multiLookAndFeel = getLAFState().multiLookAndFeel;
  790. if (multiLookAndFeel == null) {
  791. String defaultName = "javax.swing.plaf.multi.MultiLookAndFeel";
  792. String className = getLAFState().swingProps.getProperty(multiplexingLAFKey, defaultName);
  793. try {
  794. Class lnfClass = SwingUtilities.loadSystemClass(className);
  795. multiLookAndFeel = (LookAndFeel)lnfClass.newInstance();
  796. } catch (Exception exc) {
  797. System.err.println("UIManager: failed loading " + className);
  798. }
  799. }
  800. return multiLookAndFeel;
  801. }
  802. /**
  803. * Adds a <code>LookAndFeel</code> to the list of auxiliary look and feels.
  804. * The auxiliary look and feels tell the multiplexing look and feel what
  805. * other <code>LookAndFeel</code> classes for a component instance are to be used
  806. * in addition to the default <code>LookAndFeel</code> class when creating a
  807. * multiplexing UI. The change will only take effect when a new
  808. * UI class is created or when the default look and feel is changed
  809. * on a component instance.
  810. * <p>Note these are not the same as the installed look and feels.
  811. *
  812. * @param laf the <code>LookAndFeel</code> object
  813. * @see #removeAuxiliaryLookAndFeel
  814. * @see #setLookAndFeel
  815. * @see #getAuxiliaryLookAndFeels
  816. * @see #getInstalledLookAndFeels
  817. */
  818. static public void addAuxiliaryLookAndFeel(LookAndFeel laf) {
  819. maybeInitialize();
  820. if (!laf.isSupportedLookAndFeel()) {
  821. // Ideally we would throw an exception here, but it's too late
  822. // for that.
  823. return;
  824. }
  825. Vector v = getLAFState().auxLookAndFeels;
  826. if (v == null) {
  827. v = new Vector();
  828. }
  829. if (!v.contains(laf)) {
  830. v.addElement(laf);
  831. laf.initialize();
  832. getLAFState().auxLookAndFeels = v;
  833. if (getLAFState().multiLookAndFeel == null) {
  834. getLAFState().multiLookAndFeel = getMultiLookAndFeel();
  835. }
  836. }
  837. }
  838. /**
  839. * Removes a <code>LookAndFeel</code> from the list of auxiliary look and feels.
  840. * The auxiliary look and feels tell the multiplexing look and feel what
  841. * other <code>LookAndFeel</code> classes for a component instance are to be used
  842. * in addition to the default <code>LookAndFeel</code> class when creating a
  843. * multiplexing UI. The change will only take effect when a new
  844. * UI class is created or when the default look and feel is changed
  845. * on a component instance.
  846. * <p>Note these are not the same as the installed look and feels.
  847. * @return true if the <code>LookAndFeel</code> was removed from the list
  848. * @see #removeAuxiliaryLookAndFeel
  849. * @see #getAuxiliaryLookAndFeels
  850. * @see #setLookAndFeel
  851. * @see #getInstalledLookAndFeels
  852. */
  853. static public boolean removeAuxiliaryLookAndFeel(LookAndFeel laf) {
  854. maybeInitialize();
  855. boolean result;
  856. Vector v = getLAFState().auxLookAndFeels;
  857. if ((v == null) || (v.size() == 0)) {
  858. return false;
  859. }
  860. result = v.removeElement(laf);
  861. if (result) {
  862. if (v.size() == 0) {
  863. getLAFState().auxLookAndFeels = null;
  864. getLAFState().multiLookAndFeel = null;
  865. } else {
  866. getLAFState().auxLookAndFeels = v;
  867. }
  868. }
  869. laf.uninitialize();
  870. return result;
  871. }
  872. /**
  873. * Returns the list of auxiliary look and feels (can be <code>null</code>).
  874. * The auxiliary look and feels tell the multiplexing look and feel what
  875. * other <code>LookAndFeel</code> classes for a component instance are
  876. * to be used in addition to the default LookAndFeel class when creating a
  877. * multiplexing UI.
  878. * <p>Note these are not the same as the installed look and feels.
  879. *
  880. * @return list of auxiliary <code>LookAndFeel</code>s or <code>null</code>
  881. * @see #addAuxiliaryLookAndFeel
  882. * @see #removeAuxiliaryLookAndFeel
  883. * @see #setLookAndFeel
  884. * @see #getInstalledLookAndFeels
  885. */
  886. static public LookAndFeel[] getAuxiliaryLookAndFeels() {
  887. maybeInitialize();
  888. Vector v = getLAFState().auxLookAndFeels;
  889. if ((v == null) || (v.size() == 0)) {
  890. return null;
  891. }
  892. else {
  893. LookAndFeel[] rv = new LookAndFeel[v.size()];
  894. for (int i = 0; i < rv.length; i++) {
  895. rv[i] = (LookAndFeel)v.elementAt(i);
  896. }
  897. return rv;
  898. }
  899. }
  900. /**
  901. * Adds a <code>PropertyChangeListener</code> to the listener list.
  902. * The listener is registered for all properties.
  903. *
  904. * @param listener the <code>PropertyChangeListener</code> to be added
  905. * @see java.beans.PropertyChangeSupport
  906. */
  907. public static void addPropertyChangeListener(PropertyChangeListener listener)
  908. {
  909. synchronized (classLock) {
  910. getLAFState().getPropertyChangeSupport(true).
  911. addPropertyChangeListener(listener);
  912. }
  913. }
  914. /**
  915. * Removes a <code>PropertyChangeListener</code> from the listener list.
  916. * This removes a <code>PropertyChangeListener</code> that was registered
  917. * for all properties.
  918. *
  919. * @param listener the <code>PropertyChangeListener</code> to be removed
  920. * @see java.beans.PropertyChangeSupport
  921. */
  922. public static void removePropertyChangeListener(PropertyChangeListener listener)
  923. {
  924. synchronized (classLock) {
  925. getLAFState().getPropertyChangeSupport(true).
  926. removePropertyChangeListener(listener);
  927. }
  928. }
  929. /**
  930. * Returns an array of all the <code>PropertyChangeListener</code>s added
  931. * to this UIManager with addPropertyChangeListener().
  932. *
  933. * @return all of the <code>PropertyChangeListener</code>s added or an empty
  934. * array if no listeners have been added
  935. * @since 1.4
  936. */
  937. public static PropertyChangeListener[] getPropertyChangeListeners() {
  938. synchronized(classLock) {
  939. return getLAFState().getPropertyChangeSupport(true).
  940. getPropertyChangeListeners();
  941. }
  942. }
  943. private static Properties loadSwingProperties()
  944. {
  945. /* Don't bother checking for Swing properties if untrusted, as
  946. * there's no way to look them up without triggering SecurityExceptions.
  947. */
  948. if (UIManager.class.getClassLoader() != null) {
  949. return new Properties();
  950. }
  951. else {
  952. final Properties props = new Properties();
  953. java.security.AccessController.doPrivileged(
  954. new java.security.PrivilegedAction() {
  955. public Object run() {
  956. try {
  957. File file = new File(makeSwingPropertiesFilename());
  958. if (file.exists()) {
  959. // InputStream has been buffered in Properties
  960. // class
  961. FileInputStream ins = new FileInputStream(file);
  962. props.load(ins);
  963. ins.close();
  964. }
  965. }
  966. catch (Exception e) {
  967. // No such file, or file is otherwise non-readable.
  968. }
  969. // Check whether any properties were overridden at the
  970. // command line.
  971. checkProperty(props, defaultLAFKey);
  972. checkProperty(props, auxiliaryLAFsKey);
  973. checkProperty(props, multiplexingLAFKey);
  974. checkProperty(props, installedLAFsKey);
  975. checkProperty(props, disableMnemonicKey);
  976. // Don't care about return value.
  977. return null;
  978. }
  979. });
  980. return props;
  981. }
  982. }
  983. private static void checkProperty(Properties props, String key) {
  984. // No need to do catch the SecurityException here, this runs
  985. // in a doPrivileged.
  986. String value = System.getProperty(key);
  987. if (value != null) {
  988. props.put(key, value);
  989. }
  990. }
  991. /**
  992. * If a swing.properties file exist and it has a swing.installedlafs property
  993. * then initialize the <code>installedLAFs</code> field.
  994. *
  995. * @see #getInstalledLookAndFeels
  996. */
  997. private static void initializeInstalledLAFs(Properties swingProps)
  998. {
  999. String ilafsString = swingProps.getProperty(installedLAFsKey);
  1000. if (ilafsString == null) {
  1001. return;
  1002. }
  1003. /* Create a vector that contains the value of the swing.installedlafs
  1004. * property. For example given "swing.installedlafs=motif,windows"
  1005. * lafs = {"motif", "windows"}.
  1006. */
  1007. Vector lafs = new Vector();
  1008. StringTokenizer st = new StringTokenizer(ilafsString, ",", false);
  1009. while (st.hasMoreTokens()) {
  1010. lafs.addElement(st.nextToken());
  1011. }
  1012. /* Look up the name and class for each name in the "swing.installedlafs"
  1013. * list. If they both exist then add a LookAndFeelInfo to
  1014. * the installedLafs array.
  1015. */
  1016. Vector ilafs = new Vector(lafs.size());
  1017. for(int i = 0; i < lafs.size(); i++) {
  1018. String laf = (String)lafs.elementAt(i);
  1019. String name = swingProps.getProperty(makeInstalledLAFKey(laf, "name"), laf);
  1020. String cls = swingProps.getProperty(makeInstalledLAFKey(laf, "class"));
  1021. if (cls != null) {
  1022. ilafs.addElement(new LookAndFeelInfo(name, cls));
  1023. }
  1024. }
  1025. installedLAFs = new LookAndFeelInfo[ilafs.size()];
  1026. for(int i = 0; i < ilafs.size(); i++) {
  1027. installedLAFs[i] = (LookAndFeelInfo)(ilafs.elementAt(i));
  1028. }
  1029. }
  1030. /**
  1031. * If the user has specified a default look and feel, use that.
  1032. * Otherwise use the look and feel that's native to this platform.
  1033. * If this code is called after the application has explicitly
  1034. * set it's look and feel, do nothing.
  1035. *
  1036. * @see #maybeInitialize
  1037. */
  1038. private static void initializeDefaultLAF(Properties swingProps)
  1039. {
  1040. if (getLAFState().lookAndFeel != null) {
  1041. return;
  1042. }
  1043. String metalLnf = getCrossPlatformLookAndFeelClassName();
  1044. String lnfDefault = metalLnf;
  1045. String lnfName = "<undefined>" ;
  1046. try {
  1047. lnfName = swingProps.getProperty(defaultLAFKey, lnfDefault);
  1048. setLookAndFeel(lnfName);
  1049. } catch (Exception e) {
  1050. try {
  1051. lnfName = swingProps.getProperty(defaultLAFKey, metalLnf);
  1052. setLookAndFeel(lnfName);
  1053. } catch (Exception e2) {
  1054. throw new Error("can't load " + lnfName);
  1055. }
  1056. }
  1057. }
  1058. private static void initializeAuxiliaryLAFs(Properties swingProps)
  1059. {
  1060. String auxLookAndFeelNames = swingProps.getProperty(auxiliaryLAFsKey);
  1061. if (auxLookAndFeelNames == null) {
  1062. return;
  1063. }
  1064. Vector auxLookAndFeels = new Vector();
  1065. StringTokenizer p = new StringTokenizer(auxLookAndFeelNames,",");
  1066. String factoryName;
  1067. /* Try to load each LookAndFeel subclass in the list.
  1068. */
  1069. while (p.hasMoreTokens()) {
  1070. String className = p.nextToken();
  1071. try {
  1072. Class lnfClass = SwingUtilities.loadSystemClass(className);
  1073. LookAndFeel newLAF = (LookAndFeel)lnfClass.newInstance();
  1074. newLAF.initialize();
  1075. auxLookAndFeels.addElement(newLAF);
  1076. }
  1077. catch (Exception e) {
  1078. System.err.println("UIManager: failed loading auxiliary look and feel " + className);
  1079. }
  1080. }
  1081. /* If there were problems and no auxiliary look and feels were
  1082. * loaded, make sure we reset auxLookAndFeels to null.
  1083. * Otherwise, we are going to use the MultiLookAndFeel to get
  1084. * all component UI's, so we need to load it now.
  1085. */
  1086. if (auxLookAndFeels.size() == 0) {
  1087. auxLookAndFeels = null;
  1088. }
  1089. else {
  1090. getLAFState().multiLookAndFeel = getMultiLookAndFeel();
  1091. if (getLAFState().multiLookAndFeel == null) {
  1092. auxLookAndFeels = null;
  1093. }
  1094. }
  1095. getLAFState().auxLookAndFeels = auxLookAndFeels;
  1096. }
  1097. private static void initializeSystemDefaults(Properties swingProps) {
  1098. getLAFState().swingProps = swingProps;
  1099. }
  1100. /*
  1101. * This method is called before any code that depends on the
  1102. * <code>AppContext</code> specific LAFState object runs. When the AppContext
  1103. * corresponds to a set of applets it's possible for this method
  1104. * to be re-entered, which is why we grab a lock before calling
  1105. * initialize().
  1106. */
  1107. private static void maybeInitialize() {
  1108. synchronized (classLock) {
  1109. if (!getLAFState().initialized) {
  1110. getLAFState().initialized = true;
  1111. initialize();
  1112. }
  1113. }
  1114. }
  1115. /*
  1116. * Only called by maybeInitialize().
  1117. */
  1118. private static void initialize() {
  1119. Properties swingProps = loadSwingProperties();
  1120. initializeSystemDefaults(swingProps);
  1121. initializeDefaultLAF(swingProps);
  1122. initializeAuxiliaryLAFs(swingProps);
  1123. initializeInstalledLAFs(swingProps);
  1124. // Enable the Swing default LayoutManager.
  1125. String toolkitName = Toolkit.getDefaultToolkit().getClass().getName();
  1126. // don't set default policy if this is XAWT.
  1127. if (!"sun.awt.X11.XToolkit".equals(toolkitName)) {
  1128. if (FocusManager.isFocusManagerEnabled()) {
  1129. KeyboardFocusManager.getCurrentKeyboardFocusManager().
  1130. setDefaultFocusTraversalPolicy(
  1131. new LayoutFocusTraversalPolicy());
  1132. }
  1133. }
  1134. // Install a hook that will be invoked if no one consumes the
  1135. // KeyEvent. If the source isn't a JComponent this will process
  1136. // key bindings, if the source is a JComponent it implies that
  1137. // processKeyEvent was already invoked and thus no need to process
  1138. // the bindings again, unless the Component is disabled, in which
  1139. // case KeyEvents will no longer be dispatched to it so that we
  1140. // handle it here.
  1141. KeyboardFocusManager.getCurrentKeyboardFocusManager().
  1142. addKeyEventPostProcessor(new KeyEventPostProcessor() {
  1143. public boolean postProcessKeyEvent(KeyEvent e) {
  1144. Component c = e.getComponent();
  1145. if ((!(c instanceof JComponent) ||
  1146. (c != null && !((JComponent)c).isEnabled())) &&
  1147. JComponent.KeyboardState.shouldProcess(e) &&
  1148. SwingUtilities.processKeyBindings(e)) {
  1149. e.consume();
  1150. return true;
  1151. }
  1152. return false;
  1153. }
  1154. });
  1155. }
  1156. }