/*
 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
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.

Subclasses must override the actionPropertyChanged method, which is invoked from the propertyChange method as long as the target is still valid.

WARNING WARNING WARNING WARNING WARNING WARNING:
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.

Author:Georges Saab
Params:
  • T – the type of JComponent the underlying Action is attached to
See Also:
/** * 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 * * @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 PropertyChangeListener from the Action, otherwise this will invoke actionPropertyChanged.
/** * 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.
/** * 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; } } }