From c4446c36493a20b5aaf24031f70a76a3873ff9e5 Mon Sep 17 00:00:00 2001 From: Reino Ruusu Date: Fri, 4 Oct 2019 14:55:00 +0300 Subject: [PATCH] Change selection logic for n lowest/highest value queries gitlab #62 Change-Id: I2dce7f429c112fcf028edfebd110bd13a0f8ed26 (cherry picked from commit ae7a997a6776a0b3b6f94cc82b8cc93a6e82cc79) --- .../selection/ui/ElementSelectorTableUI.java | 37 +++--- .../district/selection/ElementSelector.java | 112 +++++++++++------- 2 files changed, 94 insertions(+), 55 deletions(-) diff --git a/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/ElementSelectorTableUI.java b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/ElementSelectorTableUI.java index 09f34609..001c8730 100644 --- a/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/ElementSelectorTableUI.java +++ b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/ElementSelectorTableUI.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.List; import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.DoubleClickEvent; @@ -21,6 +22,7 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Tree; import org.simantics.Simantics; import org.simantics.browsing.ui.common.AdaptableHintContext; @@ -39,9 +41,9 @@ import org.simantics.district.selection.ElementSelectionResource; import org.simantics.district.selection.ElementSelector; import org.simantics.district.selection.ElementSelector.DiagramGenerator; import org.simantics.district.selection.ElementSelector.ExplicitGenerator; +import org.simantics.district.selection.ElementSelector.PropertySelector; +import org.simantics.district.selection.ElementSelector.SelectionResult; import org.simantics.layer0.Layer0; -import org.simantics.scl.runtime.Lists; -import org.simantics.scl.runtime.function.FunctionImpl1; import org.simantics.ui.selection.AnyResource; import org.simantics.ui.selection.AnyVariable; import org.simantics.ui.selection.WorkbenchSelectionContentType; @@ -233,13 +235,13 @@ public class ElementSelectorTableUI extends Composite { TreeSelection selection = (TreeSelection) event.getViewer().getSelection(); ElementSelector query = (ElementSelector) selection.getFirstElement(); try { - List result = Simantics.getSession().syncRequest(new Read>() { + SelectionResult result = Simantics.getSession().syncRequest(new Read() { @Override - public List perform(ReadGraph graph) throws DatabaseException { + public SelectionResult perform(ReadGraph graph) throws DatabaseException { model = ActiveModels.getPossibleActiveModel(graph, Simantics.getProjectResource()); if (model == null) { LOGGER.warn("No active model"); - return Collections.emptyList(); + return new SelectionResult(Collections.emptyList(), 0, 0); } return query.selectElementsFrom(graph, model); @@ -247,17 +249,24 @@ public class ElementSelectorTableUI extends Composite { }); if (query.getGenerator() instanceof DiagramGenerator || query.getGenerator() instanceof ExplicitGenerator) { - DistrictNetworkUIUtil.openDNDiagramWithSelection(event.getViewer().getControl().getDisplay(), result); + DistrictNetworkUIUtil.openDNDiagramWithSelection(event.getViewer().getControl().getDisplay(), new ArrayList<>(result.elements)); } else { - selectionService.setPostSelection(new StructuredSelection(Lists.map(new FunctionImpl1() { - public AdaptableHintContext apply(Resource p0) { - AdaptableHintContext selectionElement = new SelectionElement(SelectionHints.STD_KEYS); - selectionElement.setHint(SelectionHints.KEY_MAIN, p0); - selectionElement.setHint(SelectionHints.KEY_MODEL, model); - return selectionElement; - } - }, result))); + selectionService.setPostSelection(new StructuredSelection(result.elements.stream() + .map(p0 -> { + AdaptableHintContext selectionElement = new SelectionElement(SelectionHints.STD_KEYS); + selectionElement.setHint(SelectionHints.KEY_MAIN, p0); + selectionElement.setHint(SelectionHints.KEY_MODEL, model); + return selectionElement; + }) + .toArray())); + } + + if (result.tailCount != result.tailSize) { + String name = query.getSelector() != null && query.getSelector() instanceof PropertySelector ? ((PropertySelector)query.getSelector()).propertyName : null; + String msg = "Last " + result.tailCount + " of the " + result.elements.size() + " selected elements are an arbitraty subset of " + result.tailSize + " elements with equal values" + + (name != null ? " for " + name : ""); + MessageDialog.openInformation(Display.getDefault().getActiveShell(), "Note", msg); } } catch (DatabaseException e) { LOGGER.error("Element selection query failed", e); 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 bf051b4c..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 @@ -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 selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException { + 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 { @@ -458,7 +457,7 @@ 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))); } @@ -473,17 +472,28 @@ public class ElementSelector { 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()); } } @@ -515,8 +525,20 @@ public class ElementSelector { // Selectors + 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 Collection select(ReadGraph graph, Collection elements); + abstract SelectionResult select(ReadGraph graph, Collection elements); } public static class All extends Selector { @@ -524,8 +546,8 @@ public class ElementSelector { } @Override - Collection select(ReadGraph graph, Collection elements) { - return elements; + SelectionResult select(ReadGraph graph, Collection elements) { + return new SelectionResult(elements, 0, 0); } } @@ -540,40 +562,48 @@ public class ElementSelector { public String propertyName; public int resultCount; - @SuppressWarnings("unchecked") @Override - Collection select(ReadGraph graph, Collection elements) { - List result2 = Lists.map(new FunctionImpl1() { - @Override - public Tuple2 apply(Resource r) { - return new Tuple2(r, getPropertyValue(graph, r, propertyName)); - } - }, new ArrayList<>(elements)); + 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()) { - 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) 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); + } + + // Map to list or resources + List selection = result2.stream().map(p -> p.first).collect(Collectors.toList()); + return new SelectionResult(selection, tailCount, tailSize); } } -- 2.45.1