LookAndFeelAddons.java
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:12k
源码类别:

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: LookAndFeelAddons.java,v 1.13 2005/10/10 18:02:20 rbair Exp $
  3.  *
  4.  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
  5.  * Santa Clara, California 95054, U.S.A. All rights reserved.
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  20.  */
  21. package org.jdesktop.swingx.plaf;
  22. import java.beans.PropertyChangeEvent;
  23. import java.beans.PropertyChangeListener;
  24. import java.lang.reflect.Method;
  25. import java.util.ArrayList;
  26. import java.util.Iterator;
  27. import java.util.List;
  28. import javax.swing.JComponent;
  29. import javax.swing.UIManager;
  30. import javax.swing.plaf.ComponentUI;
  31. import org.jdesktop.swingx.plaf.aqua.AquaLookAndFeelAddons;
  32. import org.jdesktop.swingx.plaf.metal.MetalLookAndFeelAddons;
  33. import org.jdesktop.swingx.plaf.motif.MotifLookAndFeelAddons;
  34. import org.jdesktop.swingx.plaf.windows.WindowsClassicLookAndFeelAddons;
  35. import org.jdesktop.swingx.plaf.windows.WindowsLookAndFeelAddons;
  36. import org.jdesktop.swingx.util.OS;
  37. /**
  38.  * Provides additional pluggable UI for new components added by the
  39.  * library. By default, the library uses the pluggable UI returned by
  40.  * {@link #getBestMatchAddonClassName()}.
  41.  * <p>
  42.  * The default addon can be configured using the
  43.  * <code>swing.addon</code> system property as follow:
  44.  * <ul>
  45.  * <li>on the command line,
  46.  * <code>java -Dswing.addon=ADDONCLASSNAME ...</code></li>
  47.  * <li>at runtime and before using the library components
  48.  * <code>System.getProperties().put("swing.addon", ADDONCLASSNAME);</code>
  49.  * </li>
  50.  * </ul>
  51.  * <p>
  52.  * The addon can also be installed directly by calling the
  53.  * {@link #setAddon(String)}method. For example, to install the
  54.  * Windows addons, add the following statement
  55.  * <code>LookAndFeelAddons.setAddon("org.jdesktop.swingx.plaf.windows.WindowsLookAndFeelAddons");</code>.
  56.  * 
  57.  * @author <a href="mailto:fred@L2FProd.com">Frederic Lavigne</a> 
  58.  */
  59. public class LookAndFeelAddons {
  60.   private static List<ComponentAddon> contributedComponents =
  61.     new ArrayList<ComponentAddon>();
  62.   /**
  63.    * Key used to ensure the current UIManager has been populated by the
  64.    * LookAndFeelAddons.
  65.    */
  66.   private static final Object APPCONTEXT_INITIALIZED = new Object();
  67.   
  68.   static {
  69.     // load the default addon
  70.     String addonClassname = getBestMatchAddonClassName();
  71.     try {
  72.       addonClassname = System.getProperty("swing.addon", addonClassname);
  73.     } catch (SecurityException e) {
  74.       // security exception may arise in Java Web Start
  75.     }
  76.     try {
  77.       setAddon(addonClassname);
  78.     } catch (Exception e) {
  79.       // PENDING(fred) do we want to log an error and continue with a default
  80.       // addon class or do we just fail?
  81.       throw new ExceptionInInitializerError(e);
  82.     }
  83.     
  84.     setTrackingLookAndFeelChanges(true);
  85.       
  86.     // this addon ensure resource bundle gets added to lookandfeel defaults
  87.     // and re-added by #maybeInitialize if needed      
  88.     contribute(new AbstractComponentAddon("MinimumAddon") {
  89.       @Override
  90.       protected void addBasicDefaults(LookAndFeelAddons addon, List<Object> defaults) {
  91.         addResource(defaults, LookAndFeelAddons.class.getPackage().getName()
  92.           + ".resources.swingx");
  93.       }
  94.     });
  95.   }
  96.   private static LookAndFeelAddons currentAddon;
  97.   public void initialize() {
  98.     for (Iterator<ComponentAddon> iter = contributedComponents.iterator(); iter
  99.       .hasNext();) {
  100.       ComponentAddon addon = iter.next();
  101.       addon.initialize(this);
  102.     }
  103.   }
  104.   public void uninitialize() {
  105.     for (Iterator<ComponentAddon> iter = contributedComponents.iterator(); iter
  106.       .hasNext();) {
  107.       ComponentAddon addon = iter.next();
  108.       addon.uninitialize(this);
  109.     }
  110.   }
  111.   /**
  112.    * Adds the given defaults in UIManager.
  113.    * 
  114.    * @param keysAndValues
  115.    */
  116.   public void loadDefaults(Object[] keysAndValues) {
  117.     for (int i = 0, c = keysAndValues.length; i < c; i = i + 2) {
  118.       UIManager.getLookAndFeelDefaults().put(keysAndValues[i], keysAndValues[i + 1]);
  119.     }
  120.   }
  121.   public void unloadDefaults(Object[] keysAndValues) {
  122.     for (int i = 0, c = keysAndValues.length; i < c; i = i + 2) {
  123.       UIManager.getLookAndFeelDefaults().put(keysAndValues[i], null);
  124.     }
  125.   }
  126.   public static void setAddon(String addonClassName)
  127.     throws InstantiationException, IllegalAccessException,
  128.     ClassNotFoundException {
  129.     setAddon(Class.forName(addonClassName));
  130.   }
  131.   public static void setAddon(Class addonClass) throws InstantiationException,
  132.     IllegalAccessException {
  133.     LookAndFeelAddons addon = (LookAndFeelAddons)addonClass.newInstance();
  134.     setAddon(addon);
  135.   }
  136.    
  137.   public static void setAddon(LookAndFeelAddons addon) {
  138.     if (currentAddon != null) {
  139.       currentAddon.uninitialize();
  140.     }
  141.     addon.initialize();
  142.     currentAddon = addon;    
  143.     UIManager.put(APPCONTEXT_INITIALIZED, Boolean.TRUE);
  144.   }
  145.   public static LookAndFeelAddons getAddon() {
  146.     return currentAddon;
  147.   }
  148.   /**
  149.    * Based on the current look and feel (as returned by
  150.    * <code>UIManager.getLookAndFeel()</code>), this method returns
  151.    * the name of the closest <code>LookAndFeelAddons</code> to use.
  152.    * 
  153.    * @return the addon matching the currently installed look and feel
  154.    */
  155.   public static String getBestMatchAddonClassName() {
  156.     String lnf = UIManager.getLookAndFeel().getClass().getName();
  157.     String addon;
  158.     if (UIManager.getCrossPlatformLookAndFeelClassName().equals(lnf)) {
  159.       addon = MetalLookAndFeelAddons.class.getName();
  160.     } else if (UIManager.getSystemLookAndFeelClassName().equals(lnf)) {
  161.       addon = getSystemAddonClassName();
  162.     } else if ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel".equals(lnf) ||
  163.       "com.jgoodies.looks.windows.WindowsLookAndFeel".equals(lnf)) {
  164.       if (OS.isUsingWindowsVisualStyles()) {
  165.         addon = WindowsLookAndFeelAddons.class.getName();
  166.       } else {
  167.         addon = WindowsClassicLookAndFeelAddons.class.getName();
  168.       }
  169.     } else if ("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel"
  170.       .equals(lnf)) {
  171.       addon = WindowsClassicLookAndFeelAddons.class.getName();
  172.     } else if (UIManager.getLookAndFeel().getID().equals("Motif")) {
  173.       addon = MotifLookAndFeelAddons.class.getName();
  174.     } else {
  175.       addon = getSystemAddonClassName();
  176.     }
  177.     return addon;
  178.   }
  179.   /**
  180.    * Gets the addon best suited for the operating system where the
  181.    * virtual machine is running.
  182.    * 
  183.    * @return the addon matching the native operating system platform.
  184.    */
  185.   public static String getSystemAddonClassName() {
  186.     String addon = WindowsClassicLookAndFeelAddons.class.getName();
  187.     if (OS.isMacOSX()) {
  188.       addon = AquaLookAndFeelAddons.class.getName();
  189.     } else if (OS.isWindows()) {
  190.       // see whether of not visual styles are used
  191.       if (OS.isUsingWindowsVisualStyles()) {
  192.         addon = WindowsLookAndFeelAddons.class.getName();
  193.       } else {
  194.         addon = WindowsClassicLookAndFeelAddons.class.getName();
  195.       }
  196.     }
  197.     return addon;
  198.   }
  199.   /**
  200.    * Each new component added by the library will contribute its
  201.    * default UI classes, colors and fonts to the LookAndFeelAddons.
  202.    * See {@link ComponentAddon}.
  203.    * 
  204.    * @param component
  205.    */
  206.   public static void contribute(ComponentAddon component) {
  207.     contributedComponents.add(component);
  208.     if (currentAddon != null) {
  209.       // make sure to initialize any addons added after the
  210.       // LookAndFeelAddons has been installed
  211.       component.initialize(currentAddon);
  212.     }
  213.   }
  214.   /**
  215.    * Removes the contribution of the given addon
  216.    * 
  217.    * @param component
  218.    */
  219.   public static void uncontribute(ComponentAddon component) {
  220.     contributedComponents.remove(component);
  221.     
  222.     if (currentAddon != null) {
  223.       component.uninitialize(currentAddon);
  224.     }
  225.   }
  226.   /**
  227.    * Workaround for IDE mixing up with classloaders and Applets environments.
  228.    * Consider this method as API private. It must not be called directly.
  229.    * 
  230.    * @param component
  231.    * @param expectedUIClass
  232.    * @return an instance of expectedUIClass 
  233.    */
  234.   public static ComponentUI getUI(JComponent component, Class expectedUIClass) {
  235.     maybeInitialize();
  236.     // solve issue with ClassLoader not able to find classes
  237.     String uiClassname = (String)UIManager.get(component.getUIClassID());
  238.     try {
  239.       Class uiClass = Class.forName(uiClassname);
  240.       UIManager.put(uiClassname, uiClass);
  241.     } catch (ClassNotFoundException e) {
  242.       // we ignore the ClassNotFoundException
  243.     }
  244.     
  245.     ComponentUI ui = UIManager.getUI(component);
  246.     
  247.     if (expectedUIClass.isInstance(ui)) {
  248.       return ui;
  249.     } else {
  250.       String realUI = ui.getClass().getName();
  251.       Class realUIClass;
  252.       try {
  253.         realUIClass = expectedUIClass.getClassLoader()
  254.         .loadClass(realUI);
  255.       } catch (ClassNotFoundException e) {
  256.         throw new RuntimeException("Failed to load class " + realUI, e);
  257.       }
  258.       Method createUIMethod = null;
  259.       try {
  260.         createUIMethod = realUIClass.getMethod("createUI", new Class[]{JComponent.class});
  261.       } catch (NoSuchMethodException e1) {
  262.         throw new RuntimeException("Class " + realUI + " has no method createUI(JComponent)");
  263.       }
  264.       try {
  265.         return (ComponentUI)createUIMethod.invoke(null, new Object[]{component});
  266.       } catch (Exception e2) {
  267.         throw new RuntimeException("Failed to invoke " + realUI + "#createUI(JComponent)");
  268.       }
  269.     }
  270.   }
  271.   
  272.   /**
  273.    * With applets, if you reload the current applet, the UIManager will be
  274.    * reinitialized (entries previously added by LookAndFeelAddons will be
  275.    * removed) but the addon will not reinitialize because addon initialize
  276.    * itself through the static block in components and the classes do not get
  277.    * reloaded. This means component.updateUI will fail because it will not find
  278.    * its UI.
  279.    * 
  280.    * This method ensures LookAndFeelAddons get re-initialized if needed. It must
  281.    * be called in every component updateUI methods.
  282.    */
  283.   private static synchronized void maybeInitialize() {
  284.     if (currentAddon != null) {
  285.       // this is to ensure "UIManager#maybeInitialize" gets called and the
  286.       // LAFState initialized
  287.       UIManager.getLookAndFeelDefaults();
  288.       
  289.       if (!UIManager.getBoolean(APPCONTEXT_INITIALIZED)) {
  290.         setAddon(currentAddon);
  291.       }
  292.     }
  293.   }
  294.   
  295.   //
  296.   // TRACKING OF THE CURRENT LOOK AND FEEL
  297.   //
  298.   private static boolean trackingChanges = false;
  299.   private static PropertyChangeListener changeListener;    
  300.   private static class UpdateAddon implements PropertyChangeListener {
  301.     public void propertyChange(PropertyChangeEvent evt) {
  302.       try {
  303.         setAddon(getBestMatchAddonClassName());
  304.       } catch (Exception e) {
  305.         // should not happen
  306.         throw new RuntimeException(e);
  307.       }
  308.     }
  309.   }
  310.   
  311.   /**
  312.    * If true, everytime the Swing look and feel is changed, the addon which
  313.    * best matches the current look and feel will be automatically selected.
  314.    * 
  315.    * @param tracking
  316.    *          true to automatically update the addon, false to not automatically
  317.    *          track the addon. Defaults to false.
  318.    * @see #getBestMatchAddonClassName()
  319.    */
  320.   public static synchronized void setTrackingLookAndFeelChanges(boolean tracking) {
  321.     if (trackingChanges != tracking) {
  322.       if (tracking) {
  323.         if (changeListener == null) {
  324.           changeListener = new UpdateAddon();
  325.         }
  326.         UIManager.addPropertyChangeListener(changeListener);
  327.       } else {
  328.         if (changeListener != null) {
  329.           UIManager.removePropertyChangeListener(changeListener);
  330.         }
  331.         changeListener = null;
  332.       }
  333.       trackingChanges = tracking;
  334.     }
  335.   }
  336.   
  337.   /**
  338.    * @return true if the addon will be automatically change to match the current
  339.    *         look and feel
  340.    * @see #setTrackingLookAndFeelChanges(boolean)
  341.    */
  342.   public static synchronized boolean isTrackingLookAndFeelChanges() {
  343.     return trackingChanges;
  344.   }
  345.    
  346. }