package jas.plot; import java.awt.AWTEvent; import java.awt.Component; import java.awt.Container; import java.awt.Point; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; import java.awt.event.FocusEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import javax.swing.SwingUtilities; public class PlotPanel extends PlotComponent implements ContainerListener, MouseListener, MouseMotionListener { public PlotPanel() { super(new ChartLayout()); enableEvents(AWTEvent.CONTAINER_EVENT_MASK); enableEvents(AWTEvent.MOUSE_EVENT_MASK); } public Component add(Component c) { // Make sure the data area is always last (so other things get painted on top) if (c instanceof DataArea) return super.add(c); return super.add(c,0); } final protected void processContainerEvent(final ContainerEvent e) { if (e.getID() == ContainerEvent.COMPONENT_ADDED) { componentAdded(e); } else { componentRemoved(e); } } public void restoreDefaultLayout() { ChartLayout cl = (ChartLayout) this.getLayout(); cl.restoreDefaultLayout(); revalidate(); } public boolean hasDefaultLayout() { ChartLayout cl = (ChartLayout) this.getLayout(); return cl.hasDefaultLayout(); } final protected void processMouseEvent(final MouseEvent e) { if (!allowUserInteraction) return; // this is called when a mouse event occurs on the panel, but not // in one of the children components // if this happens and the mouse is pressed, we want the blue border to go away if (e.getID() == MouseEvent.MOUSE_PRESSED && componentWithHandles != null) { componentWithHandles.hideHandles(); componentWithHandles = null; } // The plot panel itself may contain a popup menu, deal with it here if (allowPopupMenus) menuBuilder.buildMenu(e); } private void propagateMouseMotionEvent(final MouseEvent e) { if (!allowUserInteraction) return; // If a component is active (ie has handles) and the event is contained within it, then we // give the event to it. (What if it has a subobject?) // Otherwise give it to the smallest thing that contains it? Component source = (Component) e.getSource(); if (componentWithHandles != null) { componentWithHandles.mouseMotionEventNotify(SwingUtilities.convertMouseEvent(source,e,componentWithHandles)); } else { for (Component c=source; c != null; c=c.getParent()) { if (c instanceof MovableObject) { ((MovableObject) c).mouseMotionEventNotify(SwingUtilities.convertMouseEvent(source,e,c)); } } } } private void propagateMouseEvent(final MouseEvent e) { if (!allowUserInteraction) return; // If a component is active (ie has handles) and the event is contained within it, then we // give the event to it. (What if it has a subobject?) // Otherwise give it to the smallest thing that contains it? Component source = (Component) e.getSource(); if (componentWithHandles != null) { componentWithHandles.mouseEventNotify(SwingUtilities.convertMouseEvent(source,e,componentWithHandles)); } //else //{ for (Component c=source; c != null; c=c.getParent()) { if (c instanceof JASPlotMouseListener) { ((JASPlotMouseListener) c).mouseEventNotify(SwingUtilities.convertMouseEvent(source,e,c)); } } //} if (allowPopupMenus) menuBuilder.buildMenu(e); } private void addComponent(final Component comp) { comp.addMouseListener(this); comp.addMouseMotionListener(this); if (comp instanceof Container) { final Container cont = (Container) comp; cont.addContainerListener(this); Component[] children = cont.getComponents(); for (int i = 0; i < children.length; i++) addComponent(children[i]); } } private void removeComponent(final Component comp) { comp.removeMouseListener(this); comp.removeMouseMotionListener(this); if (comp instanceof Container) { final Container cont = (Container) comp; cont.removeContainerListener(this); Component[] children = cont.getComponents(); for (int i = 0; i < children.length; i++) removeComponent(children[i]); } } public final void deselected() { if (componentWithHandles != null) { componentWithHandles.hideHandles(); componentWithHandles = null; } } ////////////////////////////////////////////////////////////// // ContainerListener methods // final public void componentAdded(final ContainerEvent e) { addComponent(e.getChild()); } final public void componentRemoved(final ContainerEvent e) { removeComponent(e.getChild()); } ////////////////////////////////////////////////////////////// // MouseListener methods // final public void mouseClicked(final MouseEvent e) { propagateMouseEvent(e); } final public void mouseEntered(final MouseEvent e) { propagateMouseEvent(e); } final public void mouseExited(final MouseEvent e) { propagateMouseEvent(e); } final public void mousePressed(final MouseEvent e) { if (!allowUserInteraction) return; final Object source = e.getSource(); MovableObject mo = null; // If the event is INSIDE the componentWithHandles, then do not change focus. if (componentWithHandles != null && source instanceof Component) { Point p = SwingUtilities.convertPoint((Component) source,e.getX(),e.getY(),componentWithHandles); if (componentWithHandles.contains(p)) { propagateMouseEvent(e); return; } } if (source instanceof MovableObject) mo = (MovableObject) source; else mo = (MovableObject) SwingUtilities.getAncestorOfClass(MovableObject.class, (Component) source); // if the source or any of its parents is a MovableObject then mo is that object // if not, mo is null if (mo != null && mo != componentWithHandles) { if (componentWithHandles != null) componentWithHandles.hideHandles(); componentWithHandles = mo; componentWithHandles.showHandles(); // we request focus so we will be told when we lose focus, and can remove the handles // BUG: What if someone INSIDE the componentWithHandles gets focus? requestFocus(); } propagateMouseEvent(e); } final public void processFocusEvent(FocusEvent e) { if (e.getID() == e.FOCUS_LOST) deselected(); super.processFocusEvent(e); } final public void mouseReleased(final MouseEvent e) { propagateMouseEvent(e); } ////////////////////////////////////////////////////////////// // MouseMotionListener methods // final public void mouseDragged(final MouseEvent e) { propagateMouseMotionEvent(e); } final public void mouseMoved(final MouseEvent e) { propagateMouseMotionEvent(e); } public void setAllowUserInteraction(boolean allow) { allowUserInteraction = allow; } public boolean getAllowUserInteraction() { return allowUserInteraction; } public void setAllowPopupMenus(boolean allow) { allowPopupMenus = allow; } public boolean getAllowPopupMenus() { return allowPopupMenus; } //////////////////////////////////////////////////////////// // members // private PopupMenuBuilder menuBuilder = new PopupMenuBuilder(); private MovableObject componentWithHandles; private boolean allowUserInteraction = true; private boolean allowPopupMenus = true; }