/******************************************************************************* | |
* Copyright (c) 2000, 2003 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Common Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/cpl-v10.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.update.internal.core; | |
/** | |
* This class is used to maintain a list of listeners, and | |
* is used in the implementations of several classes within JFace | |
* which allow you to register listeners of various kinds. | |
* It is a fairly lightweight object, occupying minimal space when | |
* no listeners are registered. | |
* <p> | |
* Note that the <code>add</code> method checks for and eliminates | |
* duplicates based on identity (not equality). Likewise, the | |
* <code>remove</code> method compares based on identity. | |
* </p> | |
* <p> | |
* Use the <code>getListeners</code> method when notifying listeners. | |
* Note that no garbage is created if no listeners are registered. | |
* The recommended code sequence for notifying all registered listeners | |
* of say, <code>FooListener.eventHappened</code>, is: | |
* <pre> | |
* Object[] listeners = myListenerList.getListeners(); | |
* for (int i = 0; i < listeners.length; ++i) { | |
* ((FooListener) listeners[i]).eventHappened(event); | |
* } | |
* </pre> | |
* </p> | |
*/ | |
public class ListenersList { | |
/** | |
* The initial capacity of the list. Always >= 1. | |
*/ | |
private int capacity; | |
/** | |
* The current number of listeners. | |
* Maintains invariant: 0 <= size <= listeners.length. | |
*/ | |
private int size; | |
/** | |
* The list of listeners. Initially <code>null</code> but initialized | |
* to an array of size capacity the first time a listener is added. | |
* Maintains invariant: listeners != null IFF size != 0 | |
*/ | |
private Object[] listeners = null; | |
/** | |
* The empty array singleton instance, returned by getListeners() | |
* when size == 0. | |
*/ | |
private static final Object[] EmptyArray = new Object[0]; | |
/** | |
* Creates a listener list with an initial capacity of 3. | |
*/ | |
public ListenersList() { | |
this(3); | |
} | |
/** | |
* Creates a listener list with the given initial capacity. | |
* | |
* @param capacity the number of listeners which this list can initially accept | |
* without growing its internal representation; must be at least 1 | |
*/ | |
public ListenersList(int capacity) { | |
Assert.isTrue(capacity >= 1); | |
this.capacity = capacity; | |
} | |
/** | |
* Adds the given listener to this list. Has no effect if an identical listener | |
* is already registered. | |
* | |
* @param listener the listener | |
*/ | |
public void add(Object listener) { | |
Assert.isNotNull(listener); | |
if (size == 0) { | |
listeners = new Object[capacity]; | |
} else { | |
// check for duplicates using identity | |
for (int i = 0; i < size; ++i) { | |
if (listeners[i] == listener) { | |
return; | |
} | |
} | |
// grow array if necessary | |
if (size == listeners.length) { | |
System.arraycopy(listeners, 0, listeners = new Object[size * 2 + 1], 0, size); | |
} | |
} | |
listeners[size++] = listener; | |
} | |
/** | |
* Returns an array containing all the registered listeners. | |
* The resulting array is unaffected by subsequent adds or removes. | |
* If there are no listeners registered, the result is an empty array | |
* singleton instance (no garbage is created). | |
* Use this method when notifying listeners, so that any modifications | |
* to the listener list during the notification will have no effect on the | |
* notification itself. | |
* | |
* @return the list of registered listeners | |
*/ | |
public Object[] getListeners() { | |
if (size == 0) | |
return EmptyArray; | |
Object[] result = new Object[size]; | |
System.arraycopy(listeners, 0, result, 0, size); | |
return result; | |
} | |
/** | |
* Returns whether this listener list is empty. | |
* | |
* @return <code>true</code> if there are no registered listeners, and | |
* <code>false</code> otherwise | |
*/ | |
public boolean isEmpty() { | |
return size == 0; | |
} | |
/** | |
* Removes the given listener from this list. Has no effect if an identical | |
* listener was not already registered. | |
* | |
* @param listener the listener | |
*/ | |
public void remove(Object listener) { | |
Assert.isNotNull(listener); | |
for (int i = 0; i < size; ++i) { | |
if (listeners[i] == listener) { | |
if (size == 1) { | |
listeners = null; | |
size = 0; | |
} | |
else { | |
System.arraycopy(listeners, i + 1, listeners, i, --size - i); | |
listeners[size] = null; | |
} | |
return; | |
} | |
} | |
} | |
/** | |
* Returns the number of registered listeners. | |
* | |
* @return the number of registered listeners | |
*/ | |
public int size() { | |
return size; | |
} | |
} | |