1 /* 2 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing; 26 27 import java.beans.PropertyChangeEvent; 28 import java.beans.PropertyChangeListener; 29 import java.io.*; 30 import java.lang.ref.WeakReference; 31 import java.lang.ref.ReferenceQueue; 32 33 /** 34 * A package-private PropertyChangeListener which listens for 35 * property changes on an Action and updates the properties 36 * of an ActionEvent source. 37 * <p> 38 * Subclasses must override the actionPropertyChanged method, 39 * which is invoked from the propertyChange method as long as 40 * the target is still valid. 41 * </p> 42 * <p> 43 * WARNING WARNING WARNING WARNING WARNING WARNING:<br> 44 * Do NOT create an annonymous inner class that extends this! If you do 45 * a strong reference will be held to the containing class, which in most 46 * cases defeats the purpose of this class. 47 * 48 * @param T the type of JComponent the underlying Action is attached to 49 * 50 * @author Georges Saab 51 * @see AbstractButton 52 */ 53 abstract class ActionPropertyChangeListener<T extends JComponent> 54 implements PropertyChangeListener, Serializable { 55 private static ReferenceQueue<JComponent> queue; 56 57 // WeakReference's aren't serializable. 58 private transient OwnedWeakReference<T> target; 59 // The Component's that reference an Action do so through a strong 60 // reference, so that there is no need to check for serialized. 61 private Action action; 62 63 private static ReferenceQueue<JComponent> getQueue() { 64 synchronized(ActionPropertyChangeListener.class) { 65 if (queue == null) { 66 queue = new ReferenceQueue<JComponent>(); 67 } 68 } 69 return queue; 70 } 71 72 public ActionPropertyChangeListener(T c, Action a) { 73 super(); 74 setTarget(c); 75 this.action = a; 76 } 77 78 /** 79 * PropertyChangeListener method. If the target has been gc'ed this 80 * will remove the <code>PropertyChangeListener</code> from the Action, 81 * otherwise this will invoke actionPropertyChanged. 82 */ 83 public final void propertyChange(PropertyChangeEvent e) { 84 T target = getTarget(); 85 if (target == null) { 86 getAction().removePropertyChangeListener(this); 87 } else { 88 actionPropertyChanged(target, getAction(), e); 89 } 90 } 91 92 /** 93 * Invoked when a property changes on the Action and the target 94 * still exists. 95 */ 96 protected abstract void actionPropertyChanged(T target, Action action, 97 PropertyChangeEvent e); 98 99 private void setTarget(T c) { 100 ReferenceQueue<JComponent> queue = getQueue(); 101 // Check to see whether any old buttons have 102 // been enqueued for GC. If so, look up their 103 // PCL instance and remove it from its Action. 104 OwnedWeakReference<?> r; 105 while ((r = (OwnedWeakReference)queue.poll()) != null) { 106 ActionPropertyChangeListener<?> oldPCL = r.getOwner(); 107 Action oldAction = oldPCL.getAction(); 108 if (oldAction!=null) { 109 oldAction.removePropertyChangeListener(oldPCL); 110 } 111 } 112 this.target = new OwnedWeakReference<T>(c, queue, this); 113 } 114 115 public T getTarget() { 116 if (target == null) { 117 // Will only happen if serialized and real target was null 118 return null; 119 } 120 return this.target.get(); 121 } 122 123 public Action getAction() { 124 return action; 125 } 126 127 private void writeObject(ObjectOutputStream s) throws IOException { 128 s.defaultWriteObject(); 129 s.writeObject(getTarget()); 130 } 131 132 @SuppressWarnings("unchecked") 133 private void readObject(ObjectInputStream s) 134 throws IOException, ClassNotFoundException { 135 s.defaultReadObject(); 136 T target = (T)s.readObject(); 137 if (target != null) { 138 setTarget(target); 139 } 140 } 141 142 143 private static class OwnedWeakReference<U extends JComponent> extends 144 WeakReference<U> { 145 private ActionPropertyChangeListener<?> owner; 146 147 OwnedWeakReference(U target, ReferenceQueue<? super U> queue, 148 ActionPropertyChangeListener<?> owner) { 149 super(target, queue); 150 this.owner = owner; 151 } 152 153 public ActionPropertyChangeListener<?> getOwner() { 154 return owner; 155 } 156 } 157 }