All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.swingx.event.WeakEventListenerList Maven / Gradle / Ivy

Go to download

Contains extensions to the Swing GUI toolkit, including new and enhanced components that provide functionality commonly required by rich client applications.

The newest version!
/*
 * $Id: WeakEventListenerList.java 3190 2009-01-20 17:47:52Z kschaefe $
 *
 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.jdesktop.swingx.event;

import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;

/**
 * A class that holds a list of EventListeners.  A single instance
 * can be used to hold all listeners (of all types) for the instance
 * using the list.  It is the responsibility of the class using the
 * EventListenerList to provide type-safe API (preferably conforming
 * to the JavaBeans spec) and methods which dispatch event notification
 * methods to appropriate Event Listeners on the list.
 * 
 * The main benefit that this class provides is that it releases
 * garbage collected listeners (internally uses weak references). 

* * PENDING: serialization support * * * Usage example: * Say one is defining a class that sends out FooEvents, and one wants * to allow users of the class to register FooListeners and receive * notification when FooEvents occur. The following should be added * to the class definition: *

 * EventListenerList listenerList = new EventListenerList();
 * FooEvent fooEvent = null;
 *
 * public void addFooListener(FooListener l) {
 *     listenerList.add(FooListener.class, l);
 * }
 *
 * public void removeFooListener(FooListener l) {
 *     listenerList.remove(FooListener.class, l);
 * }
 *
 *
 * // Notify all listeners that have registered interest for
 * // notification on this event type.  The event instance 
 * // is lazily created using the parameters passed into 
 * // the fire method.
 *
 * 
 * protected void fireFooXXX() {
 *     // Guaranteed to return a non-null array
 *     FooListener[] listeners = listenerList.getListeners(FooListener.class);
 *     // Process the listeners last to first, notifying
 *     // those that are interested in this event
 *     for (FooListener listener: listeners) {
 *             // Lazily create the event:
 *             if (fooEvent == null)
 *                 fooEvent = new FooEvent(this);
 *             listener.fooXXX(fooEvent);
 *         }
 *     }
 * }
 * 
* foo should be changed to the appropriate name, and fireFooXxx to the * appropriate method name. One fire method should exist for each * notification method in the FooListener interface. *

* Warning: * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeansTM * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. * * @version 1.37 11/17/05 * @author Georges Saab * @author Hans Muller * @author James Gosling */ public class WeakEventListenerList implements Serializable { protected transient List> weakReferences; protected transient List> classes; /** * Passes back the event listener list as an array * of ListenerType-listener pairs. * As a side-effect, cleans out any * garbage collected listeners before building the array. * * @return a array of listenerType-listener pairs. */ public Object[] getListenerList() { List listeners = cleanReferences(); Object[] result = new Object[listeners.size() * 2]; for (int i = 0; i < listeners.size(); i++) { result[2*i + 1] = listeners.get(i); result[2*i] = getClasses().get(i); } return result; } /** * Returns a list of strongly referenced EventListeners. Removes * internal weak references to garbage collected listeners. * * @return */ @SuppressWarnings("unchecked") private synchronized List cleanReferences() { List listeners = new ArrayList(); for (int i = getReferences().size() - 1; i >= 0; i--) { Object listener = getReferences().get(i).get(); if (listener == null) { getReferences().remove(i); getClasses().remove(i); } else { listeners.add(0, (T) listener); } } return listeners; } private List> getReferences() { if (weakReferences == null) { weakReferences = new ArrayList>(); } return weakReferences; } private List> getClasses() { if (classes == null) { classes = new ArrayList>(); } return classes; } /** * Return an array of all the listeners of the given type. * As a side-effect, cleans out any * garbage collected listeners before building the array. * @return all of the listeners of the specified type. * @exception ClassCastException if the supplied class * is not assignable to EventListener * * @since 1.3 */ @SuppressWarnings("unchecked") public T[] getListeners(Class t) { List liveListeners = cleanReferences(); List listeners = new ArrayList(); for (int i = 0; i < liveListeners.size(); i++) { if (getClasses().get(i) == t) { listeners.add(liveListeners.get(i)); } } T[] result = (T[])Array.newInstance(t, listeners.size()); return listeners.toArray(result); } /** * Adds the listener as a listener of the specified type. * As a side-effect, cleans out any garbage collected * listeners before adding. * @param t the type of the listener to be added * @param l the listener to be added */ public synchronized void add(Class t, T l) { if (l==null) { // In an ideal world, we would do an assertion here // to help developers know they are probably doing // something wrong return; } if (!t.isInstance(l)) { throw new IllegalArgumentException("Listener " + l + " is not of type " + t); } cleanReferences(); getReferences().add(new WeakReference(l)); getClasses().add(t); } /** * Removes the listener as a listener of the specified type. * @param t the type of the listener to be removed * @param l the listener to be removed */ public synchronized void remove(Class t, T l) { if (l ==null) { // In an ideal world, we would do an assertion here // to help developers know they are probably doing // something wrong return; } if (!t.isInstance(l)) { throw new IllegalArgumentException("Listener " + l + " is not of type " + t); } for (int i = 0; i < getReferences().size(); i++) { if (l.equals(getReferences().get(i).get()) && (t == getClasses().get(i))) { getReferences().remove(i); getClasses().remove(i); break; } } } // // Serialization support. // private void writeObject(ObjectOutputStream s) throws IOException { // Object[] lList = listenerList; // s.defaultWriteObject(); // // // Save the non-null event listeners: // for (int i = 0; i < lList.length; i+=2) { // Class t = (Class)lList[i]; // EventListener l = (EventListener)lList[i+1]; // if ((l!=null) && (l instanceof Serializable)) { // s.writeObject(t.getName()); // s.writeObject(l); // } // } // // s.writeObject(null); // } // // private void readObject(ObjectInputStream s) // throws IOException, ClassNotFoundException { // listenerList = NULL_ARRAY; // s.defaultReadObject(); // Object listenerTypeOrNull; // // while (null != (listenerTypeOrNull = s.readObject())) { // ClassLoader cl = Thread.currentThread().getContextClassLoader(); // EventListener l = (EventListener)s.readObject(); // add((Class)Class.forName((String)listenerTypeOrNull, true, cl), l); // } // } // /** // * Returns a string representation of the EventListenerList. // */ // public String toString() { // Object[] lList = listenerList; // String s = "EventListenerList: "; // s += lList.length/2 + " listeners: "; // for (int i = 0 ; i <= lList.length-2 ; i+=2) { // s += " type " + ((Class)lList[i]).getName(); // s += " listener " + lList[i+1]; // } // return s; // } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy