X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fparticipant%2FDiagramModelActivityTracker.java;fp=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fparticipant%2FDiagramModelActivityTracker.java;h=a12043f10375dd7c781c402e531c18e200772e01;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/DiagramModelActivityTracker.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/DiagramModelActivityTracker.java new file mode 100644 index 000000000..a12043f10 --- /dev/null +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/DiagramModelActivityTracker.java @@ -0,0 +1,245 @@ +/******************************************************************************* + * 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.participant; + +import java.awt.Color; +import java.awt.Font; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.simantics.Simantics; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.PossibleIndexRoot; +import org.simantics.db.common.request.UnaryRead; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.adapter.Instances; +import org.simantics.db.layer0.request.IsActive; +import org.simantics.db.layer0.util.Layer0Utils; +import org.simantics.db.procedure.Listener; +import org.simantics.diagram.elements.TextNode; +import org.simantics.diagram.stubs.DiagramResource; +import org.simantics.g2d.canvas.Hints; +import org.simantics.g2d.canvas.ICanvasContext; +import org.simantics.g2d.canvas.SGDesignation; +import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant; +import org.simantics.g2d.canvas.impl.HintReflection.HintListener; +import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; +import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; +import org.simantics.g2d.utils.Alignment; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.structural.stubs.StructuralResource2; +import org.simantics.utils.datastructures.hints.IHintContext; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; +import org.simantics.utils.datastructures.hints.IHintObservable; +import org.simantics.utils.ui.ErrorLogger; + +/** + * DiagramModelActivityTracker tracks whether or not the specified input + * resource is part of the diagram model or not and modifies the canvas + * background color accordingly. If the diagram is not in an active model, an + * INACTIVE MODEL banner is also shown in the background using + * {@link TextNode}. + * + * @author Tuukka Lehtonen + */ +public class DiagramModelActivityTracker extends AbstractCanvasParticipant { + + public static final Key KEY_IN_ACTIVE_MODEL = new KeyOf(String.class, "IN_ACTIVE_MODEL"); + public static final Key KEY_ACTIVE_BACKGROUND = new KeyOf(Color.class, "ACTIVE_BACKGROUND"); + public static final Key KEY_INACTIVE_BACKGROUND = new KeyOf(Color.class, "INACTIVE_BACKGROUND"); + + private static final Color DEFAULT_ACTIVE_BACKGROUND = Color.WHITE; + private static final Color DEFAULT_INACTIVE_BACKGROUND = new Color(242, 242, 242); + + Resource input; + IsInActiveModelListener listener; + TextNode bannerNode; + + public DiagramModelActivityTracker(Resource input) { + if (input == null) + throw new NullPointerException("null input"); + this.input = input; + } + + @HintListener(Class=Hints.class, Field="KEY_CONTROL_BOUNDS") + public void controlBoundsChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { + if (bannerNode == null) + return; + if (newValue != null) { + Rectangle2D bounds = (Rectangle2D) newValue; + AffineTransform at = new AffineTransform(); + at.translate(5,5); +// at.translate(bounds.getWidth() / 2, bounds.getHeight() / 2); +// at.scale(2, 2); +// at.rotate(-Math.PI/6); +// at.translate(bounds.getWidth() - 150, bounds.getHeight() - 30); +// at.scale(1, 1); + bannerNode.setTransform(at); + } else { + // Disable rendering + bannerNode.setColor(null); + } + } + + @HintListener(Class=DiagramModelActivityTracker.class, Field="KEY_IN_ACTIVE_MODEL") + public void containingModelActivityChanged(IHintObservable sender, Key key, Object oldValue, Object _newValue) { + String newValue = (String)_newValue; + if (bannerNode == null) + return; + if (newValue == null) { + bannerNode.setText(""); + } else { + bannerNode.setText(newValue); + //bannerNode.setColor(new Color(192, 32, 32, 128)); + //bannerNode.setColor(new Color(192, 32, 32, 32)); + } + } + + @Override + public void addedToContext(ICanvasContext ctx) { + super.addedToContext(ctx); + + listener = new IsInActiveModelListener(ctx); + Simantics.getSession().async(new IsActiveDiagram(input), listener); + + if (!ctx.getHintStack().containsHint(KEY_ACTIVE_BACKGROUND)) + ctx.getDefaultHintContext().setHint(KEY_ACTIVE_BACKGROUND, DEFAULT_ACTIVE_BACKGROUND); + if (!ctx.getHintStack().containsHint(KEY_INACTIVE_BACKGROUND)) + ctx.getDefaultHintContext().setHint(KEY_INACTIVE_BACKGROUND, DEFAULT_INACTIVE_BACKGROUND); + } + + @Override + public void removedFromContext(ICanvasContext ctx) { + if (listener != null) { + listener.dispose(); + listener = null; + } + super.removedFromContext(ctx); + } + + @SGInit(designation = SGDesignation.CONTROL) + public void initSG(G2DParentNode parent) { + bannerNode = parent.addNode("inactivity-banner", TextNode.class); + bannerNode.setZIndex(Integer.MIN_VALUE / 4); + //bannerNode.setZIndex(Integer.MAX_VALUE / 4); + bannerNode.setHorizontalAlignment((byte) Alignment.LEADING.ordinal()); + bannerNode.setVerticalAlignment((byte) Alignment.LEADING.ordinal()); + //bannerNode.setText("Model is not active."); + bannerNode.setText(""); + bannerNode.setFont(Font.decode("Arial 16")); + //bannerNode.setBackgroundColor(new Color(192, 192, 192, 128)); + bannerNode.setPadding(10, 10); + bannerNode.setBorderColor(Color.GRAY); + bannerNode.setBorderWidth(0); + bannerNode.setEditable(false); + } + + @SGCleanup + public void cleanupSG() { + if (bannerNode != null) { + bannerNode.remove(); + bannerNode = null; + } + } + + static class IsActiveDiagram extends UnaryRead { + public IsActiveDiagram(Resource parameter) { + super(parameter); + } + @Override + public String perform(ReadGraph graph) throws DatabaseException { + + Resource indexRoot = graph.syncRequest( new PossibleIndexRoot(parameter) ); + if (indexRoot == null) { + return "This diagram is not part of any model or shared library"; + } + Layer0 L0 = Layer0.getInstance(graph); + StructuralResource2 STR = StructuralResource2.getInstance(graph); + ModelingResources MOD = ModelingResources.getInstance(graph); + Resource composite = graph.getPossibleObject(parameter, MOD.DiagramToComposite); + if(composite == null) + return "This diagram does not have a corresponding configuration"; + + Resource componentType = graph.getPossibleObject(composite, STR.Defines); + if(componentType != null) { + // This is a component type + boolean published = Layer0Utils.isPublished(graph, componentType); + if(published) + return "This diagram defines a published (read-only) user component"; + } + + if(graph.isInstanceOf(indexRoot, L0.SharedOntology)) { + return ""; + } + + boolean activeModel = graph.syncRequest( new IsActive(indexRoot) ); + if(!activeModel) + return "The model of this diagram is not active"; + + DiagramResource DIA = DiagramResource.getInstance(graph); + Instances query = graph.adapt(DIA.DiagramActivityCondition, Instances.class); + + for(Resource condition : query.find(graph, indexRoot)) { + String value = Simantics.tryInvokeSCL(graph, condition, DIA.DiagramActivityCondition_test, parameter); + if(value != null && !value.isEmpty()) return value; + } + + return ""; + + } + } + + static class IsInActiveModelListener implements Listener { + ICanvasContext context; + public IsInActiveModelListener(ICanvasContext context) { + this.context = context; + } + @Override + public void execute(final String result) { + final Color color = (result.isEmpty()) + ? context.getHintStack().getHint(KEY_ACTIVE_BACKGROUND) + : context.getHintStack().getHint(KEY_INACTIVE_BACKGROUND); + + context.getThreadAccess().asyncExec(new Runnable() { + @Override + public void run() { + ICanvasContext ctx = context; + if (ctx == null) + return; + if (ctx.isDisposed()) + return; + IHintContext hints = ctx.getDefaultHintContext(); + if (color != null) + hints.setHint(Hints.KEY_BACKGROUND_COLOR, color); + hints.setHint(KEY_IN_ACTIVE_MODEL, result); + } + }); + } + public void dispose() { + context = null; + } + @Override + public boolean isDisposed() { + ICanvasContext context = this.context; + return context == null || context.isDisposed(); + } + @Override + public void exception(Throwable t) { + ErrorLogger.defaultLogError(t); + } + } + +}