-\r
- private static final boolean DEBUG_EVENTS = false;\r
- private static final boolean DEBUG_HANDLER_SORT = false;\r
-\r
- public static class TreePreOrderComparator implements Comparator<IEventHandler> {\r
-\r
- static enum Order {\r
- ASCENDING,\r
- DESCENDING\r
- }\r
-\r
- static class Temp {\r
- ArrayList<INode> path1 = new ArrayList<INode>();\r
- ArrayList<INode> path2 = new ArrayList<INode>();\r
- }\r
-\r
- private transient ThreadLocal<Temp> temp = new ThreadLocal<Temp>() {\r
- protected Temp initialValue() {\r
- return new Temp();\r
- }\r
- };\r
-\r
- Order order;\r
-\r
- public TreePreOrderComparator(Order order) {\r
- this.order = order;\r
- }\r
-\r
- void getTreePath(INode node, ArrayList<INode> result) {\r
- result.clear();\r
- for (INode parent = node.getParent(); parent != null; parent = parent.getParent())\r
- result.add(parent);\r
- }\r
-\r
- void notSameGraph(INode o1, INode o2) {\r
- throw new IllegalStateException("nodes " + o1 + " and " + o2\r
- + " not part of same scene graph.\n\t root 1: " + o1.getRootNode() + "\n\troot 2: "\r
- + o2.getRootNode());\r
- }\r
-\r
- @Override\r
- public int compare(IEventHandler e1, IEventHandler e2) {\r
- if (e1 == e2)\r
- return 0;\r
-\r
- Temp tmp = temp.get();\r
- ArrayList<INode> path1 = tmp.path1;\r
- ArrayList<INode> path2 = tmp.path2;\r
-\r
- // Get path to root node for both nodes\r
- INode o1 = (INode) e1;\r
- INode o2 = (INode) e2;\r
- getTreePath(o1, path1);\r
- getTreePath(o2, path2);\r
-\r
- // Sanity checks: nodes part of same scene graph\r
- INode root1 = path1.isEmpty() ? o1 : path1.get(path1.size() - 1);\r
- INode root2 = path2.isEmpty() ? o2 : path2.get(path2.size() - 1);\r
- if (root1 != root2)\r
- notSameGraph(o1, o2);\r
-\r
- try {\r
- // Find first non-matching nodes in the paths starting from the root node\r
- int i1 = path1.size() - 1;\r
- int i2 = path2.size() - 1;\r
- for (; i1 >= 0 && i2 >= 0; --i1, --i2) {\r
- INode p1 = path1.get(i1);\r
- INode p2 = path2.get(i2);\r
- if (p1 != p2) {\r
- break;\r
- }\r
- }\r
-\r
- // Pre-order: a node that is on the tree path of another node is first\r
- if (i1 < 0)\r
- return Order.ASCENDING == order ? -1 : 1;\r
- if (i2 < 0)\r
- return Order.ASCENDING == order ? 1 : -1;\r
-\r
- INode n1 = path1.get(i1);\r
- INode n2 = path2.get(i2);\r
- IG2DNode g1 = n1 instanceof IG2DNode ? (IG2DNode) n1 : null;\r
- IG2DNode g2 = n2 instanceof IG2DNode ? (IG2DNode) n2 : null;\r
- if (g1 != null && g2 != null) {\r
- int z1 = g1.getZIndex();\r
- int z2 = g2.getZIndex();\r
- int c = compare(z1, z2);\r
- return order == Order.ASCENDING ? c : -c;\r
- }\r
- // Can't sort non-IG2DNodes.\r
- return 0;\r
- } finally {\r
- // Don't hold on to objects unnecessarily\r
- path1.clear();\r
- path2.clear();\r
- }\r
- }\r
-\r
- private int compare(int v1, int v2) {\r
- return v1 < v2 ? -1 : (v1 > v2 ? 1 : 0);\r
- }\r
- };\r
-\r
- TreePreOrderComparator COMPARATOR = new TreePreOrderComparator(TreePreOrderComparator.Order.DESCENDING);\r
-\r
- /**\r
- * FocusEvents are propagated to event handlers in undefined order.\r
- */\r
- protected ListenerList<IEventHandler> focusListeners = new ListenerList<IEventHandler>(IEventHandler.class);\r
-\r
- /**\r
- * TimeEvents are propagated to events handlers in an undefined order.\r
- */\r
- protected ListenerList<IEventHandler> timeListeners = new ListenerList<IEventHandler>(IEventHandler.class);\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
- */\r
- protected ListenerList<IEventHandler> commandListeners = new ListenerList<IEventHandler>(IEventHandler.class);\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
- */\r
- protected ListenerList<IEventHandler> keyListeners = new ListenerList<IEventHandler>(IEventHandler.class);\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
- */\r
- protected ListenerList<IEventHandler> mouseListeners = new ListenerList<IEventHandler>(IEventHandler.class);\r
- protected IEventHandler[] sortedMouseListeners = 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
-
- public NodeEventHandler(G2DSceneGraph sg) {\r
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NodeEventHandler.class);
+
+ private static final boolean DEBUG_EVENTS = false;
+ private static final boolean DEBUG_HANDLER_SORT = false;
+
+ private static final IEventHandler[] NONE = {};
+
+ public static class TreePreOrderComparator implements Comparator<IEventHandler> {
+
+ static enum Order {
+ ASCENDING,
+ DESCENDING
+ }
+
+ static class Temp {
+ ArrayList<INode> path1 = new ArrayList<INode>();
+ ArrayList<INode> path2 = new ArrayList<INode>();
+ }
+
+ private transient ThreadLocal<Temp> temp = new ThreadLocal<Temp>() {
+ protected Temp initialValue() {
+ return new Temp();
+ }
+ };
+
+ Order order;
+
+ public TreePreOrderComparator(Order order) {
+ this.order = order;
+ }
+
+ void getTreePath(INode node, ArrayList<INode> result) {
+ result.clear();
+ for (; node != null; node = node.getParent())
+ result.add(node);
+ }
+
+ void notSameGraph(INode o1, INode o2) {
+ throw new IllegalStateException("nodes " + o1 + " and " + o2
+ + " not part of same scene graph.\n\t root 1: " + o1.getRootNode() + "\n\troot 2: "
+ + o2.getRootNode());
+ }
+
+ @Override
+ public int compare(IEventHandler e1, IEventHandler e2) {
+ if (e1 == e2)
+ return 0;
+
+ Temp tmp = temp.get();
+ ArrayList<INode> path1 = tmp.path1;
+ ArrayList<INode> path2 = tmp.path2;
+
+ try {
+ // Get path to root node for both nodes
+ getTreePath((INode) e1, path1);
+ getTreePath((INode) e2, path2);
+
+ // Sanity checks: nodes part of same scene graph
+ if (path1.get(path1.size() - 1) != path2.get(path2.size() - 1))
+ notSameGraph((INode)e1, (INode)e2);
+
+ // Find first non-matching nodes in the paths starting from the root node
+ int i1 = path1.size() - 1;
+ int i2 = path2.size() - 1;
+ for (; i1 >= 0 && i2 >= 0; --i1, --i2) {
+ INode p1 = path1.get(i1);
+ INode p2 = path2.get(i2);
+ if (p1 != p2) {
+ break;
+ }
+ }
+
+ // Pre-order: a node that is on the tree path of another node is first
+ if (i1 < 0)
+ return Order.ASCENDING == order ? -1 : 1;
+ if (i2 < 0)
+ return Order.ASCENDING == order ? 1 : -1;
+
+ return compare(path1.get(i1), path2.get(i2));
+ } finally {
+ // Don't hold on to objects unnecessarily
+ path1.clear();
+ path2.clear();
+ }
+ }
+
+ private int compare(INode n1, INode n2) {
+ if(n1 instanceof IG2DNode) {
+ if(n2 instanceof IG2DNode) {
+ int z1 = ((IG2DNode)n1).getZIndex();
+ int z2 = ((IG2DNode)n2).getZIndex();
+ int c = Integer.compare(z1, z2);
+ return order == Order.ASCENDING ? c : -c;
+ }
+ else
+ return -1; // sort IG2DNodes before non-IG2DNodes
+ }
+ else {
+ if(n2 instanceof IG2DNode)
+ return 1;
+ else
+ return 0; // all non-IG2DNodes are equal in comparison
+ }
+ }
+ };
+
+ TreePreOrderComparator COMPARATOR = new TreePreOrderComparator(TreePreOrderComparator.Order.DESCENDING);
+
+ /**
+ * {@link FocusEvent} are propagated first to the scene graph focus node,
+ * then to event handler nodes in scene graph tree pre-order.
+ */
+ protected List<IEventHandler> focusListeners = new ArrayList<IEventHandler>();
+ protected IEventHandler[] sortedFocusListeners = null;
+
+ /**
+ * {@link TimeEvent} are propagated first to the scene graph focus node,
+ * then to event handler nodes in scene graph tree pre-order.
+ */
+ protected List<IEventHandler> timeListeners = new ArrayList<IEventHandler>();
+ protected IEventHandler[] sortedTimeListeners = null;
+
+ /**
+ * {@link CommandEvent} are propagated first to the scene graph focus node,
+ * then to event handler nodes in scene graph tree pre-order.
+ */
+ protected List<IEventHandler> commandListeners = new ArrayList<IEventHandler>();
+ protected IEventHandler[] sortedCommandListeners = null;
+
+ /**
+ * {@link KeyEvent} are propagated first to the scene graph focus node, then
+ * to event handler nodes in scene graph tree pre-order.
+ */
+ protected List<IEventHandler> keyListeners = new ArrayList<IEventHandler>();
+ protected IEventHandler[] sortedKeyListeners = null;
+
+ /**
+ * {@link MouseEvent} are propagated first to the scene graph focus node,
+ * then to event handler nodes in scene graph tree pre-order.
+ */
+ protected List<IEventHandler> mouseListeners = new ArrayList<IEventHandler>();
+ protected IEventHandler[] sortedMouseListeners = null;
+
+ /**
+ * {@link MouseDragBegin} events are propagated first to the scene graph focus node, then
+ * to event handler nodes in scene graph tree pre-order.
+ */
+ protected List<IEventHandler> mouseDragBeginListeners = new ArrayList<IEventHandler>();
+ protected IEventHandler[] sortedMouseDragBeginListeners = null;
+
+ /**
+ * The scene graph this instance handles event propagation for.
+ */
+ protected G2DSceneGraph sg;
+
+ public NodeEventHandler(G2DSceneGraph sg) {