X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.district.selection%2Fsrc%2Forg%2Fsimantics%2Fdistrict%2Fselection%2FElementSelector.java;h=f0cbf4b1af9d02bfe0bee56b9eea098561e499be;hb=c4446c36493a20b5aaf24031f70a76a3873ff9e5;hp=7d429e4e04a5669667b11d35d678851f0af06874;hpb=c21f2dc656cbd621185a0bb88175db618d78eef9;p=simantics%2Fdistrict.git diff --git a/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java b/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java index 7d429e4e..f0cbf4b1 100644 --- a/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java +++ b/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java @@ -3,39 +3,46 @@ package org.simantics.district.selection; import java.awt.geom.Path2D; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.simantics.Simantics; import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; import org.simantics.db.common.request.ResourceRead; import org.simantics.db.common.utils.ListUtils; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.QueryIndexUtils; import org.simantics.db.layer0.request.ActiveModels; import org.simantics.db.layer0.request.ActiveRuns; import org.simantics.db.layer0.request.Configuration; +import org.simantics.db.layer0.request.PossibleActiveModel; import org.simantics.db.layer0.variable.RVI; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; +import org.simantics.db.request.Read; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.district.network.ontology.DistrictNetworkResource; import org.simantics.district.region.ontology.DiagramRegionsResource; import org.simantics.district.selection.ElementSelector.AggregateCondition.Type; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; -import org.simantics.scl.runtime.Lists; -import org.simantics.scl.runtime.function.FunctionImpl1; -import org.simantics.scl.runtime.tuple.Tuple2; import org.simantics.structural.stubs.StructuralResource2; +import org.simantics.utils.datastructures.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ElementSelector { String name; String expression; - Integer count; + Resource resource; Generator generator; @@ -51,6 +58,8 @@ public class ElementSelector { static DiagramResource DIA; static DistrictNetworkResource DN; + private static Logger LOGGER = LoggerFactory.getLogger(ElementSelector.class); + ElementSelector(ReadGraph graph, Resource resource) throws DatabaseException { super(); @@ -62,39 +71,175 @@ public class ElementSelector { DN = DistrictNetworkResource.getInstance(graph); this.resource = resource; - this.count = -1; try { this.name = graph.getRelatedValue(resource, L0.HasLabel); - this.expression = buildExpression(graph, resource); + this.expression = getExpression(graph, resource); } catch (DatabaseException e) { LOG.error("Error reading element selector", e); throw e; } } - public static ElementSelector getSelector(ReadGraph graph, Resource resource) throws DatabaseException { + /** + * Instantiate an element selector object for an ES.Selection resource. + */ + public static ElementSelector getSelector(RequestProcessor graph, Resource resource) throws DatabaseException { return graph.syncRequest(new ElementSelectorQuery(resource)); } + + /** + * Get an SQL-like textual description of an ES.Selection resource. + */ + public static String getExpression(RequestProcessor graph, Resource resource) throws DatabaseException { + return graph.syncRequest(new SelectionExpressionRequest(resource)); + } + + /** + * Get a Java object representation of an ES.Condition resource. + */ + public static Condition getCondition(RequestProcessor graph, Resource condition) throws DatabaseException { + return graph.syncRequest(new SelectionConditionRequest(condition)); + } + /** + * Get the name of the element selector. + */ public String getName() { return name; } + /** + * Get a textual SQL-like description of the element selector. + */ public String getExpression() { return expression; } + /** + * Get the resource that this selector represents. + */ public Resource getResource() { return resource; } - public List selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException { + /** + * Get the generator component. Use {@link #buildSelection(ReadGraph)} to make it available first. + */ + public Generator getGenerator() { + return generator; + } + + /** + * Get the selector component. Use {@link #buildSelection(ReadGraph)} to make it available first. + */ + public Selector getSelector() { + return selector; + } + + /** + * Get the condition component. Use {@link #buildSelection(ReadGraph)} to make it available first. + */ + public Condition getCondition() { + return condition; + } + + /** + * + * @param graph + * @throws DatabaseException + */ + public void buildSelection(ReadGraph graph) throws DatabaseException { + Resource selector = graph.getSingleObject(resource, ES.Selection_HasSelector); + Resource generator = graph.getSingleObject(resource, ES.Selection_HasGenerator); + Resource condition = graph.getPossibleObject(resource, ES.Selection_HasCondition); + + this.selector = buildSelector(graph, selector); + this.generator = buildGenerator(graph, generator); + this.condition = buildCondition(graph, condition); + } + + public static Map findDiagrams() { + try { + return Simantics.getSession().syncRequest(new Read>() { + @Override + public Map perform(ReadGraph graph) throws DatabaseException { + Map result = new HashMap<>(); + Resource model = graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource())); + List composites = QueryIndexUtils.searchByType(graph, model, StructuralResource2.getInstance(graph).Composite); + for (Resource r : composites) { + // Get diagram + Resource diagram = graph.getPossibleObject(r, ModelingResources.getInstance(graph).CompositeToDiagram); + if (diagram == null) continue; + + // Filter out user component diagrams + Resource parent = graph.getPossibleObject(r, Layer0.getInstance(graph).PartOf); + if (parent == null || graph.isInheritedFrom(parent, StructuralResource2.getInstance(graph).Component)) + continue; + + result.put(r, graph.getRelatedValue(r, Layer0.getInstance(graph).HasName)); + } + + return result; + } + }); + } catch (DatabaseException e) { + LOGGER.error("Query for model diagrams failed", e); + return Collections.emptyMap(); + } + } + + public static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException { + Resource component = graph.getPossibleObject(element, MOD.ElementToComponent); + if (component != null) { + Variable var = Variables.getVariable(graph, component); + RVI realRvi = var.getRVI(graph); + + for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) { + for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) { + Variable v = realRvi.resolvePossible(graph, run); + if (v != null) { + return v; + } + } + Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel); + if (configuration != null) { + Variable v = realRvi.resolvePossible(graph, configuration); + if (v != null) { + return v; + } + } + } + } + + return null; + } + + public static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) { + try { + Variable v = getVariableForElement(graph, element); + if (v != null) { + Number value = v.getPossiblePropertyValue(graph, propertyName); + if (value != null) + return value.doubleValue(); + } + + // No property found - try possible mapped element property as well + Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent); + if (mappedElement != null) + return getPropertyValue(graph, mappedElement, propertyName); + } + catch (DatabaseException e) { + } + + return null; + } + + public SelectionResult selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException { if (selector == null) { buildSelection(graph); } - Collection result = gather(graph, model); - return result instanceof List ? (List) result : new ArrayList<>(result); + return gather(graph, model); } private static Generator buildGenerator(ReadGraph graph, Resource resource) throws DatabaseException { @@ -147,19 +292,20 @@ public class ElementSelector { String propertyName = graph.getRelatedValue(resource, ES.PropertyCondition_HasPropertyName); Double lowerLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasLowerLimit); Double upperLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasUpperLimit); - cond = new PropertyCondition(propertyName, lowerLimit, upperLimit); + cond = new PropertyCondition(resource, propertyName, lowerLimit, upperLimit); } else if (graph.isInstanceOf(resource, ES.RegionCondition)) { DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph); - double[] region = graph.getRelatedValue(graph.getSingleObject(resource, ES.RegionCondition_HasRegion), DR.Region_area); - cond = new RegionCondition(region); + Resource regionResource = graph.getSingleObject(resource, ES.RegionCondition_HasRegion); + double[] region = graph.getRelatedValue(regionResource, DR.Region_area); + cond = new RegionCondition(resource, regionResource, region); } else if (graph.isInstanceOf(resource, ES.RouteCondition)) { - Set routePoints = new HashSet<>(ListUtils.toList(graph, graph.getSingleObject(resource, ES.RouteCondition_HasRoute))); - cond = new RouteCondition(routePoints); + Resource routeResource = graph.getSingleObject(resource, ES.RouteCondition_HasRoute); + Set routePoints = new HashSet<>(ListUtils.toList(graph, routeResource)); + cond = new RouteCondition(resource, routeResource, routePoints); } else if (graph.isInstanceOf(resource, ES.AggregateCondition)) { - boolean isDisjunction = graph.isInstanceOf(resource, ES.Disjunction); Collection conditionResources = graph.getObjects(resource, ES.HasSubcondition); List conditions = new ArrayList<>(conditionResources.size()); for (Resource c : conditionResources) { @@ -175,23 +321,22 @@ public class ElementSelector { else throw new IllegalArgumentException("Unknown aggreate condition type " + graph.getURI(graph.getSingleType(resource))); - cond = new AggregateCondition(type, conditions); + cond = new AggregateCondition(resource, type, conditions); } else { throw new IllegalArgumentException("Unknown condition type " + graph.getURI(graph.getSingleType(resource))); } - cond.isInverse = graph.hasStatement(resource, ES.Condition_IsInverse, resource); return cond; } private static String buildExpression(ReadGraph graph, Resource r) throws DatabaseException { if (graph.isInstanceOf(r, ES.Selection)) { - String exp = "select " + buildExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) + - " from " + buildExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator)); + String exp = "select " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) + + " from " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator)); Resource cond = graph.getPossibleObject(r, ES.Selection_HasCondition); - return cond != null ? exp + " where {" + buildExpression(graph, cond) + "}" : exp; + return cond != null ? exp + " where {" + getExpression(graph, cond) + "}" : exp; } else if (graph.isInstanceOf(r, ES.Condition)) { if (graph.isInstanceOf(r, ES.PropertyCondition)) { @@ -212,7 +357,7 @@ public class ElementSelector { List exps = new ArrayList<>(); Collection objects = graph.getObjects(r, ES.HasSubcondition); for (Resource c : objects) { - String exp = buildExpression(graph, c); + String exp = getExpression(graph, c); exps.add(objects.size() > 1 ? "{" + exp + "}" : exp); } String result = String.join(op, exps); @@ -300,16 +445,6 @@ public class ElementSelector { return result; } - private void buildSelection(ReadGraph graph) throws DatabaseException { - Resource selector = graph.getSingleObject(resource, ES.Selection_HasSelector); - Resource generator = graph.getSingleObject(resource, ES.Selection_HasGenerator); - Resource condition = graph.getPossibleObject(resource, ES.Selection_HasCondition); - - this.selector = buildSelector(graph, selector); - this.generator = buildGenerator(graph, generator); - this.condition = buildCondition(graph, condition); - } - private Collection filterElementsFrom(ReadGraph graph, Collection elements) throws DatabaseException { if (condition == null) return elements; @@ -322,83 +457,48 @@ public class ElementSelector { return result; } - private Collection gather(ReadGraph graph, Resource model) throws DatabaseException { + private SelectionResult gather(ReadGraph graph, Resource model) throws DatabaseException { return selector.select(graph, filterElementsFrom(graph, generator.generate(graph, model))); } - static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException { - Resource component = graph.getPossibleObject(element, MOD.ElementToComponent); - if (component != null) { - Variable var = Variables.getVariable(graph, component); - RVI realRvi = var.getRVI(graph); - - for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) { - for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) { - Variable v = realRvi.resolvePossible(graph, run); - if (v != null) { - return v; - } - } - Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel); - if (configuration != null) { - Variable v = realRvi.resolvePossible(graph, configuration); - if (v != null) { - return v; - } - } - } - } - - return null; - } - - static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) { - try { - Variable v = getVariableForElement(graph, element); - if (v != null) { - Number value = v.getPossiblePropertyValue(graph, propertyName); - if (value != null) - return value.doubleValue(); - } - - // No property found - try possible mapped element property as well - Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent); - if (mappedElement != null) - return getPropertyValue(graph, mappedElement, propertyName); - } - catch (DatabaseException e) { - } - - return null; - } - // Generators - static abstract class Generator { + public static abstract class Generator { abstract Collection generate(ReadGraph graph, Resource model) throws DatabaseException; } - static class ModelGenerator extends Generator { + public static class ModelGenerator extends Generator { @Override Collection generate(ReadGraph graph, Resource model) throws DatabaseException { Resource conf = graph.syncRequest(new Configuration(model)); - ArrayList result = new ArrayList<>(); + HashMap fromMapped = new HashMap(); // Iterate over diagrams + // Each model element is represented by the corresponding mapping element, if present for (Resource comp : graph.getObjects(conf, L0.ConsistsOf)) { if (!graph.isInstanceOf(comp, STR.Composite)) continue; Resource diagram = graph.getPossibleObject(comp, MOD.CompositeToDiagram); - if (diagram != null) result.addAll(elementsOfDiagram(graph, diagram)); + if (diagram != null) { + for (Resource elem : elementsOfDiagram(graph, diagram)) { + Resource mapped = graph.getPossibleObject(elem, DN.MappedComponent); + if (mapped != null) { + fromMapped.put(mapped, elem); + } + else if (!fromMapped.containsKey(elem)) { + fromMapped.put(elem, elem); + } + } + } } - return result; + return new ArrayList<>(fromMapped.values()); } } - static class DiagramGenerator extends Generator { - Resource diagram; + public static class DiagramGenerator extends Generator { + public Resource diagram; public DiagramGenerator(Resource diagram) { this.diagram = diagram; @@ -410,12 +510,12 @@ public class ElementSelector { } } - static class ExplicitGenerator extends Generator { + public static class ExplicitGenerator extends Generator { public ExplicitGenerator(Collection elements) { this.elements = elements; } - Collection elements; + public Collection elements; @Override Collection generate(ReadGraph graph, Resource model) { @@ -425,83 +525,112 @@ public class ElementSelector { // Selectors - static abstract class Selector { - abstract Collection select(ReadGraph graph, Collection elements); + public static class SelectionResult { + public final Collection elements; + public final int tailCount; + public final int tailSize; + + public SelectionResult(Collection elements, int tailCount, int tailSize) { + this.elements = elements; + this.tailCount = tailCount; + this.tailSize = tailSize; + } + } + + public static abstract class Selector { + abstract SelectionResult select(ReadGraph graph, Collection elements); } - static class All extends Selector { + public static class All extends Selector { public All() { } @Override - Collection select(ReadGraph graph, Collection elements) { - return elements; + SelectionResult select(ReadGraph graph, Collection elements) { + return new SelectionResult(elements, 0, 0); } } - static class PropertySelector extends Selector { + public static class PropertySelector extends Selector { public PropertySelector(boolean smallest, String propertyName, int resultCount) { this.smallest = smallest; this.propertyName = propertyName; this.resultCount = resultCount; } - boolean smallest; - String propertyName; - int resultCount; + public boolean smallest; + public String propertyName; + public int resultCount; - @SuppressWarnings("unchecked") @Override - Collection select(ReadGraph graph, Collection elements) { - List result = new ArrayList<>(elements); - List result2 = Lists.map(new FunctionImpl1() { - @Override - public Tuple2 apply(Resource r) { - return new Tuple2(r, getPropertyValue(graph, r, propertyName)); - } - }, result); + SelectionResult select(ReadGraph graph, Collection elements) { + // Select sorting direction + Comparator> comparator = smallest ? + (p1, p2) -> Double.compare(p1.second, p2.second) : + (p1, p2) -> Double.compare(p1.second, p2.second); - result2 = Lists.filter(new FunctionImpl1() { - @Override - public Boolean apply(Tuple2 t) { - return t.c1 != null; - } - }, result2); + // Get association list to property values + List> result2 = elements.stream() + .map(r -> Pair.make(r, getPropertyValue(graph, r, propertyName))) + .filter(t -> t.second != null) + .sorted(comparator) + .collect(Collectors.toList()); + int count = Math.min(resultCount, result2.size()); - result2.sort((t1, t2) -> smallest ? Double.compare((Double) t1.c1, (Double) t2.c1) : Double.compare((Double) t2.c1, (Double) t1.c1)); + // Count number of equal values at the end of the list + int tailCount = 0; + double tailValue = count > 0 ? result2.get(count-1).second : 0.0; + for (int i = count-1; i >= 0; i--) { + if (result2.get(i).second == tailValue) + tailCount++; + else + break; + } - if (resultCount < result2.size()) - result2 = result2.subList(0, resultCount); + // Count number of elements with value equal to the end of the list + int tailSize = tailCount; + for (int i = count; i < result2.size(); i++) { + if (result2.get(i).second == tailValue) + tailSize++; + else + break; + } - result = Lists.map(new FunctionImpl1() { - @Override - public Resource apply(Tuple2 p0) { - return (Resource) p0.c0; - } - }, result2); + // Take first n items + if (count < result2.size()) { + result2 = result2.subList(0, resultCount); + } - return result; + // Map to list or resources + List selection = result2.stream().map(p -> p.first).collect(Collectors.toList()); + return new SelectionResult(selection, tailCount, tailSize); } } // Conditions - static abstract class Condition { - boolean isInverse; + public static abstract class Condition { + public Resource resource; + + Condition(Resource r) { + resource = r; + } + abstract boolean match(ReadGraph graph, Resource r) throws DatabaseException; } - static class PropertyCondition extends Condition { - public PropertyCondition(String propertyName, Double lowerLimit, Double upperLimit) { - super(); + public static class PropertyCondition extends Condition { + public PropertyCondition(Resource r, String propertyName, Double lowerLimit, Double upperLimit) { + super(r); + this.propertyName = propertyName; this.lowerLimit = lowerLimit; this.upperLimit = upperLimit; } - String propertyName; - Double lowerLimit; - Double upperLimit; + public String propertyName; + public Double lowerLimit; + public Double upperLimit; @Override boolean match(ReadGraph graph, Resource r) { @@ -510,9 +639,9 @@ public class ElementSelector { } } - static class RegionCondition extends Condition { - public RegionCondition(double[] region) { - super(); + public static class RegionCondition extends Condition { + public RegionCondition(Resource r, Resource regionResoruce, double[] region) { + super(r); this.region = region; Path2D path = new Path2D.Double(); @@ -524,8 +653,10 @@ public class ElementSelector { path.closePath(); this.path = path; + this.regionResource = regionResoruce; } + public Resource regionResource; double[] region; Path2D path; @@ -538,12 +669,14 @@ public class ElementSelector { } } - static class RouteCondition extends Condition { - public RouteCondition(Set routePoints) { - super(); + public static class RouteCondition extends Condition { + public RouteCondition(Resource r, Resource routeResource, Set routePoints) { + super(r); this.routePoints = routePoints; + this.routeResource = routeResource; } + public Resource routeResource; Set routePoints; @Override @@ -552,31 +685,17 @@ public class ElementSelector { } } - static class DiagramCondition extends Condition { - public DiagramCondition(Resource diagram) { - super(); - this.diagram = diagram; - } - - Resource diagram; - - @Override - boolean match(ReadGraph graph, Resource r) throws DatabaseException { - return graph.getSingleObject(r, L0.PartOf).equals(diagram); - } - } - - static class AggregateCondition extends Condition { - static enum Type { DISJUNCTION, CONJUNCTION, NEGATION }; + public static class AggregateCondition extends Condition { + public static enum Type { DISJUNCTION, CONJUNCTION, NEGATION }; - public AggregateCondition(Type type, List conditions) { - super(); + public AggregateCondition(Resource r, Type type, List conditions) { + super(r); this.type = type; this.conditions = conditions; } - Type type; - List conditions; + public Type type; + public List conditions; @Override boolean match(ReadGraph graph, Resource r) throws DatabaseException { @@ -610,4 +729,26 @@ public class ElementSelector { return new ElementSelector(graph, resource); } } + + public final static class SelectionExpressionRequest extends ResourceRead { + public SelectionExpressionRequest(Resource condition) { + super(condition); + } + + @Override + public String perform(ReadGraph graph) throws DatabaseException { + return ElementSelector.buildExpression(graph, resource); + } + } + + public static final class SelectionConditionRequest extends ResourceRead { + public SelectionConditionRequest(Resource resource) { + super(resource); + } + + @Override + public Condition perform(ReadGraph graph) throws DatabaseException { + return buildCondition(graph, resource); + } + } }