X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.district.network%2Fsrc%2Forg%2Fsimantics%2Fdistrict%2Fnetwork%2Ftechtype%2FTechTypeUtils.java;h=377253dde3d108b433c572d6e0ddc576872b30ab;hb=62f9a86961adc4fd44782e3c2f79852b1269810d;hp=7a25ff84113586434703da818750dfb901271c18;hpb=8af3aedc6b9fc6ff41bb60884cfe667d5ebca164;p=simantics%2Fdistrict.git diff --git a/org.simantics.district.network/src/org/simantics/district/network/techtype/TechTypeUtils.java b/org.simantics.district.network/src/org/simantics/district/network/techtype/TechTypeUtils.java index 7a25ff84..377253dd 100644 --- a/org.simantics.district.network/src/org/simantics/district/network/techtype/TechTypeUtils.java +++ b/org.simantics.district.network/src/org/simantics/district/network/techtype/TechTypeUtils.java @@ -1,7 +1,14 @@ package org.simantics.district.network.techtype; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Collection; +import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import org.simantics.Simantics; import org.simantics.databoard.Bindings; @@ -20,11 +27,16 @@ import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.QueryIndexUtils; import org.simantics.db.layer0.request.PossibleVariable; +import org.simantics.db.layer0.request.PropertyInfo; +import org.simantics.db.layer0.request.PropertyInfoRequest; import org.simantics.db.layer0.variable.Variable; import org.simantics.district.network.ontology.DistrictNetworkResource; import org.simantics.district.network.techtype.requests.PossibleTechTypeItem; import org.simantics.district.network.techtype.requests.PossibleTechTypeTable; +import org.simantics.district.network.techtype.requests.TechTypeTableData; import org.simantics.district.network.techtype.requests.TechTypeTableKeyName; +import org.simantics.district.network.techtype.requests.WriteTechTypeTable; +import org.simantics.layer0.Layer0; import org.simantics.scl.runtime.SCLContext; import org.simantics.structural.stubs.StructuralResource2; import org.slf4j.Logger; @@ -36,6 +48,31 @@ public class TechTypeUtils { public static String DEFAULT_KEY_NAME = "pipeCode"; + /** + * Load a tech type table from a CSV file and write it in the active model. + * + * @param componentType The component type that the tech type table is associated with + * @param filePath A path to a CSV file + * @throws DatabaseException + * @throws IOException + */ + public static void loadTechTypeTable(Resource componentType, String filePath) throws DatabaseException, IOException { + String data; + try { + data = Files.lines(Paths.get(filePath), Charset.defaultCharset()).collect(Collectors.joining("\n")); + } catch (IOException e) { + LOGGER.error("Failed to read contents of file '{}' as {}", filePath, Charset.defaultCharset(), e); + return; + } + + Simantics.getSession().syncRequest(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + graph.syncRequest(new WriteTechTypeTable(componentType, data)); + } + }); + } + /** * Execute a cached query for a possible tech type table item in a table with a given item key. * @@ -93,6 +130,111 @@ public class TechTypeUtils { }); } + /** + * Reset all diagram elements to tech type table values. + * + * @param table A tech type table + * @throws DatabaseException + */ + public static void resetMapElements(Resource table) throws DatabaseException { + Simantics.getSession().syncRequest(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + Resource model = graph.syncRequest(new PossibleIndexRoot(table), TransientCacheListener.instance()); + if (model == null) + return; + + DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); + Resource type = graph.getPossibleObject(table, DN.TechType_TechTypeTable_HasComponentType); + if (type == null) + return; + + Layer0 L0 = Layer0.getInstance(graph); + String typeName = graph.getRelatedValue2(type, L0.HasName); + + Resource mapping = null; + for (Resource m : QueryIndexUtils.searchByType(graph, model, DN.Mapping_Base)) { + String name = graph.getRelatedValue2(m, DN.Mapping_ComponentType); + if (Objects.equals(name, typeName)) { + mapping = m; + break; + } + } + + if (mapping == null) { + LOGGER.warn("No mapping found for component type {}", type); + return; + } + + Map properties = new HashMap<>(); + Resource mappingType = graph.getSingleType(mapping, DN.Mapping_Base); + Collection mappingRelations = graph.getObjects(mappingType, L0.DomainOf); + for (Resource r : mappingRelations) { + String propertyName = graph.getPossibleRelatedValue2(mapping, r); + if (propertyName == null) + continue; + + Resource relation = graph.getPossibleObject(r, DN.Mapping_HasPropertyRelation); + if (relation == null) + continue; + + properties.put(propertyName, graph.syncRequest(new PropertyInfoRequest(relation))); + } + + Map> data = graph.syncRequest(new TechTypeTableData(table), TransientCacheListener.instance()); + String keyName = graph.syncRequest(new TechTypeTableKeyName(table), TransientCacheListener.instance()); + Resource keyRelation = properties.get(keyName).predicate; + + if (keyRelation == null) { + LOGGER.warn("No relation mapped to property {} found in {} mapping", keyName, mapping); + return; + } + + Resource elementType = graph.isInstanceOf(mapping, DN.Mapping_EdgeMapping) ? DN.Edge : + graph.isInstanceOf(mapping, DN.Mapping_VertexMapping) ? DN.Vertex : + DN.Element; + + Collection elements = QueryIndexUtils.searchByType(graph, model, elementType); + for (Resource element : elements) { + Resource elementMapping = graph.getPossibleObject(element, DN.HasMapping); + if (!mapping.equals(elementMapping)) + continue; + + String key = graph.getPossibleRelatedValue2(element, keyRelation); + Map values = data.get(key); + if (values == null) { + LOGGER.info("Key {} not found in tech type table {}", key, table); + continue; + } + + for (Map.Entry entry : values.entrySet()) { + PropertyInfo prop = properties.get(entry.getKey()); + if (prop == null) + continue; + + String value = entry.getValue(); + Datatype dt = prop.requiredDatatype; + if (dt instanceof NumberType) { + try { + Object num = ((NumberBinding)prop.defaultBinding).create(value.replace(",", ".")); + graph.claimLiteral(element, prop.predicate, prop.literalRange, num, prop.defaultBinding); + } catch (NumberFormatException e) { + // Revert to asserted value + graph.deny(element, prop.predicate); + } catch (BindingException e) { + LOGGER.error("Failed to get binding for datatype {}", dt, e); + } + } else if (dt instanceof StringType) { + graph.claimLiteral(element, prop.predicate, prop.literalRange, value, Bindings.STRING); + } else { + LOGGER.warn("updateComponent: Unsupported property type {}", dt); + } + } + } + } + }); + } + /** * Update property values of a component based on the values in an associated tech type table, if any * @@ -204,4 +346,46 @@ public class TechTypeUtils { if (name == null) name = "_" + DEFAULT_KEY_NAME; return name; } + + /** + * Compare strings so that contained numbers are sorted in numerical order instead of lexicographic. + * (From https://stackoverflow.com/questions/104599/sort-on-a-string-that-may-contain-a-number) + */ + public static final int compareNatural(String s1, String s2) { + // Skip all identical characters + int len1 = s1.length(); + int len2 = s2.length(); + int i; + char c1, c2; + for (i = 0, c1 = 0, c2 = 0; (i < len1) && (i < len2) && (c1 = s1.charAt(i)) == (c2 = s2.charAt(i)); i++) + ; + + // Check end of string + if (c1 == c2) + return (len1 - len2); + + // Check digit in first string + if (Character.isDigit(c1)) { + // Check digit only in first string + if (!Character.isDigit(c2)) + return (1); + + // Scan all integer digits + int x1, x2; + for (x1 = i + 1; (x1 < len1) && Character.isDigit(s1.charAt(x1)); x1++) + ; + for (x2 = i + 1; (x2 < len2) && Character.isDigit(s2.charAt(x2)); x2++) + ; + + // Longer integer wins, first digit otherwise + return (x2 == x1 ? c1 - c2 : x1 - x2); + } + + // Check digit only in second string + if (Character.isDigit(c2)) + return (-1); + + // No digits + return (c1 - c2); + } }