package org.freehep.swing.popup;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.event.EventListenerList;
/**
* This class is designed to work around a deficiency in Swing's mouse handling.
* It enables a listener to be applied to a component so that all mouse events
* in that component, or any of its subcomponents will be reported. This is
* useful for example in creating Popup menus for complex graphical objects
* (such as plots).
* <p>
* There is no easy way to implement this functionality in Swing, so this class
* works by recursively adding mouse listeners to all components in the heirarchy.
* It also adds a ComponentListener so that it can add and remove listeners from
* items as they are added to the tree.
* <p>
* Warning: This class can have unexpected side effects in some rare cases.
* Normally swing will delegate mouse events to a component's parent if that component
* does not listen for mouse events itself. Since this class adds mouse listeners to
* all components, it can have the side effect of preventing this mouse event delegation.
* (In Java 1.4 it is possible to tell if a mouse listener already exists on a component,
* so maybe it would be possible to work around this limitation. Not clear how you would
* know if a mouse listener was subsequently added).
* @author tonyj
* @version $Id: GlobalMouseListener.java 8584 2006-08-10 23:06:37Z duns $
*/
public class GlobalMouseListener {
/** Create a new GlobalMouseListener associated to a component
* @param c The component on which to listen for mouse events
*/
public GlobalMouseListener(Component c) {
final MouseListener ml = new MouseListener() {
public void mouseClicked(MouseEvent e) {
redispatch(e);
}
public void mouseEntered(MouseEvent e) {
redispatch(e);
}
public void mouseExited(MouseEvent e) {
redispatch(e);
}
public void mousePressed(MouseEvent e) {
redispatch(e);
}
public void mouseReleased(MouseEvent e) {
redispatch(e);
}
};
ContainerListener cl = new ContainerListener() {
public void componentAdded(ContainerEvent e) {
Component source = e.getChild();
changeGlobalMouseListener(true,source,ml,this);
}
public void componentRemoved(ContainerEvent e) {
Component source = e.getChild();
changeGlobalMouseListener(false,source,ml,this);
}
};
changeGlobalMouseListener(true,c,ml,cl);
}
private void changeGlobalMouseListener(boolean add, Component c, MouseListener ml, ContainerListener cl) {
if (add) c.addMouseListener(ml);
else c.removeMouseListener(ml);
if (c instanceof Container) {
Container cc = (Container) c;
if (add) cc.addContainerListener(cl);
else cc.removeContainerListener(cl);
int l = cc.getComponentCount();
for (int i=0; i<l; i++) {
Component child = cc.getComponent(i);
changeGlobalMouseListener(add,child,ml,cl);
}
}
}
/** Add a mouse listener.
* @param l The listener to add
*/
public void addMouseListener(MouseListener l) {
listeners.add(MouseListener.class,l);
}
/** Remove a mouse listener
* @param l The listener to remove
*/
public void removeMouseListener(MouseListener l) {
listeners.remove(MouseListener.class,l);
}
private void redispatch(MouseEvent e)
{
int count = listeners.getListenerCount(MouseListener.class);
if (count > 0)
{
MouseListener[] list = (MouseListener[]) listeners.getListeners(MouseListener.class);
switch (e.getID())
{
case MouseEvent.MOUSE_CLICKED: for (int i=0; i<count; i++) list[i].mouseClicked(e); break;
case MouseEvent.MOUSE_ENTERED: for (int i=0; i<count; i++) list[i].mouseEntered(e); break;
case MouseEvent.MOUSE_EXITED: for (int i=0; i<count; i++) list[i].mouseExited(e); break;
case MouseEvent.MOUSE_PRESSED: for (int i=0; i<count; i++) list[i].mousePressed(e); break;
case MouseEvent.MOUSE_RELEASED: for (int i=0; i<count; i++) list[i].mouseReleased(e); break;
}
}
}
private EventListenerList listeners = new EventListenerList();
}