Merge "InputStream returns -1 on EOF instead of throwing IOException"
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagram / style / IssueDecorationStyle.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.modeling.ui.diagram.style;\r
13 \r
14 import java.awt.geom.AffineTransform;\r
15 import java.awt.geom.Rectangle2D;\r
16 import java.util.ArrayList;\r
17 import java.util.Collections;\r
18 import java.util.List;\r
19 import java.util.Map;\r
20 import java.util.Set;\r
21 \r
22 import org.simantics.db.ReadGraph;\r
23 import org.simantics.db.Resource;\r
24 import org.simantics.db.common.procedure.adapter.TransientCacheListener;\r
25 import org.simantics.db.exception.DatabaseException;\r
26 import org.simantics.db.layer0.variable.Variable;\r
27 import org.simantics.db.layer0.variable.Variables;\r
28 import org.simantics.diagram.profile.StyleBase;\r
29 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
30 import org.simantics.issues.Severity;\r
31 import org.simantics.issues.common.IssueResourcesContexts;\r
32 import org.simantics.issues.common.ListModelIssuesBySeverity;\r
33 import org.simantics.modeling.ModelingResources;\r
34 import org.simantics.modeling.ui.Activator;\r
35 import org.simantics.scenegraph.INode;\r
36 import org.simantics.scenegraph.g2d.nodes.Decoration;\r
37 import org.simantics.scenegraph.g2d.nodes.DecorationSVGNode;\r
38 import org.simantics.scenegraph.g2d.nodes.SVGNode;\r
39 import org.simantics.scenegraph.profile.EvaluationContext;\r
40 import org.simantics.scenegraph.profile.common.ProfileVariables;\r
41 import org.simantics.scenegraph.utils.NodeUtil;\r
42 import org.simantics.utils.datastructures.map.Tuple;\r
43 \r
44 \r
45 /**\r
46  * @author Tuukka Lehtonen\r
47  */\r
48 public class IssueDecorationStyle extends StyleBase<IssueResult> {\r
49 \r
50     private static final String DECORATION_NODE_NAME = "issueDecorations";\r
51 \r
52     private List<Resource> getContexts(ReadGraph graph, Resource element) throws DatabaseException {\r
53 \r
54         ModelingResources MOD = ModelingResources.getInstance(graph);\r
55         List<Resource> result = new ArrayList<Resource>(3);\r
56         result.add(element);\r
57         Resource config = graph.getPossibleObject(element, MOD.ElementToComponent);\r
58         if (config != null && result.indexOf(config) == -1) result.add(config);\r
59         config = graph.getPossibleObject(element, MOD.DiagramConnectionToConnection);\r
60         if (config != null && result.indexOf(config) == -1) result.add(config);\r
61         // For diagram reference element support\r
62         config = graph.getPossibleObject(element, MOD.HasParentComponent);\r
63         if (config != null && result.indexOf(config) == -1) result.add(config);\r
64         return result;\r
65 \r
66     }\r
67 \r
68     @Override\r
69     public IssueResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {\r
70 \r
71         Resource model = Variables.getModel(graph, configuration);\r
72         if (model == null)\r
73             return null;\r
74 \r
75         List<Resource> contexts = getContexts(graph, element);\r
76         AffineTransform transform = DiagramGraphUtil.getAffineTransform(graph, element);\r
77         Map<Severity, List<Resource>> issuesBySeverity = graph.syncRequest(new ListModelIssuesBySeverity(model, true, true, Severity.NOTE),\r
78                 TransientCacheListener.<Map<Severity, List<Resource>>>instance());\r
79 \r
80         for (Severity severity : Severity.values()) {\r
81             List<Resource> issues = issuesBySeverity.get(severity);\r
82             if (issues != null) {\r
83                 Set<Resource> issueContexts = graph.syncRequest(new IssueResourcesContexts(issues));\r
84                 if (!Collections.disjoint(issueContexts, contexts))\r
85                     return new IssueResult(severity, transform);\r
86             }\r
87         }\r
88 \r
89         return null;\r
90     }\r
91 \r
92     @Override\r
93     public void applyStyleForNode(EvaluationContext observer, INode node, IssueResult result) {\r
94         if (result == null) {\r
95             ProfileVariables.denyChild(node, "", DECORATION_NODE_NAME);\r
96             return;\r
97         }\r
98 \r
99         SVGNode svgNode = ProfileVariables.claimChild(node, "", DECORATION_NODE_NAME, DecorationSVGNode.class, observer);\r
100 \r
101         Rectangle2D bounds = NodeUtil.getLocalBounds(node, Decoration.class);\r
102 \r
103         double tx = bounds.getX();\r
104         double ty = bounds.getY();\r
105 \r
106         //new Exception("tx=" + tx + " ty=" + ty).printStackTrace();\r
107         \r
108         svgNode.setZIndex( Integer.MAX_VALUE );\r
109         svgNode.setTransform( AffineTransform.getTranslateInstance(tx, ty) ); \r
110 \r
111         String svgData = svgDataForSeverity(result.getSeverity());\r
112         if (svgData != null)\r
113             svgNode.setData(svgData);\r
114     }\r
115 \r
116     private String svgDataForSeverity(Severity s) {\r
117         switch (s) {\r
118         case FATAL: return Activator.FATAL_SVG_TEXT;\r
119         case ERROR: return Activator.ERROR_SVG_TEXT;\r
120         case WARNING: return Activator.WARNING_SVG_TEXT;\r
121         case INFO: return Activator.INFO_SVG_TEXT;\r
122         case NOTE: return Activator.NOTE_SVG_TEXT;\r
123         default: return null;\r
124         }\r
125     }\r
126 \r
127     @Override\r
128     protected void cleanupStyleForNode(INode node) {\r
129         ProfileVariables.denyChild(node, "", DECORATION_NODE_NAME);\r
130     }\r
131 \r
132     @Override\r
133     public String toString() {\r
134         return "Issue decoration";\r
135     }\r
136 \r
137 }\r
138 \r
139 /**\r
140  * This is needed to keep the issue decoration up-to-date when its parent\r
141  * element moves.\r
142  */\r
143 class IssueResult extends Tuple {\r
144     public IssueResult(Severity severity, AffineTransform transform) {\r
145         super(severity, transform);\r
146     }\r
147     public Severity getSeverity() {\r
148         return (Severity) getField(0);\r
149     }\r
150 }\r