FileDocCategorySizeDatePackage
ActionPropertyChangeListener.javaAPI DocJava SE 6 API4449Tue Jun 10 00:26:34 BST 2008javax.swing

ActionPropertyChangeListener.java

/*
 * @(#)ActionPropertyChangeListener.java	1.15 06/02/09
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package javax.swing;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;

/**
 * A package-private PropertyChangeListener which listens for
 * property changes on an Action and updates the properties
 * of an ActionEvent source.
 * <p>
 * Subclasses must override the actionPropertyChanged method, 
 * which is invoked from the propertyChange method as long as
 * the target is still valid.
 * </p>
 * <p>
 * WARNING WARNING WARNING WARNING WARNING WARNING:<br>
 * Do NOT create an annonymous inner class that extends this!  If you do
 * a strong reference will be held to the containing class, which in most
 * cases defeats the purpose of this class.
 *
 * @param T the type of JComponent the underlying Action is attached to
 *
 * @version 1.15 02/09/06
 * @author Georges Saab
 * @see AbstractButton
 */
abstract class ActionPropertyChangeListener<T extends JComponent>
        implements PropertyChangeListener, Serializable {
    private static ReferenceQueue<JComponent> queue;

    // WeakReference's aren't serializable.
    private transient OwnedWeakReference<T> target;
    // The Component's that reference an Action do so through a strong
    // reference, so that there is no need to check for serialized.
    private Action action;

    private static ReferenceQueue<JComponent> getQueue() {
        synchronized(ActionPropertyChangeListener.class) {
            if (queue == null) {
                queue = new ReferenceQueue<JComponent>();
            }
        }
        return queue;
    }

    public ActionPropertyChangeListener(T c, Action a) {
	super();
	setTarget(c);
	this.action = a;
    }

    /**
     * PropertyChangeListener method.  If the target has been gc'ed this
     * will remove the <code>PropertyChangeListener</code> from the Action,
     * otherwise this will invoke actionPropertyChanged.
     */
    public final void propertyChange(PropertyChangeEvent e) {
        T target = getTarget();
        if (target == null) {
            getAction().removePropertyChangeListener(this);
        } else {
            actionPropertyChanged(target, getAction(), e);
        }
    }

    /**
     * Invoked when a property changes on the Action and the target
     * still exists.
     */
    protected abstract void actionPropertyChanged(T target, Action action,
                                                  PropertyChangeEvent e);
    
    private void setTarget(T c) {
        ReferenceQueue<JComponent> queue = getQueue();
	// Check to see whether any old buttons have
	// been enqueued for GC.  If so, look up their
	// PCL instance and remove it from its Action.
	OwnedWeakReference r;
        while ((r = (OwnedWeakReference)queue.poll()) != null) {
            ActionPropertyChangeListener oldPCL = r.getOwner();
	    Action oldAction = oldPCL.getAction();
	    if (oldAction!=null) {
	        oldAction.removePropertyChangeListener(oldPCL);
	    }
	}
        this.target = new OwnedWeakReference<T>(c, queue, this);
    }
    
    public T getTarget() {
        if (target == null) {
            // Will only happen if serialized and real target was null
            return null;
        }
        return this.target.get();
    }

    public Action getAction() {
	  return action;
    }

    private void writeObject(ObjectOutputStream s) throws IOException {
        s.defaultWriteObject();
        s.writeObject(getTarget());
    }

    @SuppressWarnings("unchecked")
    private void readObject(ObjectInputStream s) 
                     throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        T target = (T)s.readObject();
        if (target != null) {
            setTarget(target);
        }
    }


    private static class OwnedWeakReference<U extends JComponent> extends
                              WeakReference<U> {
        private ActionPropertyChangeListener owner;

        OwnedWeakReference(U target, ReferenceQueue<? super U> queue,
                           ActionPropertyChangeListener owner) {
	    super(target, queue);
	    this.owner = owner;
	}

        public ActionPropertyChangeListener getOwner() {
	    return owner;
	}
    }
}