]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/CanvasContext.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / canvas / impl / CanvasContext.java
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
new file mode 100644 (file)
index 0000000..035211c
--- /dev/null
@@ -0,0 +1,301 @@
+/*******************************************************************************\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+" dependies unsatisfied");\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