0N/A/*
2362N/A * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage javax.swing;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.*;
0N/Aimport java.beans.*;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.Enumeration;
0N/Aimport java.io.Serializable;
0N/Aimport java.io.IOException;
0N/Aimport java.io.ObjectInputStream;
0N/Aimport java.io.ObjectOutputStream;
0N/Aimport java.security.AccessController;
0N/Aimport javax.swing.event.SwingPropertyChangeSupport;
0N/Aimport sun.security.action.GetPropertyAction;
0N/A
0N/A/**
0N/A * This class provides default implementations for the JFC <code>Action</code>
0N/A * interface. Standard behaviors like the get and set methods for
0N/A * <code>Action</code> object properties (icon, text, and enabled) are defined
0N/A * here. The developer need only subclass this abstract class and
0N/A * define the <code>actionPerformed</code> method.
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A *
0N/A * @author Georges Saab
0N/A * @see Action
0N/A */
0N/Apublic abstract class AbstractAction implements Action, Cloneable, Serializable
0N/A{
0N/A /**
0N/A * Whether or not actions should reconfigure all properties on null.
0N/A */
0N/A private static Boolean RECONFIGURE_ON_NULL;
0N/A
0N/A /**
0N/A * Specifies whether action is enabled; the default is true.
0N/A */
0N/A protected boolean enabled = true;
0N/A
0N/A
0N/A /**
0N/A * Contains the array of key bindings.
0N/A */
0N/A private transient ArrayTable arrayTable;
0N/A
0N/A /**
0N/A * Whether or not to reconfigure all action properties from the
0N/A * specified event.
0N/A */
0N/A static boolean shouldReconfigure(PropertyChangeEvent e) {
0N/A if (e.getPropertyName() == null) {
0N/A synchronized(AbstractAction.class) {
0N/A if (RECONFIGURE_ON_NULL == null) {
0N/A RECONFIGURE_ON_NULL = Boolean.valueOf(
0N/A AccessController.doPrivileged(new GetPropertyAction(
0N/A "swing.actions.reconfigureOnNull", "false")));
0N/A }
0N/A return RECONFIGURE_ON_NULL;
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Sets the enabled state of a component from an Action.
0N/A *
0N/A * @param c the Component to set the enabled state on
0N/A * @param a the Action to set the enabled state from, may be null
0N/A */
0N/A static void setEnabledFromAction(JComponent c, Action a) {
0N/A c.setEnabled((a != null) ? a.isEnabled() : true);
0N/A }
0N/A
0N/A /**
0N/A * Sets the tooltip text of a component from an Action.
0N/A *
0N/A * @param c the Component to set the tooltip text on
0N/A * @param a the Action to set the tooltip text from, may be null
0N/A */
0N/A static void setToolTipTextFromAction(JComponent c, Action a) {
0N/A c.setToolTipText(a != null ?
0N/A (String)a.getValue(Action.SHORT_DESCRIPTION) : null);
0N/A }
0N/A
0N/A static boolean hasSelectedKey(Action a) {
0N/A return (a != null && a.getValue(Action.SELECTED_KEY) != null);
0N/A }
0N/A
0N/A static boolean isSelected(Action a) {
0N/A return Boolean.TRUE.equals(a.getValue(Action.SELECTED_KEY));
0N/A }
0N/A
0N/A
0N/A
0N/A /**
0N/A * Creates an {@code Action}.
0N/A */
0N/A public AbstractAction() {
0N/A }
0N/A
0N/A /**
0N/A * Creates an {@code Action} with the specified name.
0N/A *
0N/A * @param name the name ({@code Action.NAME}) for the action; a
0N/A * value of {@code null} is ignored
0N/A */
0N/A public AbstractAction(String name) {
0N/A putValue(Action.NAME, name);
0N/A }
0N/A
0N/A /**
0N/A * Creates an {@code Action} with the specified name and small icon.
0N/A *
0N/A * @param name the name ({@code Action.NAME}) for the action; a
0N/A * value of {@code null} is ignored
0N/A * @param icon the small icon ({@code Action.SMALL_ICON}) for the action; a
0N/A * value of {@code null} is ignored
0N/A */
0N/A public AbstractAction(String name, Icon icon) {
0N/A this(name);
0N/A putValue(Action.SMALL_ICON, icon);
0N/A }
0N/A
0N/A /**
0N/A * Gets the <code>Object</code> associated with the specified key.
0N/A *
0N/A * @param key a string containing the specified <code>key</code>
0N/A * @return the binding <code>Object</code> stored with this key; if there
0N/A * are no keys, it will return <code>null</code>
0N/A * @see Action#getValue
0N/A */
0N/A public Object getValue(String key) {
0N/A if (key == "enabled") {
0N/A return enabled;
0N/A }
0N/A if (arrayTable == null) {
0N/A return null;
0N/A }
0N/A return arrayTable.get(key);
0N/A }
0N/A
0N/A /**
0N/A * Sets the <code>Value</code> associated with the specified key.
0N/A *
0N/A * @param key the <code>String</code> that identifies the stored object
0N/A * @param newValue the <code>Object</code> to store using this key
0N/A * @see Action#putValue
0N/A */
0N/A public void putValue(String key, Object newValue) {
0N/A Object oldValue = null;
0N/A if (key == "enabled") {
0N/A // Treat putValue("enabled") the same way as a call to setEnabled.
0N/A // If we don't do this it means the two may get out of sync, and a
0N/A // bogus property change notification would be sent.
0N/A //
0N/A // To avoid dependencies between putValue & setEnabled this
0N/A // directly changes enabled. If we instead called setEnabled
0N/A // to change enabled, it would be possible for stack
0N/A // overflow in the case where a developer implemented setEnabled
0N/A // in terms of putValue.
0N/A if (newValue == null || !(newValue instanceof Boolean)) {
0N/A newValue = false;
0N/A }
0N/A oldValue = enabled;
0N/A enabled = (Boolean)newValue;
0N/A } else {
0N/A if (arrayTable == null) {
0N/A arrayTable = new ArrayTable();
0N/A }
0N/A if (arrayTable.containsKey(key))
0N/A oldValue = arrayTable.get(key);
0N/A // Remove the entry for key if newValue is null
0N/A // else put in the newValue for key.
0N/A if (newValue == null) {
0N/A arrayTable.remove(key);
0N/A } else {
0N/A arrayTable.put(key,newValue);
0N/A }
0N/A }
0N/A firePropertyChange(key, oldValue, newValue);
0N/A }
0N/A
0N/A /**
0N/A * Returns true if the action is enabled.
0N/A *
0N/A * @return true if the action is enabled, false otherwise
0N/A * @see Action#isEnabled
0N/A */
0N/A public boolean isEnabled() {
0N/A return enabled;
0N/A }
0N/A
0N/A /**
0N/A * Sets whether the {@code Action} is enabled. The default is {@code true}.
0N/A *
0N/A * @param newValue {@code true} to enable the action, {@code false} to
0N/A * disable it
0N/A * @see Action#setEnabled
0N/A */
0N/A public void setEnabled(boolean newValue) {
0N/A boolean oldValue = this.enabled;
0N/A
0N/A if (oldValue != newValue) {
0N/A this.enabled = newValue;
0N/A firePropertyChange("enabled",
0N/A Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns an array of <code>Object</code>s which are keys for
0N/A * which values have been set for this <code>AbstractAction</code>,
0N/A * or <code>null</code> if no keys have values set.
0N/A * @return an array of key objects, or <code>null</code> if no
0N/A * keys have values set
0N/A * @since 1.3
0N/A */
0N/A public Object[] getKeys() {
0N/A if (arrayTable == null) {
0N/A return null;
0N/A }
0N/A Object[] keys = new Object[arrayTable.size()];
0N/A arrayTable.getKeys(keys);
0N/A return keys;
0N/A }
0N/A
0N/A /**
0N/A * If any <code>PropertyChangeListeners</code> have been registered, the
0N/A * <code>changeSupport</code> field describes them.
0N/A */
0N/A protected SwingPropertyChangeSupport changeSupport;
0N/A
0N/A /**
0N/A * Supports reporting bound property changes. This method can be called
0N/A * when a bound property has changed and it will send the appropriate
0N/A * <code>PropertyChangeEvent</code> to any registered
0N/A * <code>PropertyChangeListeners</code>.
0N/A */
0N/A protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
0N/A if (changeSupport == null ||
0N/A (oldValue != null && newValue != null && oldValue.equals(newValue))) {
0N/A return;
0N/A }
0N/A changeSupport.firePropertyChange(propertyName, oldValue, newValue);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Adds a <code>PropertyChangeListener</code> to the listener list.
0N/A * The listener is registered for all properties.
0N/A * <p>
0N/A * A <code>PropertyChangeEvent</code> will get fired in response to setting
0N/A * a bound property, e.g. <code>setFont</code>, <code>setBackground</code>,
0N/A * or <code>setForeground</code>.
0N/A * Note that if the current component is inheriting its foreground,
0N/A * background, or font from its container, then no event will be
0N/A * fired in response to a change in the inherited property.
0N/A *
0N/A * @param listener The <code>PropertyChangeListener</code> to be added
0N/A *
0N/A * @see Action#addPropertyChangeListener
0N/A */
0N/A public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
0N/A if (changeSupport == null) {
0N/A changeSupport = new SwingPropertyChangeSupport(this);
0N/A }
0N/A changeSupport.addPropertyChangeListener(listener);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Removes a <code>PropertyChangeListener</code> from the listener list.
0N/A * This removes a <code>PropertyChangeListener</code> that was registered
0N/A * for all properties.
0N/A *
0N/A * @param listener the <code>PropertyChangeListener</code> to be removed
0N/A *
0N/A * @see Action#removePropertyChangeListener
0N/A */
0N/A public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
0N/A if (changeSupport == null) {
0N/A return;
0N/A }
0N/A changeSupport.removePropertyChangeListener(listener);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns an array of all the <code>PropertyChangeListener</code>s added
0N/A * to this AbstractAction with addPropertyChangeListener().
0N/A *
0N/A * @return all of the <code>PropertyChangeListener</code>s added or an empty
0N/A * array if no listeners have been added
0N/A * @since 1.4
0N/A */
0N/A public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
0N/A if (changeSupport == null) {
0N/A return new PropertyChangeListener[0];
0N/A }
0N/A return changeSupport.getPropertyChangeListeners();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Clones the abstract action. This gives the clone
0N/A * its own copy of the key/value list,
0N/A * which is not handled for you by <code>Object.clone()</code>.
0N/A **/
0N/A
0N/A protected Object clone() throws CloneNotSupportedException {
0N/A AbstractAction newAction = (AbstractAction)super.clone();
0N/A synchronized(this) {
0N/A if (arrayTable != null) {
0N/A newAction.arrayTable = (ArrayTable)arrayTable.clone();
0N/A }
0N/A }
0N/A return newAction;
0N/A }
0N/A
0N/A private void writeObject(ObjectOutputStream s) throws IOException {
0N/A // Store the default fields
0N/A s.defaultWriteObject();
0N/A
0N/A // And the keys
0N/A ArrayTable.writeArrayTable(s, arrayTable);
0N/A }
0N/A
0N/A private void readObject(ObjectInputStream s) throws ClassNotFoundException,
0N/A IOException {
0N/A s.defaultReadObject();
0N/A for (int counter = s.readInt() - 1; counter >= 0; counter--) {
0N/A putValue((String)s.readObject(), s.readObject());
0N/A }
0N/A }
0N/A}