]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/participant/DiagramModelActivityTracker.java
Merge commit 'bd5bc6e45f700e755b61bd112631796631330ecb'
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / participant / DiagramModelActivityTracker.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.diagram.participant;\r
13 \r
14 import java.awt.Color;\r
15 import java.awt.Font;\r
16 import java.awt.geom.AffineTransform;\r
17 import java.awt.geom.Rectangle2D;\r
18 \r
19 import org.simantics.Simantics;\r
20 import org.simantics.db.ReadGraph;\r
21 import org.simantics.db.Resource;\r
22 import org.simantics.db.common.request.PossibleIndexRoot;\r
23 import org.simantics.db.common.request.UnaryRead;\r
24 import org.simantics.db.exception.DatabaseException;\r
25 import org.simantics.db.layer0.adapter.Instances;\r
26 import org.simantics.db.layer0.request.IsActive;\r
27 import org.simantics.db.layer0.util.Layer0Utils;\r
28 import org.simantics.db.procedure.Listener;\r
29 import org.simantics.diagram.elements.TextNode;\r
30 import org.simantics.diagram.stubs.DiagramResource;\r
31 import org.simantics.g2d.canvas.Hints;\r
32 import org.simantics.g2d.canvas.ICanvasContext;\r
33 import org.simantics.g2d.canvas.SGDesignation;\r
34 import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;\r
35 import org.simantics.g2d.canvas.impl.HintReflection.HintListener;\r
36 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup;\r
37 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;\r
38 import org.simantics.g2d.utils.Alignment;\r
39 import org.simantics.layer0.Layer0;\r
40 import org.simantics.modeling.ModelingResources;\r
41 import org.simantics.scenegraph.g2d.G2DParentNode;\r
42 import org.simantics.structural.stubs.StructuralResource2;\r
43 import org.simantics.utils.datastructures.hints.IHintContext;\r
44 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
45 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
46 import org.simantics.utils.datastructures.hints.IHintObservable;\r
47 import org.simantics.utils.ui.ErrorLogger;\r
48 \r
49 /**\r
50  * DiagramModelActivityTracker tracks whether or not the specified input\r
51  * resource is part of the diagram model or not and modifies the canvas\r
52  * background color accordingly. If the diagram is not in an active model, an\r
53  * <b>INACTIVE MODEL</b> banner is also shown in the background using\r
54  * {@link TextNode}.\r
55  * \r
56  * @author Tuukka Lehtonen\r
57  */\r
58 public class DiagramModelActivityTracker extends AbstractCanvasParticipant {\r
59 \r
60     public static final Key    KEY_IN_ACTIVE_MODEL         = new KeyOf(String.class, "IN_ACTIVE_MODEL");\r
61     public static final Key    KEY_ACTIVE_BACKGROUND       = new KeyOf(Color.class, "ACTIVE_BACKGROUND");\r
62     public static final Key    KEY_INACTIVE_BACKGROUND     = new KeyOf(Color.class, "INACTIVE_BACKGROUND");\r
63 \r
64     private static final Color DEFAULT_ACTIVE_BACKGROUND   = Color.WHITE;\r
65     private static final Color DEFAULT_INACTIVE_BACKGROUND = new Color(242, 242, 242);\r
66 \r
67     Resource                   input;\r
68     IsInActiveModelListener    listener;\r
69     TextNode                   bannerNode;\r
70 \r
71     public DiagramModelActivityTracker(Resource input) {\r
72         if (input == null)\r
73             throw new NullPointerException("null input");\r
74         this.input = input;\r
75     }\r
76 \r
77     @HintListener(Class=Hints.class, Field="KEY_CONTROL_BOUNDS")\r
78     public void controlBoundsChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
79         if (bannerNode == null)\r
80             return;\r
81         if (newValue != null) {\r
82             Rectangle2D bounds = (Rectangle2D) newValue;\r
83             AffineTransform at = new AffineTransform();\r
84             at.translate(5,5);\r
85 //            at.translate(bounds.getWidth() / 2, bounds.getHeight() / 2);\r
86 //            at.scale(2, 2);\r
87 //            at.rotate(-Math.PI/6);\r
88 //            at.translate(bounds.getWidth() - 150, bounds.getHeight() - 30);\r
89 //            at.scale(1, 1);\r
90             bannerNode.setTransform(at);\r
91         } else {\r
92             // Disable rendering\r
93             bannerNode.setColor(null);\r
94         }\r
95     }\r
96 \r
97     @HintListener(Class=DiagramModelActivityTracker.class, Field="KEY_IN_ACTIVE_MODEL")\r
98     public void containingModelActivityChanged(IHintObservable sender, Key key, Object oldValue, Object _newValue) {\r
99         String newValue = (String)_newValue;\r
100         if (bannerNode == null)\r
101             return;\r
102         if (newValue == null) {\r
103                 bannerNode.setText("");\r
104         } else {\r
105                 bannerNode.setText(newValue);\r
106             //bannerNode.setColor(new Color(192, 32, 32, 128));\r
107             //bannerNode.setColor(new Color(192, 32, 32, 32));\r
108         }\r
109     }\r
110 \r
111     @Override\r
112     public void addedToContext(ICanvasContext ctx) {\r
113         super.addedToContext(ctx);\r
114 \r
115         listener = new IsInActiveModelListener(ctx);\r
116         Simantics.getSession().async(new IsActiveDiagram(input), listener);\r
117 \r
118         if (!ctx.getHintStack().containsHint(KEY_ACTIVE_BACKGROUND))\r
119             ctx.getDefaultHintContext().setHint(KEY_ACTIVE_BACKGROUND, DEFAULT_ACTIVE_BACKGROUND);\r
120         if (!ctx.getHintStack().containsHint(KEY_INACTIVE_BACKGROUND))\r
121             ctx.getDefaultHintContext().setHint(KEY_INACTIVE_BACKGROUND, DEFAULT_INACTIVE_BACKGROUND);\r
122     }\r
123 \r
124     @Override\r
125     public void removedFromContext(ICanvasContext ctx) {\r
126         if (listener != null) {\r
127             listener.dispose();\r
128             listener = null;\r
129         }\r
130         super.removedFromContext(ctx);\r
131     }\r
132 \r
133     @SGInit(designation = SGDesignation.CONTROL)\r
134     public void initSG(G2DParentNode parent) {\r
135         bannerNode = parent.addNode("inactivity-banner", TextNode.class);\r
136         bannerNode.setZIndex(Integer.MIN_VALUE / 4);\r
137         //bannerNode.setZIndex(Integer.MAX_VALUE / 4);\r
138         bannerNode.setHorizontalAlignment((byte) Alignment.LEADING.ordinal());\r
139         bannerNode.setVerticalAlignment((byte) Alignment.LEADING.ordinal());\r
140         //bannerNode.setText("Model is not active.");\r
141         bannerNode.setText("");\r
142         bannerNode.setFont(Font.decode("Arial 16"));\r
143         //bannerNode.setBackgroundColor(new Color(192, 192, 192, 128));\r
144         bannerNode.setPadding(10, 10);\r
145         bannerNode.setBorderColor(Color.GRAY);\r
146         bannerNode.setBorderWidth(0);\r
147         bannerNode.setEditable(false);\r
148     }\r
149 \r
150     @SGCleanup\r
151     public void cleanupSG() {\r
152         if (bannerNode != null) {\r
153             bannerNode.remove();\r
154             bannerNode = null;\r
155         }\r
156     }\r
157 \r
158     static class IsActiveDiagram extends UnaryRead<Resource, String> {\r
159         public IsActiveDiagram(Resource parameter) {\r
160             super(parameter);\r
161         }\r
162         @Override\r
163         public String perform(ReadGraph graph) throws DatabaseException {\r
164                 \r
165             Resource indexRoot = graph.syncRequest( new PossibleIndexRoot(parameter) );\r
166             if (indexRoot == null) {\r
167                 return "This diagram is not part of any model or shared library";\r
168             }\r
169                 Layer0 L0 = Layer0.getInstance(graph);\r
170                 StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
171                 ModelingResources MOD = ModelingResources.getInstance(graph);\r
172                 Resource composite = graph.getPossibleObject(parameter, MOD.DiagramToComposite);\r
173                 if(composite == null)\r
174                 return "This diagram does not have a corresponding configuration";\r
175                 \r
176                 Resource componentType = graph.getPossibleObject(composite, STR.Defines);\r
177                 if(componentType != null) {\r
178                         // This is a component type\r
179                         boolean published = Layer0Utils.isPublished(graph, componentType);\r
180                         if(published)\r
181                     return "This diagram defines a published (read-only) user component";\r
182                 }\r
183                 \r
184                 if(graph.isInstanceOf(indexRoot, L0.SharedOntology)) {\r
185                         return "";\r
186                 }\r
187                 \r
188                 boolean activeModel = graph.syncRequest( new IsActive(indexRoot) );\r
189                 if(!activeModel)\r
190                 return "The model of this diagram is not active";\r
191                 \r
192                 DiagramResource DIA = DiagramResource.getInstance(graph);\r
193                 Instances query = graph.adapt(DIA.DiagramActivityCondition, Instances.class);\r
194 \r
195                 for(Resource condition : query.find(graph, indexRoot)) {\r
196                 String value = Simantics.tryInvokeSCL(graph, condition, DIA.DiagramActivityCondition_test, parameter);\r
197                 if(value != null && !value.isEmpty()) return value;\r
198                 }\r
199                 \r
200             return "";\r
201             \r
202         }\r
203     }\r
204 \r
205     static class IsInActiveModelListener implements Listener<String> {\r
206         ICanvasContext context;\r
207         public IsInActiveModelListener(ICanvasContext context) {\r
208             this.context = context;\r
209         }\r
210         @Override\r
211         public void execute(final String result) {\r
212             final Color color = (result.isEmpty())\r
213                     ? context.getHintStack().<Color>getHint(KEY_ACTIVE_BACKGROUND)\r
214                     : context.getHintStack().<Color>getHint(KEY_INACTIVE_BACKGROUND);\r
215 \r
216             context.getThreadAccess().asyncExec(new Runnable() {\r
217                 @Override\r
218                 public void run() {\r
219                     ICanvasContext ctx = context;\r
220                     if (ctx == null)\r
221                         return;\r
222                     if (ctx.isDisposed())\r
223                         return;\r
224                     IHintContext hints = ctx.getDefaultHintContext();\r
225                     if (color != null)\r
226                         hints.setHint(Hints.KEY_BACKGROUND_COLOR, color);\r
227                     hints.setHint(KEY_IN_ACTIVE_MODEL, result);\r
228                 }\r
229             });\r
230         }\r
231         public void dispose() {\r
232             context = null;\r
233         }\r
234         @Override\r
235         public boolean isDisposed() {\r
236             ICanvasContext context = this.context;\r
237             return context == null || context.isDisposed();\r
238         }\r
239         @Override\r
240         public void exception(Throwable t) {\r
241             ErrorLogger.defaultLogError(t);\r
242         }\r
243     }\r
244 \r
245 }\r