]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/events/NodeEventHandler.java
Sync git svn branch with SVN repository r33269.
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / events / NodeEventHandler.java
index d1f6e6ef2da50f32399b0b914d4bc02692738e21..ac0e36f73804b8c171db1282dabe05707c6097b9 100644 (file)
@@ -20,10 +20,12 @@ import java.awt.dnd.DragSourceDragEvent;
 import java.awt.dnd.DragSourceDropEvent;\r
 import java.awt.dnd.DragSourceEvent;\r
 import java.awt.dnd.DragSourceListener;\r
 import java.awt.dnd.DragSourceDropEvent;\r
 import java.awt.dnd.DragSourceEvent;\r
 import java.awt.dnd.DragSourceListener;\r
+import java.awt.event.InputEvent;\r
 import java.awt.geom.Point2D;\r
 import java.util.ArrayList;\r
 import java.util.Arrays;\r
 import java.util.Comparator;\r
 import java.awt.geom.Point2D;\r
 import java.util.ArrayList;\r
 import java.util.Arrays;\r
 import java.util.Comparator;\r
+import java.util.List;\r
 \r
 import org.simantics.scenegraph.INode;\r
 import org.simantics.scenegraph.g2d.G2DFocusManager;\r
 \r
 import org.simantics.scenegraph.INode;\r
 import org.simantics.scenegraph.g2d.G2DFocusManager;\r
@@ -31,6 +33,7 @@ import org.simantics.scenegraph.g2d.G2DSceneGraph;
 import org.simantics.scenegraph.g2d.IG2DNode;\r
 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
 import org.simantics.scenegraph.g2d.IG2DNode;\r
 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
+import org.simantics.scenegraph.g2d.events.adapter.AWTMouseEventAdapter;\r
 import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
 
 /**\r
 import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
 
 /**\r
@@ -44,6 +47,8 @@ public class NodeEventHandler implements IEventHandler {
     private static final boolean DEBUG_EVENTS       = false;\r
     private static final boolean DEBUG_HANDLER_SORT = false;\r
 \r
     private static final boolean DEBUG_EVENTS       = false;\r
     private static final boolean DEBUG_HANDLER_SORT = false;\r
 \r
+    private static final IEventHandler[] NONE = {};\r
+\r
     public static class TreePreOrderComparator implements Comparator<IEventHandler> {\r
 \r
         static enum Order {\r
     public static class TreePreOrderComparator implements Comparator<IEventHandler> {\r
 \r
         static enum Order {\r
@@ -146,120 +151,129 @@ public class NodeEventHandler implements IEventHandler {
     TreePreOrderComparator COMPARATOR = new TreePreOrderComparator(TreePreOrderComparator.Order.DESCENDING);\r
 \r
     /**\r
     TreePreOrderComparator COMPARATOR = new TreePreOrderComparator(TreePreOrderComparator.Order.DESCENDING);\r
 \r
     /**\r
-     * FocusEvents are propagated to event handlers in undefined order.\r
+     * {@link FocusEvent} are propagated first to the scene graph focus node,\r
+     * then to event handler nodes in scene graph tree pre-order.\r
      */\r
      */\r
-    protected ListenerList<IEventHandler> focusListeners         = new ListenerList<IEventHandler>(IEventHandler.class);\r
+    protected List<IEventHandler>         focusListeners         = new ArrayList<IEventHandler>();\r
+    protected IEventHandler[]             sortedFocusListeners   = null;\r
 \r
     /**\r
 \r
     /**\r
-     * TimeEvents are propagated to events handlers in an undefined order.\r
+     * {@link TimeEvent} are propagated first to the scene graph focus node,\r
+     * then to event handler nodes in scene graph tree pre-order.\r
      */\r
      */\r
-    protected ListenerList<IEventHandler> timeListeners          = new ListenerList<IEventHandler>(IEventHandler.class);\r
+    protected List<IEventHandler>         timeListeners          = new ArrayList<IEventHandler>();\r
+    protected IEventHandler[]             sortedTimeListeners    = null;\r
 \r
     /**\r
 \r
     /**\r
-     * CommandEvents are propagated first to the scene graph focus node, then to\r
-     * event handler nodes in scene graph tree pre-order.\r
+     * {@link CommandEvent} are propagated first to the scene graph focus node,\r
+     * then to event handler nodes in scene graph tree pre-order.\r
      */\r
      */\r
-    protected ListenerList<IEventHandler> commandListeners       = new ListenerList<IEventHandler>(IEventHandler.class);\r
+    protected List<IEventHandler>         commandListeners       = new ArrayList<IEventHandler>();\r
     protected IEventHandler[]             sortedCommandListeners = null;\r
 \r
     /**\r
     protected IEventHandler[]             sortedCommandListeners = null;\r
 \r
     /**\r
-     * KeyEvents are propagated first to the scene graph focus node, then to\r
-     * event handler nodes in scene graph tree pre-order.\r
+     * {@link KeyEvent} are propagated first to the scene graph focus node, then\r
+     * to event handler nodes in scene graph tree pre-order.\r
      */\r
      */\r
-    protected ListenerList<IEventHandler> keyListeners           = new ListenerList<IEventHandler>(IEventHandler.class);\r
+    protected List<IEventHandler>         keyListeners           = new ArrayList<IEventHandler>();\r
     protected IEventHandler[]             sortedKeyListeners     = null;\r
 \r
     /**\r
     protected IEventHandler[]             sortedKeyListeners     = null;\r
 \r
     /**\r
-     * MouseEvents are propagated first to the scene graph focus node, then to\r
-     * event handler nodes in scene graph tree pre-order.\r
+     * {@link MouseEvent} are propagated first to the scene graph focus node,\r
+     * then to event handler nodes in scene graph tree pre-order.\r
      */\r
      */\r
-    protected ListenerList<IEventHandler> mouseListeners         = new ListenerList<IEventHandler>(IEventHandler.class);\r
+    protected List<IEventHandler>         mouseListeners         = new ArrayList<IEventHandler>();\r
     protected IEventHandler[]             sortedMouseListeners   = null;\r
     protected IEventHandler[]             sortedMouseListeners   = null;\r
+\r
+    /**\r
+     * {@link MouseDragBegin} events are propagated first to the scene graph focus node, then\r
+     * to event handler nodes in scene graph tree pre-order.\r
+     */\r
+    protected List<IEventHandler>         mouseDragBeginListeners = new ArrayList<IEventHandler>();\r
+    protected IEventHandler[]             sortedMouseDragBeginListeners = null;\r
 
     /**\r
      * The scene graph this instance handles event propagation for.\r
      */\r
     protected G2DSceneGraph               sg;\r
 
     /**\r
      * The scene graph this instance handles event propagation for.\r
      */\r
     protected G2DSceneGraph               sg;\r
-    \r
-    protected DragSource ds = new DragSource();\r
+\r
+    /**\r
+     * For proper initiation of native DnD operations within this AWT-based\r
+     * scenegraph system.\r
+     */\r
+    protected DragSource                  ds = new DragSource();\r
 
     public NodeEventHandler(G2DSceneGraph sg) {\r
         this.sg = sg;
     }
 \r
 
     public NodeEventHandler(G2DSceneGraph sg) {\r
         this.sg = sg;
     }
 \r
+    @SuppressWarnings("unused")\r
     private IEventHandler[] sort(IEventHandler[] sort) {\r
         if (DEBUG_HANDLER_SORT)\r
     private IEventHandler[] sort(IEventHandler[] sort) {\r
         if (DEBUG_HANDLER_SORT)\r
-            debug("sort " + sort.length + " handlers");\r
-        IEventHandler[] copy = Arrays.copyOf(sort, sort.length);\r
-        Arrays.sort(copy, COMPARATOR);\r
-        return copy;\r
+            debug("copy sort " + sort.length + " handlers");\r
+        return sortInplace(Arrays.copyOf(sort, sort.length));\r
     }\r
     }\r
-    \r
-    public void setRootPane(Component rootPane) {\r
-       \r
-       final DragSourceListener dsl = new DragSourceListener() {\r
-                       \r
-                       @Override\r
-                       public void dropActionChanged(DragSourceDragEvent dsde) {\r
-                       }\r
-                       \r
-                       @Override\r
-                       public void dragOver(DragSourceDragEvent dsde) {\r
-                       }\r
-                       \r
-                       @Override\r
-                       public void dragExit(DragSourceEvent dse) {\r
-                       }\r
-                       \r
-                       @Override\r
-                       public void dragEnter(DragSourceDragEvent dsde) {\r
-                       }\r
-                       \r
-                       @Override\r
-                       public void dragDropEnd(DragSourceDropEvent dsde) {\r
-                       }\r
-               };\r
-               ds.createDefaultDragGestureRecognizer(rootPane, DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK, new DragGestureListener() {\r
-                       \r
-                       @Override\r
-                       public void dragGestureRecognized(DragGestureEvent dge) {\r
-                               MouseDragBegin event = new MouseDragBegin(NodeEventHandler.this,\r
-                                               0, 0, 0, 0, 0,\r
-                                               new Point2D.Double(),new Point2D.Double(),\r
-                                               new Point2D.Double(),new Point2D.Double());\r
-                               handleMouseEvent(event, EventTypes.MouseDragBegin);\r
-                               if(event.transferable != null) {\r
-                                       ds.startDrag(dge, null, event.transferable, dsl);\r
-                                       if (DEBUG_EVENTS)\r
-                                               debug("dragGestureRecognized: startDrag " + event.transferable);\r
-                               }\r
-                       }\r
-               });\r
-               ds.addDragSourceListener(dsl);\r
-       \r
+\r
+    private IEventHandler[] sortInplace(IEventHandler[] sort) {\r
+        if (DEBUG_HANDLER_SORT)\r
+            debug("in-place sort " + sort.length + " handlers");\r
+        Arrays.sort(sort, COMPARATOR);\r
+        return sort;\r
     }\r
 \r
     }\r
 \r
-//    @Override
-//    public void mouseReleased(MouseEvent event) {
-//        Point op = event.getPoint();
-//        for (MouseListener l : mouseListeners.getListeners()) {
-//            MouseEvent e = (MouseEvent) NodeUtil.transformEvent(event,(IG2DNode) l);
-//            l.mouseReleased(e);
-//            event.translatePoint((int)(op.getX()-event.getX()), (int)(op.getY()-event.getY()));
-//            if (e.isConsumed())
-//                break;
-//        }
-//    }
-//
-//    @Override
-//    public void mouseMoved(MouseEvent event) {
-//        for (MouseMotionListener l : mouseMotionListeners.getListeners()) {
-//            MouseEvent e = (MouseEvent) NodeUtil.transformEvent(event,(IG2DNode) l);
-//            l.mouseMoved(e);
-//            if (e.isConsumed())
-//                break;
-//        }
-//    }
+    public void setRootPane(Component rootPane) {\r
+        final DragSourceListener dsl = new DragSourceListener() {\r
+            @Override\r
+            public void dropActionChanged(DragSourceDragEvent dsde) {\r
+            }\r
+            @Override\r
+            public void dragOver(DragSourceDragEvent dsde) {\r
+            }\r
+            @Override\r
+            public void dragExit(DragSourceEvent dse) {\r
+            }\r
+            @Override\r
+            public void dragEnter(DragSourceDragEvent dsde) {\r
+            }\r
+            @Override\r
+            public void dragDropEnd(DragSourceDropEvent dsde) {\r
+            }\r
+        };\r
+        DragGestureListener dgl = new DragGestureListener() {\r
+            @Override\r
+            public void dragGestureRecognized(DragGestureEvent dge) {\r
+                InputEvent ie = dge.getTriggerEvent();\r
+                if (ie instanceof java.awt.event.MouseEvent) {\r
+                    java.awt.event.MouseEvent e = (java.awt.event.MouseEvent) ie;\r
+                    Point2D controlPos = AWTMouseEventAdapter.getControlPosition(e);\r
+                    MouseDragBegin event = new MouseDragBegin(NodeEventHandler.this,\r
+                            e.getWhen(), 0,\r
+                            AWTMouseEventAdapter.getButtonStatus(e),\r
+                            AWTMouseEventAdapter.getStateMask(e),\r
+                            AWTMouseEventAdapter.getMouseButton(e),\r
+                            // TODO: fix canvas position if necessary\r
+                            new Point2D.Double(),\r
+                            controlPos,\r
+                            controlPos,\r
+                            AWTMouseEventAdapter.getScreenPosition(e));\r
+\r
+                    // Send MouseDragBegin to the scenegraph and see\r
+                    // if anyone sets event.transferable to start DnD.\r
+                    handleMouseDragBeginEvent(event, EventTypes.MouseDragBegin);\r
+                    if (event.transferable != null) {\r
+                        ds.startDrag(dge, null, event.transferable, dsl);\r
+                        if (DEBUG_EVENTS)\r
+                            debug("dragGestureRecognized: startDrag " + event.transferable);\r
+                    }\r
+                }\r
+            }\r
+        };\r
+        ds.createDefaultDragGestureRecognizer(\r
+                rootPane,\r
+                DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK,\r
+                dgl);\r
+        ds.addDragSourceListener(dsl);\r
+    }\r
 
     public boolean mousePressed(MouseButtonPressedEvent event) {\r
         G2DFocusManager.INSTANCE.clearFocus();\r
 
     public boolean mousePressed(MouseButtonPressedEvent event) {\r
         G2DFocusManager.INSTANCE.clearFocus();\r
@@ -283,47 +297,65 @@ public class NodeEventHandler implements IEventHandler {
         }\r
     }\r
 \r
         }\r
     }\r
 \r
-    private boolean handleMouseEvent(MouseEvent e, int eventType) {\r
-        IEventHandler[] sorted = sortedMouseListeners;\r
-        if (sorted == null)\r
-            sortedMouseListeners = sorted = sort(mouseListeners.getListeners());\r
-        return handleEvent(e, sg.getFocusNode(), sorted);\r
-    }\r
-\r
     private boolean handleEvent(Event e, IG2DNode focusNode, IEventHandler[] handlers) {\r
     private boolean handleEvent(Event e, IG2DNode focusNode, IEventHandler[] handlers) {\r
+        int typeMask = EventTypes.toTypeMask(e);\r
         if (focusNode instanceof IEventHandler) {\r
             IEventHandler h = (IEventHandler) focusNode;\r
         if (focusNode instanceof IEventHandler) {\r
             IEventHandler h = (IEventHandler) focusNode;\r
-            if (eats(h.getEventMask(), EventTypes.toTypeMask(e))) {\r
+            if (eats(h.getEventMask(), typeMask)) {\r
                 if (h.handleEvent(e))\r
                     return true;\r
             }\r
         }\r
         for (IEventHandler l : handlers) {\r
                 if (h.handleEvent(e))\r
                     return true;\r
             }\r
         }\r
         for (IEventHandler l : handlers) {\r
-            if (l.handleEvent(e))\r
-                return true;\r
+            if (eats(l.getEventMask(), typeMask)) {\r
+                if (l.handleEvent(e))\r
+                    return true;\r
+            }\r
         }\r
         return false;\r
     }\r
 \r
         }\r
         return false;\r
     }\r
 \r
+    private boolean handleMouseEvent(MouseEvent e, int eventType) {\r
+        IEventHandler[] sorted = sortedMouseListeners;\r
+        if (sorted == null)\r
+            sortedMouseListeners = sorted = sortInplace(mouseListeners.toArray(NONE));\r
+        return handleEvent(e, sg.getFocusNode(), sorted);\r
+    }\r
+\r
+    private boolean handleMouseDragBeginEvent(MouseEvent e, int eventType) {\r
+        IEventHandler[] sorted = sortedMouseDragBeginListeners;\r
+        if (sorted == null)\r
+            sortedMouseDragBeginListeners = sorted = sortInplace(mouseDragBeginListeners.toArray(NONE));\r
+        // Give null for focusNode because we want to propagate\r
+        // this event in scene tree pre-order only.\r
+        return handleEvent(e, null, sorted);\r
+    }\r
+\r
     private boolean handleFocusEvent(FocusEvent e) {\r
     private boolean handleFocusEvent(FocusEvent e) {\r
-        return handleEvent(e, null, focusListeners.getListeners());\r
+        IEventHandler[] sorted = sortedFocusListeners;\r
+        if (sorted == null)\r
+            sortedFocusListeners = sorted = sortInplace(focusListeners.toArray(NONE));\r
+        return handleEvent(e, null, sorted);\r
     }\r
 \r
     private boolean handleTimeEvent(TimeEvent e) {\r
     }\r
 \r
     private boolean handleTimeEvent(TimeEvent e) {\r
-        return handleEvent(e, null, timeListeners.getListeners());\r
+        IEventHandler[] sorted = sortedTimeListeners;\r
+        if (sorted == null)\r
+            sortedTimeListeners = sorted = sortInplace(timeListeners.toArray(NONE));\r
+        return handleEvent(e, null, sorted);\r
     }\r
 \r
     private boolean handleCommandEvent(CommandEvent e) {\r
         IEventHandler[] sorted = sortedCommandListeners;\r
         if (sorted == null)\r
     }\r
 \r
     private boolean handleCommandEvent(CommandEvent e) {\r
         IEventHandler[] sorted = sortedCommandListeners;\r
         if (sorted == null)\r
-            sortedCommandListeners = sorted = sort(commandListeners.getListeners());\r
+            sortedCommandListeners = sorted = sortInplace(commandListeners.toArray(NONE));\r
         return handleEvent(e, sg.getFocusNode(), sorted);\r
     }\r
 \r
     private boolean handleKeyEvent(KeyEvent e) {\r
         IEventHandler[] sorted = sortedKeyListeners;\r
         if (sorted == null)\r
         return handleEvent(e, sg.getFocusNode(), sorted);\r
     }\r
 \r
     private boolean handleKeyEvent(KeyEvent e) {\r
         IEventHandler[] sorted = sortedKeyListeners;\r
         if (sorted == null)\r
-            sortedKeyListeners = sorted = sort(keyListeners.getListeners());\r
+            sortedKeyListeners = sorted = sortInplace(keyListeners.toArray(NONE));\r
         return handleEvent(e, sg.getFocusNode(), sorted);\r
     }\r
 
         return handleEvent(e, sg.getFocusNode(), sorted);\r
     }\r
 
@@ -350,11 +382,13 @@ public class NodeEventHandler implements IEventHandler {
             case EventTypes.KeyReleased:\r
                 return handleKeyEvent((KeyEvent) e);\r
 \r
             case EventTypes.KeyReleased:\r
                 return handleKeyEvent((KeyEvent) e);\r
 \r
+            case EventTypes.MouseDragBegin:\r
+                return handleMouseDragBeginEvent((MouseEvent) e, eventType);\r
+\r
             case EventTypes.MouseButtonPressed:\r
             case EventTypes.MouseButtonReleased:\r
             case EventTypes.MouseClick:\r
             case EventTypes.MouseDoubleClick:\r
             case EventTypes.MouseButtonPressed:\r
             case EventTypes.MouseButtonReleased:\r
             case EventTypes.MouseClick:\r
             case EventTypes.MouseDoubleClick:\r
-            case EventTypes.MouseDragBegin:\r
             case EventTypes.MouseEnter:\r
             case EventTypes.MouseExit:\r
             case EventTypes.MouseMoved:\r
             case EventTypes.MouseEnter:\r
             case EventTypes.MouseExit:\r
             case EventTypes.MouseMoved:\r
@@ -378,17 +412,23 @@ public class NodeEventHandler implements IEventHandler {
         }\r
         if (eats(mask, EventTypes.FocusMask)) {\r
             focusListeners.add(item);\r
         }\r
         if (eats(mask, EventTypes.FocusMask)) {\r
             focusListeners.add(item);\r
+            sortedFocusListeners = null;\r
         }\r
         if (eats(mask, EventTypes.KeyMask)) {\r
             keyListeners.add(item);\r
             sortedKeyListeners = null;\r
         }\r
         }\r
         if (eats(mask, EventTypes.KeyMask)) {\r
             keyListeners.add(item);\r
             sortedKeyListeners = null;\r
         }\r
-        if (eats(mask, EventTypes.MouseMask)) {\r
+        if (eats(mask, EventTypes.MouseDragBeginMask)) {\r
+            mouseDragBeginListeners.add(item);\r
+            sortedMouseDragBeginListeners = null;\r
+        }\r
+        if (eats(mask, EventTypes.MouseMask & ~EventTypes.MouseDragBeginMask)) {\r
             mouseListeners.add(item);\r
             sortedMouseListeners = null;\r
         }\r
         if (eats(mask, EventTypes.TimeMask)) {\r
             timeListeners.add(item);\r
             mouseListeners.add(item);\r
             sortedMouseListeners = null;\r
         }\r
         if (eats(mask, EventTypes.TimeMask)) {\r
             timeListeners.add(item);\r
+            sortedTimeListeners = null;\r
         }\r
     }\r
 \r
         }\r
     }\r
 \r
@@ -404,17 +444,23 @@ public class NodeEventHandler implements IEventHandler {
         }\r
         if (eats(mask, EventTypes.FocusMask)) {\r
             removed |= focusListeners.remove(item);\r
         }\r
         if (eats(mask, EventTypes.FocusMask)) {\r
             removed |= focusListeners.remove(item);\r
+            sortedFocusListeners = null;\r
         }\r
         if (eats(mask, EventTypes.KeyMask)) {\r
             removed |= keyListeners.remove(item);\r
             sortedKeyListeners = null;\r
         }\r
         }\r
         if (eats(mask, EventTypes.KeyMask)) {\r
             removed |= keyListeners.remove(item);\r
             sortedKeyListeners = null;\r
         }\r
-        if (eats(mask, EventTypes.MouseMask)) {\r
+        if (eats(mask, EventTypes.MouseDragBeginMask)) {\r
+            removed |= mouseDragBeginListeners.remove(item);\r
+            sortedMouseDragBeginListeners = null;\r
+        }\r
+        if (eats(mask, EventTypes.MouseMask & ~EventTypes.MouseDragBeginMask)) {\r
             removed |= mouseListeners.remove(item);\r
             sortedMouseListeners = null;\r
         }\r
         if (eats(mask, EventTypes.TimeMask)) {\r
             removed |= timeListeners.remove(item);\r
             removed |= mouseListeners.remove(item);\r
             sortedMouseListeners = null;\r
         }\r
         if (eats(mask, EventTypes.TimeMask)) {\r
             removed |= timeListeners.remove(item);\r
+            sortedTimeListeners = null;\r
         }\r
         return removed;\r
     }\r
         }\r
         return removed;\r
     }\r