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.util.List;\r
\r
import org.simantics.scenegraph.INode;\r
import org.simantics.scenegraph.g2d.G2DFocusManager;\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
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
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
- 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
- * 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
- 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
- * 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
- 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
- * 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
- 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
- * 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
- protected ListenerList<IEventHandler> mouseListeners = new ListenerList<IEventHandler>(IEventHandler.class);\r
+ protected List<IEventHandler> mouseListeners = new ArrayList<IEventHandler>();\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
- 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
+ @SuppressWarnings("unused")\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
- 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
-// @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
}\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
+ int typeMask = EventTypes.toTypeMask(e);\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 (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
+ 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
- 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
- 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
- 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
- sortedKeyListeners = sorted = sort(keyListeners.getListeners());\r
+ sortedKeyListeners = sorted = sortInplace(keyListeners.toArray(NONE));\r
return handleEvent(e, sg.getFocusNode(), sorted);\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.MouseDragBegin:\r
case EventTypes.MouseEnter:\r
case EventTypes.MouseExit:\r
case EventTypes.MouseMoved:\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
- 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
+ sortedTimeListeners = null;\r
}\r
}\r
\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
- 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
+ sortedTimeListeners = null;\r
}\r
return removed;\r
}\r