--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.g2d.diagram.impl;\r
+\r
+import java.awt.Color;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+import java.util.Comparator;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
+\r
+import org.simantics.g2d.canvas.Hints;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.canvas.ICanvasParticipant;\r
+import org.simantics.g2d.canvas.IContentContext;\r
+import org.simantics.g2d.canvas.IMouseCaptureContext;\r
+import org.simantics.g2d.canvas.IMouseCursorContext;\r
+import org.simantics.g2d.canvas.impl.MouseCaptureContext;\r
+import org.simantics.g2d.canvas.impl.MouseCursorContext;\r
+import org.simantics.g2d.canvas.impl.PaintableContextImpl;\r
+import org.simantics.g2d.chassis.ITooltipProvider;\r
+import org.simantics.g2d.diagram.DiagramClass;\r
+import org.simantics.g2d.diagram.DiagramHints;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.participant.DiagramParticipant;\r
+import org.simantics.g2d.diagram.participant.ElementInteractor;\r
+import org.simantics.g2d.diagram.participant.ElementPainter;\r
+import org.simantics.g2d.diagram.participant.Selection;\r
+import org.simantics.g2d.diagram.participant.TerminalPainter;\r
+import org.simantics.g2d.diagram.participant.ZOrderHandler;\r
+import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.g2d.multileveldiagram.TransitionFunction;\r
+import org.simantics.g2d.multileveldiagram.ZoomTransitionParticipant;\r
+import org.simantics.g2d.participant.BackgroundPainter;\r
+import org.simantics.g2d.participant.CanvasGrab;\r
+import org.simantics.g2d.participant.GridPainter;\r
+import org.simantics.g2d.participant.HandPainter;\r
+import org.simantics.g2d.participant.KeyToCommand;\r
+import org.simantics.g2d.participant.KeyUtil;\r
+import org.simantics.g2d.participant.MouseUtil;\r
+import org.simantics.g2d.participant.PointerPainter;\r
+import org.simantics.g2d.participant.RulerPainter;\r
+import org.simantics.g2d.participant.SubCanvas;\r
+import org.simantics.g2d.participant.SymbolUtil;\r
+import org.simantics.g2d.participant.TimeParticipant;\r
+import org.simantics.g2d.participant.TransformUtil;\r
+import org.simantics.g2d.scenegraph.SceneGraphConstants;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+import org.simantics.scenegraph.g2d.G2DSceneGraph;\r
+import org.simantics.scenegraph.g2d.events.Event;\r
+import org.simantics.scenegraph.g2d.events.EventHandlerStack;\r
+import org.simantics.scenegraph.g2d.events.EventQueue;\r
+import org.simantics.scenegraph.g2d.events.IEventHandlerStack;\r
+import org.simantics.scenegraph.g2d.events.IEventQueue;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEventCoalescer;\r
+import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;\r
+import org.simantics.scenegraph.g2d.events.IEventQueue.IEventQueueListener;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent;\r
+import org.simantics.scenegraph.g2d.events.command.CommandKeyBinding;\r
+import org.simantics.utils.datastructures.context.Context;\r
+import org.simantics.utils.datastructures.context.IContext;\r
+import org.simantics.utils.datastructures.context.IContextListener;\r
+import org.simantics.utils.datastructures.hints.HintContext;\r
+import org.simantics.utils.datastructures.hints.HintStack;\r
+import org.simantics.utils.datastructures.hints.IHintContext;\r
+import org.simantics.utils.datastructures.hints.IHintListener;\r
+import org.simantics.utils.datastructures.hints.IHintStack;\r
+import org.simantics.utils.threads.IThreadWorkQueue;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+/**\r
+ * Creates subcanvas on top of parent canvas. Size and position of the subcanvas\r
+ * can be changed.\r
+ * \r
+ * Beware: every CanvasParticipant that handles mouseEvents must be replaced\r
+ * since mouse coordinates must be translated. Currently Implemented\r
+ * participants: - MouseUtil - ElementInteractor\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ * \r
+ * TODO: CanvasContext implementation needs to implement scene graph methods too\r
+ */\r
+public class ElementDiagram implements IDiagram {\r
+ private final ICanvasContext ctx;\r
+\r
+ private final ICanvasContext parentCtx;\r
+\r
+ private IDiagram diagram;\r
+\r
+ private final SubCanvas subCanvas;\r
+\r
+ private Rectangle2D canvasRect = new Rectangle2D.Double(0, 0, 200, 200);\r
+\r
+ private int canvasPosX = 100;\r
+\r
+ private int canvasPosY = 100;\r
+\r
+ public ElementDiagram(ICanvasContext parentCtx) {\r
+ this.parentCtx = parentCtx;\r
+ ctx = createCanvas(parentCtx.getThreadAccess(),parentCtx.getSceneGraph());\r
+ ICanvasParticipant mouseUtil = ctx.getSingleItem(MouseUtil.class);\r
+ if (mouseUtil != null) {\r
+ ctx.remove(mouseUtil);\r
+ ctx.add(new ElementDiagramMouseUtil());\r
+ // ctx.add(new MouseUtil());\r
+ }\r
+ ICanvasParticipant elementInteractor = ctx.getSingleItem(ElementInteractor.class);\r
+ if (elementInteractor != null) {\r
+ ctx.remove(elementInteractor);\r
+ ctx.add(new ElementDiagramElementInteractor());\r
+ }\r
+ diagram = createDiagram();\r
+ ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);\r
+ subCanvas = new SubCanvas(ctx, 10000, Integer.MAX_VALUE - 100, 10000);\r
+ parentCtx.add(subCanvas);\r
+ }\r
+\r
+ public void setSize(int x, int y, int width, int height) {\r
+ canvasPosX = x;\r
+ canvasPosY = y;\r
+ canvasRect = new Rectangle2D.Double(0, 0, width, height);\r
+ getCanvas().getCanvasNode().setTransform(new AffineTransform(1,0,0,1,x,y));\r
+ \r
+ }\r
+\r
+ public Rectangle2D getSize() {\r
+ return canvasRect;\r
+ }\r
+\r
+ /**\r
+ * Override this for custom functionality\r
+ * \r
+ * @return\r
+ */\r
+ public IDiagram createDiagram() {\r
+ IDiagram d = Diagram.spawnNew(DiagramClass.DEFAULT);\r
+ return d;\r
+ }\r
+\r
+ /**\r
+ * Override this for custom functionality\r
+ * \r
+ * @param thread\r
+ * @return\r
+ */\r
+ public ICanvasContext createCanvas(IThreadWorkQueue thread, G2DSceneGraph sg) {\r
+ return createDefaultCanvas(thread,sg);\r
+ }\r
+\r
+ public void setDiagram(IDiagram diagram) {\r
+ this.diagram = diagram;\r
+ ctx.getDefaultHintContext().setHint(DiagramHints.KEY_DIAGRAM, diagram);\r
+ }\r
+\r
+ public ICanvasContext getCanvas() {\r
+ return ctx;\r
+ }\r
+\r
+ public ICanvasContext getParentCanvas() {\r
+ return parentCtx;\r
+ }\r
+\r
+ public SubCanvas getSubCanvas() {\r
+ return subCanvas;\r
+ }\r
+\r
+ public IDiagram getDiagram() {\r
+ return diagram;\r
+ }\r
+\r
+ @Override\r
+ public void addElement(IElement element) {\r
+ diagram.addElement(element);\r
+ }\r
+\r
+ @Override\r
+ public void removeElement(IElement element) {\r
+ diagram.removeElement(element);\r
+ }\r
+\r
+ @Override\r
+ public void addCompositionListener(CompositionListener listener) {\r
+ diagram.addCompositionListener(listener);\r
+ }\r
+\r
+ @Override\r
+ public void addCompositionVetoListener(CompositionVetoListener listener) {\r
+ diagram.addCompositionVetoListener(listener);\r
+ }\r
+\r
+ @Override\r
+ public void addHintListener(IHintListener listener) {\r
+ diagram.addHintListener(listener);\r
+ }\r
+\r
+ @Override\r
+ public void addHintListener(IThreadWorkQueue threadAccess, IHintListener listener) {\r
+ diagram.addHintListener(threadAccess, listener);\r
+ }\r
+\r
+ @Override\r
+ public void addKeyHintListener(IThreadWorkQueue threadAccess, Key key, IHintListener listener) {\r
+ diagram.addKeyHintListener(threadAccess, key, listener);\r
+ }\r
+\r
+ @Override\r
+ public void addKeyHintListener(Key key, IHintListener listener) {\r
+ diagram.addKeyHintListener(key, listener);\r
+ }\r
+\r
+ @Override\r
+ public boolean bringToTop(IElement e) {\r
+ return diagram.bringToTop(e);\r
+ }\r
+\r
+ @Override\r
+ public boolean bringUp(IElement e) {\r
+ return diagram.bringUp(e);\r
+ }\r
+\r
+ @Override\r
+ public void destroy() {\r
+ diagram.destroy();\r
+ }\r
+\r
+ @Override\r
+ public void dispose() {\r
+ diagram.dispose();\r
+ }\r
+\r
+ @Override\r
+ public DiagramClass getDiagramClass() {\r
+ return diagram.getDiagramClass();\r
+ }\r
+\r
+ @Override\r
+ public boolean containsElement(IElement element) {\r
+ return diagram.containsElement(element);\r
+ }\r
+\r
+ @Override\r
+ public List<IElement> getElements() {\r
+ return diagram.getElements();\r
+ }\r
+\r
+ @Override\r
+ public void sort(Comparator<IElement> comparator) {\r
+ diagram.sort(comparator);\r
+ }\r
+\r
+ @Override\r
+ public List<IElement> getSnapshot() {\r
+ return diagram.getSnapshot();\r
+ }\r
+\r
+ @Override\r
+ public void clearWithoutNotification() {\r
+ diagram.clearWithoutNotification();\r
+ }\r
+\r
+ @Override\r
+ public boolean containsHint(Key key) {\r
+ return diagram.containsHint(key);\r
+ }\r
+\r
+ @Override\r
+ public <E> E getHint(Key key) {\r
+ return diagram.getHint(key);\r
+ }\r
+\r
+ @Override\r
+ public Map<Key, Object> getHints() {\r
+ return diagram.getHints();\r
+ }\r
+\r
+ @Override\r
+ public Map<Key, Object> getHintsUnsafe() {\r
+ return diagram.getHintsUnsafe();\r
+ }\r
+\r
+ @Override\r
+ public <E extends Key> Map<E, Object> getHintsOfClass(Class<E> clazz) {\r
+ return diagram.getHintsOfClass(clazz);\r
+ }\r
+\r
+ @Override\r
+ public boolean moveTo(IElement e, int position) {\r
+ return diagram.moveTo(e, position);\r
+ }\r
+\r
+ @Override\r
+ public void removeCompositionListener(CompositionListener listener) {\r
+ diagram.removeCompositionListener(listener);\r
+ }\r
+\r
+ @Override\r
+ public void removeCompositionVetoListener(CompositionVetoListener listener) {\r
+ diagram.removeCompositionVetoListener(listener);\r
+ }\r
+\r
+ @Override\r
+ public <E> E removeHint(Key key) {\r
+ return diagram.removeHint(key);\r
+ }\r
+\r
+ @Override\r
+ public void removeHintListener(IHintListener listener) {\r
+ diagram.removeHintListener(listener);\r
+ }\r
+\r
+ @Override\r
+ public void removeHintListener(IThreadWorkQueue threadAccess, IHintListener listener) {\r
+ diagram.removeHintListener(threadAccess, listener);\r
+ }\r
+\r
+ @Override\r
+ public void removeKeyHintListener(IThreadWorkQueue threadAccess, Key key, IHintListener listener) {\r
+ diagram.removeKeyHintListener(threadAccess, key, listener);\r
+ }\r
+\r
+ @Override\r
+ public void removeKeyHintListener(Key key, IHintListener listener) {\r
+ diagram.removeKeyHintListener(key, listener);\r
+ }\r
+\r
+ @Override\r
+ public boolean sendDown(IElement e) {\r
+ return diagram.sendDown(e);\r
+ }\r
+\r
+ @Override\r
+ public boolean sendToBottom(IElement e) {\r
+ return diagram.sendToBottom(e);\r
+ }\r
+\r
+ @Override\r
+ public void setHint(Key key, Object value) {\r
+ diagram.setHint(key, value);\r
+ }\r
+\r
+ @Override\r
+ public void setHints(Map<Key, Object> hints) {\r
+ diagram.setHints(hints);\r
+ }\r
+\r
+ public ICanvasContext createDefaultCanvas(IThreadWorkQueue thread, G2DSceneGraph sg) {\r
+ // Create canvas context and a layer of interactors\r
+ ICanvasContext canvasContext = new ElementDiagramCanvasContext(thread,sg);\r
+ IHintContext h = canvasContext.getDefaultHintContext();\r
+\r
+ //canvasContext.add(new PanZoomRotateHandler()); // Must be before\r
+ // TransformUtil\r
+\r
+ // Support & Util Participants\r
+ canvasContext.add(new TransformUtil());\r
+ canvasContext.add(new MouseUtil());\r
+ canvasContext.add(new KeyUtil());\r
+ canvasContext.add(new CanvasGrab());\r
+ canvasContext.add(new SymbolUtil());\r
+ canvasContext.add(new TimeParticipant());\r
+\r
+ // Debug participant(s)\r
+ // canvasContext.add( new PointerPainter() );\r
+ canvasContext.add(new HandPainter());\r
+ h.setHint(PointerPainter.KEY_PAINT_POINTER, true);\r
+\r
+ // Pan & Zoom & Rotate\r
+ // canvasContext.add( new MousePanZoomInteractor() );\r
+ // canvasContext.add( new MultitouchPanZoomRotateInteractor() );\r
+ // canvasContext.add( new OrientationRestorer() );\r
+\r
+ // Grid & Ruler & Background\r
+ canvasContext.add(new GridPainter());\r
+ canvasContext.add(new RulerPainter());\r
+ canvasContext.add(new BackgroundPainter());\r
+ h.setHint(Hints.KEY_GRID_COLOR, new Color(0.9f, 0.9f, 0.9f));\r
+ h.setHint(Hints.KEY_BACKGROUND_COLOR, Color.LIGHT_GRAY);\r
+\r
+ // Key bindings\r
+ canvasContext.add(new KeyToCommand(CommandKeyBinding.DEFAULT_BINDINGS));\r
+\r
+ // //// Diagram Participants //////\r
+ canvasContext.add(new PointerInteractor());\r
+ canvasContext.add(new ElementInteractor());\r
+ canvasContext.add(new Selection());\r
+ canvasContext.add(new DiagramParticipant());\r
+ canvasContext.add(new ElementPainter());\r
+ canvasContext.add(new TerminalPainter(true, true, false, true));\r
+ //canvasContext.add(new ElementHeartbeater());\r
+ canvasContext.add(new ZOrderHandler());\r
+ canvasContext.add(new ZoomTransitionParticipant(TransitionFunction.SIGMOID));\r
+ h.setHint(Hints.KEY_TOOL, Hints.PANTOOL);\r
+\r
+ return canvasContext;\r
+ }\r
+\r
+ public class ElementDiagramCanvasContext extends Context<ICanvasParticipant> implements ICanvasContext {\r
+\r
+ protected HintStack hintStack = new HintStack();\r
+\r
+ protected HintContext bottomHintContext = new HintContext();\r
+\r
+ protected IEventHandlerStack eventHandlerStack = null;\r
+\r
+ protected boolean eventHandlingOrdered = false;\r
+\r
+ protected EventQueue eventQueue = null;\r
+\r
+ protected IContentContext paintableCtx = new PaintableContextImpl();\r
+\r
+ protected final IThreadWorkQueue thread;\r
+\r
+ protected IMouseCaptureContext mouseCaptureCtx = new MouseCaptureContext();\r
+\r
+ protected IMouseCursorContext mouseCursorCtx = new MouseCursorContext();\r
+ \r
+ protected G2DSceneGraph sg;\r
+ protected G2DParentNode canvasNode = null;\r
+ \r
+ protected ITooltipProvider tooltip;\r
+\r
+ /**\r
+ * \r
+ * @param thread context thread, or null if sync policy not used\r
+ */\r
+ public ElementDiagramCanvasContext(IThreadWorkQueue thread, G2DSceneGraph sg) {\r
+ super(ICanvasParticipant.class);\r
+ if (thread == null)\r
+ throw new IllegalArgumentException("null");\r
+ this.thread = thread;\r
+ eventHandlerStack = new EventHandlerStack(thread);\r
+ eventQueue = new EventQueue(eventHandlerStack);\r
+ hintStack.addHintContext(bottomHintContext, Integer.MIN_VALUE);\r
+\r
+ \r
+ \r
+ this.sg = sg;\r
+ canvasNode = sg.addNode("elementd" + SceneGraphConstants.NAVIGATION_NODE_NAME , G2DParentNode.class); // Add dummy parent node\r
+ canvasNode.setZIndex(1000);\r
+ \r
+ this.addContextListener(thread, new IContextListener<ICanvasParticipant>() {\r
+ @Override\r
+ public void itemAdded(IContext<ICanvasParticipant> sender, ICanvasParticipant item) {\r
+ item.addedToContext(ElementDiagramCanvasContext.this);\r
+ }\r
+\r
+ @Override\r
+ public void itemRemoved(IContext<ICanvasParticipant> sender, ICanvasParticipant item) {\r
+ item.removedFromContext(ElementDiagramCanvasContext.this);\r
+ }\r
+ });\r
+\r
+ eventQueue.addEventCoalesceler(MouseEventCoalescer.INSTANCE);\r
+ // Order event handling if events are added to the queue\r
+ eventQueue.addQueueListener(new IEventQueueListener() {\r
+ @Override\r
+ public void onEventAdded(IEventQueue queue, Event e, int index) {\r
+ asyncHandleEvents();\r
+ }\r
+\r
+ @Override\r
+ public void onQueueEmpty(IEventQueue queue) {\r
+ }\r
+ });\r
+ }\r
+\r
+ public IHintStack getHintStack() {\r
+ assertNotDisposed();\r
+ return hintStack;\r
+ }\r
+\r
+ private final Runnable eventHandling = new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ eventHandlingOrdered = false;\r
+ eventQueue.handleEvents();\r
+ }\r
+ };\r
+\r
+ synchronized void asyncHandleEvents() {\r
+ if (eventHandlingOrdered)\r
+ return;\r
+ eventHandlingOrdered = true;\r
+ ThreadUtils.asyncExec(thread, eventHandling);\r
+ }\r
+\r
+ synchronized void syncHandleEvents() {\r
+ if (eventHandlingOrdered)\r
+ return;\r
+ eventHandlingOrdered = true;\r
+ ThreadUtils.syncExec(thread, eventHandling);\r
+ }\r
+\r
+ @Override\r
+ public IEventHandlerStack getEventHandlerStack() {\r
+ assertNotDisposed();\r
+ return eventHandlerStack;\r
+ }\r
+\r
+ @Override\r
+ public IThreadWorkQueue getThreadAccess() {\r
+ // assertNotDisposed();\r
+ return thread;\r
+ }\r
+\r
+ @Override\r
+ protected void doDispose() {\r
+ ThreadUtils.syncExec(getThreadAccess(), new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ clear();\r
+ \r
+ // HN: added to decrease memory leaks\r
+ if (sg != null) {\r
+ // Makes sure that scene graph nodes free their resources!\r
+ sg.removeNodes();\r
+ sg = null;\r
+ }\r
+ }\r
+ });\r
+ }\r
+\r
+ @Override\r
+ public IHintContext getDefaultHintContext() {\r
+ return bottomHintContext;\r
+ }\r
+\r
+ @Override\r
+ public IMouseCursorContext getMouseCursorContext() {\r
+ return mouseCursorCtx;\r
+ }\r
+\r
+ @Override\r
+ public void setMouseCursorContext(IMouseCursorContext ctx) {\r
+ this.mouseCursorCtx = ctx;\r
+ }\r
+\r
+ @Override\r
+ public IMouseCaptureContext getMouseCaptureContext() {\r
+ return mouseCaptureCtx;\r
+ }\r
+\r
+ @Override\r
+ public void setMouseCaptureContext(IMouseCaptureContext mctx) {\r
+ this.mouseCaptureCtx = mctx;\r
+ }\r
+\r
+ @Override\r
+ public IEventQueue getEventQueue() {\r
+ return eventQueue;\r
+ }\r
+\r
+ @Override\r
+ public IContentContext getContentContext() {\r
+ return paintableCtx;\r
+ }\r
+\r
+ @Override\r
+ public void setContentContext(IContentContext ctx) {\r
+ this.paintableCtx = ctx;\r
+ }\r
+\r
+ @Override\r
+ public G2DSceneGraph getSceneGraph() {\r
+ return sg;\r
+ }\r
+\r
+ @Override\r
+ public G2DParentNode getCanvasNode() {\r
+ return canvasNode;\r
+ }\r
+\r
+ @Override\r
+ public void setCanvasNode(G2DParentNode node) {\r
+ throw new RuntimeException("Cannot set canvasNode");\r
+\r
+ }\r
+\r
+ protected final AtomicBoolean locked = new AtomicBoolean(false);\r
+\r
+ @Override\r
+ public boolean isLocked() {\r
+ return this.locked.get();\r
+ }\r
+\r
+ @Override\r
+ public void setLocked(boolean locked) {\r
+ boolean previous = this.locked.getAndSet(locked);\r
+ if (!locked && previous != locked) {\r
+ // The context was unlocked!\r
+ getContentContext().setDirty();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public ITooltipProvider getTooltipProvider() {\r
+ return tooltip;\r
+ }\r
+\r
+ @Override\r
+ public void setTooltipProvider(ITooltipProvider tooltipProvider) {\r
+ this.tooltip = tooltipProvider;\r
+ }\r
+\r
+ }\r
+\r
+ public class ElementDiagramMouseUtil extends MouseUtil {\r
+\r
+ @Override\r
+ @EventHandler(priority = Integer.MAX_VALUE)\r
+ public boolean handleMouseEvent(MouseEvent e) {\r
+ MouseEvent ne = createMouseEvent(e);\r
+ if (ne != null)\r
+ return handleMouseEvent2(ne);\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Copy-pasted MouseUtil.handleMouseEvent with one modification;\r
+ * Generating MouseClickEvents has been removed, because it created\r
+ * duplicated events (with incorrect coordinates).\r
+ * \r
+ * @param e\r
+ * @return\r
+ */\r
+ public boolean handleMouseEvent2(MouseEvent e) {\r
+ assertDependencies();\r
+ if (e instanceof MouseEnterEvent) {\r
+ Point2D canvasPosition = util.controlToCanvas(e.controlPosition, null);\r
+ // Reset mouse\r
+ MouseInfo mi = new MouseInfo(e.mouseId, e.controlPosition, canvasPosition, e.buttons);\r
+ miceInfo.put(e.mouseId, mi);\r
+ } else if (e instanceof MouseExitEvent) {\r
+ miceInfo.remove(e.mouseId);\r
+ } else if (e instanceof MouseMovedEvent) {\r
+ Point2D canvasPosition = util.controlToCanvas(e.controlPosition, null);\r
+ double deltaDistance = 0;\r
+ MouseInfo mi = miceInfo.get(e.mouseId);\r
+ if (mi == null) {\r
+ mi = new MouseInfo(e.mouseId, e.controlPosition, canvasPosition, 0/*e.buttons*/);\r
+ miceInfo.put(e.mouseId, mi);\r
+ } else {\r
+ deltaDistance = e.controlPosition.distance(mi.controlPosition);\r
+ mi.controlPosition = e.controlPosition;\r
+ mi.canvasPosition = canvasPosition;\r
+ }\r
+\r
+ if (deltaDistance > 0)\r
+ mi.addDistanceForButtons(deltaDistance);\r
+\r
+ // Send mouse drag events.\r
+ for (ButtonInfo bi : mi.buttonPressInfo.values()) {\r
+ if (!bi.down)\r
+ continue;\r
+ if (bi.deltaMotion <= profile.movementTolerance)\r
+ continue;\r
+ if (bi.drag)\r
+ continue;\r
+ bi.drag = true;\r
+ MouseDragBegin db = new MouseDragBegin(this, e.time, e.mouseId, e.buttons, e.stateMask, bi.button,\r
+ bi.canvasPosition, bi.controlPosition, e.controlPosition, e.screenPosition);\r
+ getContext().getEventQueue().queueFirst(db);\r
+ }\r
+\r
+ } else if (e instanceof MouseButtonPressedEvent) {\r
+ Point2D canvasPosition = util.controlToCanvas(e.controlPosition, null);\r
+ MouseButtonPressedEvent me = (MouseButtonPressedEvent) e;\r
+ MouseInfo mi = miceInfo.get(e.mouseId);\r
+ if (mi == null) {\r
+ mi = new MouseInfo(e.mouseId, e.controlPosition, canvasPosition, e.buttons);\r
+ miceInfo.put(e.mouseId, mi);\r
+ } else {\r
+ mi.controlPosition = e.controlPosition;\r
+ mi.canvasPosition = canvasPosition;\r
+ }\r
+ mi.setButtonPressed(me.button, e.stateMask, e.controlPosition, canvasPosition, e.time);\r
+ } else if (e instanceof MouseButtonReleasedEvent) {\r
+ MouseButtonReleasedEvent me = (MouseButtonReleasedEvent) e;\r
+ Point2D canvasPosition = util.controlToCanvas(me.controlPosition, null);\r
+ MouseInfo mi = miceInfo.get(me.mouseId);\r
+ if (mi == null) {\r
+ mi = new MouseInfo(e.mouseId, me.controlPosition, canvasPosition, 0/*me.buttons*/);\r
+ miceInfo.put(me.mouseId, mi);\r
+ } else {\r
+ mi.controlPosition = me.controlPosition;\r
+ mi.canvasPosition = canvasPosition;\r
+ }\r
+ ButtonInfo bi = mi.releaseButton(me.button, me.time);\r
+ if (bi == null)\r
+ return false;\r
+\r
+ if (me.holdTime > profile.clickHoldTimeTolerance)\r
+ return false;\r
+ if (bi.deltaMotion > profile.movementTolerance)\r
+ return false;\r
+ // This is a click\r
+\r
+ long timeSinceLastClick = me.time - bi.lastClickEventTime;\r
+ bi.lastClickEventTime = me.time;\r
+\r
+ // reset click counter\r
+ if (timeSinceLastClick > profile.consecutiveToleranceTime)\r
+ bi.clickCount = 0;\r
+ else\r
+ bi.clickCount++;\r
+\r
+ }\r
+ return false;\r
+ }\r
+ }\r
+\r
+ public class ElementDiagramElementInteractor extends ElementInteractor {\r
+ @Override\r
+ @EventHandler(priority = INTERACTOR_PRIORITY)\r
+ public boolean handleMouseEvent(MouseEvent me) {\r
+ MouseEvent ne = createMouseEvent(me);\r
+ if (ne != null)\r
+ return super.handleMouseEvent(ne);\r
+ return false;\r
+ }\r
+ }\r
+\r
+ public MouseEvent createMouseEvent(MouseEvent e) {\r
+ MouseEvent newEvent = null;\r
+ double x = e.controlPosition.getX();\r
+ double y = e.controlPosition.getY();\r
+ Point2D newPos = new Point2D.Double(x - canvasPosX, y - canvasPosY);\r
+\r
+ if (!canvasRect.contains(newPos))\r
+ return new MouseExitEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos, e.screenPosition);\r
+ if (e instanceof MouseButtonPressedEvent) {\r
+ newEvent = new MouseButtonPressedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask,\r
+ ((MouseButtonEvent) e).button, newPos, e.screenPosition);\r
+ } else if (e instanceof MouseButtonReleasedEvent) {\r
+ newEvent = new MouseButtonReleasedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask,\r
+ ((MouseButtonEvent) e).button, ((MouseButtonReleasedEvent) e).holdTime, newPos, e.screenPosition);\r
+ } else if (e instanceof MouseDoubleClickedEvent) {\r
+ newEvent = new MouseDoubleClickedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask,\r
+ ((MouseButtonEvent) e).button, newPos, e.screenPosition);\r
+ } else if (e instanceof MouseClickEvent) {\r
+ newEvent = new MouseClickEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask,\r
+ ((MouseButtonEvent) e).button, ((MouseClickEvent) e).clickCount, newPos, e.screenPosition);\r
+ } else if (e instanceof MouseDragBegin) {\r
+ newEvent = new MouseDragBegin(e.context, e.time, e.mouseId, e.buttons, e.stateMask,\r
+ ((MouseButtonEvent) e).button, ((MouseDragBegin) e).startCanvasPos,\r
+ ((MouseDragBegin) e).startControlPos, newPos, e.screenPosition);\r
+ } else if (e instanceof MouseEnterEvent) {\r
+ newEvent = new MouseEnterEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos,\r
+ e.screenPosition);\r
+ } else if (e instanceof MouseExitEvent) {\r
+ newEvent = new MouseExitEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos,\r
+ e.screenPosition);\r
+ } else if (e instanceof MouseMovedEvent) {\r
+ newEvent = new MouseMovedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos,\r
+ e.screenPosition);\r
+ } else if (e instanceof MouseWheelMovedEvent) {\r
+ newEvent = new MouseWheelMovedEvent(e.context, e.time, e.mouseId, e.buttons, e.stateMask, newPos,\r
+ e.screenPosition, ((MouseWheelMovedEvent) e).scrollType, ((MouseWheelMovedEvent) e).scrollAmount,\r
+ ((MouseWheelMovedEvent) e).wheelRotation);\r
+ } else {\r
+ throw new Error("Unknow event " + e.getClass() + " " + e);\r
+ }\r
+ // System.out.println(newPos + " " + newEvent + " "+ e);\r
+ return newEvent;\r
+ }\r
+\r
+}\r