Save This Page
Home » openjdk-7 » javax » swing » event » [javadoc | source]
    1   /*
    2    * Copyright 1997-2004 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package javax.swing.event;
   26   
   27   import java.io;
   28   import java.util;
   29   import java.lang.reflect.Array;
   30   
   31   /**
   32    * A class that holds a list of EventListeners.  A single instance
   33    * can be used to hold all listeners (of all types) for the instance
   34    * using the list.  It is the responsiblity of the class using the
   35    * EventListenerList to provide type-safe API (preferably conforming
   36    * to the JavaBeans spec) and methods which dispatch event notification
   37    * methods to appropriate Event Listeners on the list.
   38    *
   39    * The main benefits that this class provides are that it is relatively
   40    * cheap in the case of no listeners, and it provides serialization for
   41    * event-listener lists in a single place, as well as a degree of MT safety
   42    * (when used correctly).
   43    *
   44    * Usage example:
   45    *    Say one is defining a class that sends out FooEvents, and one wants
   46    * to allow users of the class to register FooListeners and receive
   47    * notification when FooEvents occur.  The following should be added
   48    * to the class definition:
   49    * <pre>
   50    * EventListenerList listenerList = new EventListenerList();
   51    * FooEvent fooEvent = null;
   52    *
   53    * public void addFooListener(FooListener l) {
   54    *     listenerList.add(FooListener.class, l);
   55    * }
   56    *
   57    * public void removeFooListener(FooListener l) {
   58    *     listenerList.remove(FooListener.class, l);
   59    * }
   60    *
   61    *
   62    * // Notify all listeners that have registered interest for
   63    * // notification on this event type.  The event instance
   64    * // is lazily created using the parameters passed into
   65    * // the fire method.
   66    *
   67    * protected void fireFooXXX() {
   68    *     // Guaranteed to return a non-null array
   69    *     Object[] listeners = listenerList.getListenerList();
   70    *     // Process the listeners last to first, notifying
   71    *     // those that are interested in this event
   72    *     for (int i = listeners.length-2; i>=0; i-=2) {
   73    *         if (listeners[i]==FooListener.class) {
   74    *             // Lazily create the event:
   75    *             if (fooEvent == null)
   76    *                 fooEvent = new FooEvent(this);
   77    *             ((FooListener)listeners[i+1]).fooXXX(fooEvent);
   78    *         }
   79    *     }
   80    * }
   81    * </pre>
   82    * foo should be changed to the appropriate name, and fireFooXxx to the
   83    * appropriate method name.  One fire method should exist for each
   84    * notification method in the FooListener interface.
   85    * <p>
   86    * <strong>Warning:</strong>
   87    * Serialized objects of this class will not be compatible with
   88    * future Swing releases. The current serialization support is
   89    * appropriate for short term storage or RMI between applications running
   90    * the same version of Swing.  As of 1.4, support for long term storage
   91    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   92    * has been added to the <code>java.beans</code> package.
   93    * Please see {@link java.beans.XMLEncoder}.
   94    *
   95    * @author Georges Saab
   96    * @author Hans Muller
   97    * @author James Gosling
   98    */
   99   public class EventListenerList implements Serializable {
  100       /* A null array to be shared by all empty listener lists*/
  101       private final static Object[] NULL_ARRAY = new Object[0];
  102       /* The list of ListenerType - Listener pairs */
  103       protected transient Object[] listenerList = NULL_ARRAY;
  104   
  105       /**
  106        * Passes back the event listener list as an array
  107        * of ListenerType-listener pairs.  Note that for
  108        * performance reasons, this implementation passes back
  109        * the actual data structure in which the listener data
  110        * is stored internally!
  111        * This method is guaranteed to pass back a non-null
  112        * array, so that no null-checking is required in
  113        * fire methods.  A zero-length array of Object should
  114        * be returned if there are currently no listeners.
  115        *
  116        * WARNING!!! Absolutely NO modification of
  117        * the data contained in this array should be made -- if
  118        * any such manipulation is necessary, it should be done
  119        * on a copy of the array returned rather than the array
  120        * itself.
  121        */
  122       public Object[] getListenerList() {
  123           return listenerList;
  124       }
  125   
  126       /**
  127        * Return an array of all the listeners of the given type.
  128        * @return all of the listeners of the specified type.
  129        * @exception  ClassCastException if the supplied class
  130        *          is not assignable to EventListener
  131        *
  132        * @since 1.3
  133        */
  134       public <T extends EventListener> T[] getListeners(Class<T> t) {
  135           Object[] lList = listenerList;
  136           int n = getListenerCount(lList, t);
  137           T[] result = (T[])Array.newInstance(t, n);
  138           int j = 0;
  139           for (int i = lList.length-2; i>=0; i-=2) {
  140               if (lList[i] == t) {
  141                   result[j++] = (T)lList[i+1];
  142               }
  143           }
  144           return result;
  145       }
  146   
  147       /**
  148        * Returns the total number of listeners for this listener list.
  149        */
  150       public int getListenerCount() {
  151           return listenerList.length/2;
  152       }
  153   
  154       /**
  155        * Returns the total number of listeners of the supplied type
  156        * for this listener list.
  157        */
  158       public int getListenerCount(Class<?> t) {
  159           Object[] lList = listenerList;
  160           return getListenerCount(lList, t);
  161       }
  162   
  163       private int getListenerCount(Object[] list, Class t) {
  164           int count = 0;
  165           for (int i = 0; i < list.length; i+=2) {
  166               if (t == (Class)list[i])
  167                   count++;
  168           }
  169           return count;
  170       }
  171   
  172       /**
  173        * Adds the listener as a listener of the specified type.
  174        * @param t the type of the listener to be added
  175        * @param l the listener to be added
  176        */
  177       public synchronized <T extends EventListener> void add(Class<T> t, T l) {
  178           if (l==null) {
  179               // In an ideal world, we would do an assertion here
  180               // to help developers know they are probably doing
  181               // something wrong
  182               return;
  183           }
  184           if (!t.isInstance(l)) {
  185               throw new IllegalArgumentException("Listener " + l +
  186                                            " is not of type " + t);
  187           }
  188           if (listenerList == NULL_ARRAY) {
  189               // if this is the first listener added,
  190               // initialize the lists
  191               listenerList = new Object[] { t, l };
  192           } else {
  193               // Otherwise copy the array and add the new listener
  194               int i = listenerList.length;
  195               Object[] tmp = new Object[i+2];
  196               System.arraycopy(listenerList, 0, tmp, 0, i);
  197   
  198               tmp[i] = t;
  199               tmp[i+1] = l;
  200   
  201               listenerList = tmp;
  202           }
  203       }
  204   
  205       /**
  206        * Removes the listener as a listener of the specified type.
  207        * @param t the type of the listener to be removed
  208        * @param l the listener to be removed
  209        */
  210       public synchronized <T extends EventListener> void remove(Class<T> t, T l) {
  211           if (l ==null) {
  212               // In an ideal world, we would do an assertion here
  213               // to help developers know they are probably doing
  214               // something wrong
  215               return;
  216           }
  217           if (!t.isInstance(l)) {
  218               throw new IllegalArgumentException("Listener " + l +
  219                                            " is not of type " + t);
  220           }
  221           // Is l on the list?
  222           int index = -1;
  223           for (int i = listenerList.length-2; i>=0; i-=2) {
  224               if ((listenerList[i]==t) && (listenerList[i+1].equals(l) == true)) {
  225                   index = i;
  226                   break;
  227               }
  228           }
  229   
  230           // If so,  remove it
  231           if (index != -1) {
  232               Object[] tmp = new Object[listenerList.length-2];
  233               // Copy the list up to index
  234               System.arraycopy(listenerList, 0, tmp, 0, index);
  235               // Copy from two past the index, up to
  236               // the end of tmp (which is two elements
  237               // shorter than the old list)
  238               if (index < tmp.length)
  239                   System.arraycopy(listenerList, index+2, tmp, index,
  240                                    tmp.length - index);
  241               // set the listener array to the new array or null
  242               listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;
  243               }
  244       }
  245   
  246       // Serialization support.
  247       private void writeObject(ObjectOutputStream s) throws IOException {
  248           Object[] lList = listenerList;
  249           s.defaultWriteObject();
  250   
  251           // Save the non-null event listeners:
  252           for (int i = 0; i < lList.length; i+=2) {
  253               Class t = (Class)lList[i];
  254               EventListener l = (EventListener)lList[i+1];
  255               if ((l!=null) && (l instanceof Serializable)) {
  256                   s.writeObject(t.getName());
  257                   s.writeObject(l);
  258               }
  259           }
  260   
  261           s.writeObject(null);
  262       }
  263   
  264       private void readObject(ObjectInputStream s)
  265           throws IOException, ClassNotFoundException {
  266           listenerList = NULL_ARRAY;
  267           s.defaultReadObject();
  268           Object listenerTypeOrNull;
  269   
  270           while (null != (listenerTypeOrNull = s.readObject())) {
  271               ClassLoader cl = Thread.currentThread().getContextClassLoader();
  272               EventListener l = (EventListener)s.readObject();
  273               add((Class<EventListener>)Class.forName((String)listenerTypeOrNull, true, cl), l);
  274           }
  275       }
  276   
  277       /**
  278        * Returns a string representation of the EventListenerList.
  279        */
  280       public String toString() {
  281           Object[] lList = listenerList;
  282           String s = "EventListenerList: ";
  283           s += lList.length/2 + " listeners: ";
  284           for (int i = 0 ; i <= lList.length-2 ; i+=2) {
  285               s += " type " + ((Class)lList[i]).getName();
  286               s += " listener " + lList[i+1];
  287           }
  288           return s;
  289       }
  290   }

Save This Page
Home » openjdk-7 » javax » swing » event » [javadoc | source]