1 package org.simantics.district.network.ui.function;
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;
12 import java.util.stream.Collectors;
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;
54 public class Functions {
56 private static final Logger LOGGER = LoggerFactory.getLogger(Functions.class);
61 private static class HasMappingEnumerationModifier extends GraphEnumerationModifier {
63 public HasMappingEnumerationModifier(Session session, Resource subject, Resource relation, Enumeration<Resource> enumeration, Resource value) {
64 super(session, subject, relation, enumeration, value);
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);
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);
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);
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);
97 @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
98 public static Object mappingModifier(ReadGraph graph, Resource resource, final Variable context) throws DatabaseException {
100 Resource element = resolveElement(graph, context);
101 Resource mappingType = resolveMappingType(graph, element);
102 return baseMappingModifier(graph, element, DistrictNetworkResource.getInstance(graph).HasMapping, mappingType, context);
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);
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);
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);
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 -> {
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);
132 } catch (DatabaseException e) {
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()));
145 Resource currentMapping = graph.getSingleObject(element, property);
147 return new HasMappingEnumerationModifier(Simantics.getSession(), element, property, enums, currentMapping);
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));
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));
164 return variable.getRepresents(graph);
167 private static EnumeratedValue<Resource> createEnumeratedValue(ReadGraph graph, Resource resource) {
169 String label = NameLabelUtil.modalName(graph, resource);
170 return new EnumeratedValue<Resource>(label, resource);
171 } catch (DatabaseException e) {
172 throw new RuntimeDatabaseException(e);
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();
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);
187 label = graph.getRelatedValue(resource, L0.HasName, Bindings.STRING);
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(), () -> {
197 queryInitialValuesAndCreateComposite(compositeType, target, defaultName, procedure);
198 } catch (Throwable t) {
199 procedure.exception(t);
202 procedure.execute(null);
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);
211 if (dialog.open() != Dialog.OK) {
212 procedure.execute(null);
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(),
224 }, new Procedure<Resource>() {
227 public void execute(Resource composite) {
228 DefaultActions.asyncPerformDefaultAction(Simantics.getSession(), composite, false, false, true);
229 procedure.execute(composite);
233 public void exception(Throwable t) {
234 LOGGER.error("Failed to create composite, see exception for details.", t);
235 procedure.exception(t);
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);
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);
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);
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);
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);
272 private static final Function1<Resource, Double> ONE = new FunctionImpl1<Resource, Double>() {
273 private final Double ONE = 1.0;
275 public Double apply(Resource edge) {
279 public String toString() {
284 @SCLValue(type = "ReadGraph -> Resource -> Variable -> b")
285 public static Function1<Resource, Double> constantOne(ReadGraph graph, Resource resource, Variable context) throws DatabaseException {
289 private static Function1<Resource, Double> directPropertyValueFunction(Resource property, double defaultValue) throws DatabaseException {
290 Double def = defaultValue;
291 return new FunctionImpl1<Resource, Double>() {
293 public Double apply(Resource edge) {
294 ReadGraph graph = (ReadGraph) SCLContext.getCurrent().get("graph");
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);
306 private static class RangeValidator implements Function1<String, String> {
309 public RangeValidator(double min, double max) {
314 public String apply(String s) {
316 double d = Double.parseDouble(s);
318 return "Value must be greater than or equal to " + min;
320 return "Value must be less than or equal to " + max;
322 } catch (NumberFormatException e) {
323 return "Specified value is not a number";
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);
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);
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);
343 Resource sclmain = Layer0Utils.getPossibleChild(graph, root, "SCLMain");
344 if (sclmain != null) {
345 importEntry = graph.getPossibleURI(sclmain);
348 SCLContext ctx = SCLContext.getCurrent();
349 Object oldGraph = ctx.put("graph", graph);
351 return new BrightnessExpressionValidator(
353 ? Arrays.asList(importEntry)
354 : Collections.emptyList());
356 ctx.put("graph", oldGraph);
360 private static class BrightnessExpressionValidator implements Function1<String, String> {
361 private CommandSession session;
363 public BrightnessExpressionValidator(List<String> importEntries) {
364 this.session = new CommandSession(SCLOsgi.MODULE_REPOSITORY, SCLReportingHandler.DEFAULT);
365 this.session.setImportEntries(imports(importEntries));
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"));
377 public String apply(String s) {
379 if (!s.startsWith("="))
380 return "Expression expected, must start with '='";
381 CompilationError[] errors = session.validate(s.substring(1));
382 if(errors.length == 0)
384 return errors[0].description;