X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fcanvas%2Fimpl%2FAbstractCanvasParticipant.java;fp=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fcanvas%2Fimpl%2FAbstractCanvasParticipant.java;h=4de85481281222fc2646c8960bd452f51dffb6f6;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/AbstractCanvasParticipant.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/AbstractCanvasParticipant.java new file mode 100644 index 000000000..4de854812 --- /dev/null +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/AbstractCanvasParticipant.java @@ -0,0 +1,554 @@ +/******************************************************************************* + * 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.lang.reflect.Field; + +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.canvas.ICanvasParticipant; +import org.simantics.g2d.canvas.IContentContext; +import org.simantics.g2d.canvas.impl.DependencyReflection.ReferenceDefinition; +import org.simantics.g2d.canvas.impl.DependencyReflection.ReferenceType; +import org.simantics.g2d.canvas.impl.HintReflection.HintListenerDefinition; +import org.simantics.g2d.canvas.impl.SGNodeReflection.CanvasSGNodeDefinition; +import org.simantics.scenegraph.g2d.events.EventHandlerReflection; +import org.simantics.scenegraph.g2d.events.IEventHandler; +import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandlerDefinition; +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.IHintContext; +import org.simantics.utils.datastructures.hints.IHintStack; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.prioritystack.IPriorityStack; +import org.simantics.utils.threads.IThreadWorkQueue; +import org.simantics.utils.threads.ThreadUtils; + + +/** + * AbstractCanvasParticipant is base implementation for canvas participants. + * There is an assertion that states AbstractCanvasParticipant can be added + * only once to a canvas. + * + *
+ * There is convenience mechanism for adding painter and event handler + * listeners. Subclasses create listeners with usage of Painter and + * EventHandler annotations. Listeners are automatically added and + * removed to/from canvas context. + *
+ * + *+ * Example: + *
+ *+ * + *+ * @EventHandler(priority=200) + * public boolean handleEvent(Event e) { + * return false; + * } + * + * @EventHandler(priority=400) + * public boolean handleMousePressEvent(MouseButtonPressedEvent e) { + * return false; + * } + * + * IG2DNode node; + * + * @SGInit + * public void initSG(G2DParentNode parent) { + * // Insert a node into the scene graph rendered by the canvas + * // this participant is attached to and initialize it to render + * // something. Later on, to modify what the node will render, just + * // update the node's attributes. + * node = parent.addNode("myNode", MyNode.class); + * node.setZIndex(Integer.MIN_VALUE); + * } + * + * @SGCleanup + * public void cleanup() { + * // Remove our node from the scene graph where it belonged. + * // The node must not be used after this anymore. + * if (node != null) { + * node.remove(); + * node = null; + * } + * } + *
+ * Local fields are automatically assigned with ICanvasParticipant instances if they
+ * are annotated with either @Dependency
or @Reference
annotation tag.
+ * @Depedency
is a requirement, @Reference
is optional.
+ *
+ * assertDependencies() verifies that dependencies are satisfied.
+ * Local depsSatisfied field is true when dependencies are satisfied.
+ *
+ *
+ * Example: + *
+ *+ * + *+ * class MyParticipant implements ICanvasParticipant { + * @Reference MouseMonitor mouseMonitor; + * @Dependency TimeParticipant timeParticipant; + * + * @Painter(priority=100) + * public void paint(GraphicsContext gc) { + * assertDependencies(); // timeParticipant != null + * + * timeParticipant.doSomething(); + * + * if (mouseMonitor!=null) doSomethingElse(); + * } + * }
+ * Hint listener annotation. + *
+ * + *+ * Example: + *
+ *+ * + * @author Toni Kalajainen + */ +public abstract class AbstractCanvasParticipant implements ICanvasParticipant { + + /** The interactor/canvas context */ + private ICanvasContext context; + + /** The thread used in the context */ + private IThreadWorkQueue thread; + + /** the local hint context */ + protected IHintContext localHintCtx = null; + protected int localPriority = 0; + + /** wrapped local hint context. reads from hint stack */ + protected IHintContext hintCtx = null; + + /** Cached hint stack value */ + protected IHintStack hintStack; + + /** Painters found with reflection */ + protected CanvasSGNodeDefinition[] sghandlers; + + /** Painters found with reflection */ + protected EventHandlerDefinition[] eventHandlers; + + protected HintListenerDefinition[] hintListeners; + + /** Reference definitions */ + protected ReferenceDefinition[] refDefs; + protected boolean depsSatisfied = false; + private final IContextListener+ * @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM") + * public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { + * ... + * } + * @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM") + * public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { + * ... + * } + *
+ * Local context must be created with createLocalHintContext() method. + * constructor has defualt value Integer.MIN_VALUE. + *
+ * Reading from this context returns only the local hint and not + * from the shared hint stack of the canvas context. + *
+ * To read from the shared hint stack, use getHint() or getHintStack() instead.
+ *
+ * @return the local hint context
+ */
+ public synchronized IHintContext getLocalHintContext()
+ {
+ return localHintCtx;
+ }
+
+ /**
+ * Get hint context. Read operations are to hint stack, writes to local stack.
+ *
+ * @return
+ */
+ public synchronized IHintContext getWriteableHintStack()
+ {
+ if (hintCtx==null)
+ hintCtx = getHintStack().createStackRead(getLocalHintContext());
+ return hintCtx;
+ }
+
+ /**
+ * Get hint context; local if exists, otherwise stack's default context.
+ *
+ * @return
+ */
+ public IHintContext getWriteableHintContext()
+ {
+ ICanvasContext ctx = context;
+ assert(ctx!=null);
+ if (localHintCtx!=null) return localHintCtx;
+ return ctx.getDefaultHintContext();
+ }
+
+ /**
+ * Read hint from the hint stack.
+ *
+ * @param key
+ * @return
+ */
+ public
+ * Local hint context overrides default context in the following convenience methods:
+ * getHint(), setHint(), setHintAsync()
+ *
+ * Q: What is the purpose of local hint stack?
+ * A: To override hints for the lifetime of the participant.
+ * For example, Special editing mode overrides viewport and toolmode.
+ *
+ * @param priority
+ */
+ public void createLocalHintContext(int priority)
+ {
+ localHintCtx = new HintContext();
+ }
+
+ /**
+ * Set hint to the local hint stack if one exists otherwise to the default context.
+ * Switches thread to the appropriate context thread.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ public void setHintAsync(final Key key, final Object value)
+ {
+ assert(context!=null);
+ asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (isRemoved())
+ return;
+ if (localHintCtx!=null)
+ localHintCtx.setHint(key, value);
+ else
+ context.getDefaultHintContext().setHint(key, value);
+ }});
+ }
+
+ /**
+ * Get the interactor context.
+ * @return the context
+ */
+ public ICanvasContext getContext()
+ {
+ return context;
+ }
+
+ public IThreadWorkQueue getThread()
+ {
+ return thread;
+ }
+
+
+ /**
+ * Asserts that dependencies of participants are satisfied.
+ */
+ public void assertDependencies()
+ {
+ assert(depsSatisfied);
+ }
+
+ private boolean checkDependencies() {
+ synchronized ( ctxListener ) {
+ try {
+ for (ReferenceDefinition rd : refDefs) {
+ if (!rd.dependency)
+ continue;
+ Field f = rd.field;
+ Object o = f.get(this);
+ if (o == null)
+ return false;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+ }
+
+ public void setDirty()
+ {
+ ICanvasContext ctx = getContext();
+ if ( ctx==null ) return;
+ IContentContext cctx = ctx.getContentContext();
+ if ( cctx==null ) return;
+ cctx.setDirty();
+ }
+
+}