package org.limewire.listener; import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; /** * A {@link PropertyChangeSupport} that automatically calls * {@link PropertyChangeListener#propertyChange(PropertyChangeEvent)} from * within the Swing thread if the listener is added on the Swing thread. */ public class SwingSafePropertyChangeSupport extends PropertyChangeSupport { public SwingSafePropertyChangeSupport(Object sourceBean) { super(sourceBean); } @Override public synchronized PropertyChangeListener[] getPropertyChangeListeners() { return unwrap(super.getPropertyChangeListeners()); } @Override public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { return unwrap(super.getPropertyChangeListeners(propertyName)); } @Override public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { if(EventQueue.isDispatchThread()) { listener = wrap(listener); } super.addPropertyChangeListener(listener); } @Override public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { if(EventQueue.isDispatchThread()) { listener = wrap(listener); } super.addPropertyChangeListener(propertyName, listener); } @Override public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { listener = wrap(listener, super.getPropertyChangeListeners()); super.removePropertyChangeListener(listener); } @Override public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { listener = wrap(listener, super.getPropertyChangeListeners(propertyName)); super.removePropertyChangeListener(propertyName, listener); } /** Wraps toFind in the appropriate SwingSafePropertyChangeListener, finding it from the list of all. */ private PropertyChangeListener wrap(PropertyChangeListener toFind, PropertyChangeListener[] all) { for(PropertyChangeListener listener : all) { if(listener == toFind) { return listener; } else if(listener instanceof SwingSafePropertyChangeListener) { if(((SwingSafePropertyChangeListener)listener).delegate == toFind) { return listener; } } } return toFind; } /** Wraps the listener. */ private PropertyChangeListener wrap(PropertyChangeListener listener) { return new SwingSafePropertyChangeListener(listener); } /** Unwraps all SwingSafePropertyChangeListeners. */ private PropertyChangeListener[] unwrap(PropertyChangeListener[] propertyChangeListeners) { PropertyChangeListener[] newListeners = null; for(int i = 0; i < propertyChangeListeners.length; i++) { PropertyChangeListener listener = propertyChangeListeners[i]; if(listener instanceof SwingSafePropertyChangeListener) { if(newListeners == null) { newListeners = new PropertyChangeListener[propertyChangeListeners.length]; System.arraycopy(propertyChangeListeners, 0, newListeners, 0, newListeners.length); } newListeners[i] = ((SwingSafePropertyChangeListener)listener).delegate; } } return newListeners == null ? propertyChangeListeners : newListeners; } private static class SwingSafePropertyChangeListener implements PropertyChangeListener { private final PropertyChangeListener delegate; public SwingSafePropertyChangeListener(PropertyChangeListener delegate) { this.delegate = delegate; } @Override public void propertyChange(final PropertyChangeEvent evt) { if(EventQueue.isDispatchThread()) { delegate.propertyChange(evt); } else { EventQueue.invokeLater(new Runnable() { @Override public void run() { delegate.propertyChange(evt); } }); } } } }