/******************************************************************************* * Copyright (c) 2004, 2006 IBM 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.internal.preferences; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; /** * @since 3.1 */ public final class PropertyListenerList { private Map listeners; private List globalListeners; private static String[] singlePropertyDelta; private static Object mutex = new Object(); public PropertyListenerList() { } public void firePropertyChange(String prefId) { String[] delta; // Optimization: as long as we're not being called recursively, // we can reuse the same delta object to avoid repeated memory // allocation. synchronized(mutex) { if (singlePropertyDelta != null) { delta = singlePropertyDelta; singlePropertyDelta = null; } else { delta = new String[] {prefId}; } } delta[0] = prefId; firePropertyChange(delta); // Optimization: allow this same delta object to be reused at a later // time if (singlePropertyDelta == null) { synchronized(mutex) { singlePropertyDelta = delta; } } } public void firePropertyChange(String[] propertyIds) { if (globalListeners != null) { for (Iterator iter = globalListeners.iterator(); iter.hasNext();) { IPropertyMapListener next = (IPropertyMapListener) iter.next(); next.propertyChanged(propertyIds); } } if (listeners != null) { // To avoid temporary memory allocation, we try to simply move the // result pointer around if possible. We only allocate a HashSet // to compute which listeners we care about Collection result = Collections.EMPTY_SET; HashSet union = null; for (int i = 0; i < propertyIds.length; i++) { String property = propertyIds[i]; List existingListeners = (List)listeners.get(property); if (existingListeners != null) { if (result == Collections.EMPTY_SET) { result = existingListeners; } else { if (union == null) { union = new HashSet(); union.addAll(result); result = union; } union.addAll(existingListeners); } } } for (Iterator iter = result.iterator(); iter.hasNext();) { IPropertyMapListener next = (IPropertyMapListener) iter.next(); next.propertyChanged(propertyIds); } } } public void add(IPropertyMapListener newListener) { if (globalListeners == null) { globalListeners = new ArrayList(); } globalListeners.add(newListener); newListener.listenerAttached(); } /** * Adds a listener which will be notified when the given property changes * * @param propertyId * @param newListener * @since 3.1 */ private void addInternal(String propertyId, IPropertyMapListener newListener) { if (listeners == null) { listeners = new HashMap(); } List listenerList = (List)listeners.get(propertyId); if (listenerList == null) { listenerList = new ArrayList(1); listeners.put(propertyId, listenerList); } if (!listenerList.contains(newListener)) { listenerList.add(newListener); } } public void add(String[] propertyIds, IPropertyMapListener newListener) { for (int i = 0; i < propertyIds.length; i++) { String id = propertyIds[i]; addInternal(id, newListener); } newListener.listenerAttached(); } public void remove(String propertyId, IPropertyMapListener toRemove) { if (listeners == null) { return; } List listenerList = (List)listeners.get(propertyId); if (listenerList != null) { listenerList.remove(toRemove); if (listenerList.isEmpty()) { listeners.remove(propertyId); if (listeners.isEmpty()) { listeners = null; } } } } public void removeAll() { globalListeners = null; listeners = null; } public void remove(IPropertyMapListener toRemove) { if (globalListeners != null) { globalListeners.remove(toRemove); if (globalListeners.isEmpty()) { globalListeners = null; } } if (listeners != null) { for (Iterator iter = listeners.keySet().iterator(); iter.hasNext();) { String key = (String) iter.next(); remove(key, toRemove); } } } public boolean isEmpty() { return globalListeners == null && listeners == null; } }