Revision: 655
Author: allain.lalonde
Date: Thu Aug  6 09:07:42 2009
Log: Resolved Issue 32 using steveonjava's code.
Also, tidied up the PSwingEventHandler code.
http://code.google.com/p/piccolo2d/source/detail?r=655

Added:
   
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEvent.java
   
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseWheelEvent.java
Modified:
   
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
   
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
   
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java
   
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java
   
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
   
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java

=======================================
--- /dev/null
+++  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEvent.java
   
Thu Aug  6 09:07:42 2009
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2007 Stephen Chin
+ *
+ * All rights reserved.
+ */
+package edu.umd.cs.piccolox.pswing;
+
+import java.awt.event.MouseEvent;
+import java.awt.geom.Point2D;
+
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.util.PPickPath;
+
+public interface PSwingEvent {
+    /**
+     * Returns the x,y position of the event in the local coordinate  
system of
+     * the node the event occurred on.
+     *
+     * @return a Point2D object containing the x and y coordinates local  
to the
+     *         node.
+     */
+    Point2D getLocalPoint();
+
+    /**
+     * Returns the horizontal x position of the event in the local  
coordinate
+     * system of the node the event occurred on.
+     *
+     * @return x a double indicating horizontal position local to the node.
+     */
+    double getLocalX();
+
+    /**
+     * Returns the vertical y position of the event in the local coordinate
+     * system of the node the event occurred on.
+     *
+     * @return y a double indicating vertical position local to the node.
+     */
+    double getLocalY();
+
+    /**
+     * Determine the event type.
+     *
+     * @return the id
+     */
+    int getID();
+
+    /**
+     * Determine the node the event originated at. If an event percolates  
up the
+     * tree and is handled by an event listener higher up in the tree than  
the
+     * original node that generated the event, this returns the original  
node.
+     * For mouse drag and release events, this is the node that the  
original
+     * matching press event went to - in other words, the event  
is 'grabbed' by
+     * the originating node.
+     *
+     * @return the node
+     */
+    PNode getNode();
+
+    /**
+     * Determine the path the event took from the PCanvas down to the  
visual
+     * component.
+     *
+     * @return the path
+     */
+    PPickPath getPath();
+
+    /**
+     * Determine the node the event originated at. If an event percolates  
up the
+     * tree and is handled by an event listener higher up in the tree than  
the
+     * original node that generated the event, this returns the original  
node.
+     * For mouse drag and release events, this is the node that the  
original
+     * matching press event went to - in other words, the event  
is 'grabbed' by
+     * the originating node.
+     *
+     * @return the node
+     */
+    PNode getGrabNode();
+
+    /**
+     * Return the path from the PCanvas down to the currently grabbed  
object.
+     *
+     * @return the path
+     */
+    PPickPath getGrabPath();
+
+    /**
+     * Get the current node that is under the cursor. This may return a
+     * different result then getGrabNode() when in a MOUSE_RELEASED or
+     * MOUSE_DRAGGED event.
+     *
+     * @return the current node.
+     */
+    PNode getCurrentNode();
+
+    /**
+     * Get the path from the PCanvas down to the visual component currently
+     * under the mouse.This may give a different result then getGrabPath()
+     * during a MOUSE_DRAGGED or MOUSE_RELEASED operation.
+     *
+     * @return the current path.
+     */
+    PPickPath getCurrentPath();
+
+    /**
+     * Calls appropriate method on the listener based on this events ID.
+     *
+     * @param listener the MouseListener or MouseMotionListener to  
dispatch to.
+     */
+    void dispatchTo(Object listener);
+
+    /**
+     * Set the souce of this event. As the event is fired up the tree the  
source
+     * of the event will keep changing to reflect the scenegraph object  
that is
+     * firing the event.
+     *
+     * @param aSource
+     */
+    void setSource(Object aSource);
+
+    /**
+     * Returns this event as a mouse event. This reduces the need to cast
+     * instances of this interface when they are known to all extend  
MouseEvent.
+     *
+     * @return this object casted to a MouseEvent
+     */
+    MouseEvent asMouseEvent();
+}
=======================================
--- /dev/null
+++  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseWheelEvent.java
         
Thu Aug  6 09:07:42 2009
@@ -0,0 +1,215 @@
+/**
+ * Copyright (C) 1998-2000 by University of Maryland, College Park, MD
+20742, USA
+ * All rights reserved.
+ */
+package edu.umd.cs.piccolox.pswing;
+
+import java.awt.Component;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.geom.Point2D;
+
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.event.PInputEvent;
+import edu.umd.cs.piccolo.util.PPickPath;
+
+/**
+ * <b>PMouseMotionEvent</b> is an event which indicates that a mouse motion
+ * action occurred in a node.
+ * <p/>
+ * This low-level event is generated by a node object for:
+ * <ul>
+ * <li>Mouse Motion Events
+ * <ul>
+ * <li>the mouse is moved
+ * <li>the mouse is dragged
+ * </ul>
+ * </ul>
+ * <p/>
+ * A PMouseEvent object is passed to every  
<code>PMouseMotionListener</code> or
+ * <code>PMouseMotionAdapter</code> object which registered to receive  
mouse
+ * motion events using the component's <code>addMouseMotionListener</code>
+ * method. (<code>PMouseMotionAdapter</code> objects implement the
+ * <code>PMouseMotionListener</code> interface.) Each such listener object  
gets
+ * a <code>PMouseEvent</code> containing the mouse motion event.
+ * <p/>
+ * <p/>
+ * <b>Warning:</b> Serialized objects of this class will not be compatible  
with
+ * future Piccolo releases. The current serialization support is  
appropriate for
+ * short term storage or RMI between applications running the same version  
of
+ * Piccolo. A future release of Piccolo will provide support for long term
+ * persistence.
+ *
+ * @author Benjamin B. Bederson
+ * @author Sam R. Reid
+ * @author Lance E. Good
+ */
+public class PSwingMouseWheelEvent extends MouseWheelEvent implements  
PSwingEvent {
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+    private final int id;
+    private final PInputEvent event;
+
+    /**
+     * Constructs a new PMouseWheel event from a Java MouseWheelEvent.
+     *
+     * @param id The event type (MOUSE_WHEEL)
+     * @param e The original Java mouse wheel event.
+     */
+    protected PSwingMouseWheelEvent(final int id, final MouseWheelEvent e,  
final PInputEvent event) {
+        super((Component) e.getSource(), e.getID(), e.getWhen(),  
e.getModifiers(), e.getX(), e.getY(), e
+                .getClickCount(), e.isPopupTrigger(), e.getScrollType(),  
e.getScrollAmount(), e.getWheelRotation());
+        this.id = id;
+        this.event = event;
+    }
+
+    /**
+     * Returns the x,y position of the event in the local coordinate  
system of
+     * the node the event occurred on.
+     *
+     * @return a Point2D object containing the x and y coordinates local  
to the
+     *         node.
+     */
+    public Point2D getLocalPoint() {
+        return new Point2D.Double(getX(), getY());
+    }
+
+    /**
+     * Returns the horizontal x position of the event in the local  
coordinate
+     * system of the node the event occurred on.
+     *
+     * @return x a double indicating horizontal position local to the node.
+     */
+    public double getLocalX() {
+        return getLocalPoint().getX();
+    }
+
+    /**
+     * Returns the vertical y position of the event in the local coordinate
+     * system of the node the event occurred on.
+     *
+     * @return y a double indicating vertical position local to the node.
+     */
+    public double getLocalY() {
+        return getLocalPoint().getY();
+    }
+
+    /**
+     * Determine the event type.
+     *
+     * @return the id
+     */
+    public int getID() {
+        return id;
+    }
+
+    /**
+     * Determine the node the event originated at. If an event percolates  
up the
+     * tree and is handled by an event listener higher up in the tree than  
the
+     * original node that generated the event, this returns the original  
node.
+     * For mouse drag and release events, this is the node that the  
original
+     * matching press event went to - in other words, the event  
is 'grabbed' by
+     * the originating node.
+     *
+     * @return the node
+     */
+    public PNode getNode() {
+        return event.getPickedNode();
+    }
+
+    /**
+     * Determine the path the event took from the PCanvas down to the  
visual
+     * component.
+     *
+     * @return the path
+     */
+    public PPickPath getPath() {
+        return event.getPath();
+    }
+
+    /**
+     * Determine the node the event originated at. If an event percolates  
up the
+     * tree and is handled by an event listener higher up in the tree than  
the
+     * original node that generated the event, this returns the original  
node.
+     * For mouse drag and release events, this is the node that the  
original
+     * matching press event went to - in other words, the event  
is 'grabbed' by
+     * the originating node.
+     *
+     * @return the node
+     */
+    public PNode getGrabNode() {
+        return event.getPickedNode();
+    }
+
+    /**
+     * Return the path from the PCanvas down to the currently grabbed  
object.
+     *
+     * @return the path
+     */
+    public PPickPath getGrabPath() {
+        return getPath();
+    }
+
+    /**
+     * Get the current node that is under the cursor. This may return a
+     * different result then getGrabNode() when in a MOUSE_RELEASED or
+     * MOUSE_DRAGGED event.
+     *
+     * @return the current node.
+     */
+    public PNode getCurrentNode() {
+        return event.getPickedNode();
+    }
+
+    /**
+     * Get the path from the PCanvas down to the visual component currently
+     * under the mouse.This may give a different result then getGrabPath()
+     * durring a MOUSE_DRAGGED or MOUSE_RELEASED operation.
+     *
+     * @return the current path.
+     */
+    public PPickPath getCurrentPath() {
+        return getPath();
+    }
+
+    /**
+     * Calls appropriate method on the listener based on this events ID.
+     *
+     * @param listener the target for dispatch.
+     */
+    public void dispatchTo(final Object listener) {
+        final MouseWheelListener mouseWheelListener = (MouseWheelListener)  
listener;
+        switch (getID()) {
+            case MouseEvent.MOUSE_WHEEL:
+                mouseWheelListener.mouseWheelMoved(this);
+                break;
+            default:
+                throw new RuntimeException("PMouseWheelEvent with bad ID");
+        }
+    }
+
+    /**
+     * Set the souce of this event. As the event is fired up the tree the  
source
+     * of the event will keep changing to reflect the scenegraph object  
that is
+     * firing the event.
+     *
+     * @param aSource
+     */
+    public void setSource(final Object aSource) {
+        source = aSource;
+    }
+
+    /**
+     * Returns this event as a mouse event. This reduces the need to cast
+     * instances of this interface when they are known to all extend  
MouseEvent.
+     *
+     * @return this object casted to a MouseEvent
+     */
+    public MouseEvent asMouseEvent() {
+        return this;
+    }
+}
=======================================
---  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
        
Sun Aug  2 19:49:04 2009
+++  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
        
Thu Aug  6 09:07:42 2009
@@ -220,11 +220,18 @@
      /** Minimum font size. */
      private double minFontSize = Double.MAX_VALUE;

-    /** Default stroke, <code>new BasicStroke()</code>.   Cannot be made  
static because BasicStroke is not serializable. */
+    /**
+     * Default stroke, <code>new BasicStroke()</code>. Cannot be made  
static
+     * because BasicStroke is not serializable.
+     */
      private transient Stroke defaultStroke = new BasicStroke();

-    /** Default font, 12 point <code>"SansSerif"</code>. Will be made  
final in version 2.0. */
-    // public static final Font DEFAULT_FONT = new Font(Font.SANS_SERIF,  
Font.PLAIN, 12); jdk 1.6+
+    /**
+     * Default font, 12 point <code>"SansSerif"</code>. Will be made final  
in
+     * version 2.0.
+     */
+    // public static final Font DEFAULT_FONT = new Font(Font.SANS_SERIF,
+    // Font.PLAIN, 12); jdk 1.6+
      public static final Font DEFAULT_FONT = new Font("SansSerif",  
Font.PLAIN, 12);

      /** Greek threshold in scale. */
@@ -293,7 +300,6 @@
      public PSwing(final PSwingCanvas swingCanvas, final JComponent  
component) {
          this(component);
      }
-

      /**
       * Ensures the bounds of the underlying component are accurate, and  
sets the
@@ -347,8 +353,9 @@
      }

      /**
-     * Workaround to prevent text-rendering Swing components from drawing  
an ellipsis incorrectly.
-     *
+     * Workaround to prevent text-rendering Swing components from drawing  
an
+     * ellipsis incorrectly.
+     *
       * @param text text
       * @param icon icon
       * @param iconGap icon gap
@@ -407,8 +414,7 @@
       *         specified paint context
       */
      protected boolean shouldRenderGreek(final PPaintContext paintContext) {
-        return paintContext.getScale() < greekThreshold
-                || minFontSize * paintContext.getScale() < 0.5;
+        return paintContext.getScale() < greekThreshold || minFontSize *  
paintContext.getScale() < 0.5;
      }

      /**
@@ -419,7 +425,7 @@
       *
       * @param paintContext paint context
       */
-    protected void paintGreek(PPaintContext paintContext) {
+    protected void paintGreek(final PPaintContext paintContext) {
          final Graphics2D graphics = paintContext.getGraphics();
          final Color background = component.getBackground();
          final Color foreground = component.getForeground();
@@ -448,7 +454,7 @@

      /**
       * Paint the Swing component with the specified paint context.
-     *
+     *
       * @param paintContext paint context
       */
      protected void paintComponent(final PPaintContext paintContext) {
=======================================
---  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
  
Thu Jul 30 12:36:17 2009
+++  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
  
Thu Aug  6 09:07:42 2009
@@ -59,8 +59,8 @@
      }

      private void initRepaintManager() {
-        final RepaintManager repaintManager =  
RepaintManager.currentManager(this);
-        if (!(repaintManager instanceof PSwingRepaintManager)) {
+        final RepaintManager repaintManager =  
RepaintManager.currentManager(this);
+        if (!(repaintManager instanceof PSwingRepaintManager)) {
              RepaintManager.setCurrentManager(new PSwingRepaintManager());
          }
      }
=======================================
---  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java
    
Tue Jul 28 13:41:36 2009
+++  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java
    
Thu Aug  6 09:07:42 2009
@@ -33,6 +33,7 @@
  import java.awt.Point;
  import java.awt.event.InputEvent;
  import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
  import java.awt.geom.AffineTransform;
  import java.awt.geom.NoninvertibleTransformException;
  import java.awt.geom.Point2D;
@@ -44,6 +45,7 @@
  import edu.umd.cs.piccolo.PNode;
  import edu.umd.cs.piccolo.event.PInputEvent;
  import edu.umd.cs.piccolo.event.PInputEventListener;
+import edu.umd.cs.piccolo.util.PAffineTransform;
  import edu.umd.cs.piccolo.util.PAffineTransformException;

  /**
@@ -57,34 +59,46 @@
  public class PSwingEventHandler implements PInputEventListener {

      private PNode listenNode = null; // used to listen to for events
-    private boolean active = false; // True when event handlers are set  
active.
-
-    // The previous component - used to generate mouseEntered and
-    // mouseExited events
-    private Component prevComponent = null;
-
-    // Previous points used in generating mouseEntered and mouseExited  
events
+
+    /** Tracks whether this event handler is active. */
+    private boolean active = false;
+
+    /**
+     * The previous component - used to generate mouseEntered and  
mouseExited
+     * events.
+     */
+    private Component previousComponent = null;
+
+    /** Previous point used for mouseEntered and exited events. */
      private Point2D prevPoint = null;
-    private Point2D prevOff = null;
+
+    /** Previous offset used for mouseEntered and exited events. */
+    private Point2D previousOffset = null;

      private boolean recursing = false;// to avoid accidental recursive  
handling

+    /** Used for tracking the left button's state. */
      private final ButtonData leftButtonData = new ButtonData();
-    private final ButtonData rightButtonData = new ButtonData();
+
+    /** Used for tracking the middle button's state. */
      private final ButtonData middleButtonData = new ButtonData();

+    /** Used for tracking the right button's state. */
+    private final ButtonData rightButtonData = new ButtonData();
+
+    /** The Canvas in which all this pswing activity is taking place. */
      private final PSwingCanvas canvas;

      /**
       * Constructs a new PSwingEventHandler for the given canvas, and a  
node that
-     * will recieve the mouse events.
+     * will receive the mouse events.
       *
       * @param canvas the canvas associated with this PSwingEventHandler.
       * @param node the node the mouse listeners will be attached to.
       */
-    public PSwingEventHandler(final PSwingCanvas canvas, final PNode node)  
{
+    public PSwingEventHandler(final PSwingCanvas canvas, final PNode  
listenNode) {
          this.canvas = canvas;
-        listenNode = node;
+        this.listenNode = listenNode;
      }

      /**
@@ -113,7 +127,7 @@
      }

      /**
-     * Determines if this event handler is active.
+     * Returns if this event handler is active.
       *
       * @return True if active
       */
@@ -124,38 +138,45 @@
      /**
       * Finds the component at the specified location (must be showing).
       *
-     * @param c
+     * @param component
       * @param x
       * @param y
       * @return the component at the specified location.
       */
-    private Component findShowingComponentAt(final Component c, final int  
x, final int y) {
-        if (!c.contains(x, y)) {
+    private Component findShowingComponentAt(final Component component,  
final int x, final int y) {
+        if (!component.contains(x, y)) {
              return null;
          }

-        if (c instanceof Container) {
-            final Container contain = (Container) c;
-            final int ncomponents = contain.getComponentCount();
-            final Component component[] = contain.getComponents();
-
-            for (int i = 0; i < ncomponents; i++) {
-                Component comp = component[i];
-                if (comp != null) {
-                    final Point p = comp.getLocation();
-                    if (comp instanceof Container) {
-                        comp = findShowingComponentAt(comp, x - (int)  
p.getX(), y - (int) p.getY());
-                    }
-                    else {
-                        comp = comp.getComponentAt(x - (int) p.getX(), y -  
(int) p.getY());
-                    }
-                    if (comp != null && comp.isShowing()) {
-                        return comp;
-                    }
+        if (component instanceof Container) {
+            final Container contain = (Container) component;
+            final Component child = findShowingChildAt(contain, x, y);
+            if (child != null) {
+                return child;
+            }
+        }
+        return component;
+    }
+
+    private Component findShowingChildAt(final Container container, final  
int x, final int y) {
+        final Component[] children = container.getComponents();
+
+        for (int i = 0; i < children.length; i++) {
+            Component child = children[i];
+            if (child != null) {
+                final Point p = child.getLocation();
+                if (child instanceof Container) {
+                    child = findShowingComponentAt(child, x - p.x, y -  
p.y);
+                }
+                else {
+                    child = child.getComponentAt(x - p.x, y - p.y);
+                }
+                if (child != null && child.isShowing()) {
+                    return child;
                  }
              }
          }
-        return c;
+        return null;
      }

      /**
@@ -167,55 +188,49 @@
       * @param pSwingMouseEvent
       * @param aEvent
       */
-    void dispatchEvent(final PSwingMouseEvent pSwingMouseEvent, final  
PInputEvent aEvent) {
-        Component comp = null;
-        Point2D pt = null;
+    void dispatchEvent(final PSwingEvent pSwingMouseEvent, final  
PInputEvent aEvent) {
+        final MouseEvent mEvent = pSwingMouseEvent.asMouseEvent();
          final PNode pickedNode =  
pSwingMouseEvent.getPath().getPickedNode();
-
-        // The offsets to put the event in the correct context
-        int offX = 0;
-        int offY = 0;
-
-        final PNode currentNode = pSwingMouseEvent.getCurrentNode();
-
-        if (currentNode instanceof PSwing) {
+        final PNode currentNode = pSwingMouseEvent.getCurrentNode();
+
+        Component comp = null;
+        Point point = null;
+
+        Point offset = new Point();
+
+        if (currentNode instanceof PSwing &&  
pickedNode.isDescendentOf(canvas.getRoot())) {

              final PSwing swing = (PSwing) currentNode;
              final PNode grabNode = pickedNode;

-            if (grabNode.isDescendentOf(canvas.getRoot())) {
-                pt = new Point2D.Double(pSwingMouseEvent.getX(),  
pSwingMouseEvent.getY());
-                cameraToLocal(pSwingMouseEvent.getPath().getTopCamera(),  
pt, grabNode);
-                prevPoint = new Point2D.Double(pt.getX(), pt.getY());
-
-                // This is only partially fixed to find the deepest
-                // component at pt. It needs to do something like
-                // package private method:
-                // Container.getMouseEventTarget(int,int,boolean)
-                comp = findShowingComponentAt(swing.getComponent(), (int)  
pt.getX(), (int) pt.getY());
-
-                // We found the right component - but we need to
-                // get the offset to put the event in the component's
-                // coordinates
-                if (comp != null && comp != swing.getComponent()) {
-                    for (Component c = comp; c != swing.getComponent(); c  
= c.getParent()) {
-                        offX += c.getLocation().getX();
-                        offY += c.getLocation().getY();
-                    }
-                }
-
-                // Mouse Pressed gives focus - effects Mouse Drags and
-                // Mouse Releases
-                if (comp != null && pSwingMouseEvent.getID() ==  
MouseEvent.MOUSE_PRESSED) {
-                    if  
(SwingUtilities.isLeftMouseButton(pSwingMouseEvent)) {
-                        leftButtonData.setState(swing, pickedNode, comp,  
offX, offY);
-                    }
-                    else if  
(SwingUtilities.isMiddleMouseButton(pSwingMouseEvent)) {
-                        middleButtonData.setState(swing, pickedNode, comp,  
offX, offY);
-                    }
-                    else if  
(SwingUtilities.isRightMouseButton(pSwingMouseEvent)) {
-                        rightButtonData.setState(swing, pickedNode, comp,  
offX, offY);
-                    }
+            point = new Point(mEvent.getX(), mEvent.getY());
+            cameraToLocal(pSwingMouseEvent.getPath().getTopCamera(),  
point, grabNode);
+            prevPoint = (Point) point.clone();
+
+            // This is only partially fixed to find the deepest
+            // component at pt. It needs to do something like
+            // package private method:
+            // Container.getMouseEventTarget(int,int,boolean)
+            comp = findShowingComponentAt(swing.getComponent(), point.x,  
point.y);
+
+            // We found the right component - but we need to
+            // get the offset to put the event in the component's
+            // coordinates
+            if (comp != null && comp != swing.getComponent()) {
+                offset = extractSwingOffset(comp, swing);
+            }
+
+            // Mouse Pressed gives focus - effects Mouse Drags and
+            // Mouse Releases
+            if (comp != null && isMousePress(pSwingMouseEvent)) {
+                if (SwingUtilities.isLeftMouseButton(mEvent)) {
+                    leftButtonData.setState(pickedNode, comp, offset.x,  
offset.y);
+                }
+                else if (SwingUtilities.isMiddleMouseButton(mEvent)) {
+                    middleButtonData.setState(pickedNode, comp, offset.x,  
offset.y);
+                }
+                else if (SwingUtilities.isRightMouseButton(mEvent)) {
+                    rightButtonData.setState(pickedNode, comp, offset.x,  
offset.y);
                  }
              }
          }
@@ -223,121 +238,143 @@
          // This first case we don't want to give events to just
          // any Swing component - but to the one that got the
          // original mousePressed
-        if (pSwingMouseEvent.getID() == MouseEvent.MOUSE_DRAGGED
-                || pSwingMouseEvent.getID() == MouseEvent.MOUSE_RELEASED) {
-
-            // LEFT MOUSE BUTTON
-            if (SwingUtilities.isLeftMouseButton(pSwingMouseEvent) &&  
leftButtonData.getFocusedComponent() != null) {
+        if (isDragOrRelease(pSwingMouseEvent)) {
+            if (isLeftMouseButtonOnComponent(mEvent)) {
                  handleButton(pSwingMouseEvent, aEvent, leftButtonData);
              }

-            // MIDDLE MOUSE BUTTON
-            if (SwingUtilities.isMiddleMouseButton(pSwingMouseEvent) &&  
middleButtonData.getFocusedComponent() != null) {
+            if (isMiddleMouseButtonOnComponent(mEvent)) {
                  handleButton(pSwingMouseEvent, aEvent, middleButtonData);
              }

-            // RIGHT MOUSE BUTTON
-            if (SwingUtilities.isRightMouseButton(pSwingMouseEvent) &&  
rightButtonData.getFocusedComponent() != null) {
+            if (isRightMouseButtonOnComponent(mEvent)) {
                  handleButton(pSwingMouseEvent, aEvent, rightButtonData);
              }
          }
-        // This case covers the cases mousePressed, mouseClicked,
-        // and mouseMoved events
-        else if ((pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED
-                || pSwingMouseEvent.getID() == MouseEvent.MOUSE_CLICKED ||  
pSwingMouseEvent.getID() == MouseEvent.MOUSE_MOVED)
-                && comp != null) {
-
-            final MouseEvent e_temp = new MouseEvent(comp,  
pSwingMouseEvent.getID(), pSwingMouseEvent.getWhen(),
-                    pSwingMouseEvent.getModifiers(), (int) pt.getX() -  
offX, (int) pt.getY() - offY, pSwingMouseEvent
-                            .getClickCount(),  
pSwingMouseEvent.isPopupTrigger());
-
-            final PSwingMouseEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+        else if (isPressOrClickOrMove(pSwingMouseEvent) && comp != null) {
+            final MouseEvent e_temp = new MouseEvent(comp,  
pSwingMouseEvent.getID(), mEvent.getWhen(), mEvent
+                    .getModifiers(), point.x - offset.x, point.y -  
offset.y, mEvent.getClickCount(), mEvent
+                    .isPopupTrigger());
+
+            final PSwingEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+            dispatchEvent(comp, e2);
+        }
+        else if (isWheelEvent(pSwingMouseEvent) && comp != null) {
+            final MouseWheelEvent mWEvent = (MouseWheelEvent) mEvent;
+            final MouseWheelEvent e_temp = new MouseWheelEvent(comp,  
pSwingMouseEvent.getID(), mEvent.getWhen(), mEvent
+                    .getModifiers(), point.x - offset.x, point.y -  
offset.y, mEvent.getClickCount(), mEvent
+                    .isPopupTrigger(), mWEvent.getScrollType(),  
mWEvent.getScrollAmount(), mWEvent.getWheelRotation());
+
+            final PSwingMouseWheelEvent e2 = new  
PSwingMouseWheelEvent(e_temp.getID(), e_temp, aEvent);
              dispatchEvent(comp, e2);
          }

          // Now we need to check if an exit or enter event needs to
          // be dispatched - this code is independent of the mouseButtons.
          // I tested in normal Swing to see the correct behavior.
-        if (prevComponent != null) {
+        if (previousComponent != null) {
              // This means mouseExited

              // This shouldn't happen - since we're only getting node events
              if (comp == null || pSwingMouseEvent.getID() ==  
MouseEvent.MOUSE_EXITED) {
-                final MouseEvent e_temp =  
createExitEvent(pSwingMouseEvent);
-
-                final PSwingMouseEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
-
-                dispatchEvent(prevComponent, e2);
-                prevComponent = null;
+                final MouseEvent e_temp = createExitEvent(mEvent);
+
+                final PSwingEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+
+                dispatchEvent(previousComponent, e2);
+                previousComponent = null;
              }

              // This means mouseExited prevComponent and mouseEntered comp
-            else if (prevComponent != comp) {
-                MouseEvent e_temp = createExitEvent(pSwingMouseEvent);
-                PSwingMouseEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
-                dispatchEvent(prevComponent, e2);
-
-                e_temp = createEnterEvent(comp, pSwingMouseEvent, offX,  
offY);
+            else if (previousComponent != comp) {
+                MouseEvent e_temp = createExitEvent(mEvent);
+                PSwingEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+                dispatchEvent(previousComponent, e2);
+
+                e_temp = createEnterEvent(comp, mEvent, offset.x,  
offset.y);
                  e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(),  
e_temp, aEvent);
-                comp.dispatchEvent(e2);
+                comp.dispatchEvent(e2.asMouseEvent());
              }
          }
-        else {
-            // This means mouseEntered
-            if (comp != null) {
-                final MouseEvent e_temp = createEnterEvent(comp,  
pSwingMouseEvent, offX, offY);
-                final PSwingMouseEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
-                dispatchEvent(comp, e2);
-            }
+        else if (comp != null) { // This means mouseEntered
+            final MouseEvent e_temp = createEnterEvent(comp, mEvent,  
offset.x, offset.y);
+            final PSwingEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+            dispatchEvent(comp, e2);
          }

-        // todo add cursors
-        // // We have to manager our own Cursors since this is normally
-        // // done on the native side
-        // if( comp != cursorComponent &&
-        // focusNodeLeft == null &&
-        // focusNodeMiddle == null &&
-        // focusNodeRight == null ) {
-        // if( comp != null ) {
-        // cursorComponent = comp;
-        // canvas.setCursor( comp.getCursor(), false );
-        // }
-        // else {
-        // cursorComponent = null;
-        // canvas.resetCursor();
-        // }
-        // }
-
-        // Set the previous variables for next time
-        prevComponent = comp;
+        previousComponent = comp;

          if (comp != null) {
-            prevOff = new Point2D.Double(offX, offY);
+            previousOffset = offset;
          }
      }

-    private MouseEvent createEnterEvent(final Component comp, final  
PSwingMouseEvent e1, final int offX, final int offY) {
+    private Point extractSwingOffset(final Component comp, final PSwing  
swing) {
+        int offsetX = 0;
+        int offsetY = 0;
+
+        for (Component c = comp; c != swing.getComponent(); c =  
c.getParent()) {
+            offsetX += c.getLocation().x;
+            offsetY += c.getLocation().y;
+        }
+
+        return new Point(offsetX, offsetY);
+    }
+
+    private boolean isRightMouseButtonOnComponent(final MouseEvent mEvent)  
{
+        return SwingUtilities.isRightMouseButton(mEvent) &&  
rightButtonData.getFocusedComponent() != null;
+    }
+
+    private boolean isMiddleMouseButtonOnComponent(final MouseEvent  
mEvent) {
+        return SwingUtilities.isMiddleMouseButton(mEvent) &&  
middleButtonData.getFocusedComponent() != null;
+    }
+
+    private boolean isLeftMouseButtonOnComponent(final MouseEvent mEvent) {
+        return SwingUtilities.isLeftMouseButton(mEvent) &&  
leftButtonData.getFocusedComponent() != null;
+    }
+
+    private boolean isMousePress(final PSwingEvent pSwingMouseEvent) {
+        return pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED;
+    }
+
+    private boolean isWheelEvent(final PSwingEvent pSwingMouseEvent) {
+        return pSwingMouseEvent.getID() == MouseEvent.MOUSE_WHEEL;
+    }
+
+    private boolean isPressOrClickOrMove(final PSwingEvent  
pSwingMouseEvent) {
+        return isMousePress(pSwingMouseEvent) || pSwingMouseEvent.getID()  
== MouseEvent.MOUSE_CLICKED
+                || pSwingMouseEvent.getID() == MouseEvent.MOUSE_MOVED;
+    }
+
+    private boolean isDragOrRelease(final PSwingEvent pSwingMouseEvent) {
+        return pSwingMouseEvent.getID() == MouseEvent.MOUSE_DRAGGED
+                || pSwingMouseEvent.getID() == MouseEvent.MOUSE_RELEASED;
+    }
+
+    private MouseEvent createEnterEvent(final Component comp, final  
MouseEvent e1, final int offX, final int offY) {
          return new MouseEvent(comp, MouseEvent.MOUSE_ENTERED,  
e1.getWhen(), 0, (int) prevPoint.getX() - offX,
                  (int) prevPoint.getY() - offY, e1.getClickCount(),  
e1.isPopupTrigger());
      }

-    private MouseEvent createExitEvent(final PSwingMouseEvent e1) {
-        return new MouseEvent(prevComponent, MouseEvent.MOUSE_EXITED,  
e1.getWhen(), 0, (int) prevPoint.getX()
-                - (int) prevOff.getX(), (int) prevPoint.getY() - (int)  
prevOff.getY(), e1.getClickCount(), e1
-                .isPopupTrigger());
+    private MouseEvent createExitEvent(final MouseEvent e1) {
+        return new MouseEvent(previousComponent, MouseEvent.MOUSE_EXITED,  
e1.getWhen(), 0, (int) prevPoint.getX()
+                - (int) previousOffset.getX(), (int) prevPoint.getY() -  
(int) previousOffset.getY(),
+                e1.getClickCount(), e1.isPopupTrigger());
      }

-    private void handleButton(final PSwingMouseEvent e1, final PInputEvent  
aEvent, final ButtonData buttonData) {
-        Point2D pt;
-        if (buttonData.getPNode().isDescendentOf(canvas.getRoot())) {
-            pt = new Point2D.Double(e1.getX(), e1.getY());
+    private void handleButton(final PSwingEvent e1, final PInputEvent  
aEvent, final ButtonData buttonData) {
+        final MouseEvent m1 = e1.asMouseEvent();
+        if (involvesSceneNode(buttonData)) {
+            // TODO: this probably won't handle viewing through multiple
+            // cameras.
+
+            final Point2D pt = new Point2D.Double(m1.getX(), m1.getY());
              cameraToLocal(e1.getPath().getTopCamera(), pt,  
buttonData.getPNode());
-            // todo this probably won't handle viewing through multiple  
cameras.
-            final MouseEvent e_temp = new  
MouseEvent(buttonData.getFocusedComponent(), e1.getID(), e1.getWhen(), e1
+            final MouseEvent tempEvent = new  
MouseEvent(buttonData.getFocusedComponent(), m1.getID(), m1.getWhen(), m1
                      .getModifiers(), (int) pt.getX() -  
buttonData.getOffsetX(), (int) pt.getY()
-                    - buttonData.getOffsetY(), e1.getClickCount(),  
e1.isPopupTrigger());
-
-            final PSwingMouseEvent e2 =  
PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent);
+                    - buttonData.getOffsetY(), m1.getClickCount(),  
m1.isPopupTrigger());
+
+            final PSwingEvent e2 =  
PSwingMouseEvent.createMouseEvent(tempEvent.getID(), tempEvent, aEvent);
              dispatchEvent(buttonData.getFocusedComponent(), e2);
          }
          else {
@@ -346,46 +383,75 @@
          // buttonData.getPSwing().repaint(); //Experiment with  
SliderExample
          // (from Martin) suggests this line is unnecessary, and a serious
          // problem in performance.
-        e1.consume();
+        m1.consume();
          if (e1.getID() == MouseEvent.MOUSE_RELEASED) {
              buttonData.mouseReleased();
          }
      }

-    private void dispatchEvent(final Component target, final  
PSwingMouseEvent event) {
+    private boolean involvesSceneNode(final ButtonData buttonData) {
+        return buttonData.getPNode().isDescendentOf(canvas.getRoot());
+    }
+
+    private void dispatchEvent(final Component target, final PSwingEvent  
event) {
          SwingUtilities.invokeLater(new Runnable() {
              public void run() {
-                target.dispatchEvent(event);
+                target.dispatchEvent(event.asMouseEvent());
              }
          });
      }

-    private void cameraToLocal(final PCamera topCamera, final Point2D pt,  
final PNode node) {
-        AffineTransform inverse;
-        try {
-            inverse = topCamera.getViewTransform().createInverse();
-        }
-        catch (final NoninvertibleTransformException e) {
-            throw new PAffineTransformException(e,  
topCamera.getViewTransform());
-        }
-
-        /*
-         * Only apply the camera's view transform when this node is a  
descendant
-         * of PLayer
-         */
+    /**
+     * Transforms the given point from camera coordinates to the node's  
local
+     * system.
+     *
+     * @param camera camera from which coordinates are measured
+     * @param pt point to transform (will be modified)
+     * @param node node from which local coordinates are measured
+     */
+    private void cameraToLocal(final PCamera camera, final Point2D pt,  
final PNode node) {
+        if (node != null) {
+            if (descendsFromLayer(node)) {
+                final AffineTransform inverse =  
invertTransform(camera.getViewTransform());
+                inverse.transform(pt, pt);
+            }
+
+            node.globalToLocal(pt);
+        }
+    }
+
+    /**
+     * Returns true if the provided layer has a PLayer ancestor.
+     *
+     * @param node node being tested
+     *
+     * @return true if node is a descendant of a PLayer
+     */
+    private boolean descendsFromLayer(final PNode node) {
          PNode searchNode = node;
-        do {
+        while (searchNode != null) {
              searchNode = searchNode.getParent();
              if (searchNode instanceof PLayer) {
-                inverse.transform(pt, pt);
-                break;
-            }
-        } while (searchNode != null);
-
-        if (node != null) {
-            node.globalToLocal(pt);
-        }
-        return;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the inverse transform for the provided transform. Throws
+     * exception if transform is non invertible.
+     *
+     * @param transform transform to invert
+     * @return inverted transform
+     */
+    private AffineTransform invertTransform(final PAffineTransform  
transform) {
+        try {
+            return transform.createInverse();
+        }
+        catch (final NoninvertibleTransformException e) {
+            throw new PAffineTransformException(e, transform);
+        }
      }

      /**
@@ -400,12 +466,12 @@
              final InputEvent sourceSwingEvent =  
aEvent.getSourceSwingEvent();
              if (sourceSwingEvent instanceof MouseEvent) {
                  final MouseEvent swingMouseEvent = (MouseEvent)  
sourceSwingEvent;
-                final PSwingMouseEvent pSwingMouseEvent =  
PSwingMouseEvent.createMouseEvent(swingMouseEvent.getID(),
+                final PSwingEvent pSwingMouseEvent =  
PSwingMouseEvent.createMouseEvent(swingMouseEvent.getID(),
                          swingMouseEvent, aEvent);
                  if (!recursing) {
                      recursing = true;
                      dispatchEvent(pSwingMouseEvent, aEvent);
-                    if (pSwingMouseEvent.isConsumed()) {
+                    if (pSwingMouseEvent.asMouseEvent().isConsumed()) {
                          aEvent.setHandled(true);
                      }
                      recursing = false;
@@ -422,15 +488,12 @@
       * Internal Utility class for handling button interactivity.
       */
      private static class ButtonData {
-        private PSwing focusPSwing = null;
          private PNode focusNode = null;
          private Component focusComponent = null;
          private int focusOffX = 0;
          private int focusOffY = 0;

-        public void setState(final PSwing swing, final PNode visualNode,  
final Component comp, final int offX,
-                final int offY) {
-            focusPSwing = swing;
+        public void setState(final PNode visualNode, final Component comp,  
final int offX, final int offY) {
              focusComponent = comp;
              focusNode = visualNode;
              focusOffX = offX;
@@ -452,10 +515,6 @@
          public int getOffsetY() {
              return focusOffY;
          }
-
-        public PSwing getPSwing() {
-            return focusPSwing;
-        }

          public void mouseReleased() {
              focusComponent = null;
=======================================
---  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java
      
Tue Jul 28 12:46:54 2009
+++  
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java
      
Thu Aug  6 09:07:42 2009
@@ -31,7 +31,7 @@
  import java.awt.Component;
  import java.awt.event.MouseEvent;
  import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
  import java.awt.geom.Point2D;
  import java.io.Serializable;

@@ -74,7 +74,7 @@
   * @author Sam R. Reid
   * @author Lance E. Good
   */
-public class PSwingMouseEvent extends MouseEvent implements Serializable {
+public class PSwingMouseEvent extends MouseEvent implements Serializable,  
PSwingEvent {
      /**
       *
       */
@@ -104,10 +104,13 @@
       * @param e The original Java mouse event when in MOUSE_DRAGGED and
       *            MOUSE_RELEASED events.
       */
-    public static PSwingMouseEvent createMouseEvent(final int id, final  
MouseEvent e, final PInputEvent pEvent) {
+    public static PSwingEvent createMouseEvent(final int id, final  
MouseEvent e, final PInputEvent pEvent) {
          if (id == MouseEvent.MOUSE_MOVED || id ==  
MouseEvent.MOUSE_DRAGGED) {
              return new PSwingMouseMotionEvent(id, e, pEvent);
          }
+        else if (id == MouseEvent.MOUSE_WHEEL) {
+            return new PSwingMouseWheelEvent(id, (MouseWheelEvent) e,  
pEvent);
+        }
          else {
              return new PSwingMouseEvent(id, e, pEvent);
          }
@@ -228,40 +231,25 @@
       * @param listener the MouseListener or MouseMotionListener to  
dispatch to.
       */
      public void dispatchTo(final Object listener) {
-        if (listener instanceof MouseListener) {
-            final MouseListener mouseListener = (MouseListener) listener;
-            switch (getID()) {
-                case MouseEvent.MOUSE_CLICKED:
-                    mouseListener.mouseClicked(this);
-                    break;
-                case MouseEvent.MOUSE_ENTERED:
-                    mouseListener.mouseEntered(this);
-                    break;
-                case MouseEvent.MOUSE_EXITED:
-                    mouseListener.mouseExited(this);
-                    break;
-                case MouseEvent.MOUSE_PRESSED:
-                    mouseListener.mousePressed(this);
-                    break;
-                case MouseEvent.MOUSE_RELEASED:
-                    mouseListener.mouseReleased(this);
-                    break;
-                default:
-                    throw new RuntimeException("PMouseEvent with bad ID");
-            }
-        }
-        else {
-            final MouseMotionListener mouseMotionListener =  
(MouseMotionListener) listener;
-            switch (getID()) {
-                case MouseEvent.MOUSE_DRAGGED:
-                    mouseMotionListener.mouseDragged(this);
-                    break;
-                case MouseEvent.MOUSE_MOVED:
-                    mouseMotionListener.mouseMoved(this);
-                    break;
-                default:
-                    throw new RuntimeException("PMouseMotionEvent with bad  
ID");
-            }
+        final MouseListener mouseListener = (MouseListener) listener;
+        switch (getID()) {
+            case MouseEvent.MOUSE_CLICKED:
+                mouseListener.mouseClicked(this);
+                break;
+            case MouseEvent.MOUSE_ENTERED:
+                mouseListener.mouseEntered(this);
+                break;
+            case MouseEvent.MOUSE_EXITED:
+                mouseListener.mouseExited(this);
+                break;
+            case MouseEvent.MOUSE_PRESSED:
+                mouseListener.mousePressed(this);
+                break;
+            case MouseEvent.MOUSE_RELEASED:
+                mouseListener.mouseReleased(this);
+                break;
+            default:
+                throw new RuntimeException("PMouseEvent with bad ID");
          }
      }

@@ -275,4 +263,8 @@
      public void setSource(final Object aSource) {
          source = aSource;
      }
-}
+
+    public MouseEvent asMouseEvent() {
+        return this;
+    }
+}
=======================================
---  
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
      
Thu Jul 30 12:36:17 2009
+++  
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
      
Thu Aug  6 09:07:42 2009
@@ -40,11 +40,11 @@

      public void setUp() {
          finalizerCallCount = 0;
-    }
-
+    }
+
      public void testRemovePSwingDoesNothingWithForeignPSwing() {
-        PSwingCanvas canvas = new PSwingCanvas();
-        PSwing orphanPSwing = new PSwing(new JLabel());
+        final PSwingCanvas canvas = new PSwingCanvas();
+        final PSwing orphanPSwing = new PSwing(new JLabel());
          canvas.removePSwing(orphanPSwing);
      }
  }
=======================================
---  
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java
    
Sun Aug  2 19:50:05 2009
+++  
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java
    
Thu Aug  6 09:07:42 2009
@@ -38,10 +38,9 @@
  import javax.swing.JPanel;
  import javax.swing.RepaintManager;

+import junit.framework.TestCase;
  import edu.umd.cs.piccolo.util.PPaintContext;

-import junit.framework.TestCase;
-
  /**
   * JUnit test class to exercise PSwing bugfixes.
   *
@@ -102,7 +101,8 @@

          final BufferedImage img = new BufferedImage(100, 100,  
BufferedImage.TYPE_INT_RGB);
          final Graphics2D graphics =  
GraphicsEnvironment.getLocalGraphicsEnvironment().createGraphics(img);
-        final PPaintContext paintContext = new PPaintContext(graphics);;
+        final PPaintContext paintContext = new PPaintContext(graphics);
+        ;
          pSwing.paintComponent(paintContext);
          assertEquals(Color.RED.getRGB(), img.getRGB(50, 50));
      }

--~--~---------~--~----~------------~-------~--~----~
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to