]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/function/Functions.java
Fixed most warnings from district codebase after JavaSE-11 switch
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / function / Functions.java
1 package org.simantics.district.network.ui.function;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.stream.Collectors;
13
14 import org.eclipse.jface.dialogs.Dialog;
15 import org.eclipse.ui.PlatformUI;
16 import org.simantics.NameLabelUtil;
17 import org.simantics.Simantics;
18 import org.simantics.browsing.ui.common.modifiers.EnumeratedValue;
19 import org.simantics.browsing.ui.common.modifiers.Enumeration;
20 import org.simantics.browsing.ui.graph.impl.GraphEnumerationModifier;
21 import org.simantics.databoard.Bindings;
22 import org.simantics.db.ReadGraph;
23 import org.simantics.db.Resource;
24 import org.simantics.db.Session;
25 import org.simantics.db.common.request.IndexRoot;
26 import org.simantics.db.common.request.ObjectsWithType;
27 import org.simantics.db.exception.DatabaseException;
28 import org.simantics.db.exception.RuntimeDatabaseException;
29 import org.simantics.db.layer0.QueryIndexUtils;
30 import org.simantics.db.layer0.util.Layer0Utils;
31 import org.simantics.db.layer0.variable.Variable;
32 import org.simantics.db.layer0.variable.Variables;
33 import org.simantics.db.layer0.variable.Variables.Role;
34 import org.simantics.db.procedure.Procedure;
35 import org.simantics.db.request.WriteResult;
36 import org.simantics.district.network.DistrictNetworkUtil;
37 import org.simantics.district.network.ontology.DistrictNetworkResource;
38 import org.simantics.layer0.Layer0;
39 import org.simantics.modeling.typicals.TypicalUtil;
40 import org.simantics.scl.compiler.commands.CommandSession;
41 import org.simantics.scl.compiler.commands.CommandSessionImportEntry;
42 import org.simantics.scl.compiler.errors.CompilationError;
43 import org.simantics.scl.osgi.SCLOsgi;
44 import org.simantics.scl.reflection.annotations.SCLValue;
45 import org.simantics.scl.runtime.SCLContext;
46 import org.simantics.scl.runtime.function.Function1;
47 import org.simantics.scl.runtime.function.FunctionImpl1;
48 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
49 import org.simantics.ui.workbench.action.DefaultActions;
50 import org.simantics.utils.ui.SWTUtils;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 public class Functions {
55
56     private static final Logger LOGGER = LoggerFactory.getLogger(Functions.class);
57     
58     private Functions() {
59     }
60
61     private static class HasMappingEnumerationModifier extends GraphEnumerationModifier {
62
63         public HasMappingEnumerationModifier(Session session, Resource subject, Resource relation, Enumeration<Resource> enumeration, Resource value) {
64             super(session, subject, relation, enumeration, value);
65         }
66
67     }
68
69     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
70     public static Object defaultEdgeMappingModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
71         Resource diagram = resolveElement(graph, context);
72         DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
73         return baseMappingModifier(graph, diagram, DN.EdgeDefaultMapping, DN.Mapping_EdgeMapping, context);
74     }
75     
76     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
77     public static Object defaultVertexMappingModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
78         Resource diagram = resolveElement(graph, context);
79         DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
80         return baseMappingModifier(graph, diagram, DN.VertexDefaultMapping, DN.Mapping_VertexMapping, context);
81     }
82
83     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
84     public static Object rightClickVertexMappingModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
85         Resource diagram = resolveElement(graph, context);
86         DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
87         return baseMappingModifier(graph, diagram, DN.RightClickDefaultMapping, DN.Mapping_VertexMapping, context);
88     }
89
90     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
91     public static Object leftClickVertexMappingModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
92         Resource diagram = resolveElement(graph, context);
93         DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
94         return baseMappingModifier(graph, diagram, DN.LeftClickDefaultMapping, DN.Mapping_VertexMapping, context);
95     }
96
97     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
98     public static Object mappingModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
99         
100         Resource element = resolveElement(graph, context);
101         Resource mappingType = resolveMappingType(graph, element);
102         return baseMappingModifier(graph, element, DistrictNetworkResource.getInstance(graph).HasMapping, mappingType, context);
103     }
104
105     public static Map<String, Resource> getVertexMappings(ReadGraph graph, Resource indexRoot) throws DatabaseException {
106         Map<String, Resource> second = getNetworkMappingsByType(graph, indexRoot, DistrictNetworkResource.getInstance(graph).Mapping_VertexMapping);
107         return second;
108     }
109
110     public static Map<String, Resource> getEdgeMappings(ReadGraph graph, Resource indexRoot) throws DatabaseException {
111         Map<String, Resource> second = getNetworkMappingsByType(graph, indexRoot, DistrictNetworkResource.getInstance(graph).Mapping_EdgeMapping);
112         return second;
113     }
114     
115     public static Map<String, Resource> getCRSs(ReadGraph graph, Resource resource) throws DatabaseException {
116         Map<String, Resource> result = getNetworkMappingsByType(graph, graph.sync(new IndexRoot(resource)), DistrictNetworkResource.getInstance(graph).SpatialRefSystem);
117         return result;
118         
119     }
120
121     public static Map<String, Resource> getNetworkMappingsByType(ReadGraph graph, Resource indexRoot, Resource mappingType) throws DatabaseException {
122         List<Resource> mappings = QueryIndexUtils.searchByType(graph, indexRoot, mappingType);
123         Map<String, Resource> result = new HashMap<>(mappings.size());
124         Layer0 L0 = Layer0.getInstance(graph);
125         mappings.forEach(mapping -> {
126             try {
127                 String name = graph.getRelatedValue2(mapping, L0.HasName);
128                 Resource existing = result.put(name, mapping);
129                 if (existing != null) {
130                     LOGGER.warn("Duplicate mapping name! {} {} and existing is {}", name, mapping, existing);
131                 }
132             } catch (DatabaseException e) {
133                 e.printStackTrace();
134             }
135         });
136         return result;
137     }
138     
139     private static Object baseMappingModifier(ReadGraph graph, Resource element, Resource property, Resource mappingType, Variable context) throws DatabaseException {
140         Resource indexRoot = graph.sync(new IndexRoot(element));
141         List<Resource> mappings = QueryIndexUtils.searchByType(graph, indexRoot, mappingType);
142         Enumeration<Resource> enums = Enumeration
143                 .make(mappings.stream().map(m -> createEnumeratedValue(graph, m)).collect(Collectors.toList()));
144         
145         Resource currentMapping = graph.getSingleObject(element, property);
146         
147         return new HasMappingEnumerationModifier(Simantics.getSession(), element, property, enums, currentMapping);
148     }
149     
150     private static Resource resolveMappingType(ReadGraph graph, Resource element) throws DatabaseException {
151         DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
152         if (graph.isInstanceOf(element, DN.Edge))
153             return DN.Mapping_EdgeMapping;
154         else if (graph.isInstanceOf(element, DN.Vertex))
155             return DN.Mapping_VertexMapping;
156         throw new IllegalStateException("No mapping type found for element " + element + " : " + graph.getPossibleURI(element));
157     }
158
159     private static Resource resolveElement(ReadGraph graph, Variable variable) throws DatabaseException {
160         Role role = variable.getPossibleRole(graph);
161         if (role.equals(Role.PROPERTY))
162             return resolveElement(graph, variable.getParent(graph));
163         else
164             return variable.getRepresents(graph);
165     }
166
167     private static EnumeratedValue<Resource> createEnumeratedValue(ReadGraph graph, Resource resource) {
168         try {
169             String label = NameLabelUtil.modalName(graph, resource);
170             return new EnumeratedValue<Resource>(label, resource);
171         } catch (DatabaseException e) {
172             throw new RuntimeDatabaseException(e);
173         }
174     }
175     
176     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
177     public static Object enumerationValues(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
178         //Variable var = (Variable) context;
179         return Collections.emptyList();
180     }
181     
182     @SCLValue(type = "ReadGraph -> Resource -> a -> b")
183     public static Object convertToValue(ReadGraph graph, Resource resource, Object context) throws DatabaseException {
184         Layer0 L0 = Layer0.getInstance(graph);
185         String label = graph.getPossibleRelatedValue2(resource, L0.HasLabel, Bindings.STRING);
186         if (label == null)
187             label = graph.getRelatedValue(resource, L0.HasName, Bindings.STRING);
188         return label;
189     }
190     
191     
192     @SCLValue(type = "Resource -> String -> Resource -> Resource")
193     public static Resource compositeInstantiator(final Resource compositeType, final String defaultName, final Resource target) throws DatabaseException {
194         return TypicalUtil.syncExec(procedure -> {
195             if (!SWTUtils.asyncExec(PlatformUI.getWorkbench().getDisplay(), () -> {
196                 try {
197                     queryInitialValuesAndCreateComposite(compositeType, target, defaultName, procedure);
198                 } catch (Throwable t) {
199                     procedure.exception(t);
200                 }
201             })) {
202                 procedure.execute(null);
203             }
204         });
205     }
206
207     public static void queryInitialValuesAndCreateComposite(final Resource compositeType, final Resource target,
208             String defaultName, final Procedure<Resource> procedure) {
209         DefaultMappingsDialog dialog = new DefaultMappingsDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), target);
210
211         if (dialog.open() != Dialog.OK) {
212             procedure.execute(null);
213             return;
214         }
215
216         Simantics.getSession().asyncRequest((WriteResult<Resource>) graph -> {
217             return DistrictNetworkUtil.createNetworkDiagram(graph, target, compositeType, defaultName, 
218                     dialog.getDefaultEdgeMapping(),
219                     dialog.getDefaultVertexMapping(),
220                     dialog.getRightClickVertexMapping(),
221                     dialog.getLeftClickVertexMapping(),
222                     dialog.getCRS()
223                     );
224         }, new Procedure<Resource>() {
225
226             @Override
227             public void execute(Resource composite) {
228                 DefaultActions.asyncPerformDefaultAction(Simantics.getSession(), composite, false, false, true);
229                 procedure.execute(composite);
230             }
231
232             @Override
233             public void exception(Throwable t) {
234                 LOGGER.error("Failed to create composite, see exception for details.", t);
235                 procedure.exception(t);
236             }
237         });
238     }
239
240     public static Collection<Resource> getDistrictDiagrams(ReadGraph graph) throws DatabaseException {
241         Layer0 L0 = Layer0.getInstance(graph);
242         Collection<Resource> indexRoots = graph.sync(new ObjectsWithType(Simantics.getProjectResource(), L0.ConsistsOf, L0.IndexRoot));
243         DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
244         Set<Resource> results = new HashSet<>();
245         for (Resource indexRoot : indexRoots) {
246             Collection<Resource> diagrams = QueryIndexUtils.searchByType(graph, indexRoot, DN.Diagram);
247             results.addAll(diagrams);
248         }
249         return results;
250     }
251
252     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
253     public static Function1<Resource, Double> hasDiameterValue(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
254         return directPropertyValueFunction(DistrictNetworkResource.getInstance(graph).Edge_HasDiameter, 0);
255     }
256
257     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
258     public static Function1<Resource, Double> hasNominalMassFlowValue(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
259         return directPropertyValueFunction(DistrictNetworkResource.getInstance(graph).Edge_HasNominalMassFlow, 0);
260     }
261
262     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
263     public static Function1<Resource, Double> hasNominalSupplyPressure(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
264         return directPropertyValueFunction(DistrictNetworkResource.getInstance(graph).Vertex_HasSupplyPressure, 0);
265     }
266
267     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
268     public static Function1<Resource, Double> hasElevation(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
269         return directPropertyValueFunction(DistrictNetworkResource.getInstance(graph).Vertex_HasElevation, 0);
270     }
271
272     private static final Function1<Resource, Double> ONE = new FunctionImpl1<Resource, Double>() {
273         private final Double ONE = 1.0;
274         @Override
275         public Double apply(Resource edge) {
276             return ONE;
277         }
278         @Override
279         public String toString() {
280             return "1";
281         }
282     };
283
284     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
285     public static Function1<Resource, Double> constantOne(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
286         return ONE;
287     }
288
289     private static Function1<Resource, Double> directPropertyValueFunction(Resource property, double defaultValue) throws DatabaseException {
290         Double def = defaultValue;
291         return new FunctionImpl1<Resource, Double>() {
292             @Override
293             public Double apply(Resource edge) {
294                 ReadGraph graph = (ReadGraph) SCLContext.getCurrent().get("graph");
295                 try {
296                     Double d = graph.getPossibleRelatedValue(edge, property, Bindings.DOUBLE);
297                     return d != null ? d : def;
298                 } catch (DatabaseException e) {
299                     LOGGER.error("Failed to evaluate property value", e);
300                     return def;
301                 }
302             }
303         };
304     }
305
306     private static class RangeValidator implements Function1<String, String> {
307         private double min;
308         private double max;
309         public RangeValidator(double min, double max) {
310             this.min = min;
311             this.max = max;
312         }
313         @Override
314         public String apply(String s) {
315             try {
316                 double d = Double.parseDouble(s);
317                 if (d < min)
318                     return "Value must be greater than or equal to " + min;
319                 if (d > max)
320                     return "Value must be less than or equal to " + max;
321                 return null;
322             } catch (NumberFormatException e) {
323                 return "Specified value is not a number";
324             }
325         }
326     }
327
328     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
329     public static Object hueValidator(ReadGraph graph, Resource r, Variable context) throws DatabaseException {
330         return new RangeValidator(0, 360);
331     }
332
333     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
334     public static Object saturationValidator(ReadGraph graph, Resource r, Variable context) throws DatabaseException {
335         return new RangeValidator(0, 100);
336     }
337
338     @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
339     public static Object brightnessValidator(ReadGraph graph, Resource r, Variable context) throws DatabaseException {
340         String importEntry = null;
341         Resource root = Variables.getPossibleIndexRoot(graph, context);
342         if (root != null) {
343             Resource sclmain = Layer0Utils.getPossibleChild(graph, root, "SCLMain");
344             if (sclmain != null) {
345                 importEntry = graph.getPossibleURI(sclmain);
346             }
347         }
348         SCLContext ctx = SCLContext.getCurrent();
349         Object oldGraph = ctx.put("graph", graph);
350         try {
351             return new BrightnessExpressionValidator(
352                     importEntry != null
353                     ? Arrays.asList(importEntry)
354                     : Collections.emptyList());
355         } finally {
356             ctx.put("graph", oldGraph);
357         }
358     }
359
360     private static class BrightnessExpressionValidator implements Function1<String, String> {
361         private CommandSession session;
362
363         public BrightnessExpressionValidator(List<String> importEntries) {
364             this.session = new CommandSession(SCLOsgi.MODULE_REPOSITORY, SCLReportingHandler.DEFAULT);
365             this.session.setImportEntries(imports(importEntries));
366         }
367
368         private ArrayList<CommandSessionImportEntry> imports(List<String> entries) {
369             ArrayList<CommandSessionImportEntry> result = new ArrayList<>();
370             entries.stream().map(CommandSessionImportEntry::new).forEach(result::add);
371             if (entries.isEmpty())
372                 result.add(new CommandSessionImportEntry("Simantics/District/SCLMain"));
373             return result;
374         }
375
376         @Override
377         public String apply(String s) {
378             s = s.trim();
379             if (!s.startsWith("="))
380                 return "Expression expected, must start with '='";
381             CompilationError[] errors = session.validate(s.substring(1));
382             if(errors.length == 0)
383                 return null;
384             return errors[0].description;
385         }
386     }
387
388 }