1. /*
  2. * @(#)UIManager.java 1.75 01/11/29
  3. *
  4. * Copyright 2002 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.Container;
  9. import java.awt.Window;
  10. import java.awt.Font;
  11. import java.awt.Color;
  12. import java.awt.Insets;
  13. import java.awt.Dimension;
  14. import javax.swing.plaf.ComponentUI;
  15. import javax.swing.border.Border;
  16. import javax.swing.event.SwingPropertyChangeSupport;
  17. import java.beans.PropertyChangeListener;
  18. import java.beans.PropertyChangeEvent;
  19. import java.io.FileOutputStream;
  20. import java.io.IOException;
  21. import java.io.ObjectOutputStream;
  22. import java.io.ObjectInputStream;
  23. import java.io.Serializable;
  24. import java.io.File;
  25. import java.io.FileInputStream;
  26. import java.io.BufferedInputStream;
  27. import java.util.Enumeration;
  28. import java.util.Hashtable;
  29. import java.util.Properties;
  30. import java.util.StringTokenizer;
  31. import java.util.Vector;
  32. /**
  33. * This class keeps track of the current look and feel and its
  34. * defaults.
  35. * <p>
  36. * We manage three levels of defaults: user defaults, look
  37. * and feel defaults, system defaults. A call to UIManager.get()
  38. * checks all three levels in order and returns the first non-null
  39. * value for a key, if any. A call to UIManager.put() just
  40. * affects the user defaults. Note that a call to
  41. * setLookAndFeel() doesn't affect the user defaults, it just
  42. * replaces the middle defaults "level".
  43. * <p>
  44. * <strong>Warning:</strong>
  45. * Serialized objects of this class will not be compatible with
  46. * future Swing releases. The current serialization support is appropriate
  47. * for short term storage or RMI between applications running the same
  48. * version of Swing. A future release of Swing will provide support for
  49. * long term persistence.
  50. *
  51. * @version 1.75 11/29/01
  52. * @author Thomas Ball
  53. * @author Hans Muller
  54. */
  55. public class UIManager implements Serializable
  56. {
  57. /**
  58. * This class defines the state managed by the UIManager. For
  59. * Swing applications the fields in this class could just as well
  60. * be static members of UIManager however we give them "AppContext"
  61. * scope instead so that applets (and potentially multiple lightweight
  62. * applications running in a single VM) have their own state. For
  63. * example an applet can it's look and feel, see setLookAndFeel().
  64. * Doing so has no affect on other applets (or the browser).
  65. */
  66. private static class LAFState
  67. {
  68. Properties swingProps;
  69. private UIDefaults[] tables = new UIDefaults[2];
  70. boolean initialized = false;
  71. MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables);
  72. LookAndFeel lookAndFeel;
  73. LookAndFeel multiLookAndFeel = null;
  74. Vector auxLookAndFeels = null;
  75. SwingPropertyChangeSupport changeSupport =
  76. new SwingPropertyChangeSupport(UIManager.class);
  77. UIDefaults getLookAndFeelDefaults() { return tables[0]; }
  78. void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; }
  79. UIDefaults getSystemDefaults() { return tables[1]; }
  80. void setSystemDefaults(UIDefaults x) { tables[1] = x; }
  81. }
  82. /**
  83. * The AppContext key for our one LAFState instance.
  84. */
  85. private static final Object lafStateACKey = new StringBuffer("LookAndFeel State");
  86. /* Lock object used in place of class object for synchronization.
  87. * (4187686)
  88. */
  89. private static final Object classLock = new Object();
  90. /* Cache the last referenced LAFState to improve performance
  91. * when accessing it. The cache is based on last thread rather
  92. * than last AppContext because of the cost of looking up the
  93. * AppContext each time. Since most Swing UI work is on the
  94. * EventDispatchThread, this hits often enough to justify the
  95. * overhead. (4193032)
  96. */
  97. private static Thread currentLAFStateThread = null;
  98. private static LAFState currentLAFState = null;
  99. /**
  100. * Return the LAFState object, lazily create one if neccessary. All access
  101. * to the LAFState fields is done via this method, e.g.:
  102. * <pre>
  103. * getLAFState().initialized = true;
  104. * </pre>
  105. */
  106. private static LAFState getLAFState() {
  107. // First check whether we're running on the same thread as
  108. // the last request.
  109. Thread thisThread = Thread.currentThread();
  110. if (thisThread == currentLAFStateThread) {
  111. return currentLAFState;
  112. }
  113. LAFState rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey);
  114. if (rv == null) {
  115. synchronized (classLock) {
  116. rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey);
  117. if (rv == null) {
  118. SwingUtilities.appContextPut(lafStateACKey,
  119. (rv = new LAFState()));
  120. }
  121. }
  122. }
  123. currentLAFStateThread = thisThread;
  124. currentLAFState = rv;
  125. return rv;
  126. }
  127. /* Keys used for the properties file in <java.home>/lib/swing.properties.
  128. * See loadUserProperties(), initialize().
  129. */
  130. private static final String defaultLAFKey = "swing.defaultlaf";
  131. private static final String auxiliaryLAFsKey = "swing.auxiliarylaf";
  132. private static final String multiplexingLAFKey = "swing.plaf.multiplexinglaf";
  133. private static final String installedLAFsKey = "swing.installedlafs";
  134. /**
  135. * Return a swing.properties file key for the attribute of specified
  136. * look and feel. The attr is either "name" or "class", a typical
  137. * key would be: "swing.installedlaf.windows.name"
  138. */
  139. private static String makeInstalledLAFKey(String laf, String attr) {
  140. return "swing.installedlaf." + laf + "." + attr;
  141. }
  142. /**
  143. * The filename for swing.properties is a path like this (Unix version):
  144. * <java.home>/lib/swing.properties. This method returns a bogus
  145. * filename if java.home isn't defined.
  146. */
  147. private static String makeSwingPropertiesFilename() {
  148. final String homeDir[] = new String[]{"<java.home undefined>"};
  149. SwingUtilities.doPrivileged(new Runnable() {
  150. public void run() {
  151. homeDir[0] = System.getProperty("java.home", "<java.home undefined>");
  152. }
  153. });
  154. String sep = File.separator;
  155. return homeDir[0] + sep + "lib" + sep + "swing.properties";
  156. }
  157. /**
  158. * Provide a little information about an installed LookAndFeel
  159. * for the sake of configuring a menu or for initial application
  160. * set up.
  161. *
  162. * @see UIManager#getInstalledLookAndFeels
  163. * @see LookAndFeel
  164. */
  165. public static class LookAndFeelInfo {
  166. private String name;
  167. private String className;
  168. /**
  169. * Constructs an UIManager$LookAndFeelInfo object.
  170. *
  171. * @param name a String specifying the name of the look and feel
  172. * @param className a String specifiying the name of the class that
  173. * implements the look and feel
  174. */
  175. public LookAndFeelInfo(String name, String className) {
  176. this.name = name;
  177. this.className = className;
  178. }
  179. /**
  180. * Returns the name of the look and feel in a form suitable
  181. * for a menu or other presentation
  182. * @return a String containing the name
  183. * @see LookAndFeel#getName
  184. */
  185. public String getName() {
  186. return name;
  187. }
  188. /**
  189. * Returns the name of the class that implements this look and feel.
  190. * @return the name of the class that implements this LookAndFeel
  191. * @see LookAndFeel
  192. */
  193. public String getClassName() {
  194. return className;
  195. }
  196. /**
  197. * Returns a string that displays and identifies this
  198. * object's properties.
  199. *
  200. * @return a String representation of this object
  201. */
  202. public String toString() {
  203. return getClass().getName() + "[" + getName() + " " + getClassName() + "]";
  204. }
  205. }
  206. /**
  207. * The default value of installedLAFS is used when no swing.properties
  208. * file is available or if the file doesn't contain a "swing.installedlafs"
  209. * property.
  210. *
  211. * @see #initializeInstalledLAFs
  212. */
  213. private static LookAndFeelInfo[] installedLAFs = {
  214. new LookAndFeelInfo("Metal", "javax.swing.plaf.metal.MetalLookAndFeel"),
  215. new LookAndFeelInfo("CDE/Motif", "com.sun.java.swing.plaf.motif.MotifLookAndFeel"),
  216. new LookAndFeelInfo("Windows", "com.sun.java.swing.plaf.windows.WindowsLookAndFeel")
  217. };
  218. /**
  219. * Return an array of objects that provide some information about the
  220. * LookAndFeel implementations that have been installed with this
  221. * java development kit. The LookAndFeel info objects can be used
  222. * by an application to construct a menu of look and feel options for
  223. * the user or to set the look and feel at start up time. Note that
  224. * we do not return the LookAndFeel classes themselves here to avoid the
  225. * cost of unnecessarily loading them.
  226. * <p>
  227. * Given a LookAndFeelInfo object one can set the current look and feel
  228. * like this:
  229. * <pre>
  230. * UIManager.setLookAndFeel(info.getClassName());
  231. * </pre>
  232. *
  233. * @see #setLookAndFeel
  234. */
  235. public static LookAndFeelInfo[] getInstalledLookAndFeels() {
  236. maybeInitialize();
  237. LookAndFeelInfo[] ilafs = installedLAFs;
  238. LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length];
  239. System.arraycopy(ilafs, 0, rv, 0, ilafs.length);
  240. return rv;
  241. }
  242. /**
  243. * Replaces the current array of installed LookAndFeelInfos.
  244. *
  245. * @see #getInstalledLookAndFeels
  246. */
  247. public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos)
  248. throws SecurityException
  249. {
  250. LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length];
  251. System.arraycopy(infos, 0, newInfos, 0, infos.length);
  252. installedLAFs = newInfos;
  253. }
  254. /**
  255. * Adds the specified look and feel to the current array and
  256. * then calls {@link #setInstalledLookAndFeels}.
  257. * @param info a LookAndFeelInfo object that names the look and feel
  258. * and identifies that class that implements it
  259. */
  260. public static void installLookAndFeel(LookAndFeelInfo info) {
  261. LookAndFeelInfo[] infos = getInstalledLookAndFeels();
  262. LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length + 1];
  263. System.arraycopy(infos, 0, newInfos, 0, infos.length);
  264. newInfos[infos.length] = info;
  265. setInstalledLookAndFeels(newInfos);
  266. }
  267. /**
  268. * Creates a new look and feel and adds it to the current array.
  269. * Then calls {@link #setInstalledLookAndFeels}.
  270. *
  271. * @param name a String specifying the name of the look and feel
  272. * @param className a String specifying the class name that implements the
  273. * look and feel
  274. */
  275. public static void installLookAndFeel(String name, String className) {
  276. installLookAndFeel(new LookAndFeelInfo(name, className));
  277. }
  278. /**
  279. * Returns The current default look and feel, or null.
  280. *
  281. * @return The current default look and feel, or null.
  282. * @see #setLookAndFeel
  283. */
  284. public static LookAndFeel getLookAndFeel() {
  285. maybeInitialize();
  286. return getLAFState().lookAndFeel;
  287. }
  288. /**
  289. * Set the current default look and feel using a LookAndFeel object.
  290. * <p>
  291. * This is a JavaBeans bound property.
  292. *
  293. * @param newLookAndFeel the LookAndFeel object
  294. * @exception UnsupportedLookAndFeelException If <code>lnf.isSupportedLookAndFeel()</code> is false.
  295. * @see #getLookAndFeel
  296. */
  297. public static void setLookAndFeel(LookAndFeel newLookAndFeel)
  298. throws UnsupportedLookAndFeelException
  299. {
  300. if ((newLookAndFeel != null) && !newLookAndFeel.isSupportedLookAndFeel()) {
  301. String s = newLookAndFeel.toString() + " not supported on this platform";
  302. throw new UnsupportedLookAndFeelException(s);
  303. }
  304. LookAndFeel oldLookAndFeel = getLAFState().lookAndFeel;
  305. if (oldLookAndFeel != null) {
  306. oldLookAndFeel.uninitialize();
  307. }
  308. getLAFState().lookAndFeel = newLookAndFeel;
  309. if (newLookAndFeel != null) {
  310. newLookAndFeel.initialize();
  311. getLAFState().setLookAndFeelDefaults(newLookAndFeel.getDefaults());
  312. }
  313. else {
  314. getLAFState().setLookAndFeelDefaults(null);
  315. }
  316. getLAFState().changeSupport.firePropertyChange("lookAndFeel", oldLookAndFeel, newLookAndFeel);
  317. }
  318. /**
  319. * Set the current default look and feel using a class name.
  320. *
  321. * @param className a string specifying the name of the class that implements
  322. * the look and feel
  323. * @exception ClassNotFoundException If the LookAndFeel class could not be found.
  324. * @exception InstantiationException If a new instance of the class couldn't be creatd.
  325. * @exception IllegalAccessException If the class or initializer isn't accessible.
  326. * @exception UnsupportedLookAndFeelException If <code>lnf.isSupportedLookAndFeel()</code> is false.
  327. */
  328. public static void setLookAndFeel(String className)
  329. throws ClassNotFoundException,
  330. InstantiationException,
  331. IllegalAccessException,
  332. UnsupportedLookAndFeelException
  333. {
  334. Class lnfClass = SwingUtilities.loadSystemClass(className);
  335. setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
  336. }
  337. /**
  338. * Returns the name of the LookAndFeel class that implements
  339. * the native systems look and feel if there is one,
  340. * otherwise the name of the default cross platform LookAndFeel
  341. * class.
  342. *
  343. * @see #setLookAndFeel
  344. * @see #getCrossPlatformLookAndFeelClassName
  345. */
  346. public static String getSystemLookAndFeelClassName() {
  347. final String osName[] = new String[]{""};
  348. SwingUtilities.doPrivileged(new Runnable() {
  349. public void run() {
  350. osName[0] = System.getProperty("os.name");
  351. }
  352. });
  353. if (osName[0] != null) {
  354. if (osName[0].indexOf("Windows") != -1) {
  355. return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
  356. }
  357. else if ((osName[0].indexOf("Solaris") != -1) ||
  358. (osName[0].indexOf("SunOS") != -1)) {
  359. return "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
  360. }
  361. else if (osName[0].indexOf("Mac") != -1 ) {
  362. return "com.sun.java.swing.plaf.mac.MacLookAndFeel";
  363. }
  364. }
  365. return getCrossPlatformLookAndFeelClassName();
  366. }
  367. /**
  368. * Returns the name of the LookAndFeel class that implements
  369. * the default cross platform look and feel, i.e. the "Java
  370. * Look and Feel", or JLF.
  371. *
  372. * @return a string with the JLF implementation-class
  373. * @see #setLookAndFeel
  374. * @see #getSystemLookAndFeelClassName
  375. */
  376. public static String getCrossPlatformLookAndFeelClassName() {
  377. return "javax.swing.plaf.metal.MetalLookAndFeel";
  378. }
  379. /**
  380. * Returns the default values for this look and feel.
  381. *
  382. * @return an UIDefaults object containing the default values
  383. */
  384. public static UIDefaults getDefaults() {
  385. maybeInitialize();
  386. return getLAFState().multiUIDefaults;
  387. }
  388. /**
  389. * Returns a drawing font from the defaults table.
  390. *
  391. * @param key an Object specifying the font
  392. * @return the Font object
  393. */
  394. public static Font getFont(Object key) {
  395. return getDefaults().getFont(key);
  396. }
  397. /**
  398. * Returns a drawing color from the defaults table.
  399. *
  400. * @param key an Object specifying the color
  401. * @return the Color object
  402. */
  403. public static Color getColor(Object key) {
  404. return getDefaults().getColor(key);
  405. }
  406. /**
  407. * Returns an Icon from the defaults table.
  408. *
  409. * @param key an Object specifying the icon
  410. * @return the Icon object
  411. */
  412. public static Icon getIcon(Object key) {
  413. return getDefaults().getIcon(key);
  414. }
  415. /**
  416. * Returns a border from the defaults table.
  417. *
  418. * @param key an Object specifying the border
  419. * @return the Border object
  420. */
  421. public static Border getBorder(Object key) {
  422. return getDefaults().getBorder(key);
  423. }
  424. /**
  425. * Returns a string from the defaults table.
  426. *
  427. * @param key an Object specifying the string
  428. * @return the String
  429. */
  430. public static String getString(Object key) {
  431. return getDefaults().getString(key);
  432. }
  433. /**
  434. * Returns an int from the defaults table.
  435. *
  436. * @param key an Object specifying the int
  437. * @return the int
  438. */
  439. public static int getInt(Object key) {
  440. return getDefaults().getInt(key);
  441. }
  442. /**
  443. * Returns an Insets object from the defaults table.
  444. *
  445. * @param key an Object specifying the Insets object
  446. * @return the Insets object
  447. */
  448. public static Insets getInsets(Object key) {
  449. return getDefaults().getInsets(key);
  450. }
  451. /**
  452. * Returns a dimension from the defaults table.
  453. *
  454. * @param key an Object specifying the dimension object
  455. * @return the Dimension object
  456. */
  457. public static Dimension getDimension(Object key) {
  458. return getDefaults().getDimension(key);
  459. }
  460. /**
  461. * Returns an object from the defaults table.
  462. *
  463. * @param key an Object specifying the desired object
  464. * @return the Object
  465. */
  466. public static Object get(Object key) {
  467. return getDefaults().get(key);
  468. }
  469. /**
  470. * Stores an object in the defaults table.
  471. *
  472. * @param key an Object specifying the retrieval key
  473. * @param value the Object to store
  474. * @return the Object returned by {@link UIDefaults.put}
  475. */
  476. public static Object put(Object key, Object value) {
  477. return getDefaults().put(key, value);
  478. }
  479. /**
  480. * Returns the L&F object that renders the target component.
  481. *
  482. * @param target the JComponent to render
  483. * @return the ComponentUI object that renders the target component
  484. */
  485. public static ComponentUI getUI(JComponent target) {
  486. maybeInitialize();
  487. ComponentUI ui = null;
  488. LookAndFeel multiLAF = getLAFState().multiLookAndFeel;
  489. if (multiLAF != null) {
  490. // This can return null if the multiplexing look and feel
  491. // doesn't support a particular UI.
  492. ui = multiLAF.getDefaults().getUI(target);
  493. }
  494. if (ui == null) {
  495. ui = getDefaults().getUI(target);
  496. }
  497. return ui;
  498. }
  499. /**
  500. * Returns the default values for this look and feel.
  501. *
  502. * @return an UIDefaults object containing the default values
  503. */
  504. public static UIDefaults getLookAndFeelDefaults() {
  505. maybeInitialize();
  506. return getLAFState().getLookAndFeelDefaults();
  507. }
  508. /**
  509. * Find the Multiplexing LookAndFeel.
  510. */
  511. private static LookAndFeel getMultiLookAndFeel() {
  512. LookAndFeel multiLookAndFeel = getLAFState().multiLookAndFeel;
  513. if (multiLookAndFeel == null) {
  514. String defaultName = "javax.swing.plaf.multi.MultiLookAndFeel";
  515. String className = getLAFState().swingProps.getProperty(multiplexingLAFKey, defaultName);
  516. try {
  517. Class lnfClass = SwingUtilities.loadSystemClass(className);
  518. multiLookAndFeel = (LookAndFeel)lnfClass.newInstance();
  519. } catch (Exception exc) {
  520. System.err.println("UIManager: failed loading " + className);
  521. }
  522. }
  523. return multiLookAndFeel;
  524. }
  525. /**
  526. * Add a LookAndFeel to the list of auxiliary look and feels. The
  527. * auxiliary look and feels tell the multiplexing look and feel what
  528. * other LookAndFeel classes for a component instance are to be used
  529. * in addition to the default LookAndFeel class when creating a
  530. * multiplexing UI. The change will only take effect when a new
  531. * UI class is created or when the default look and feel is changed
  532. * on a component instance.
  533. * <p>Note these are not the same as the installed look and feels.
  534. *
  535. * @param laf the LookAndFeel object
  536. * @see #removeAuxiliaryLookAndFeel
  537. * @see #setLookAndFeel
  538. * @see #getAuxiliaryLookAndFeels
  539. * @see #getInstalledLookAndFeels
  540. */
  541. static public void addAuxiliaryLookAndFeel(LookAndFeel laf)
  542. {
  543. maybeInitialize();
  544. Vector v = getLAFState().auxLookAndFeels;
  545. if (v == null) {
  546. v = new Vector();
  547. }
  548. if (!v.contains(laf)) {
  549. v.addElement(laf);
  550. laf.initialize();
  551. getLAFState().auxLookAndFeels = v;
  552. if (getLAFState().multiLookAndFeel == null) {
  553. getLAFState().multiLookAndFeel = getMultiLookAndFeel();
  554. }
  555. }
  556. }
  557. /**
  558. * Remove a LookAndFeel from the list of auxiliary look and feels. The
  559. * auxiliary look and feels tell the multiplexing look and feel what
  560. * other LookAndFeel classes for a component instance are to be used
  561. * in addition to the default LookAndFeel class when creating a
  562. * multiplexing UI. The change will only take effect when a new
  563. * UI class is created or when the default look and feel is changed
  564. * on a component instance.
  565. * <p>Note these are not the same as the installed look and feels.
  566. * @return true if the LookAndFeel was removed from the list
  567. * @see #removeAuxiliaryLookAndFeel
  568. * @see #getAuxiliaryLookAndFeels
  569. * @see #setLookAndFeel
  570. * @see #getInstalledLookAndFeels
  571. */
  572. static public boolean removeAuxiliaryLookAndFeel(LookAndFeel laf)
  573. {
  574. maybeInitialize();
  575. boolean result;
  576. Vector v = getLAFState().auxLookAndFeels;
  577. if ((v == null) || (v.size() == 0)) {
  578. return false;
  579. }
  580. result = v.removeElement(laf);
  581. if (result) {
  582. if (v.size() == 0) {
  583. getLAFState().auxLookAndFeels = null;
  584. getLAFState().multiLookAndFeel = null;
  585. } else {
  586. getLAFState().auxLookAndFeels = v;
  587. }
  588. }
  589. laf.uninitialize();
  590. return result;
  591. }
  592. /**
  593. * Return the list of auxiliary look and feels (can be null). The
  594. * auxiliary look and feels tell the multiplexing look and feel what
  595. * other LookAndFeel classes for a component instance are to be used
  596. * in addition to the default LookAndFeel class when creating a
  597. * multiplexing UI.
  598. * <p>Note these are not the same as the installed look and feels.
  599. * @see #addAuxiliaryLookAndFeel
  600. * @see #removeAuxiliaryLookAndFeel
  601. * @see #setLookAndFeel
  602. * @see #getInstalledLookAndFeels
  603. */
  604. static public LookAndFeel[] getAuxiliaryLookAndFeels()
  605. {
  606. maybeInitialize();
  607. Vector v = getLAFState().auxLookAndFeels;
  608. if ((v == null) || (v.size() == 0)) {
  609. return null;
  610. }
  611. else {
  612. LookAndFeel[] rv = new LookAndFeel[v.size()];
  613. for (int i = 0; i < rv.length; i++) {
  614. rv[i] = (LookAndFeel)v.elementAt(i);
  615. }
  616. return rv;
  617. }
  618. }
  619. /**
  620. * Add a PropertyChangeListener to the listener list.
  621. * The listener is registered for all properties.
  622. *
  623. * @param listener The PropertyChangeListener to be added
  624. * @see java.beans.PropertyChangeSupport
  625. */
  626. public static void addPropertyChangeListener(PropertyChangeListener listener)
  627. {
  628. synchronized (classLock) {
  629. getLAFState().changeSupport.addPropertyChangeListener(listener);
  630. }
  631. }
  632. /**
  633. * Remove a PropertyChangeListener from the listener list.
  634. * This removes a PropertyChangeListener that was registered
  635. * for all properties.
  636. *
  637. * @param listener The PropertyChangeListener to be removed
  638. * @see java.beans.PropertyChangeSupport
  639. */
  640. public static void removePropertyChangeListener(PropertyChangeListener listener)
  641. {
  642. synchronized (classLock) {
  643. getLAFState().changeSupport.removePropertyChangeListener(listener);
  644. }
  645. }
  646. private static Properties loadSwingProperties()
  647. {
  648. /* Don't bother checking for Swing properties if untrusted, as
  649. * there's no way to look them up without triggering SecurityExceptions.
  650. */
  651. if (UIManager.class.getClassLoader() != null) {
  652. return new Properties();
  653. }
  654. else {
  655. final Properties props = new Properties();
  656. SwingUtilities.doPrivileged(new Runnable() {
  657. public void run() {
  658. try {
  659. File file = new File(makeSwingPropertiesFilename());
  660. BufferedInputStream ins = new BufferedInputStream(new FileInputStream(file));
  661. props.load(ins);
  662. ins.close();
  663. }
  664. catch (Exception e) {
  665. // No such file, or file is otherwise non-readable.
  666. }
  667. // Check whether any properties were overridden at the
  668. // command line.
  669. checkProperty(props, defaultLAFKey);
  670. checkProperty(props, auxiliaryLAFsKey);
  671. checkProperty(props, multiplexingLAFKey);
  672. checkProperty(props, installedLAFsKey);
  673. }
  674. });
  675. return props;
  676. }
  677. }
  678. private static void checkProperty(Properties props, String key) {
  679. try {
  680. String value = System.getProperty(key);
  681. if (value != null) {
  682. props.put(key, value);
  683. }
  684. } catch (SecurityException e) {
  685. // If system won't give us a property, we don't want it!
  686. }
  687. }
  688. /**
  689. * If a swing.properties file exist and it has a swing.installedlafs property
  690. * then initialize the installedLAFs field.
  691. *
  692. * @see #getInstalledLookAndFeels
  693. */
  694. private static void initializeInstalledLAFs(Properties swingProps)
  695. {
  696. String ilafsString = swingProps.getProperty(installedLAFsKey);
  697. if (ilafsString == null) {
  698. return;
  699. }
  700. /* Create a vector that contains the value of the swing.installedlafs
  701. * property. For example given "swing.installedlafs=motif,windows"
  702. * lafs = {"motif", "windows"}.
  703. */
  704. Vector lafs = new Vector();
  705. StringTokenizer st = new StringTokenizer(ilafsString, ",", false);
  706. while (st.hasMoreTokens()) {
  707. lafs.addElement(st.nextToken());
  708. }
  709. /* Look up the name and class for each name in the "swing.installedlafs"
  710. * list. If they both exist then add a LookAndFeelInfo to
  711. * the installedLafs array.
  712. */
  713. Vector ilafs = new Vector(lafs.size());
  714. for(int i = 0; i < lafs.size(); i++) {
  715. String laf = (String)lafs.elementAt(i);
  716. String name = swingProps.getProperty(makeInstalledLAFKey(laf, "name"), laf);
  717. String cls = swingProps.getProperty(makeInstalledLAFKey(laf, "class"));
  718. if (cls != null) {
  719. ilafs.addElement(new LookAndFeelInfo(name, cls));
  720. }
  721. }
  722. installedLAFs = new LookAndFeelInfo[ilafs.size()];
  723. for(int i = 0; i < ilafs.size(); i++) {
  724. installedLAFs[i] = (LookAndFeelInfo)(ilafs.elementAt(i));
  725. }
  726. }
  727. /**
  728. * If the user has specified a default look and feel, use that.
  729. * Otherwise use the look and feel that's native to this platform.
  730. * If this code is called after the application has expclicitly
  731. * set it's look and feel, do nothing.
  732. *
  733. * @see #maybeInitialize
  734. */
  735. private static void initializeDefaultLAF(Properties swingProps)
  736. {
  737. if (getLAFState().lookAndFeel != null) {
  738. return;
  739. }
  740. String metalLnf = getCrossPlatformLookAndFeelClassName();
  741. String lnfDefault = metalLnf;
  742. String lnfName = "<undefined>" ;
  743. try {
  744. lnfName = swingProps.getProperty(defaultLAFKey, lnfDefault);
  745. setLookAndFeel(lnfName);
  746. } catch (Exception e) {
  747. try {
  748. lnfName = swingProps.getProperty(defaultLAFKey, metalLnf);
  749. setLookAndFeel(lnfName);
  750. } catch (Exception e2) {
  751. throw new Error("can't load " + lnfName);
  752. }
  753. }
  754. }
  755. private static void initializeAuxiliaryLAFs(Properties swingProps)
  756. {
  757. String auxLookAndFeelNames = swingProps.getProperty(auxiliaryLAFsKey);
  758. if (auxLookAndFeelNames == null) {
  759. return;
  760. }
  761. Vector auxLookAndFeels = new Vector();
  762. StringTokenizer p = new StringTokenizer(auxLookAndFeelNames,",");
  763. String factoryName;
  764. /* Try to load each LookAndFeel subclass in the list.
  765. */
  766. while (p.hasMoreTokens()) {
  767. String className = p.nextToken();
  768. try {
  769. Class lnfClass = SwingUtilities.loadSystemClass(className);
  770. auxLookAndFeels.addElement(lnfClass.newInstance());
  771. }
  772. catch (Exception e) {
  773. System.err.println("UIManager: failed loading auxiliary look and feel " + className);
  774. }
  775. }
  776. /* If there were problems and no auxiliary look and feels were
  777. * loaded, make sure we reset auxLookAndFeels to null.
  778. * Otherwise, we are going to use the MultiLookAndFeel to get
  779. * all component UI's, so we need to load it now.
  780. */
  781. if (auxLookAndFeels.size() == 0) {
  782. auxLookAndFeels = null;
  783. }
  784. else {
  785. getLAFState().multiLookAndFeel = getMultiLookAndFeel();
  786. if (getLAFState().multiLookAndFeel == null) {
  787. auxLookAndFeels = null;
  788. }
  789. }
  790. getLAFState().auxLookAndFeels = auxLookAndFeels;
  791. }
  792. private static void initializeSystemDefaults(Properties swingProps)
  793. {
  794. Object defaults[] = {
  795. "FocusManagerClassName", "javax.swing.DefaultFocusManager"
  796. };
  797. getLAFState().setSystemDefaults(new UIDefaults(defaults));
  798. getLAFState().swingProps = swingProps;
  799. }
  800. private static void initialize()
  801. {
  802. Properties swingProps = loadSwingProperties();
  803. try {
  804. // We discourage the JIT during UI initialization.
  805. // JITing here tends to be counter-productive.
  806. java.lang.Compiler.disable();
  807. initializeSystemDefaults(swingProps);
  808. initializeDefaultLAF(swingProps);
  809. initializeAuxiliaryLAFs(swingProps);
  810. initializeInstalledLAFs(swingProps);
  811. } finally {
  812. // Make sure to always re-enable the JIT.
  813. java.lang.Compiler.enable();
  814. }
  815. }
  816. /*
  817. * This method is called before any code that depends on the
  818. * AppContext specific LAFState object runs. When the AppContext
  819. * corresponds to a set of applets it's possible for this method
  820. * to be re-entered, which is why we grab a lock before calling
  821. * initialize().
  822. */
  823. private static void maybeInitialize() {
  824. synchronized (classLock) {
  825. if (!getLAFState().initialized) {
  826. getLAFState().initialized = true;
  827. initialize();
  828. }
  829. }
  830. }
  831. }