GNU Classpath (0.20) | |
Frames | No Frames |
1: /* SwingPropertyChangeSupport.java -- 2: Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.swing.event; 39: 40: import java.beans.PropertyChangeEvent; 41: import java.beans.PropertyChangeListener; 42: import java.beans.PropertyChangeListenerProxy; 43: import java.beans.PropertyChangeSupport; 44: import java.util.ArrayList; 45: import java.util.EventListener; 46: import java.util.Hashtable; 47: import java.util.Iterator; 48: import java.util.List; 49: import java.util.Map; 50: import java.util.Set; 51: 52: /** 53: * Provides a mechanism for registering {@link PropertyChangeListener}s and 54: * forwarding {@link PropertyChangeEvent}s to those listeners. 55: * 56: * @author Andrew Selkirk 57: */ 58: public final class SwingPropertyChangeSupport 59: extends PropertyChangeSupport 60: { 61: 62: private static final long serialVersionUID = 7162625831330845068L; 63: 64: /** 65: * Storage for the listeners that are not linked to a specific property. 66: */ 67: private transient EventListenerList listeners; 68: 69: /** 70: * Storage for the listeners that are linked (by name) to a specific property. 71: * The hash table maps <code>String</code> objects (the property names) to 72: * {@link EventListenerList} instances (which record the listener(s) for the 73: * given property). 74: */ 75: private Hashtable propertyListeners; 76: 77: /** 78: * The object that is used as the default source for the 79: * {@link PropertyChangeEvent}s generated by this class. 80: */ 81: private Object source; 82: 83: /** 84: * Creates a new instance. 85: * 86: * @param source the source (<code>null</code> not permitted). 87: * 88: * @throws NullPointerException if <code>source</code> is <code>null</code>. 89: */ 90: public SwingPropertyChangeSupport(Object source) 91: { 92: super(source); 93: this.source = source; 94: this.listeners = new EventListenerList(); 95: this.propertyListeners = new Hashtable(); 96: } 97: 98: /** 99: * Registers <code>listener</code> to receive notification of any future 100: * {@link PropertyChangeEvent}s generated by this instance. 101: * 102: * @param listener the listener (<code>null</code> is ignored). 103: * 104: * @see #removePropertyChangeListener(PropertyChangeListener) 105: */ 106: public synchronized void addPropertyChangeListener(PropertyChangeListener 107: listener) 108: { 109: listeners.add(PropertyChangeListener.class, listener); 110: } 111: 112: /** 113: * Registers <code>listener</code> to receive notification of any future 114: * {@link PropertyChangeEvent}s generated by this instance for the named 115: * property. 116: * 117: * @param propertyName the property name. 118: * @param listener the listener. 119: * 120: * @see #removePropertyChangeListener(String, PropertyChangeListener) 121: */ 122: public synchronized void addPropertyChangeListener(String propertyName, 123: PropertyChangeListener listener) 124: { 125: EventListenerList list; 126: list = (EventListenerList) propertyListeners.get(propertyName); 127: if (list == null) 128: { 129: list = new EventListenerList(); 130: propertyListeners.put(propertyName, list); 131: } 132: list.add(PropertyChangeListener.class, listener); 133: } 134: 135: /** 136: * Removes <code>listener</code> from the list of registered listeners, so 137: * that it will no longer receive notification of property change events. 138: * 139: * @param listener the listener to remove. 140: */ 141: public synchronized void removePropertyChangeListener(PropertyChangeListener 142: listener) 143: { 144: listeners.remove(PropertyChangeListener.class, listener); 145: } 146: 147: /** 148: * Removes <code>listener</code> from the list of registered listeners for 149: * the named property, so that it will no longer receive notification of 150: * property change events. 151: * 152: * @param propertyName the property name. 153: * @param listener the listener to remove. 154: */ 155: public synchronized void removePropertyChangeListener(String propertyName, 156: PropertyChangeListener listener) 157: { 158: EventListenerList list; 159: list = (EventListenerList) propertyListeners.get(propertyName); 160: if (list == null) 161: return; 162: list.remove(PropertyChangeListener.class, listener); 163: if (list.getListenerCount() == 0) 164: { 165: propertyListeners.remove(propertyName); 166: } 167: } 168: 169: /** 170: * Returns an array of the {@link PropertyChangeListener}s registered with 171: * this <code>SwingPropertyChangeSupport</code> instance. 172: * 173: * @return The array of listeners. 174: * 175: * @since 1.4 176: */ 177: public synchronized PropertyChangeListener[] getPropertyChangeListeners() 178: { 179: // fetch the named listeners first so we know how many there are 180: List namedListeners = new ArrayList(); 181: Set namedListenerEntries = propertyListeners.entrySet(); 182: Iterator iterator = namedListenerEntries.iterator(); 183: while (iterator.hasNext()) 184: { 185: Map.Entry e = (Map.Entry) iterator.next(); 186: String propertyName = (String) e.getKey(); 187: EventListenerList ell = (EventListenerList) e.getValue(); 188: if (ell != null) 189: { 190: Object[] list = ell.getListenerList(); 191: for (int i = 0; i < list.length; i += 2) 192: { 193: namedListeners.add(new PropertyChangeListenerProxy(propertyName, 194: (PropertyChangeListener) list[i + 1])); 195: } 196: } 197: } 198: 199: // create an array that can hold everything 200: int size = listeners.getListenerCount() + namedListeners.size(); 201: PropertyChangeListener[] result = new PropertyChangeListener[size]; 202: 203: // copy in the general listeners 204: Object[] list = listeners.getListenerList(); 205: int index = 0; 206: for (int i = 0; i < list.length; i += 2) 207: result[index++] = (PropertyChangeListener) list[i + 1]; 208: 209: // ...and the named listeners 210: Iterator iterator2 = namedListeners.iterator(); 211: while (iterator2.hasNext()) 212: result[index++] = (PropertyChangeListenerProxy) iterator2.next(); 213: 214: return result; 215: } 216: 217: /** 218: * Returns an array of all listeners that are registered to receive 219: * notification of changes to the named property. This includes the general 220: * listeners as well as those registered specifically for the named 221: * property. 222: * 223: * @param propertyName the property name. 224: * 225: * @return An array of all listeners for the named property. 226: */ 227: public synchronized PropertyChangeListener[] getPropertyChangeListeners( 228: String propertyName) 229: { 230: EventListenerList list 231: = (EventListenerList) propertyListeners.get(propertyName); 232: if (list == null) 233: return getPropertyChangeListeners(); 234: int size = listeners.getListenerCount() + list.getListenerCount(); 235: PropertyChangeListener[] result = new PropertyChangeListener[size]; 236: 237: // copy in the general listeners 238: int index = 0; 239: for (int i = 0; i < listeners.listenerList.length; i += 2) 240: { 241: result[index++] 242: = (PropertyChangeListener) listeners.listenerList[i + 1]; 243: } 244: 245: // copy in the specific listeners 246: Object[] specificListeners = list.getListenerList(); 247: for (int i = 0; i < specificListeners.length; i += 2) 248: { 249: result[index++] = (PropertyChangeListener) specificListeners[i + 1]; 250: } 251: return result; 252: } 253: 254: /** 255: * Creates a new {@link PropertyChangeEvent} using the given arguments (and 256: * the default <code>source</code> for this 257: * <code>SwingPropertyChangeSupport</code> instance) and forwards it to all 258: * registered listeners via the 259: * {@link PropertyChangeListener#propertyChange(PropertyChangeEvent)} method. 260: * <p> 261: * Note that if <code>oldValue</code> and <code>newValue</code> are non-null 262: * and equal, no listeners will be notified. 263: * 264: * @param propertyName the property name. 265: * @param oldValue the old value 266: * @param newValue the new value. 267: */ 268: public void firePropertyChange(String propertyName, Object oldValue, 269: Object newValue) 270: { 271: PropertyChangeEvent event; 272: event = new PropertyChangeEvent(source, propertyName, oldValue, newValue); 273: firePropertyChange(event); 274: } 275: 276: /** 277: * Forwards <code>event</code> to registered listeners. 278: * <p> 279: * Note that if the event's <code>getOldValue()</code> and 280: * <code>getNewValue()</code> methods return non-null and equal values, no 281: * listeners will be notified. 282: * 283: * @param event the event. 284: */ 285: public void firePropertyChange(PropertyChangeEvent event) 286: { 287: EventListenerList list; 288: EventListener[] listenerList; 289: int index; 290: PropertyChangeListener listener; 291: 292: // if the old and new values are non-null and equal, don't notify listeners 293: if (event.getOldValue() != null && event.getNewValue() != null && 294: event.getOldValue().equals(event.getNewValue())) 295: return; 296: 297: // Process Main Listener List 298: listenerList = listeners.getListeners(PropertyChangeListener.class); 299: for (index = 0; index < listenerList.length; index++) 300: { 301: listener = (PropertyChangeListener) listenerList[index]; 302: listener.propertyChange(event); 303: } 304: 305: // Process Property Listener List 306: list = (EventListenerList) propertyListeners.get(event.getPropertyName()); 307: if (list != null) 308: { 309: listenerList = list.getListeners(PropertyChangeListener.class); 310: for (index = 0; index < listenerList.length; index++) 311: { 312: listener = (PropertyChangeListener) listenerList[index]; 313: listener.propertyChange(event); 314: } 315: } 316: 317: } 318: 319: /** 320: * Tell whether the specified property is being listened on or not. This 321: * will only return <code>true</code> if there are listeners on all 322: * properties or if there is a listener specifically on this property. 323: * 324: * @param propertyName the property that may be listened on 325: * @return whether the property is being listened on 326: * @throws NullPointerException if propertyName is null 327: */ 328: public synchronized boolean hasListeners(String propertyName) 329: { 330: if (listeners.getListenerCount() > 0) 331: return true; 332: else 333: return (propertyListeners.get(propertyName) != null); 334: } 335: 336: }
GNU Classpath (0.20) |