001    /* AbstractAction.java --
002       Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing;
040    
041    import java.beans.PropertyChangeEvent;
042    import java.beans.PropertyChangeListener;
043    import java.io.Serializable;
044    import java.util.HashMap;
045    
046    import javax.swing.event.SwingPropertyChangeSupport;
047    
048    /**
049     * A base class for implementing the {@link Action} interface.
050     * 
051     * @author Andrew Selkirk
052     */
053    public abstract class AbstractAction
054      implements Action, Cloneable, Serializable
055    {
056      private static final long serialVersionUID = -6803159439231523484L;
057    
058      /**
059       * A flag that indicates whether or not the action is enabled.
060       */
061      protected boolean enabled = true;
062      
063      /**
064       * Provides support for property change event notification. 
065       */
066      protected SwingPropertyChangeSupport changeSupport =
067        new SwingPropertyChangeSupport(this);
068    
069      /**
070       * store
071       */
072      private transient HashMap store = new HashMap();
073    
074      /**
075       * Creates a new action with no properties set.
076       */
077      public AbstractAction()
078      {
079        // Nothing to do.
080      }
081    
082      /**
083       * Creates a new action with the specified name.  The name is stored as a 
084       * property with the key {@link Action#NAME}, and no other properties are
085       * initialised.
086       *
087       * @param name  the name (<code>null</code> permitted).
088       */
089      public AbstractAction(String name)
090      {
091        putValue(NAME, name);
092      }
093    
094      /**
095       * Creates a new action with the specified name and icon.  The name is stored
096       * as a property with the key {@link Action#NAME}, the icon is stored as a
097       * property with the key {@link Action#SMALL_ICON}, and no other properties 
098       * are initialised.
099       *
100       * @param name  the name (<code>null</code> permitted).
101       * @param icon  the icon (<code>null</code> permitted).
102       */
103      public AbstractAction(String name, Icon icon)
104      {
105        putValue(NAME, name);
106        putValue(SMALL_ICON, icon);
107      }
108    
109      /**
110       * Returns a clone of the action.
111       *
112       * @return A clone of the action.
113       *
114       * @exception CloneNotSupportedException if there is a problem cloning the
115       *            action.
116       */
117      protected Object clone() throws CloneNotSupportedException
118      {
119        AbstractAction copy = (AbstractAction) super.clone();
120        copy.store = (HashMap) store.clone();
121        return copy;
122      }
123    
124      /**
125       * Returns the value associated with the specified key.
126       * 
127       * @param key  the key (not <code>null</code>).
128       * 
129       * @return The value associated with the specified key, or 
130       *         <code>null</code> if the key is not found.
131       *         
132       * @see #putValue(String, Object)
133       */
134      public Object getValue(String key)
135      {
136        return store.get(key);
137      }
138    
139      /**
140       * Sets the value associated with the specified key and sends a 
141       * {@link java.beans.PropertyChangeEvent} to all registered listeners.  
142       * The standard keys are: 
143       * <ul>
144       * <li>{@link #NAME}</li>
145       * <li>{@link #SHORT_DESCRIPTION}</li> 
146       * <li>{@link #LONG_DESCRIPTION}</li>
147       * <li>{@link #SMALL_ICON}</li> 
148       * <li>{@link #ACTION_COMMAND_KEY}</li>
149       * <li>{@link #ACCELERATOR_KEY}</li> 
150       * <li>{@link #MNEMONIC_KEY}</li>
151       * </ul>
152       * Any existing value associated with the key will be overwritten.
153       * 
154       * @param key  the key (not <code>null</code>).
155       * @param value  the value (<code>null</code> permitted).
156       */
157      public void putValue(String key, Object value)
158      {
159        Object old = getValue(key);
160        if ((old == null && value != null) || (old != null && !old.equals(value)))
161        {
162          store.put(key, value);
163          firePropertyChange(key, old, value);
164        }
165      }
166    
167      /**
168       * Returns the flag that indicates whether or not the action is enabled.
169       *
170       * @return The flag.
171       * 
172       * @see #setEnabled(boolean)
173       */
174      public boolean isEnabled()
175      {
176        return enabled;
177      }
178    
179      /**
180       * Sets the flag that indicates whether or not the action is enabled and, if
181       * the value of the flag changed from the previous setting, sends a 
182       * {@link java.beans.PropertyChangeEvent} to all registered listeners (using 
183       * the property name 'enabled').
184       *
185       * @param enabled  the new flag value.
186       * 
187       * @see #isEnabled()
188       */
189      public void setEnabled(boolean enabled)
190      {
191        if (enabled != this.enabled)
192        {
193          this.enabled = enabled;
194          firePropertyChange("enabled", !this.enabled, this.enabled);
195        }
196      }
197    
198      /**
199       * Returns an array of the keys for the property values that have been 
200       * defined via the {@link #putValue(String, Object)} method (or the class
201       * constructor).
202       * 
203       * @return An array of keys.
204       */
205      public Object[] getKeys()
206      {
207        return store.keySet().toArray();
208      }
209    
210      /**
211       * Sends a {@link PropertyChangeEvent} for the named property to all 
212       * registered listeners.
213       *
214       * @param propertyName  the property name.
215       * @param oldValue  the old value of the property.
216       * @param newValue  the new value of the property.
217       */
218      protected void firePropertyChange(String propertyName, Object oldValue,
219                                        Object newValue)
220      {
221        changeSupport.firePropertyChange(propertyName, oldValue, newValue);
222      }
223      
224      /**
225       * Sends a {@link PropertyChangeEvent} for the named property to all
226       * registered listeners.  This private method is called by the 
227       * {@link #setEnabled(boolean)} method.
228       *
229       * @param propertyName  the property name.
230       * @param oldValue  the old value of the property.
231       * @param newValue  the new value of the property.
232       */
233      private void firePropertyChange(String propertyName, boolean oldValue, 
234                                      boolean newValue)
235      {
236        changeSupport.firePropertyChange(propertyName, oldValue, newValue);
237      }
238    
239      /**
240       * Registers a listener to receive {@link PropertyChangeEvent} notifications
241       * from this action.
242       *
243       * @param listener the listener.
244       * 
245       * @see #removePropertyChangeListener(PropertyChangeListener)
246       */
247      public void addPropertyChangeListener(PropertyChangeListener listener)
248      {
249        changeSupport.addPropertyChangeListener(listener);
250      }
251    
252      /**
253       * Deregisters a listener so that it no longer receives 
254       * {@link PropertyChangeEvent} notifications from this action.
255       *
256       * @param listener the listener.
257       * 
258       * @see #addPropertyChangeListener(PropertyChangeListener)
259       */
260      public void removePropertyChangeListener(PropertyChangeListener listener)
261      {
262        changeSupport.removePropertyChangeListener(listener);
263      }
264    
265      /**
266       * Returns all registered listeners.
267       *
268       * @return An array of listeners.
269       * 
270       * @since 1.4
271       */
272      public PropertyChangeListener[] getPropertyChangeListeners()
273      {
274        return changeSupport.getPropertyChangeListeners();
275      }
276    }