< prev index next >

src/java.desktop/share/classes/javax/swing/AbstractAction.java

Print this page




  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 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&trade;
  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  * @since 1.2
  59  */
  60 @SuppressWarnings("serial") // Same-version serialization only
  61 public abstract class AbstractAction implements Action, Cloneable, Serializable
  62 {
  63     /**
  64      * Whether or not actions should reconfigure all properties on null.
  65      */
  66     private static Boolean RECONFIGURE_ON_NULL;
  67 
  68     /**
  69      * Specifies whether action is enabled; the default is true.
  70      */
  71     protected boolean enabled = true;
  72 
  73 


 138      *        value of {@code null} is ignored
 139      */
 140     public AbstractAction(String name) {
 141         putValue(Action.NAME, name);
 142     }
 143 
 144     /**
 145      * Creates an {@code Action} with the specified name and small icon.
 146      *
 147      * @param name the name ({@code Action.NAME}) for the action; a
 148      *        value of {@code null} is ignored
 149      * @param icon the small icon ({@code Action.SMALL_ICON}) for the action; a
 150      *        value of {@code null} is ignored
 151      */
 152     public AbstractAction(String name, Icon icon) {
 153         this(name);
 154         putValue(Action.SMALL_ICON, icon);
 155     }
 156 
 157     /**
 158      * Gets the <code>Object</code> associated with the specified key.
 159      *
 160      * @param key a string containing the specified <code>key</code>
 161      * @return the binding <code>Object</code> stored with this key; if there
 162      *          are no keys, it will return <code>null</code>
 163      * @see Action#getValue
 164      */
 165     public Object getValue(String key) {
 166         if (key == "enabled") {
 167             return enabled;
 168         }
 169         if (arrayTable == null) {
 170             return null;
 171         }
 172         return arrayTable.get(key);
 173     }
 174 
 175     /**
 176      * Sets the <code>Value</code> associated with the specified key.
 177      *
 178      * @param key  the <code>String</code> that identifies the stored object
 179      * @param newValue the <code>Object</code> to store using this key
 180      * @see Action#putValue
 181      */
 182     public void putValue(String key, Object newValue) {
 183         Object oldValue = null;
 184         if (key == "enabled") {
 185             // Treat putValue("enabled") the same way as a call to setEnabled.
 186             // If we don't do this it means the two may get out of sync, and a
 187             // bogus property change notification would be sent.
 188             //
 189             // To avoid dependencies between putValue & setEnabled this
 190             // directly changes enabled. If we instead called setEnabled
 191             // to change enabled, it would be possible for stack
 192             // overflow in the case where a developer implemented setEnabled
 193             // in terms of putValue.
 194             if (newValue == null || !(newValue instanceof Boolean)) {
 195                 newValue = false;
 196             }
 197             oldValue = enabled;
 198             enabled = (Boolean)newValue;
 199         } else {


 225 
 226     /**
 227      * Sets whether the {@code Action} is enabled. The default is {@code true}.
 228      *
 229      * @param newValue  {@code true} to enable the action, {@code false} to
 230      *                  disable it
 231      * @see Action#setEnabled
 232      */
 233     public void setEnabled(boolean newValue) {
 234         boolean oldValue = this.enabled;
 235 
 236         if (oldValue != newValue) {
 237             this.enabled = newValue;
 238             firePropertyChange("enabled",
 239                                Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
 240         }
 241     }
 242 
 243 
 244     /**
 245      * Returns an array of <code>Object</code>s which are keys for
 246      * which values have been set for this <code>AbstractAction</code>,
 247      * or <code>null</code> if no keys have values set.
 248      * @return an array of key objects, or <code>null</code> if no
 249      *                  keys have values set
 250      * @since 1.3
 251      */
 252     public Object[] getKeys() {
 253         if (arrayTable == null) {
 254             return null;
 255         }
 256         Object[] keys = new Object[arrayTable.size()];
 257         arrayTable.getKeys(keys);
 258         return keys;
 259     }
 260 
 261     /**
 262      * If any <code>PropertyChangeListeners</code> have been registered, the
 263      * <code>changeSupport</code> field describes them.
 264      */
 265     protected SwingPropertyChangeSupport changeSupport;
 266 
 267     /**
 268      * Supports reporting bound property changes.  This method can be called
 269      * when a bound property has changed and it will send the appropriate
 270      * <code>PropertyChangeEvent</code> to any registered
 271      * <code>PropertyChangeListeners</code>.
 272      *
 273      * @param propertyName  the name of the property that has changed
 274      * @param oldValue  the old value of the property
 275      * @param newValue  the new value of the property
 276      */
 277     protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
 278         if (changeSupport == null ||
 279             (oldValue != null && newValue != null && oldValue.equals(newValue))) {
 280             return;
 281         }
 282         changeSupport.firePropertyChange(propertyName, oldValue, newValue);
 283     }
 284 
 285 
 286     /**
 287      * Adds a <code>PropertyChangeListener</code> to the listener list.
 288      * The listener is registered for all properties.
 289      * <p>
 290      * A <code>PropertyChangeEvent</code> will get fired in response to setting
 291      * a bound property, e.g. <code>setFont</code>, <code>setBackground</code>,
 292      * or <code>setForeground</code>.
 293      * Note that if the current component is inheriting its foreground,
 294      * background, or font from its container, then no event will be
 295      * fired in response to a change in the inherited property.
 296      *
 297      * @param listener  The <code>PropertyChangeListener</code> to be added
 298      *
 299      * @see Action#addPropertyChangeListener
 300      */
 301     public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
 302         if (changeSupport == null) {
 303             changeSupport = new SwingPropertyChangeSupport(this);
 304         }
 305         changeSupport.addPropertyChangeListener(listener);
 306     }
 307 
 308 
 309     /**
 310      * Removes a <code>PropertyChangeListener</code> from the listener list.
 311      * This removes a <code>PropertyChangeListener</code> that was registered
 312      * for all properties.
 313      *
 314      * @param listener  the <code>PropertyChangeListener</code> to be removed
 315      *
 316      * @see Action#removePropertyChangeListener
 317      */
 318     public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
 319         if (changeSupport == null) {
 320             return;
 321         }
 322         changeSupport.removePropertyChangeListener(listener);
 323     }
 324 
 325 
 326     /**
 327      * Returns an array of all the <code>PropertyChangeListener</code>s added
 328      * to this AbstractAction with addPropertyChangeListener().
 329      *
 330      * @return all of the <code>PropertyChangeListener</code>s added or an empty
 331      *         array if no listeners have been added
 332      * @since 1.4
 333      */
 334     public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
 335         if (changeSupport == null) {
 336             return new PropertyChangeListener[0];
 337         }
 338         return changeSupport.getPropertyChangeListeners();
 339     }
 340 
 341 
 342     /**
 343      * Clones the abstract action. This gives the clone
 344      * its own copy of the key/value list,
 345      * which is not handled for you by <code>Object.clone()</code>.
 346      **/
 347 
 348     protected Object clone() throws CloneNotSupportedException {
 349         AbstractAction newAction = (AbstractAction)super.clone();
 350         synchronized(this) {
 351             if (arrayTable != null) {
 352                 newAction.arrayTable = (ArrayTable)arrayTable.clone();
 353             }
 354         }
 355         return newAction;
 356     }
 357 
 358     private void writeObject(ObjectOutputStream s) throws IOException {
 359         // Store the default fields
 360         s.defaultWriteObject();
 361 
 362         // And the keys
 363         ArrayTable.writeArrayTable(s, arrayTable);
 364     }
 365 


  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 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}
  42  * interface. Standard behaviors like the get and set methods for
  43  * {@code Action} object properties (icon, text, and enabled) are defined
  44  * here. The developer need only subclass this abstract class and
  45  * define the {@code actionPerformed} 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&trade;
  53  * has been added to the {@code java.beans} package.
  54  * Please see {@link java.beans.XMLEncoder}.
  55  *
  56  * @author Georges Saab
  57  * @see Action
  58  * @since 1.2
  59  */
  60 @SuppressWarnings("serial") // Same-version serialization only
  61 public abstract class AbstractAction implements Action, Cloneable, Serializable
  62 {
  63     /**
  64      * Whether or not actions should reconfigure all properties on null.
  65      */
  66     private static Boolean RECONFIGURE_ON_NULL;
  67 
  68     /**
  69      * Specifies whether action is enabled; the default is true.
  70      */
  71     protected boolean enabled = true;
  72 
  73 


 138      *        value of {@code null} is ignored
 139      */
 140     public AbstractAction(String name) {
 141         putValue(Action.NAME, name);
 142     }
 143 
 144     /**
 145      * Creates an {@code Action} with the specified name and small icon.
 146      *
 147      * @param name the name ({@code Action.NAME}) for the action; a
 148      *        value of {@code null} is ignored
 149      * @param icon the small icon ({@code Action.SMALL_ICON}) for the action; a
 150      *        value of {@code null} is ignored
 151      */
 152     public AbstractAction(String name, Icon icon) {
 153         this(name);
 154         putValue(Action.SMALL_ICON, icon);
 155     }
 156 
 157     /**
 158      * Gets the {@code Object} associated with the specified key.
 159      *
 160      * @param key a string containing the specified {@code key}
 161      * @return the binding {@code Object} stored with this key; if there
 162      *          are no keys, it will return {@code null}
 163      * @see Action#getValue
 164      */
 165     public Object getValue(String key) {
 166         if (key == "enabled") {
 167             return enabled;
 168         }
 169         if (arrayTable == null) {
 170             return null;
 171         }
 172         return arrayTable.get(key);
 173     }
 174 
 175     /**
 176      * Sets the {@code Value} associated with the specified key.
 177      *
 178      * @param key  the {@code String} that identifies the stored object
 179      * @param newValue the {@code Object} to store using this key
 180      * @see Action#putValue
 181      */
 182     public void putValue(String key, Object newValue) {
 183         Object oldValue = null;
 184         if (key == "enabled") {
 185             // Treat putValue("enabled") the same way as a call to setEnabled.
 186             // If we don't do this it means the two may get out of sync, and a
 187             // bogus property change notification would be sent.
 188             //
 189             // To avoid dependencies between putValue & setEnabled this
 190             // directly changes enabled. If we instead called setEnabled
 191             // to change enabled, it would be possible for stack
 192             // overflow in the case where a developer implemented setEnabled
 193             // in terms of putValue.
 194             if (newValue == null || !(newValue instanceof Boolean)) {
 195                 newValue = false;
 196             }
 197             oldValue = enabled;
 198             enabled = (Boolean)newValue;
 199         } else {


 225 
 226     /**
 227      * Sets whether the {@code Action} is enabled. The default is {@code true}.
 228      *
 229      * @param newValue  {@code true} to enable the action, {@code false} to
 230      *                  disable it
 231      * @see Action#setEnabled
 232      */
 233     public void setEnabled(boolean newValue) {
 234         boolean oldValue = this.enabled;
 235 
 236         if (oldValue != newValue) {
 237             this.enabled = newValue;
 238             firePropertyChange("enabled",
 239                                Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
 240         }
 241     }
 242 
 243 
 244     /**
 245      * Returns an array of {@code Object}s which are keys for
 246      * which values have been set for this {@code AbstractAction},
 247      * or {@code null} if no keys have values set.
 248      * @return an array of key objects, or {@code null} if no
 249      *                  keys have values set
 250      * @since 1.3
 251      */
 252     public Object[] getKeys() {
 253         if (arrayTable == null) {
 254             return null;
 255         }
 256         Object[] keys = new Object[arrayTable.size()];
 257         arrayTable.getKeys(keys);
 258         return keys;
 259     }
 260 
 261     /**
 262      * If any {@code PropertyChangeListeners} have been registered, the
 263      * {@code changeSupport} field describes them.
 264      */
 265     protected SwingPropertyChangeSupport changeSupport;
 266 
 267     /**
 268      * Supports reporting bound property changes.  This method can be called
 269      * when a bound property has changed and it will send the appropriate
 270      * {@code PropertyChangeEvent} to any registered
 271      * {@code PropertyChangeListeners}.
 272      *
 273      * @param propertyName  the name of the property that has changed
 274      * @param oldValue  the old value of the property
 275      * @param newValue  the new value of the property
 276      */
 277     protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
 278         if (changeSupport == null ||
 279             (oldValue != null && newValue != null && oldValue.equals(newValue))) {
 280             return;
 281         }
 282         changeSupport.firePropertyChange(propertyName, oldValue, newValue);
 283     }
 284 
 285 
 286     /**
 287      * Adds a {@code PropertyChangeListener} to the listener list.
 288      * The listener is registered for all properties.
 289      * <p>
 290      * A {@code PropertyChangeEvent} will get fired in response to setting
 291      * a bound property, e.g. {@code setFont}, {@code setBackground},
 292      * or {@code setForeground}.
 293      * Note that if the current component is inheriting its foreground,
 294      * background, or font from its container, then no event will be
 295      * fired in response to a change in the inherited property.
 296      *
 297      * @param listener  The {@code PropertyChangeListener} to be added
 298      *
 299      * @see Action#addPropertyChangeListener
 300      */
 301     public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
 302         if (changeSupport == null) {
 303             changeSupport = new SwingPropertyChangeSupport(this);
 304         }
 305         changeSupport.addPropertyChangeListener(listener);
 306     }
 307 
 308 
 309     /**
 310      * Removes a {@code PropertyChangeListener} from the listener list.
 311      * This removes a {@code PropertyChangeListener} that was registered
 312      * for all properties.
 313      *
 314      * @param listener  the {@code PropertyChangeListener} to be removed
 315      *
 316      * @see Action#removePropertyChangeListener
 317      */
 318     public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
 319         if (changeSupport == null) {
 320             return;
 321         }
 322         changeSupport.removePropertyChangeListener(listener);
 323     }
 324 
 325 
 326     /**
 327      * Returns an array of all the {@code PropertyChangeListener}s added
 328      * to this AbstractAction with addPropertyChangeListener().
 329      *
 330      * @return all of the {@code PropertyChangeListener}s added or an empty
 331      *         array if no listeners have been added
 332      * @since 1.4
 333      */
 334     public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
 335         if (changeSupport == null) {
 336             return new PropertyChangeListener[0];
 337         }
 338         return changeSupport.getPropertyChangeListeners();
 339     }
 340 
 341 
 342     /**
 343      * Clones the abstract action. This gives the clone
 344      * its own copy of the key/value list,
 345      * which is not handled for you by {@code Object.clone()}.
 346      **/
 347 
 348     protected Object clone() throws CloneNotSupportedException {
 349         AbstractAction newAction = (AbstractAction)super.clone();
 350         synchronized(this) {
 351             if (arrayTable != null) {
 352                 newAction.arrayTable = (ArrayTable)arrayTable.clone();
 353             }
 354         }
 355         return newAction;
 356     }
 357 
 358     private void writeObject(ObjectOutputStream s) throws IOException {
 359         // Store the default fields
 360         s.defaultWriteObject();
 361 
 362         // And the keys
 363         ArrayTable.writeArrayTable(s, arrayTable);
 364     }
 365 
< prev index next >