1. /*
  2. * @(#)EventListenerList.java 1.24 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.event;
  8. import java.io.*;
  9. import java.util.*;
  10. /**
  11. * A class which holds a list of EventListeners. A single instance
  12. * can be used to hold all listeners (of all types) for the instance
  13. * using the lsit. It is the responsiblity of the class using the
  14. * EventListenerList to provide type-safe API (preferably conforming
  15. * to the JavaBeans spec) and methods which dispatch event notification
  16. * methods to appropriate Event Listeners on the list.
  17. *
  18. * The main benefits which this class provides are that it is relatively
  19. * cheap in the case of no listeners, and provides serialization for
  20. * eventlistener lists in a single place, as well as a degree of MT safety
  21. * (when used correctly).
  22. *
  23. * Usage example:
  24. * Say one is defining a class which sends out FooEvents, and wantds
  25. * to allow users of the class to register FooListeners and receive
  26. * notification when FooEvents occur. The following should be added
  27. * to the class definition:
  28. <pre>
  29. EventListenerList listenrList = new EventListnerList();
  30. FooEvent fooEvent = null;
  31. public void addFooListener(FooListener l) {
  32. listenerList.add(FooListener.class, l);
  33. }
  34. public void removeFooListener(FooListener l) {
  35. listenerList.remove(FooListener.class, l);
  36. }
  37. // Notify all listeners that have registered interest for
  38. // notification on this event type. The event instance
  39. // is lazily created using the parameters passed into
  40. // the fire method.
  41. protected void firefooXXX() {
  42. // Guaranteed to return a non-null array
  43. Object[] listeners = listenerList.getListenerList();
  44. // Process the listeners last to first, notifying
  45. // those that are interested in this event
  46. for (int i = listeners.length-2; i>=0; i-=2) {
  47. if (listeners[i]==FooListener.class) {
  48. // Lazily create the event:
  49. if (fooEvent == null)
  50. fooEvent = new FooEvent(this);
  51. ((FooListener)listeners[i+1]).fooXXX(fooEvent);
  52. }
  53. }
  54. }
  55. </pre>
  56. * foo should be changed to the appropriate name, and Method to the
  57. * appropriate method name (one fire method should exist for each
  58. * notification method in the FooListener interface).
  59. * <p>
  60. * <strong>Warning:</strong>
  61. * Serialized objects of this class will not be compatible with
  62. * future Swing releases. The current serialization support is appropriate
  63. * for short term storage or RMI between applications running the same
  64. * version of Swing. A future release of Swing will provide support for
  65. * long term persistence.
  66. *
  67. * @version 1.24 11/29/01
  68. * @author Georges Saab
  69. * @author Hans Muller
  70. * @author James Gosling
  71. */
  72. public class EventListenerList implements Serializable {
  73. /* A null array to be shared by all empty listener lists*/
  74. private final static Object[] NULL_ARRAY = new Object[0];
  75. /* The list of ListenerType - Listener pairs */
  76. protected transient Object[] listenerList = NULL_ARRAY;
  77. /**
  78. * This passes back the event listener list as an array
  79. * of ListenerType - listener pairs. Note that for
  80. * performance reasons, this implementation passes back
  81. * the actual data structure in which the listner data
  82. * is stored internally!
  83. * This method is guaranteed to pass back a non-null
  84. * array, so that no null-checking is required in
  85. * fire methods. A zero-length array of Object should
  86. * be returned if there are currently no listeners.
  87. *
  88. * WARNING!!! Absolutely NO modification of
  89. * the data contained in this array should be made -- if
  90. * any such manipulation is necessary, it should be done
  91. * on a copy of the array returned rather than the array
  92. * itself.
  93. */
  94. public Object[] getListenerList() {
  95. return listenerList;
  96. }
  97. /**
  98. * Return the total number of listeners for this listenerlist
  99. */
  100. public int getListenerCount() {
  101. return listenerList.length2;
  102. }
  103. /**
  104. * Return the total number of listeners of the supplied type
  105. * for this listenerlist.
  106. */
  107. public int getListenerCount(Class t) {
  108. int count = 0;
  109. Object[] lList = listenerList;
  110. for (int i = 0; i < lList.length; i+=2) {
  111. if (t == (Class)lList[i])
  112. count++;
  113. }
  114. return count;
  115. }
  116. /**
  117. * Add the listener as a listener of the specified type.
  118. * @param t the type of the listener to be added
  119. * @param l the listener to be added
  120. */
  121. public synchronized void add(Class t, EventListener l) {
  122. if (l==null) {
  123. // In an ideal world, we would do an assertion here
  124. // to help developers know they are probably doing
  125. // something wrong
  126. return;
  127. }
  128. if (!t.isInstance(l)) {
  129. throw new IllegalArgumentException("Listener " + l +
  130. " is not of type " + t);
  131. }
  132. if (listenerList == NULL_ARRAY) {
  133. // if this is the first listener added,
  134. // initialize the lists
  135. listenerList = new Object[] { t, l };
  136. } else {
  137. // Otherwise copy the array and add the new listener
  138. int i = listenerList.length;
  139. Object[] tmp = new Object[i+2];
  140. System.arraycopy(listenerList, 0, tmp, 0, i);
  141. tmp[i] = t;
  142. tmp[i+1] = l;
  143. listenerList = tmp;
  144. }
  145. }
  146. /**
  147. * Remove the listener as a listener of the specified type.
  148. * @param t the type of the listener to be removed
  149. * @param l the listener to be removed
  150. */
  151. public synchronized void remove(Class t, EventListener l) {
  152. if (l ==null) {
  153. // In an ideal world, we would do an assertion here
  154. // to help developers know they are probably doing
  155. // something wrong
  156. return;
  157. }
  158. if (!t.isInstance(l)) {
  159. throw new IllegalArgumentException("Listener " + l +
  160. " is not of type " + t);
  161. }
  162. // Is l on the list?
  163. int index = -1;
  164. for (int i = listenerList.length-2; i>=0; i-=2) {
  165. if ((listenerList[i]==t) && (listenerList[i+1].equals(l) == true)) {
  166. index = i;
  167. break;
  168. }
  169. }
  170. // If so, remove it
  171. if (index != -1) {
  172. Object[] tmp = new Object[listenerList.length-2];
  173. // Copy the list up to index
  174. System.arraycopy(listenerList, 0, tmp, 0, index);
  175. // Copy from two past the index, up to
  176. // the end of tmp (which is two elements
  177. // shorter than the old list)
  178. if (index < tmp.length)
  179. System.arraycopy(listenerList, index+2, tmp, index,
  180. tmp.length - index);
  181. // set the listener array to the new array or null
  182. listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;
  183. }
  184. }
  185. // Serialization support.
  186. private void writeObject(ObjectOutputStream s) throws IOException {
  187. Object[] lList = listenerList;
  188. s.defaultWriteObject();
  189. // Save the non-null event listeners:
  190. for (int i = 0; i < lList.length; i+=2) {
  191. Class t = (Class)lList[i];
  192. EventListener l = (EventListener)lList[i+1];
  193. if ((l!=null) && (l instanceof Serializable)) {
  194. s.writeObject(t.getName());
  195. s.writeObject(l);
  196. }
  197. }
  198. s.writeObject(null);
  199. }
  200. private void readObject(ObjectInputStream s)
  201. throws IOException, ClassNotFoundException {
  202. listenerList = NULL_ARRAY;
  203. s.defaultReadObject();
  204. Object listenerTypeOrNull;
  205. while (null != (listenerTypeOrNull = s.readObject())) {
  206. EventListener l = (EventListener)s.readObject();
  207. add(Class.forName((String)listenerTypeOrNull), l);
  208. }
  209. }
  210. /**
  211. * Return a string representation of the EventListenerList.
  212. */
  213. public String toString() {
  214. Object[] lList = listenerList;
  215. String s = "EventListenerList: ";
  216. s += lList.length2 + " listeners: ";
  217. for (int i = 0 ; i <= lList.length-2 ; i+=2) {
  218. s += " type " + ((Class)lList[i]).getName();
  219. s += " listener " + lList[i+1];
  220. }
  221. return s;
  222. }
  223. }