Home » openjdk-7 » com.sun.java.swing.plaf » windows » [javadoc | source]

    1   /*
    2    * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package com.sun.java.swing.plaf.windows;
   26   
   27   import java.awt;
   28   import java.beans;
   29   import java.lang.ref;
   30   import javax.swing;
   31   import javax.swing.plaf;
   32   
   33   /**
   34    * Wrapper for a value from the desktop. The value is lazily looked up, and
   35    * can be accessed using the <code>UIManager.ActiveValue</code> method
   36    * <code>createValue</code>. If the underlying desktop property changes this
   37    * will force the UIs to update all known Frames. You can invoke
   38    * <code>invalidate</code> to force the value to be fetched again.
   39    *
   40    */
   41   // NOTE: Don't rely on this class staying in this location. It is likely
   42   // to move to a different package in the future.
   43   public class DesktopProperty implements UIDefaults.ActiveValue {
   44       /**
   45        * Indicates if an updateUI call is pending.
   46        */
   47       private static boolean updatePending;
   48   
   49       /**
   50        * ReferenceQueue of unreferenced WeakPCLs.
   51        */
   52       private static final ReferenceQueue<DesktopProperty> queue = new ReferenceQueue<DesktopProperty>();
   53   
   54       /**
   55        * PropertyChangeListener attached to the Toolkit.
   56        */
   57       private WeakPCL pcl;
   58       /**
   59        * Key used to lookup value from desktop.
   60        */
   61       private final String key;
   62       /**
   63        * Value to return.
   64        */
   65       private Object value;
   66       /**
   67        * Fallback value in case we get null from desktop.
   68        */
   69       private final Object fallback;
   70   
   71   
   72       /**
   73        * Cleans up any lingering state held by unrefeernced
   74        * DesktopProperties.
   75        */
   76       static void flushUnreferencedProperties() {
   77           WeakPCL pcl;
   78   
   79           while ((pcl = (WeakPCL)queue.poll()) != null) {
   80               pcl.dispose();
   81           }
   82       }
   83   
   84   
   85       /**
   86        * Sets whether or not an updateUI call is pending.
   87        */
   88       private static synchronized void setUpdatePending(boolean update) {
   89           updatePending = update;
   90       }
   91   
   92       /**
   93        * Returns true if a UI update is pending.
   94        */
   95       private static synchronized boolean isUpdatePending() {
   96           return updatePending;
   97       }
   98   
   99       /**
  100        * Updates the UIs of all the known Frames.
  101        */
  102       private static void updateAllUIs() {
  103           // Check if the current UI is WindowsLookAndfeel and flush the XP style map.
  104           // Note: Change the package test if this class is moved to a different package.
  105           Class uiClass = UIManager.getLookAndFeel().getClass();
  106           if (uiClass.getPackage().equals(DesktopProperty.class.getPackage())) {
  107               XPStyle.invalidateStyle();
  108           }
  109           Frame appFrames[] = Frame.getFrames();
  110           for (Frame appFrame : appFrames) {
  111               updateWindowUI(appFrame);
  112           }
  113       }
  114   
  115       /**
  116        * Updates the UI of the passed in window and all its children.
  117        */
  118       private static void updateWindowUI(Window window) {
  119           SwingUtilities.updateComponentTreeUI(window);
  120           Window ownedWins[] = window.getOwnedWindows();
  121           for (Window ownedWin : ownedWins) {
  122               updateWindowUI(ownedWin);
  123           }
  124       }
  125   
  126   
  127       /**
  128        * Creates a DesktopProperty.
  129        *
  130        * @param key Key used in looking up desktop value.
  131        * @param fallback Value used if desktop property is null.
  132        */
  133       public DesktopProperty(String key, Object fallback) {
  134           this.key = key;
  135           this.fallback = fallback;
  136           // The only sure fire way to clear our references is to create a
  137           // Thread and wait for a reference to be added to the queue.
  138           // Because it is so rare that you will actually change the look
  139           // and feel, this stepped is forgoed and a middle ground of
  140           // flushing references from the constructor is instead done.
  141           // The implication is that once one DesktopProperty is created
  142           // there will most likely be n (number of DesktopProperties created
  143           // by the LookAndFeel) WeakPCLs around, but this number will not
  144           // grow past n.
  145           flushUnreferencedProperties();
  146       }
  147   
  148       /**
  149        * UIManager.LazyValue method, returns the value from the desktop
  150        * or the fallback value if the desktop value is null.
  151        */
  152       public Object createValue(UIDefaults table) {
  153           if (value == null) {
  154               value = configureValue(getValueFromDesktop());
  155               if (value == null) {
  156                   value = configureValue(getDefaultValue());
  157               }
  158           }
  159           return value;
  160       }
  161   
  162       /**
  163        * Returns the value from the desktop.
  164        */
  165       protected Object getValueFromDesktop() {
  166           Toolkit toolkit = Toolkit.getDefaultToolkit();
  167   
  168           if (pcl == null) {
  169               pcl = new WeakPCL(this, getKey(), UIManager.getLookAndFeel());
  170               toolkit.addPropertyChangeListener(getKey(), pcl);
  171           }
  172   
  173           return toolkit.getDesktopProperty(getKey());
  174       }
  175   
  176       /**
  177        * Returns the value to use if the desktop property is null.
  178        */
  179       protected Object getDefaultValue() {
  180           return fallback;
  181       }
  182   
  183       /**
  184        * Invalidates the current value.
  185        *
  186        * @param laf the LookAndFeel this DesktopProperty was created with
  187        */
  188       public void invalidate(LookAndFeel laf) {
  189           invalidate();
  190       }
  191   
  192       /**
  193        * Invalides the current value so that the next invocation of
  194        * <code>createValue</code> will ask for the property again.
  195        */
  196       public void invalidate() {
  197           value = null;
  198       }
  199   
  200       /**
  201        * Requests that all components in the GUI hierarchy be updated
  202        * to reflect dynamic changes in this look&feel.  This update occurs
  203        * by uninstalling and re-installing the UI objects. Requests are
  204        * batched and collapsed into a single update pass because often
  205        * many desktop properties will change at once.
  206        */
  207       protected void updateUI() {
  208           if (!isUpdatePending()) {
  209               setUpdatePending(true);
  210               Runnable uiUpdater = new Runnable() {
  211                   public void run() {
  212                       updateAllUIs();
  213                       setUpdatePending(false);
  214                   }
  215               };
  216               SwingUtilities.invokeLater(uiUpdater);
  217           }
  218       }
  219   
  220       /**
  221        * Configures the value as appropriate for a defaults property in
  222        * the UIDefaults table.
  223        */
  224       protected Object configureValue(Object value) {
  225           if (value != null) {
  226               if (value instanceof Color) {
  227                   return new ColorUIResource((Color)value);
  228               }
  229               else if (value instanceof Font) {
  230                   return new FontUIResource((Font)value);
  231               }
  232               else if (value instanceof UIDefaults.LazyValue) {
  233                   value = ((UIDefaults.LazyValue)value).createValue(null);
  234               }
  235               else if (value instanceof UIDefaults.ActiveValue) {
  236                   value = ((UIDefaults.ActiveValue)value).createValue(null);
  237               }
  238           }
  239           return value;
  240       }
  241   
  242       /**
  243        * Returns the key used to lookup the desktop properties value.
  244        */
  245       protected String getKey() {
  246           return key;
  247       }
  248   
  249   
  250   
  251       /**
  252        * As there is typically only one Toolkit, the PropertyChangeListener
  253        * is handled via a WeakReference so as not to pin down the
  254        * DesktopProperty.
  255        */
  256       private static class WeakPCL extends WeakReference<DesktopProperty>
  257                                  implements PropertyChangeListener {
  258           private String key;
  259           private LookAndFeel laf;
  260   
  261           WeakPCL(DesktopProperty target, String key, LookAndFeel laf) {
  262               super(target, queue);
  263               this.key = key;
  264               this.laf = laf;
  265           }
  266   
  267           public void propertyChange(PropertyChangeEvent pce) {
  268               DesktopProperty property = get();
  269   
  270               if (property == null || laf != UIManager.getLookAndFeel()) {
  271                   // The property was GC'ed, we're no longer interested in
  272                   // PropertyChanges, remove the listener.
  273                   dispose();
  274               }
  275               else {
  276                   property.invalidate(laf);
  277                   property.updateUI();
  278               }
  279           }
  280   
  281           void dispose() {
  282               Toolkit.getDefaultToolkit().removePropertyChangeListener(key, this);
  283           }
  284       }
  285   }

Home » openjdk-7 » com.sun.java.swing.plaf » windows » [javadoc | source]