GNU Classpath (0.95) | |
Frames | No Frames |
1: /* EventListenerList.java -- 2: Copyright (C) 2002, 2004, 2005, 2006, 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.io.IOException; 41: import java.io.ObjectInputStream; 42: import java.io.ObjectOutputStream; 43: import java.io.Serializable; 44: import java.lang.reflect.Array; 45: import java.util.EventListener; 46: 47: 48: /** 49: * A utility class for keeping track of {@link EventListener}s. 50: * 51: * <p><b>Example for using this class:</b> 52: * 53: * <blockquote><pre> import java.util.EventListener; 54: * import javax.swing.event.EventListenerList; 55: * 56: * class Foo 57: * { 58: * protected final EventListenerList listeners = new EventListenerList(); 59: * protected BarClosedEvent barClosedEvent = null; 60: * 61: * public void addBarListener(BarListener l) 62: * { 63: * listeners.<a href="#add(java.lang.Class, java.util.EventListener)" 64: * >add</a>(BarListener.class, l); 65: * } 66: * 67: * public void removeBarListener(BarListener l) 68: * { 69: * listeners.<a href="#remove(java.lang.Class, java.util.EventListener)" 70: * >remove</a>(BarListener.class, l); 71: * } 72: * 73: * protected void fireBarClosedEvent() 74: * { 75: * Object[] l = listeners.<a href="#getListenerList()" 76: * >getListenerList()</a>; 77: * 78: * for (int i = l.length - 2; i >= 0; i -= 2) 79: * if (l[i] == BarListener.class) 80: * { 81: * // Create the event on demand, when it is needed the first time. 82: * if (barClosedEvent == null) 83: * barClosedEvent = new BarClosedEvent(this); 84: * 85: * ((BarClosedListener) l[i + 1]).barClosed(barClosedEvent); 86: * } 87: * } 88: * }</pre></blockquote> 89: * 90: * @author Andrew Selkirk (aselkirk@sympatico.ca) 91: * @author Sascha Brawer (brawer@dandelis.ch) 92: */ 93: public class EventListenerList 94: implements Serializable 95: { 96: /** 97: * An ID for serializing instances of this class; verified with the 98: * serialver tool of Sun J2SE 1.4.1_01. 99: */ 100: static final long serialVersionUID = -5677132037850737084L; 101: 102: 103: /** 104: * An empty array that is shared by all instances of this class that 105: * have no listeners. 106: */ 107: private static final Object[] NO_LISTENERS = new Object[0]; 108: 109: 110: /** 111: * An array with all currently registered listeners. The array has 112: * twice as many elements as there are listeners. For an even 113: * integer <code>i</code>, <code>listenerList[i]</code> indicates 114: * the registered class, and <code>listenerList[i + 1]</code> is the 115: * listener. 116: */ 117: protected transient Object[] listenerList = NO_LISTENERS; 118: 119: 120: /** 121: * EventListenerList constructor 122: */ 123: public EventListenerList() 124: { 125: // Nothing to do here. 126: } 127: 128: 129: /** 130: * Registers a listener of a specific type. 131: * 132: * @param t the type of the listener. 133: * 134: * @param listener the listener to add, which must be an instance of 135: * <code>t</code>, or of a subclass of <code>t</code>. 136: * 137: * @throws IllegalArgumentException if <code>listener</code> is not 138: * an instance of <code>t</code> (or a subclass thereof). 139: * 140: * @throws NullPointerException if <code>t</code> is <code>null</code>. 141: */ 142: public <T extends EventListener> void add(Class<T> t, T listener) 143: { 144: int oldLength; 145: Object[] newList; 146: 147: if (listener == null) 148: return; 149: 150: if (!t.isInstance(listener)) 151: throw new IllegalArgumentException(); 152: 153: oldLength = listenerList.length; 154: newList = new Object[oldLength + 2]; 155: if (oldLength > 0) 156: System.arraycopy(listenerList, 0, newList, 0, oldLength); 157: 158: newList[oldLength] = t; 159: newList[oldLength + 1] = listener; 160: listenerList = newList; 161: } 162: 163: 164: /** 165: * Determines the number of listeners. 166: */ 167: public int getListenerCount() 168: { 169: return listenerList.length / 2; 170: } 171: 172: 173: /** 174: * Determines the number of listeners of a particular class. 175: * 176: * @param t the type of listeners to be counted. In order to get 177: * counted, a subscribed listener must be exactly of class 178: * <code>t</code>. Thus, subclasses of <code>t</code> will not be 179: * counted. 180: */ 181: public int getListenerCount(Class<?> t) 182: { 183: int result = 0; 184: for (int i = 0; i < listenerList.length; i += 2) 185: if (t == listenerList[i]) 186: ++result; 187: 188: return result; 189: } 190: 191: 192: /** 193: * Returns an array containing a sequence of listenerType/listener pairs, one 194: * for each listener. 195: * 196: * @return An array containing the listener types and references. 197: */ 198: public Object[] getListenerList() 199: { 200: // returning the internal storage is a bad idea, but tests show that the 201: // reference implementation does this... 202: return listenerList; 203: } 204: 205: 206: /** 207: * Retrieves the currently subscribed listeners of a particular 208: * type. For a listener to be returned, it must have been 209: * registered with exactly the type <code>c</code>; subclasses are 210: * not considered equal. 211: * 212: * <p>The returned array can always be cast to <code>c[]</code>. 213: * Since it is a newly allocated copy, the caller may arbitrarily 214: * modify the array. 215: * 216: * @param c the class which was passed to {@link #add}. 217: * 218: * @throws ClassCastException if <code>c</code> does not implement 219: * the {@link EventListener} interface. 220: * 221: * @throws NullPointerException if <code>c</code> is 222: * <code>null</code>. 223: * 224: * @return an array of <code>c</code> whose elements are the 225: * currently subscribed listeners of the specified type. If there 226: * are no such listeners, an empty array is returned. 227: * 228: * @since 1.3 229: */ 230: public <T extends EventListener> T[] getListeners(Class<T> c) 231: { 232: int count, f; 233: EventListener[] result; 234: 235: count = getListenerCount(c); 236: result = (EventListener[]) Array.newInstance(c, count); 237: f = 0; 238: for (int i = listenerList.length - 2; i >= 0; i -= 2) 239: if (listenerList[i] == c) 240: result[f++] = (EventListener) listenerList[i + 1]; 241: 242: return (T[]) result; 243: } 244: 245: 246: /** 247: * Removes a listener of a specific type. 248: * 249: * @param t the type of the listener. 250: * 251: * @param listener the listener to remove, which must be an instance 252: * of <code>t</code>, or of a subclass of <code>t</code>. 253: * 254: * @throws IllegalArgumentException if <code>listener</code> is not 255: * an instance of <code>t</code> (or a subclass thereof). 256: * 257: * @throws NullPointerException if <code>t</code> is <code>null</code>. 258: */ 259: public <T extends EventListener> void remove(Class<T> t, T listener) 260: { 261: Object[] oldList, newList; 262: int oldLength; 263: 264: if (listener == null) 265: return; 266: 267: if (!t.isInstance(listener)) 268: throw new IllegalArgumentException(); 269: 270: oldList = listenerList; 271: oldLength = oldList.length; 272: for (int i = 0; i < oldLength; i += 2) 273: if (oldList[i] == t && oldList[i + 1] == listener) 274: { 275: if (oldLength == 2) 276: newList = NO_LISTENERS; 277: else 278: { 279: newList = new Object[oldLength - 2]; 280: if (i > 0) 281: System.arraycopy(oldList, 0, newList, 0, i); 282: if (i < oldLength - 2) 283: System.arraycopy(oldList, i + 2, newList, i, 284: oldLength - 2 - i); 285: } 286: listenerList = newList; 287: return; 288: } 289: } 290: 291: 292: /** 293: * Returns a string representation of this object that may be useful 294: * for debugging purposes. 295: */ 296: public String toString() 297: { 298: StringBuffer buf = new StringBuffer("EventListenerList: "); 299: buf.append(listenerList.length / 2); 300: buf.append(" listeners: "); 301: for (int i = 0; i < listenerList.length; i += 2) 302: { 303: buf.append(" type "); 304: buf.append(((Class) listenerList[i]).getName()); 305: buf.append(" listener "); 306: buf.append(listenerList[i + 1]); 307: } 308: return buf.toString(); 309: } 310: 311: /** 312: * Serializes an instance to an ObjectOutputStream. 313: * 314: * @param out the stream to serialize to 315: * 316: * @throws IOException if something goes wrong 317: */ 318: private void writeObject(ObjectOutputStream out) 319: throws IOException 320: { 321: out.defaultWriteObject(); 322: for (int i = 0; i < listenerList.length; i += 2) 323: { 324: Class cl = (Class) listenerList[i]; 325: EventListener l = (EventListener) listenerList[i + 1]; 326: if (l != null && l instanceof Serializable) 327: { 328: out.writeObject(cl.getName()); 329: out.writeObject(l); 330: } 331: } 332: // Write end marker. 333: out.writeObject(null); 334: } 335: 336: /** 337: * Deserializes an instance from an ObjectInputStream. 338: * 339: * @param in the input stream 340: * 341: * @throws ClassNotFoundException if a serialized class can't be found 342: * @throws IOException if something goes wrong 343: */ 344: private <T extends EventListener> void readObject(ObjectInputStream in) 345: throws ClassNotFoundException, IOException 346: { 347: listenerList = NO_LISTENERS; 348: in.defaultReadObject(); 349: Object type; 350: ClassLoader cl = Thread.currentThread().getContextClassLoader(); 351: while ((type = in.readObject()) != null) 352: { 353: EventListener l = (EventListener) in.readObject(); 354: add(((Class<T>) Class.forName((String) type, true, cl)), (T) l); 355: } 356: } 357: }
GNU Classpath (0.95) |