-/*******************************************************************************\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.canvas.impl;\r
-\r
-import java.util.concurrent.atomic.AtomicBoolean;\r
-\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.chassis.ITooltipProvider;\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.IEventQueue.IEventQueueListener;\r
-import org.simantics.scenegraph.g2d.events.MouseEventCoalescer;\r
-import org.simantics.scenegraph.g2d.nodes.DataNode;\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.IHintStack;\r
-import org.simantics.utils.strings.EString;\r
-import org.simantics.utils.threads.IThreadWorkQueue;\r
-import org.simantics.utils.threads.ThreadUtils;\r
-\r
-/**\r
- * This class contains the UI Support the Elements need when rendering and interacting with \r
- * the Operating System. \r
- * \r
- * @author Toni Kalajainen\r
- */\r
-public class CanvasContext extends Context<ICanvasParticipant> implements ICanvasContext {\r
-\r
- protected HintStack hintStack = new HintStack();\r
- protected HintContext bottomHintContext = new HintContext();\r
- protected IEventHandlerStack eventHandlerStack = null;\r
- protected boolean eventHandlingOrdered = false;\r
- protected EventQueue eventQueue = null;\r
- protected IContentContext paintableCtx = new PaintableContextImpl();\r
- protected final IThreadWorkQueue thread;\r
-\r
- protected IMouseCaptureContext mouseCaptureCtx = new MouseCaptureContext();\r
- protected IMouseCursorContext mouseCursorCtx = new MouseCursorContext();\r
-\r
- protected G2DSceneGraph sceneGraph;\r
- protected G2DParentNode canvasNode = null;\r
- protected ITooltipProvider tooltip;\r
-\r
- protected final AtomicBoolean locked = new AtomicBoolean(false);\r
-\r
- public CanvasContext(IThreadWorkQueue thread)\r
- {\r
- this(thread, new G2DSceneGraph());\r
- }\r
-\r
- /**\r
- *\r
- * @param thread context thread, or null if sync policy not used\r
- */\r
- public CanvasContext(IThreadWorkQueue thread, G2DSceneGraph sg)\r
- {\r
- super(ICanvasParticipant.class);\r
- if ( thread == null )\r
- throw new IllegalArgumentException("null");\r
-\r
- sceneGraph = sg;\r
- canvasNode = sg.addNode(SceneGraphConstants.NAVIGATION_NODE_NAME, G2DParentNode.class); // Add dummy parent node\r
- canvasNode.setLookupId(SceneGraphConstants.NAVIGATION_NODE_NAME);\r
- DataNode dataNode = sg.addNode(SceneGraphConstants.DATA_NODE_NAME, DataNode.class);\r
- dataNode.setLookupId(SceneGraphConstants.DATA_NODE_NAME);\r
-\r
- this.thread = thread;\r
- eventHandlerStack = new EventHandlerStack(thread);\r
- eventQueue = new EventQueue(eventHandlerStack);\r
- hintStack.addHintContext(bottomHintContext, Integer.MIN_VALUE);\r
-\r
- // Install scene graph as a handler into the canvas context event\r
- // handler stack.\r
- eventHandlerStack.add(this.sceneGraph.getEventHandler(), SceneGraphConstants.SCENEGRAPH_EVENT_PRIORITY);\r
-\r
- this.addContextListener(thread, new IContextListener<ICanvasParticipant>() {\r
- @Override\r
- public void itemAdded(IContext<ICanvasParticipant> sender, ICanvasParticipant item) {\r
- item.addedToContext(CanvasContext.this);\r
- }\r
- @Override\r
- public void itemRemoved(IContext<ICanvasParticipant> sender,\r
- ICanvasParticipant item) {\r
- item.removedFromContext(CanvasContext.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
- @Override\r
- public void onQueueEmpty(IEventQueue queue) {\r
- }\r
- });\r
- }\r
-\r
- public IHintStack getHintStack()\r
- {\r
- assertNotDisposed();\r
- return hintStack;\r
- }\r
-\r
- private final Runnable eventHandling = new Runnable() {\r
- @Override\r
- public void run() {\r
- if (!isAlive())\r
- return;\r
- eventHandlingOrdered = false;\r
- eventQueue.handleEvents();\r
- }\r
- };\r
-\r
- synchronized void asyncHandleEvents() {\r
- if (eventHandlingOrdered) return;\r
- eventHandlingOrdered = true;\r
- ThreadUtils.asyncExec(thread, eventHandling);\r
- }\r
-\r
- synchronized void syncHandleEvents() {\r
- if (eventHandlingOrdered) return;\r
- eventHandlingOrdered = true;\r
- ThreadUtils.syncExec(thread, eventHandling);\r
- }\r
-\r
- @Override\r
- public G2DSceneGraph getSceneGraph() {\r
- return sceneGraph;\r
- }\r
-\r
- @Override\r
- public void setCanvasNode(G2DParentNode node) {\r
- this.canvasNode = node;\r
- }\r
-\r
- @Override\r
- public G2DParentNode getCanvasNode() {\r
- return canvasNode;\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
- bottomHintContext.clearWithoutNotification();\r
- if (sceneGraph != null) {\r
- // Makes sure that scene graph nodes free their resources!\r
- sceneGraph.removeNodes();\r
- sceneGraph.cleanup();\r
- sceneGraph = null;\r
- }\r
- // HN: added to decrease memory leaks\r
- eventHandlerStack = null;\r
- hintStack = null;\r
- canvasNode.cleanup();\r
- canvasNode = null;\r
- eventQueue = null;\r
- mouseCaptureCtx = null;\r
- mouseCursorCtx = null;\r
- paintableCtx = null;\r
- listeners.clear();\r
- listeners = null;\r
- set.clear();\r
- set = null;\r
- tooltip = null;\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
- public ITooltipProvider getTooltipProvider() {\r
- return tooltip;\r
- }\r
-\r
- public void setTooltipProvider(ITooltipProvider tooltip) {\r
- this.tooltip = tooltip;\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 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 boolean isLocked() {\r
- return this.locked.get();\r
- }\r
-\r
- /**\r
- * Assert participant dependies are OK\r
- */\r
- public void assertParticipantDependencies() {\r
- for (ICanvasParticipant ctx : toArray())\r
- if (ctx instanceof AbstractCanvasParticipant) {\r
- AbstractCanvasParticipant acp = (AbstractCanvasParticipant) ctx;\r
- if (!acp.depsSatisfied) {\r
- throw new AssertionError("Participant "+acp+" dependencies unsatisfied : " + acp.missingDependencies);\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- if (isDisposed())\r
- return super.toString();\r
-\r
- StringBuilder sb = new StringBuilder();\r
- if (locked.get())\r
- sb.append("[CanvasContext@" + System.identityHashCode(this) + " is locked]");\r
- sb.append("Participants:\n");\r
- sb.append(EString.addPrefix( super.toString(), "\t" ));\r
-// sb.append("\n\nPainter stack:\n");\r
-// sb.append(EString.addPrefix( getPainterStack().toString(), "\t" ));\r
- sb.append("\n\nEvent handler stack:\n");\r
- sb.append(EString.addPrefix( getEventHandlerStack().toString(), "\t" ));\r
- return sb.toString();\r
- }\r
-}\r
+/*******************************************************************************
+ * 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<ICanvasParticipant> 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<ICanvasParticipant>() {
+ @Override
+ public void itemAdded(IContext<ICanvasParticipant> sender, ICanvasParticipant item) {
+ item.addedToContext(CanvasContext.this);
+ }
+ @Override
+ public void itemRemoved(IContext<ICanvasParticipant> 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();
+ }
+}