/******************************************************************************* * Copyright (c) 2012 Tilera Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * William R. Swanson (Tilera Corporation) *******************************************************************************/ package org.eclipse.cdt.visualizer.ui.util; import java.util.ArrayList; // --------------------------------------------------------------------------- // ListenerList // --------------------------------------------------------------------------- /** * Utility class for managing a list of event listeners. * Maintains a list of listener instances, and dispatches events to them. * * To use this class, create a derived type that implements the raise(listener, event) * method to appropriately delegate an event to a listener. * * Note: it is the responsibility of the user of this class to check types * of listeners and events (for example, by having strongly-typed add/remove methods * that delegate to the add/remove methods on this class). */ abstract public class ListenerList { // --- members --- /** Object that owns this listener list */ protected Object m_owner = null; /** listener list display label */ protected String m_label = null; /** listener list */ protected ArrayList<Object> m_listeners = null; // --- constructors/destructors --- /** Constructor. */ public ListenerList(Object owner, String label) { m_owner = owner; m_label = label; } /** Dispose method. */ public void dispose() { m_owner = null; m_label = null; if (m_listeners != null) { clear(); m_listeners = null; } } // --- methods --- /** Clears list of listeners */ public synchronized void clear() { if (m_listeners != null) { m_listeners.clear(); } } /** Returns count of current listeners. */ public synchronized int size() { return (m_listeners == null) ? 0 : m_listeners.size(); } /** Adds a listener */ public synchronized void addListener(Object listener) { if (m_listeners == null) { m_listeners = new ArrayList<Object>(); } if (! m_listeners.contains(listener)) { m_listeners.add(listener); } } /** Removes a listener */ public synchronized void removeListener(Object listener) { if (m_listeners != null) { m_listeners.remove(listener); } } /** * Dispatches event to all attached listeners * Invokes raise(listener, event) for each attached listener. */ public void raise (final Object event) { // we can't use an iterator here, because // the listener list might change while we're walking it, // which would make the iterator throw a ConcurrentModificationException, // hence we'll make a private copy of the listener list ArrayList<Object> listeners = null; synchronized (this) { // keep the lock on the listener list as brief as possible if (m_listeners != null) { listeners = new ArrayList<Object>(m_listeners); } } int count = (listeners == null) ? 0 : listeners.size(); for (int i=0; i<count; i++) { Object listener = (Object) listeners.get(i); try { raise(listener, event); } catch (Throwable t) { // TODO: decide how to log this } } } /** * Dispatches typed event to specified listener * Intended to be overloaded by derived class to cast listener and event * to appropriate type and invoke appropriate listener method(s). * * For example: * * ListenerList m_listeners = * new ListenerList(this, "VisualizerViewer event listeners") * { * public void raise(Object listener, Object event) { * if (listener instanceof IVisualizerViewerListener && * event instanceof VisualizerViewerEvent) * { * IVisualizerViewerListener typedListener = (IVisualizerViewerListener) listener; * VisualizerViewerEvent typedEvent = (VisualizerViewerEvent) event; * typedListener.visualizerEvent(VisualizerViewer.this, typedEvent); * } * } * }; * */ abstract protected void raise(Object listener, Object event); }