]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java
Change selection logic for n lowest/highest value queries
[simantics/district.git] / org.simantics.district.selection / src / org / simantics / district / selection / ElementSelector.java
index bf051b4c9828e3f9d4d0b08a3e8409a3d4d3c091..f0cbf4b1af9d02bfe0bee56b9eea098561e499be 100644 (file)
@@ -4,11 +4,13 @@ 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;
@@ -32,10 +34,8 @@ 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;
 
@@ -234,13 +234,12 @@ public class ElementSelector {
                return null;
        }
 
-       public List<Resource> selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException {
+       public SelectionResult selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException {
                if (selector == null) {
                        buildSelection(graph);
                }
                
-               Collection<Resource> result = gather(graph, model);
-               return result instanceof List ? (List<Resource>) result : new ArrayList<>(result);
+               return gather(graph, model);
        }
 
        private static Generator buildGenerator(ReadGraph graph, Resource resource) throws DatabaseException {
@@ -458,7 +457,7 @@ public class ElementSelector {
                return result;
        }
        
-       private Collection<Resource> 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)));
        }
        
@@ -473,17 +472,28 @@ public class ElementSelector {
                Collection<Resource> generate(ReadGraph graph, Resource model) throws DatabaseException {
                        Resource conf = graph.syncRequest(new Configuration(model));
                        
-                       ArrayList<Resource> result = new ArrayList<>();
+                       HashMap<Resource, Resource> fromMapped = new HashMap<Resource, Resource>();
                        
                        // 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());
                }
        }
        
@@ -515,8 +525,20 @@ public class ElementSelector {
        
        // Selectors
        
+       public static class SelectionResult {
+               public final Collection<Resource> elements;
+               public final int tailCount;
+               public final int tailSize;
+               
+               public SelectionResult(Collection<Resource> elements, int tailCount, int tailSize) {
+                       this.elements = elements;
+                       this.tailCount = tailCount;
+                       this.tailSize = tailSize;
+               }
+       }
+
        public static abstract class Selector {
-               abstract Collection<Resource> select(ReadGraph graph, Collection<Resource> elements);
+               abstract SelectionResult select(ReadGraph graph, Collection<Resource> elements);
        }
        
        public static class All extends Selector {
@@ -524,8 +546,8 @@ public class ElementSelector {
                }
 
                @Override
-               Collection<Resource> select(ReadGraph graph, Collection<Resource> elements) {
-                       return elements;
+               SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
+                       return new SelectionResult(elements, 0, 0);
                }
        }
        
@@ -540,40 +562,48 @@ public class ElementSelector {
                public String propertyName;
                public int resultCount;
                
-               @SuppressWarnings("unchecked")
                @Override
-               Collection<Resource> select(ReadGraph graph, Collection<Resource> elements) {
-                       List<Tuple2> result2 = Lists.map(new FunctionImpl1<Resource, Tuple2>() {
-                               @Override
-                               public Tuple2 apply(Resource r) {
-                                       return new Tuple2(r, getPropertyValue(graph, r, propertyName));
-                               }
-                       }, new ArrayList<>(elements));
+               SelectionResult select(ReadGraph graph, Collection<Resource> elements) {
+                       // Select sorting direction
+                       Comparator<Pair<Resource, Double>> comparator = smallest ?
+                                       (p1, p2) -> Double.compare(p1.second, p2.second) :
+                                       (p1, p2) -> Double.compare(p1.second, p2.second);
                        
-                       result2 = Lists.filter(new FunctionImpl1<Tuple2, Boolean>() {
-                               @Override
-                               public Boolean apply(Tuple2 t) {
-                                       return t.c1 != null;
-                               }
-                       }, result2);
+                       // Get association list to property values
+                       List<Pair<Resource, Double>> 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()) {
-                               double limitValue = (double) result2.get(resultCount-1).c1;
-                               
-                               // Expand selection to contain all items with the same value as the nth one
-                               int count = resultCount;
-                               while (count < result2.size() && (double)result2.get(count).c1 == limitValue) count++;
-                               result2 = result2.subList(0, count);
+                       // 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;
                        }
                        
-                       return (List<Resource>) Lists.map(new FunctionImpl1<Tuple2, Resource>() {
-                               @Override
-                               public Resource apply(Tuple2 p0) {
-                                       return (Resource) p0.c0;
-                               }
-                       }, result2);
+                       // Take first n items
+                       if (count < result2.size()) {
+                               result2 = result2.subList(0, resultCount);
+                       }
+                       
+                       // Map to list or resources
+                       List<Resource> selection = result2.stream().map(p -> p.first).collect(Collectors.toList());
+                       return new SelectionResult(selection, tailCount, tailSize);
                }
        }