/* * @(#)AbstractAction.java 1.51 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.swing; import java.awt.*; import java.awt.event.*; import java.beans.*; import java.util.Hashtable; import java.util.Enumeration; import java.io.Serializable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import javax.swing.event.SwingPropertyChangeSupport; /** * This class provides default implementations for the JFC Action * interface. Standard behaviors like the get and set methods for * Action object properties (icon, text, and enabled) are defined * here. The developer need only subclass this abstract class and * define the actionPerformed method. *

* Warning: * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeansTM * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. * * @version 1.51 12/19/03 * @author Georges Saab * @see Action */ public abstract class AbstractAction implements Action, Cloneable, Serializable { /** * Specifies whether action is enabled; the default is true. */ protected boolean enabled = true; /** * Contains the array of key bindings. */ private transient ArrayTable arrayTable; /** * Defines an Action object with a default * description string and default icon. */ public AbstractAction() { } /** * Defines an Action object with the specified * description string and a default icon. */ public AbstractAction(String name) { putValue(Action.NAME, name); } /** * Defines an Action object with the specified * description string and a the specified icon. */ public AbstractAction(String name, Icon icon) { this(name); putValue(Action.SMALL_ICON, icon); } /** * Gets the Object associated with the specified key. * * @param key a string containing the specified key * @return the binding Object stored with this key; if there * are no keys, it will return null * @see Action#getValue */ public Object getValue(String key) { if (arrayTable == null) { return null; } return arrayTable.get(key); } /** * Sets the Value associated with the specified key. * * @param key the String that identifies the stored object * @param newValue the Object to store using this key * @see Action#putValue */ public void putValue(String key, Object newValue) { Object oldValue = null; if (arrayTable == null) { arrayTable = new ArrayTable(); } if (arrayTable.containsKey(key)) oldValue = arrayTable.get(key); // Remove the entry for key if newValue is null // else put in the newValue for key. if (newValue == null) { arrayTable.remove(key); } else { arrayTable.put(key,newValue); } firePropertyChange(key, oldValue, newValue); } /** * Returns true if the action is enabled. * * @return true if the action is enabled, false otherwise * @see Action#isEnabled */ public boolean isEnabled() { return enabled; } /** * Enables or disables the action. * * @param newValue true to enable the action, false to * disable it * @see Action#setEnabled */ public void setEnabled(boolean newValue) { boolean oldValue = this.enabled; if (oldValue != newValue) { this.enabled = newValue; firePropertyChange("enabled", Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); } } /** * Returns an array of Objects which are keys for * which values have been set for this AbstractAction, * or null if no keys have values set. * @return an array of key objects, or null if no * keys have values set * @since 1.3 */ public Object[] getKeys() { if (arrayTable == null) { return null; } Object[] keys = new Object[arrayTable.size()]; arrayTable.getKeys(keys); return keys; } /** * If any PropertyChangeListeners have been registered, the * changeSupport field describes them. */ protected SwingPropertyChangeSupport changeSupport; /** * Supports reporting bound property changes. This method can be called * when a bound property has changed and it will send the appropriate * PropertyChangeEvent to any registered * PropertyChangeListeners. */ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { if (changeSupport == null || (oldValue != null && newValue != null && oldValue.equals(newValue))) { return; } changeSupport.firePropertyChange(propertyName, oldValue, newValue); } /** * Adds a PropertyChangeListener to the listener list. * The listener is registered for all properties. *

* A PropertyChangeEvent will get fired in response to setting * a bound property, e.g. setFont, setBackground, * or setForeground. * Note that if the current component is inheriting its foreground, * background, or font from its container, then no event will be * fired in response to a change in the inherited property. * * @param listener The PropertyChangeListener to be added * * @see Action#addPropertyChangeListener */ public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { if (changeSupport == null) { changeSupport = new SwingPropertyChangeSupport(this); } changeSupport.addPropertyChangeListener(listener); } /** * Removes a PropertyChangeListener from the listener list. * This removes a PropertyChangeListener that was registered * for all properties. * * @param listener the PropertyChangeListener to be removed * * @see Action#removePropertyChangeListener */ public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { if (changeSupport == null) { return; } changeSupport.removePropertyChangeListener(listener); } /** * Returns an array of all the PropertyChangeListeners added * to this AbstractAction with addPropertyChangeListener(). * * @return all of the PropertyChangeListeners added or an empty * array if no listeners have been added * @since 1.4 */ public synchronized PropertyChangeListener[] getPropertyChangeListeners() { if (changeSupport == null) { return new PropertyChangeListener[0]; } return changeSupport.getPropertyChangeListeners(); } /** * Clones the abstract action. This gives the clone * its own copy of the key/value list, * which is not handled for you by Object.clone(). **/ protected Object clone() throws CloneNotSupportedException { AbstractAction newAction = (AbstractAction)super.clone(); synchronized(this) { if (arrayTable != null) { newAction.arrayTable = (ArrayTable)arrayTable.clone(); } } return newAction; } private void writeObject(ObjectOutputStream s) throws IOException { // Store the default fields s.defaultWriteObject(); // And the keys ArrayTable.writeArrayTable(s, arrayTable); } private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { s.defaultReadObject(); for (int counter = s.readInt() - 1; counter >= 0; counter--) { putValue((String)s.readObject(), s.readObject()); } } }