X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fcanvas%2Fimpl%2FCanvasContext.java;fp=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fcanvas%2Fimpl%2FCanvasContext.java;h=998b8a9a28aa155eadd889656b899c6b111d7d9a;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hp=18e08f5739f317228d44bbc4eec90f44b4a172fc;hpb=24e2b34260f219f0d1644ca7a138894980e25b14;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/CanvasContext.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/CanvasContext.java index 18e08f573..998b8a9a2 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/CanvasContext.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/CanvasContext.java @@ -1,301 +1,301 @@ -/******************************************************************************* - * 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.canvas.impl; - -import java.util.concurrent.atomic.AtomicBoolean; - -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.chassis.ITooltipProvider; -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.IEventQueue.IEventQueueListener; -import org.simantics.scenegraph.g2d.events.MouseEventCoalescer; -import org.simantics.scenegraph.g2d.nodes.DataNode; -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.IHintStack; -import org.simantics.utils.strings.EString; -import org.simantics.utils.threads.IThreadWorkQueue; -import org.simantics.utils.threads.ThreadUtils; - -/** - * This class contains the UI Support the Elements need when rendering and interacting with - * the Operating System. - * - * @author Toni Kalajainen - */ -public class CanvasContext 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 sceneGraph; - protected G2DParentNode canvasNode = null; - protected ITooltipProvider tooltip; - - protected final AtomicBoolean locked = new AtomicBoolean(false); - - public CanvasContext(IThreadWorkQueue thread) - { - this(thread, new G2DSceneGraph()); - } - - /** - * - * @param thread context thread, or null if sync policy not used - */ - public CanvasContext(IThreadWorkQueue thread, G2DSceneGraph sg) - { - super(ICanvasParticipant.class); - if ( thread == null ) - throw new IllegalArgumentException("null"); - - sceneGraph = sg; - canvasNode = sg.addNode(SceneGraphConstants.NAVIGATION_NODE_NAME, G2DParentNode.class); // Add dummy parent node - canvasNode.setLookupId(SceneGraphConstants.NAVIGATION_NODE_NAME); - DataNode dataNode = sg.addNode(SceneGraphConstants.DATA_NODE_NAME, DataNode.class); - dataNode.setLookupId(SceneGraphConstants.DATA_NODE_NAME); - - this.thread = thread; - eventHandlerStack = new EventHandlerStack(thread); - eventQueue = new EventQueue(eventHandlerStack); - hintStack.addHintContext(bottomHintContext, Integer.MIN_VALUE); - - // Install scene graph as a handler into the canvas context event - // handler stack. - eventHandlerStack.add(this.sceneGraph.getEventHandler(), SceneGraphConstants.SCENEGRAPH_EVENT_PRIORITY); - - this.addContextListener(thread, new IContextListener() { - @Override - public void itemAdded(IContext sender, ICanvasParticipant item) { - item.addedToContext(CanvasContext.this); - } - @Override - public void itemRemoved(IContext sender, - ICanvasParticipant item) { - item.removedFromContext(CanvasContext.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() { - if (!isAlive()) - return; - 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 G2DSceneGraph getSceneGraph() { - return sceneGraph; - } - - @Override - public void setCanvasNode(G2DParentNode node) { - this.canvasNode = node; - } - - @Override - public G2DParentNode getCanvasNode() { - return canvasNode; - } - - @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(); - bottomHintContext.clearWithoutNotification(); - if (sceneGraph != null) { - // Makes sure that scene graph nodes free their resources! - sceneGraph.removeNodes(); - sceneGraph.cleanup(); - sceneGraph = null; - } - // HN: added to decrease memory leaks - eventHandlerStack = null; - hintStack = null; - canvasNode.cleanup(); - canvasNode = null; - eventQueue = null; - mouseCaptureCtx = null; - mouseCursorCtx = null; - paintableCtx = null; - listeners.clear(); - listeners = null; - set.clear(); - set = null; - tooltip = 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; - } - - public ITooltipProvider getTooltipProvider() { - return tooltip; - } - - public void setTooltipProvider(ITooltipProvider tooltip) { - this.tooltip = tooltip; - } - - @Override - public IEventQueue getEventQueue() { - return eventQueue; - } - - @Override - public IContentContext getContentContext() { - return paintableCtx; - } - - @Override - public void setContentContext(IContentContext ctx) { - this.paintableCtx = ctx; - } - - @Override - public void setLocked(boolean locked) { - boolean previous = this.locked.getAndSet(locked); - if (!locked && previous != locked) { - // The context was unlocked! - getContentContext().setDirty(); - } - } - - @Override - public boolean isLocked() { - return this.locked.get(); - } - - /** - * Assert participant dependies are OK - */ - public void assertParticipantDependencies() { - for (ICanvasParticipant ctx : toArray()) - if (ctx instanceof AbstractCanvasParticipant) { - AbstractCanvasParticipant acp = (AbstractCanvasParticipant) ctx; - if (!acp.depsSatisfied) { - throw new AssertionError("Participant "+acp+" dependencies unsatisfied : " + acp.missingDependencies); - } - } - } - - @Override - public String toString() { - if (isDisposed()) - return super.toString(); - - StringBuilder sb = new StringBuilder(); - if (locked.get()) - sb.append("[CanvasContext@" + System.identityHashCode(this) + " is locked]"); - sb.append("Participants:\n"); - sb.append(EString.addPrefix( super.toString(), "\t" )); -// sb.append("\n\nPainter stack:\n"); -// sb.append(EString.addPrefix( getPainterStack().toString(), "\t" )); - sb.append("\n\nEvent handler stack:\n"); - sb.append(EString.addPrefix( getEventHandlerStack().toString(), "\t" )); - return sb.toString(); - } -} +/******************************************************************************* + * 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.canvas.impl; + +import java.util.concurrent.atomic.AtomicBoolean; + +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.chassis.ITooltipProvider; +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.IEventQueue.IEventQueueListener; +import org.simantics.scenegraph.g2d.events.MouseEventCoalescer; +import org.simantics.scenegraph.g2d.nodes.DataNode; +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.IHintStack; +import org.simantics.utils.strings.EString; +import org.simantics.utils.threads.IThreadWorkQueue; +import org.simantics.utils.threads.ThreadUtils; + +/** + * This class contains the UI Support the Elements need when rendering and interacting with + * the Operating System. + * + * @author Toni Kalajainen + */ +public class CanvasContext 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 sceneGraph; + protected G2DParentNode canvasNode = null; + protected ITooltipProvider tooltip; + + protected final AtomicBoolean locked = new AtomicBoolean(false); + + public CanvasContext(IThreadWorkQueue thread) + { + this(thread, new G2DSceneGraph()); + } + + /** + * + * @param thread context thread, or null if sync policy not used + */ + public CanvasContext(IThreadWorkQueue thread, G2DSceneGraph sg) + { + super(ICanvasParticipant.class); + if ( thread == null ) + throw new IllegalArgumentException("null"); + + sceneGraph = sg; + canvasNode = sg.addNode(SceneGraphConstants.NAVIGATION_NODE_NAME, G2DParentNode.class); // Add dummy parent node + canvasNode.setLookupId(SceneGraphConstants.NAVIGATION_NODE_NAME); + DataNode dataNode = sg.addNode(SceneGraphConstants.DATA_NODE_NAME, DataNode.class); + dataNode.setLookupId(SceneGraphConstants.DATA_NODE_NAME); + + this.thread = thread; + eventHandlerStack = new EventHandlerStack(thread); + eventQueue = new EventQueue(eventHandlerStack); + hintStack.addHintContext(bottomHintContext, Integer.MIN_VALUE); + + // Install scene graph as a handler into the canvas context event + // handler stack. + eventHandlerStack.add(this.sceneGraph.getEventHandler(), SceneGraphConstants.SCENEGRAPH_EVENT_PRIORITY); + + this.addContextListener(thread, new IContextListener() { + @Override + public void itemAdded(IContext sender, ICanvasParticipant item) { + item.addedToContext(CanvasContext.this); + } + @Override + public void itemRemoved(IContext sender, + ICanvasParticipant item) { + item.removedFromContext(CanvasContext.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() { + if (!isAlive()) + return; + 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 G2DSceneGraph getSceneGraph() { + return sceneGraph; + } + + @Override + public void setCanvasNode(G2DParentNode node) { + this.canvasNode = node; + } + + @Override + public G2DParentNode getCanvasNode() { + return canvasNode; + } + + @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(); + bottomHintContext.clearWithoutNotification(); + if (sceneGraph != null) { + // Makes sure that scene graph nodes free their resources! + sceneGraph.removeNodes(); + sceneGraph.cleanup(); + sceneGraph = null; + } + // HN: added to decrease memory leaks + eventHandlerStack = null; + hintStack = null; + canvasNode.cleanup(); + canvasNode = null; + eventQueue = null; + mouseCaptureCtx = null; + mouseCursorCtx = null; + paintableCtx = null; + listeners.clear(); + listeners = null; + set.clear(); + set = null; + tooltip = 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; + } + + public ITooltipProvider getTooltipProvider() { + return tooltip; + } + + public void setTooltipProvider(ITooltipProvider tooltip) { + this.tooltip = tooltip; + } + + @Override + public IEventQueue getEventQueue() { + return eventQueue; + } + + @Override + public IContentContext getContentContext() { + return paintableCtx; + } + + @Override + public void setContentContext(IContentContext ctx) { + this.paintableCtx = ctx; + } + + @Override + public void setLocked(boolean locked) { + boolean previous = this.locked.getAndSet(locked); + if (!locked && previous != locked) { + // The context was unlocked! + getContentContext().setDirty(); + } + } + + @Override + public boolean isLocked() { + return this.locked.get(); + } + + /** + * Assert participant dependies are OK + */ + public void assertParticipantDependencies() { + for (ICanvasParticipant ctx : toArray()) + if (ctx instanceof AbstractCanvasParticipant) { + AbstractCanvasParticipant acp = (AbstractCanvasParticipant) ctx; + if (!acp.depsSatisfied) { + throw new AssertionError("Participant "+acp+" dependencies unsatisfied : " + acp.missingDependencies); + } + } + } + + @Override + public String toString() { + if (isDisposed()) + return super.toString(); + + StringBuilder sb = new StringBuilder(); + if (locked.get()) + sb.append("[CanvasContext@" + System.identityHashCode(this) + " is locked]"); + sb.append("Participants:\n"); + sb.append(EString.addPrefix( super.toString(), "\t" )); +// sb.append("\n\nPainter stack:\n"); +// sb.append(EString.addPrefix( getPainterStack().toString(), "\t" )); + sb.append("\n\nEvent handler stack:\n"); + sb.append(EString.addPrefix( getEventHandlerStack().toString(), "\t" )); + return sb.toString(); + } +}