Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/swing/AbstractAction.java
38829 views
/*1* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package javax.swing;2526import java.awt.*;27import java.awt.event.*;28import java.beans.*;29import java.util.Hashtable;30import java.util.Enumeration;31import java.io.Serializable;32import java.io.IOException;33import java.io.ObjectInputStream;34import java.io.ObjectOutputStream;35import java.security.AccessController;36import javax.swing.event.SwingPropertyChangeSupport;37import sun.security.action.GetPropertyAction;3839/**40* This class provides default implementations for the JFC <code>Action</code>41* interface. Standard behaviors like the get and set methods for42* <code>Action</code> object properties (icon, text, and enabled) are defined43* here. The developer need only subclass this abstract class and44* define the <code>actionPerformed</code> method.45* <p>46* <strong>Warning:</strong>47* Serialized objects of this class will not be compatible with48* future Swing releases. The current serialization support is49* appropriate for short term storage or RMI between applications running50* the same version of Swing. As of 1.4, support for long term storage51* of all JavaBeans™52* has been added to the <code>java.beans</code> package.53* Please see {@link java.beans.XMLEncoder}.54*55* @author Georges Saab56* @see Action57*/58public abstract class AbstractAction implements Action, Cloneable, Serializable59{60/**61* Whether or not actions should reconfigure all properties on null.62*/63private static Boolean RECONFIGURE_ON_NULL;6465/**66* Specifies whether action is enabled; the default is true.67*/68protected boolean enabled = true;697071/**72* Contains the array of key bindings.73*/74private transient ArrayTable arrayTable;7576/**77* Whether or not to reconfigure all action properties from the78* specified event.79*/80static boolean shouldReconfigure(PropertyChangeEvent e) {81if (e.getPropertyName() == null) {82synchronized(AbstractAction.class) {83if (RECONFIGURE_ON_NULL == null) {84RECONFIGURE_ON_NULL = Boolean.valueOf(85AccessController.doPrivileged(new GetPropertyAction(86"swing.actions.reconfigureOnNull", "false")));87}88return RECONFIGURE_ON_NULL;89}90}91return false;92}9394/**95* Sets the enabled state of a component from an Action.96*97* @param c the Component to set the enabled state on98* @param a the Action to set the enabled state from, may be null99*/100static void setEnabledFromAction(JComponent c, Action a) {101c.setEnabled((a != null) ? a.isEnabled() : true);102}103104/**105* Sets the tooltip text of a component from an Action.106*107* @param c the Component to set the tooltip text on108* @param a the Action to set the tooltip text from, may be null109*/110static void setToolTipTextFromAction(JComponent c, Action a) {111c.setToolTipText(a != null ?112(String)a.getValue(Action.SHORT_DESCRIPTION) : null);113}114115static boolean hasSelectedKey(Action a) {116return (a != null && a.getValue(Action.SELECTED_KEY) != null);117}118119static boolean isSelected(Action a) {120return Boolean.TRUE.equals(a.getValue(Action.SELECTED_KEY));121}122123124125/**126* Creates an {@code Action}.127*/128public AbstractAction() {129}130131/**132* Creates an {@code Action} with the specified name.133*134* @param name the name ({@code Action.NAME}) for the action; a135* value of {@code null} is ignored136*/137public AbstractAction(String name) {138putValue(Action.NAME, name);139}140141/**142* Creates an {@code Action} with the specified name and small icon.143*144* @param name the name ({@code Action.NAME}) for the action; a145* value of {@code null} is ignored146* @param icon the small icon ({@code Action.SMALL_ICON}) for the action; a147* value of {@code null} is ignored148*/149public AbstractAction(String name, Icon icon) {150this(name);151putValue(Action.SMALL_ICON, icon);152}153154/**155* Gets the <code>Object</code> associated with the specified key.156*157* @param key a string containing the specified <code>key</code>158* @return the binding <code>Object</code> stored with this key; if there159* are no keys, it will return <code>null</code>160* @see Action#getValue161*/162public Object getValue(String key) {163if (key == "enabled") {164return enabled;165}166if (arrayTable == null) {167return null;168}169return arrayTable.get(key);170}171172/**173* Sets the <code>Value</code> associated with the specified key.174*175* @param key the <code>String</code> that identifies the stored object176* @param newValue the <code>Object</code> to store using this key177* @see Action#putValue178*/179public void putValue(String key, Object newValue) {180Object oldValue = null;181if (key == "enabled") {182// Treat putValue("enabled") the same way as a call to setEnabled.183// If we don't do this it means the two may get out of sync, and a184// bogus property change notification would be sent.185//186// To avoid dependencies between putValue & setEnabled this187// directly changes enabled. If we instead called setEnabled188// to change enabled, it would be possible for stack189// overflow in the case where a developer implemented setEnabled190// in terms of putValue.191if (newValue == null || !(newValue instanceof Boolean)) {192newValue = false;193}194oldValue = enabled;195enabled = (Boolean)newValue;196} else {197if (arrayTable == null) {198arrayTable = new ArrayTable();199}200if (arrayTable.containsKey(key))201oldValue = arrayTable.get(key);202// Remove the entry for key if newValue is null203// else put in the newValue for key.204if (newValue == null) {205arrayTable.remove(key);206} else {207arrayTable.put(key,newValue);208}209}210firePropertyChange(key, oldValue, newValue);211}212213/**214* Returns true if the action is enabled.215*216* @return true if the action is enabled, false otherwise217* @see Action#isEnabled218*/219public boolean isEnabled() {220return enabled;221}222223/**224* Sets whether the {@code Action} is enabled. The default is {@code true}.225*226* @param newValue {@code true} to enable the action, {@code false} to227* disable it228* @see Action#setEnabled229*/230public void setEnabled(boolean newValue) {231boolean oldValue = this.enabled;232233if (oldValue != newValue) {234this.enabled = newValue;235firePropertyChange("enabled",236Boolean.valueOf(oldValue), Boolean.valueOf(newValue));237}238}239240241/**242* Returns an array of <code>Object</code>s which are keys for243* which values have been set for this <code>AbstractAction</code>,244* or <code>null</code> if no keys have values set.245* @return an array of key objects, or <code>null</code> if no246* keys have values set247* @since 1.3248*/249public Object[] getKeys() {250if (arrayTable == null) {251return null;252}253Object[] keys = new Object[arrayTable.size()];254arrayTable.getKeys(keys);255return keys;256}257258/**259* If any <code>PropertyChangeListeners</code> have been registered, the260* <code>changeSupport</code> field describes them.261*/262protected SwingPropertyChangeSupport changeSupport;263264/**265* Supports reporting bound property changes. This method can be called266* when a bound property has changed and it will send the appropriate267* <code>PropertyChangeEvent</code> to any registered268* <code>PropertyChangeListeners</code>.269*/270protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {271if (changeSupport == null ||272(oldValue != null && newValue != null && oldValue.equals(newValue))) {273return;274}275changeSupport.firePropertyChange(propertyName, oldValue, newValue);276}277278279/**280* Adds a <code>PropertyChangeListener</code> to the listener list.281* The listener is registered for all properties.282* <p>283* A <code>PropertyChangeEvent</code> will get fired in response to setting284* a bound property, e.g. <code>setFont</code>, <code>setBackground</code>,285* or <code>setForeground</code>.286* Note that if the current component is inheriting its foreground,287* background, or font from its container, then no event will be288* fired in response to a change in the inherited property.289*290* @param listener The <code>PropertyChangeListener</code> to be added291*292* @see Action#addPropertyChangeListener293*/294public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {295if (changeSupport == null) {296changeSupport = new SwingPropertyChangeSupport(this);297}298changeSupport.addPropertyChangeListener(listener);299}300301302/**303* Removes a <code>PropertyChangeListener</code> from the listener list.304* This removes a <code>PropertyChangeListener</code> that was registered305* for all properties.306*307* @param listener the <code>PropertyChangeListener</code> to be removed308*309* @see Action#removePropertyChangeListener310*/311public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {312if (changeSupport == null) {313return;314}315changeSupport.removePropertyChangeListener(listener);316}317318319/**320* Returns an array of all the <code>PropertyChangeListener</code>s added321* to this AbstractAction with addPropertyChangeListener().322*323* @return all of the <code>PropertyChangeListener</code>s added or an empty324* array if no listeners have been added325* @since 1.4326*/327public synchronized PropertyChangeListener[] getPropertyChangeListeners() {328if (changeSupport == null) {329return new PropertyChangeListener[0];330}331return changeSupport.getPropertyChangeListeners();332}333334335/**336* Clones the abstract action. This gives the clone337* its own copy of the key/value list,338* which is not handled for you by <code>Object.clone()</code>.339**/340341protected Object clone() throws CloneNotSupportedException {342AbstractAction newAction = (AbstractAction)super.clone();343synchronized(this) {344if (arrayTable != null) {345newAction.arrayTable = (ArrayTable)arrayTable.clone();346}347}348return newAction;349}350351private void writeObject(ObjectOutputStream s) throws IOException {352// Store the default fields353s.defaultWriteObject();354355// And the keys356ArrayTable.writeArrayTable(s, arrayTable);357}358359private void readObject(ObjectInputStream s) throws ClassNotFoundException,360IOException {361s.defaultReadObject();362for (int counter = s.readInt() - 1; counter >= 0; counter--) {363putValue((String)s.readObject(), s.readObject());364}365}366}367368369