Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]
    1   /*
    2    * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package javax.swing;
   26   
   27   import java.awt;
   28   import java.awt.event;
   29   import java.beans;
   30   import java.util.Hashtable;
   31   import java.util.Enumeration;
   32   import java.io.Serializable;
   33   import java.io.IOException;
   34   import java.io.ObjectInputStream;
   35   import java.io.ObjectOutputStream;
   36   import java.security.AccessController;
   37   import javax.swing.event.SwingPropertyChangeSupport;
   38   import sun.security.action.GetPropertyAction;
   39   
   40   /**
   41    * This class provides default implementations for the JFC <code>Action</code>
   42    * interface. Standard behaviors like the get and set methods for
   43    * <code>Action</code> object properties (icon, text, and enabled) are defined
   44    * here. The developer need only subclass this abstract class and
   45    * define the <code>actionPerformed</code> method.
   46    * <p>
   47    * <strong>Warning:</strong>
   48    * Serialized objects of this class will not be compatible with
   49    * future Swing releases. The current serialization support is
   50    * appropriate for short term storage or RMI between applications running
   51    * the same version of Swing.  As of 1.4, support for long term storage
   52    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   53    * has been added to the <code>java.beans</code> package.
   54    * Please see {@link java.beans.XMLEncoder}.
   55    *
   56    * @author Georges Saab
   57    * @see Action
   58    */
   59   public abstract class AbstractAction implements Action, Cloneable, Serializable
   60   {
   61       /**
   62        * Whether or not actions should reconfigure all properties on null.
   63        */
   64       private static Boolean RECONFIGURE_ON_NULL;
   65   
   66       /**
   67        * Specifies whether action is enabled; the default is true.
   68        */
   69       protected boolean enabled = true;
   70   
   71   
   72       /**
   73        * Contains the array of key bindings.
   74        */
   75       private transient ArrayTable arrayTable;
   76   
   77       /**
   78        * Whether or not to reconfigure all action properties from the
   79        * specified event.
   80        */
   81       static boolean shouldReconfigure(PropertyChangeEvent e) {
   82           if (e.getPropertyName() == null) {
   83               synchronized(AbstractAction.class) {
   84                   if (RECONFIGURE_ON_NULL == null) {
   85                       RECONFIGURE_ON_NULL = Boolean.valueOf(
   86                           AccessController.doPrivileged(new GetPropertyAction(
   87                           "swing.actions.reconfigureOnNull", "false")));
   88                   }
   89                   return RECONFIGURE_ON_NULL;
   90               }
   91           }
   92           return false;
   93       }
   94   
   95       /**
   96        * Sets the enabled state of a component from an Action.
   97        *
   98        * @param c the Component to set the enabled state on
   99        * @param a the Action to set the enabled state from, may be null
  100        */
  101       static void setEnabledFromAction(JComponent c, Action a) {
  102           c.setEnabled((a != null) ? a.isEnabled() : true);
  103       }
  104   
  105       /**
  106        * Sets the tooltip text of a component from an Action.
  107        *
  108        * @param c the Component to set the tooltip text on
  109        * @param a the Action to set the tooltip text from, may be null
  110        */
  111       static void setToolTipTextFromAction(JComponent c, Action a) {
  112           c.setToolTipText(a != null ?
  113                            (String)a.getValue(Action.SHORT_DESCRIPTION) : null);
  114       }
  115   
  116       static boolean hasSelectedKey(Action a) {
  117           return (a != null && a.getValue(Action.SELECTED_KEY) != null);
  118       }
  119   
  120       static boolean isSelected(Action a) {
  121           return Boolean.TRUE.equals(a.getValue(Action.SELECTED_KEY));
  122       }
  123   
  124   
  125   
  126       /**
  127        * Creates an {@code Action}.
  128        */
  129       public AbstractAction() {
  130       }
  131   
  132       /**
  133        * Creates an {@code Action} with the specified name.
  134        *
  135        * @param name the name ({@code Action.NAME}) for the action; a
  136        *        value of {@code null} is ignored
  137        */
  138       public AbstractAction(String name) {
  139           putValue(Action.NAME, name);
  140       }
  141   
  142       /**
  143        * Creates an {@code Action} with the specified name and small icon.
  144        *
  145        * @param name the name ({@code Action.NAME}) for the action; a
  146        *        value of {@code null} is ignored
  147        * @param icon the small icon ({@code Action.SMALL_ICON}) for the action; a
  148        *        value of {@code null} is ignored
  149        */
  150       public AbstractAction(String name, Icon icon) {
  151           this(name);
  152           putValue(Action.SMALL_ICON, icon);
  153       }
  154   
  155       /**
  156        * Gets the <code>Object</code> associated with the specified key.
  157        *
  158        * @param key a string containing the specified <code>key</code>
  159        * @return the binding <code>Object</code> stored with this key; if there
  160        *          are no keys, it will return <code>null</code>
  161        * @see Action#getValue
  162        */
  163       public Object getValue(String key) {
  164           if (key == "enabled") {
  165               return enabled;
  166           }
  167           if (arrayTable == null) {
  168               return null;
  169           }
  170           return arrayTable.get(key);
  171       }
  172   
  173       /**
  174        * Sets the <code>Value</code> associated with the specified key.
  175        *
  176        * @param key  the <code>String</code> that identifies the stored object
  177        * @param newValue the <code>Object</code> to store using this key
  178        * @see Action#putValue
  179        */
  180       public void putValue(String key, Object newValue) {
  181           Object oldValue = null;
  182           if (key == "enabled") {
  183               // Treat putValue("enabled") the same way as a call to setEnabled.
  184               // If we don't do this it means the two may get out of sync, and a
  185               // bogus property change notification would be sent.
  186               //
  187               // To avoid dependencies between putValue & setEnabled this
  188               // directly changes enabled. If we instead called setEnabled
  189               // to change enabled, it would be possible for stack
  190               // overflow in the case where a developer implemented setEnabled
  191               // in terms of putValue.
  192               if (newValue == null || !(newValue instanceof Boolean)) {
  193                   newValue = false;
  194               }
  195               oldValue = enabled;
  196               enabled = (Boolean)newValue;
  197           } else {
  198               if (arrayTable == null) {
  199                   arrayTable = new ArrayTable();
  200               }
  201               if (arrayTable.containsKey(key))
  202                   oldValue = arrayTable.get(key);
  203               // Remove the entry for key if newValue is null
  204               // else put in the newValue for key.
  205               if (newValue == null) {
  206                   arrayTable.remove(key);
  207               } else {
  208                   arrayTable.put(key,newValue);
  209               }
  210           }
  211           firePropertyChange(key, oldValue, newValue);
  212       }
  213   
  214       /**
  215        * Returns true if the action is enabled.
  216        *
  217        * @return true if the action is enabled, false otherwise
  218        * @see Action#isEnabled
  219        */
  220       public boolean isEnabled() {
  221           return enabled;
  222       }
  223   
  224       /**
  225        * Sets whether the {@code Action} is enabled. The default is {@code true}.
  226        *
  227        * @param newValue  {@code true} to enable the action, {@code false} to
  228        *                  disable it
  229        * @see Action#setEnabled
  230        */
  231       public void setEnabled(boolean newValue) {
  232           boolean oldValue = this.enabled;
  233   
  234           if (oldValue != newValue) {
  235               this.enabled = newValue;
  236               firePropertyChange("enabled",
  237                                  Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
  238           }
  239       }
  240   
  241   
  242       /**
  243        * Returns an array of <code>Object</code>s which are keys for
  244        * which values have been set for this <code>AbstractAction</code>,
  245        * or <code>null</code> if no keys have values set.
  246        * @return an array of key objects, or <code>null</code> if no
  247        *                  keys have values set
  248        * @since 1.3
  249        */
  250       public Object[] getKeys() {
  251           if (arrayTable == null) {
  252               return null;
  253           }
  254           Object[] keys = new Object[arrayTable.size()];
  255           arrayTable.getKeys(keys);
  256           return keys;
  257       }
  258   
  259       /**
  260        * If any <code>PropertyChangeListeners</code> have been registered, the
  261        * <code>changeSupport</code> field describes them.
  262        */
  263       protected SwingPropertyChangeSupport changeSupport;
  264   
  265       /**
  266        * Supports reporting bound property changes.  This method can be called
  267        * when a bound property has changed and it will send the appropriate
  268        * <code>PropertyChangeEvent</code> to any registered
  269        * <code>PropertyChangeListeners</code>.
  270        */
  271       protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
  272           if (changeSupport == null ||
  273               (oldValue != null && newValue != null && oldValue.equals(newValue))) {
  274               return;
  275           }
  276           changeSupport.firePropertyChange(propertyName, oldValue, newValue);
  277       }
  278   
  279   
  280       /**
  281        * Adds a <code>PropertyChangeListener</code> to the listener list.
  282        * The listener is registered for all properties.
  283        * <p>
  284        * A <code>PropertyChangeEvent</code> will get fired in response to setting
  285        * a bound property, e.g. <code>setFont</code>, <code>setBackground</code>,
  286        * or <code>setForeground</code>.
  287        * Note that if the current component is inheriting its foreground,
  288        * background, or font from its container, then no event will be
  289        * fired in response to a change in the inherited property.
  290        *
  291        * @param listener  The <code>PropertyChangeListener</code> to be added
  292        *
  293        * @see Action#addPropertyChangeListener
  294        */
  295       public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
  296           if (changeSupport == null) {
  297               changeSupport = new SwingPropertyChangeSupport(this);
  298           }
  299           changeSupport.addPropertyChangeListener(listener);
  300       }
  301   
  302   
  303       /**
  304        * Removes a <code>PropertyChangeListener</code> from the listener list.
  305        * This removes a <code>PropertyChangeListener</code> that was registered
  306        * for all properties.
  307        *
  308        * @param listener  the <code>PropertyChangeListener</code> to be removed
  309        *
  310        * @see Action#removePropertyChangeListener
  311        */
  312       public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
  313           if (changeSupport == null) {
  314               return;
  315           }
  316           changeSupport.removePropertyChangeListener(listener);
  317       }
  318   
  319   
  320       /**
  321        * Returns an array of all the <code>PropertyChangeListener</code>s added
  322        * to this AbstractAction with addPropertyChangeListener().
  323        *
  324        * @return all of the <code>PropertyChangeListener</code>s added or an empty
  325        *         array if no listeners have been added
  326        * @since 1.4
  327        */
  328       public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
  329           if (changeSupport == null) {
  330               return new PropertyChangeListener[0];
  331           }
  332           return changeSupport.getPropertyChangeListeners();
  333       }
  334   
  335   
  336       /**
  337        * Clones the abstract action. This gives the clone
  338        * its own copy of the key/value list,
  339        * which is not handled for you by <code>Object.clone()</code>.
  340        **/
  341   
  342       protected Object clone() throws CloneNotSupportedException {
  343           AbstractAction newAction = (AbstractAction)super.clone();
  344           synchronized(this) {
  345               if (arrayTable != null) {
  346                   newAction.arrayTable = (ArrayTable)arrayTable.clone();
  347               }
  348           }
  349           return newAction;
  350       }
  351   
  352       private void writeObject(ObjectOutputStream s) throws IOException {
  353           // Store the default fields
  354           s.defaultWriteObject();
  355   
  356           // And the keys
  357           ArrayTable.writeArrayTable(s, arrayTable);
  358       }
  359   
  360       private void readObject(ObjectInputStream s) throws ClassNotFoundException,
  361           IOException {
  362           s.defaultReadObject();
  363           for (int counter = s.readInt() - 1; counter >= 0; counter--) {
  364               putValue((String)s.readObject(), s.readObject());
  365           }
  366       }
  367   }

Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]