X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fprofile%2FStyleBase.java;fp=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fprofile%2FStyleBase.java;h=888a6ea0ec14a16b450ce8de7b5dc61e7eeaea89;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBase.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBase.java
new file mode 100644
index 000000000..888a6ea0e
--- /dev/null
+++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/StyleBase.java
@@ -0,0 +1,483 @@
+/*******************************************************************************
+ * 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.diagram.profile;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.RequestProcessor;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.TernaryRead;
+import org.simantics.db.common.request.UnaryRead;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.procedure.Listener;
+import org.simantics.db.request.Read;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.g2d.canvas.ICanvasContext;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.element.IElement;
+import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.profile.DataNodeMap;
+import org.simantics.scenegraph.profile.EvaluationContext;
+import org.simantics.scenegraph.profile.Group;
+import org.simantics.scenegraph.profile.Observer;
+import org.simantics.scenegraph.profile.Style;
+import org.simantics.scenegraph.profile.common.ObserverGroupListener;
+import org.simantics.scenegraph.profile.common.ObserverGroupValueListener;
+import org.simantics.scenegraph.profile.impl.DebugPolicy;
+import org.simantics.scl.runtime.tuple.Tuple;
+import org.simantics.scl.runtime.tuple.Tuple2;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.threads.AWTThread;
+
+/**
+ * For most style implementations it should be enough to override the following
+ * methods:
+ *
+ * See each method for a specification of what they are intended for.
+ *
+ * Optionally you can also override
+ * {@link #styleResultChanged(Observer, Resource, Object)} for optimization
+ * purposes but this is usually not necessary.
+ *
+ * @author Tuukka Lehtonen
+ * f
+ * @param type of result objects for styled group items tracked by this
+ * style implementation, see
+ * {@link #calculateStyle(ReadGraph, Resource, Resource, Variable)}
+ */
+public abstract class StyleBase implements Style {
+
+ protected final Map values = new ConcurrentHashMap();
+
+// private Map listeners = new ConcurrentHashMap();
+
+ private Map, ObserverGroupListener> listeners = new HashMap, ObserverGroupListener>();
+
+
+ private final List removals = new ArrayList();
+
+ /**
+ * For caching this simple base request that is done in every
+ * {@link StyleBase#calculateStyle(ReadGraph, Resource, Resource, Resource)}.
+ */
+ static class RuntimeDiagramVariableRequest extends UnaryRead {
+ public RuntimeDiagramVariableRequest(Resource runtimeDiagram) {
+ super(runtimeDiagram);
+ }
+
+ @Override
+ public Variable perform(ReadGraph graph) throws DatabaseException {
+ DiagramResource DIA = DiagramResource.getInstance(graph);
+ String variableURI = graph.getPossibleRelatedValue(parameter, DIA.RuntimeDiagram_HasVariable, Bindings.STRING);
+ if (variableURI == null)
+ return null;
+ Variable activeVariable = org.simantics.db.layer0.variable.Variables.getPossibleVariable(graph, variableURI);
+ return activeVariable;
+ }
+ }
+
+ /**
+ * Calculates a typed result to be used for applying the style to a diagram
+ * in
+ * {@link #applyStyleForElement(Observer, IDiagram, Object, IElement, Object)}
+ * . The graph request system will take care of only notifying other systems
+ * when the style result actually changes.
+ *
+ *
+ * This implementation uses {@link RuntimeDiagramVariableRequest} to
+ * discover the active composite variable related to the specified
+ * runtimeDiagram and invokes
+ * {@link StyleBase#calculateStyle(ReadGraph, Resource, Resource, Resource, Variable)}
+ * with it.
+ *
+ * @param graph
+ * database read access
+ * @param runtimeDiagram
+ * resource describing the runtime data of the styled diagram
+ * @param entry
+ * profile entry resource, don't care if now aware
+ * @param groupItem
+ * an item belonging to the observed group
+ * @return the calculated style result object
+ * @throws DatabaseException
+ * @see {@link StyleBase#calculateStyle(ReadGraph, Resource, Resource, Resource, Variable)}
+ */
+ public Result calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource groupItem) throws DatabaseException {
+ Variable activeVariable = graph.syncRequest(new RuntimeDiagramVariableRequest(runtimeDiagram), TransientCacheListener.instance());
+ if (activeVariable == null)
+ return null;
+
+ //System.out.println("URI1: " + configuration.getURI(graph));
+ //System.out.println("URI2: " + activeVariable.getURI(graph));
+ return calculateStyle(graph, runtimeDiagram, entry, groupItem, activeVariable);
+ }
+
+ /**
+ * Calculates a typed result to be used for applying the style to a diagram
+ * in
+ * {@link #applyStyleForElement(Observer, IDiagram, Object, IElement, Object)}
+ * . The graph request system will take care of only notifying other systems
+ * when the style result actually changes.
+ *
+ * @param graph database read access
+ * @param runtimeDiagram resource describing the runtime data of the styled
+ * diagram
+ * @param entry profile entry resource, don't care if now aware
+ * @param groupItem an item belonging to the observed group
+ * @param activeComposite variable for accessing the active realization of the
+ * diagram's corresponding composite. This may change when
+ * experiments are activate and deactivated. When there is no
+ * experiment active, this is the base realization, i.e. the
+ * configuration.
+ * @return the calculated style result object
+ * @throws DatabaseException
+ * @see {@link StyleBase#calculateStyle(ReadGraph, Resource, Resource, Resource, Variable)}
+ */
+ public Result calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource groupItem, Variable activeComposite) throws DatabaseException {
+ return null;
+ }
+
+ /**
+ * Invoked when the result calculated by
+ * {@link #calculateStyle(ReadGraph, Resource, Resource, Variable)} changes.
+ * Used for keeping track of the latest calculated style values that are
+ * applied in
+ * {@link #applyStyleForElement(Observer, IDiagram, Object, IElement, Object)}.
+ *
+ * @param observer
+ * @param object
+ * @param result
+ */
+ public void styleResultChanged(Observer observer, Resource runtimeDiagram, Resource object, Result result) {
+ if (result == null)
+ values.remove(new Tuple2(runtimeDiagram, object));
+ else
+ values.put(new Tuple2(runtimeDiagram, object), result);
+ observer.update();
+ }
+
+ /**
+ * Apply the latest style result calculated by
+ * {@link #calculateStyle(ReadGraph, Resource, Resource, Variable)} to the
+ * scene graph of the specified diagram item (i.e. element).
+ *
+ *
+ * StyleBase ensures that this method is invoked in the AWT
+ * thread only.
+ *
+ * @param observer profile system observer
+ * @param item the styled diagram item data
+ * @param element the styled diagram element representing the data item
+ * @param result the latest result calculated by
+ * {@link #calculateStyle(ReadGraph, Resource, Resource, Variable)}
+ */
+ public void applyStyleForNode(EvaluationContext evaluationContext, INode node, Result result) {
+ }
+
+ public void applyStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item, Result value) {
+
+ final INode node = map.getNode(item);
+ if (node == null) {
+ evaluationContext.update();
+ // TODO: continue or return?
+ return;
+ }
+
+ if (DebugPolicy.DEBUG_PROFILE_STYLE_APPLICATION)
+ System.out.println(StyleBase.this + ": applying style for item " + item + " and element " + node + " with result " + value);
+
+ applyStyleForNode(evaluationContext, node, value);
+
+ }
+
+ /**
+ * This method is invoked by
+ * {@link #cleanupStyleForNode(EvaluationContext, INode)} when the style is
+ * deactivated. It is invoked for each diagram element tracked by the style
+ * before deactivation.
+ *
+ * @param node a previously tracked and styled scene graph node
+ */
+ protected void cleanupStyleForNode(INode node) {
+ }
+
+ /**
+ * This method is invoked by
+ * {@link #cleanupStyleForItem(EvaluationContext, DataNodeMap, Object)} when the style is
+ * deactivated. It is invoked for each diagram element tracked by the style
+ * before deactivation.
+ * @param evaluationContext the context of this style evaluation
+ * @param node a previously tracked and styled scene graph node
+ */
+ protected void cleanupStyleForNode(EvaluationContext evaluationContext, INode node) {
+ cleanupStyleForNode(node);
+ }
+
+ protected void cleanupStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item) {
+
+ final INode node = map.getNode(item);
+ if (node != null) {
+ if (DebugPolicy.DEBUG_PROFILE_STYLE_ACTIVATION)
+ System.out.println(this + ".cleanupStyleForItem(" + item + " = " + node + ")");
+ cleanupStyleForNode(evaluationContext, node);
+ }
+
+ }
+
+
+ static class GroupListener extends ObserverGroupListener {
+
+ private StyleBase style;
+ private Session session;
+ private Resource runtimeDiagram;
+ private Resource entry;
+
+ GroupListener(Session session, Resource runtimeDiagram, Resource entry, StyleBase style, Group group, Observer observer) {
+ super(style, group, observer);
+ this.style = style;
+ this.session = session;
+ this.runtimeDiagram = runtimeDiagram;
+ this.entry = entry;
+ }
+
+ @Override
+ public void add(final Resource item) {
+
+ if (DebugPolicy.DEBUG_PROFILE_STYLE_GROUP_TRACKING)
+ System.out.println(style + ": added to group " + group + ": " + item);
+
+ session.asyncRequest(
+ style.getStyleCalculationRequest(runtimeDiagram, entry, item),
+ style.getStyleResultListener(this, item, group, observer, runtimeDiagram)
+ );
+
+ super.add(item);
+ }
+ @Override
+ public void remove(Resource item) {
+ if (DebugPolicy.DEBUG_PROFILE_STYLE_GROUP_TRACKING)
+ System.out.println(style + ": removed from group " + group + ": " + item);
+
+ synchronized (style.removals) {
+ style.removals.add(item);
+ }
+
+ // TODO: do something here to dispose of ObserverGroupValueListeners?
+ super.remove(item);
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.simantics.diagram.profile.Style#activate(org.simantics.db.RequestProcessor, org.simantics.db.Resource, org.simantics.db.layer0.variable.Variable, org.simantics.diagram.profile.Group, org.simantics.diagram.profile.Observer)
+ */
+ @Override
+ public final void activate(RequestProcessor backend, final Resource runtimeDiagram, final Resource entry, final Group group, final EvaluationContext observer) {
+
+ ObserverGroupListener listener = getListener(runtimeDiagram, group);
+
+ if (listener == null || listener.isDisposed()) {
+
+ if (DebugPolicy.DEBUG_PROFILE_STYLE_ACTIVATION)
+ System.out.println("activate(" + runtimeDiagram + ", " + group + ", " + observer);
+
+ listener = new GroupListener(backend.getSession(), runtimeDiagram, entry, this, group, observer);
+
+ listeners.put(Pair.make(runtimeDiagram, group), listener);
+
+ group.trackItems(backend, runtimeDiagram, listener);
+
+ }
+
+ // Register this entry in the listener
+ listener.addEntry(entry);
+ }
+
+ /**
+ * Used to customize the identity given to graph requests made for this
+ * style. Default identity is getClass().
+ *
+ * @return identity object used in graph requests made by this style
+ */
+ protected Object getIdentity(Resource entry) {
+ return new Pair, Resource>(getClass(), entry);
+ }
+
+ /**
+ * @param configuration
+ * @param runtimeDiagram
+ * @param item
+ * @return
+ */
+ protected Read getStyleCalculationRequest(Resource runtimeDiagram, final Resource entry, Resource item) {
+ return new TernaryRead