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