package org.simantics.district.selection.ui.parts; 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.UUID; import java.util.function.Consumer; import javax.inject.Inject; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.layout.RowDataFactory; import org.eclipse.jface.layout.RowLayoutFactory; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.resource.ResourceLocator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Widget; import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.IndexRoot; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.RuntimeDatabaseException; import org.simantics.db.layer0.QueryIndexUtils; import org.simantics.db.layer0.request.ActiveModels; import org.simantics.db.layer0.request.PropertyInfo; import org.simantics.db.layer0.request.PropertyInfoRequest; import org.simantics.db.layer0.util.Layer0Utils; 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.route.ontology.RouteResource; import org.simantics.district.selection.ElementSelectionResource; import org.simantics.district.selection.ElementSelectionUtils; import org.simantics.district.selection.ElementSelector; import org.simantics.district.selection.ElementSelector.AggregateCondition; import org.simantics.district.selection.ElementSelector.AggregateCondition.Type; import org.simantics.district.selection.ElementSelector.All; import org.simantics.district.selection.ElementSelector.Condition; import org.simantics.district.selection.ElementSelector.DiagramGenerator; import org.simantics.district.selection.ElementSelector.ExplicitGenerator; import org.simantics.district.selection.ElementSelector.Generator; import org.simantics.district.selection.ElementSelector.ModelGenerator; import org.simantics.district.selection.ElementSelector.PropertyCondition; import org.simantics.district.selection.ElementSelector.PropertySelector; import org.simantics.district.selection.ElementSelector.RegionCondition; import org.simantics.district.selection.ElementSelector.RouteCondition; import org.simantics.district.selection.ElementSelector.Selector; import org.simantics.layer0.Layer0; import org.simantics.layer0.utils.direct.GraphUtils; import org.simantics.modeling.ModelingResources; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.utils.datastructures.Arrays; import org.simantics.utils.datastructures.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EditSelectorDialog extends Dialog { private static final RowLayoutFactory ROW_LAYOUT = RowLayoutFactory.fillDefaults().wrap(false); private static final ImageDescriptor CROSS_IMAGE = ResourceLocator.imageDescriptorFromBundle("com.famfamfam.silk", "icons/cross.png").get(); private static final ImageDescriptor PLUS_IMAGE = ResourceLocator.imageDescriptorFromBundle("com.famfamfam.silk", "icons/add.png").get(); private static Logger LOGGER = LoggerFactory.getLogger(EditSelectorDialog.class); private ElementSelector elementSelector; // Currently selected elements Collection currentSelection; // Data for comboboxes private List diagrams; private ArrayList diagramNames; private String[] regionNames; private Resource[] regionResources; private String[] routeNames; private Resource[] routeResources; private List componentTypes; private List componentTypeNames; private List propertyNames; private List propertyLabels; private Composite conditionPanel; // Dialog fields private int generatorIndex; private Combo sourceField; private String name; private Text nameField; private Resource diagram; private Combo diagramField; private int selectorIndex; private Combo selectorField; private Resource componentType; private Combo componentTypeField; private String propertyName; private Combo propertyField; private int numberOfItems; private Text nField; private Condition condition; // Dialog area component private Composite content; private int diagramIndex; private LocalResourceManager resourceManager; // Function type for updating condition objects with optional validation static interface Updater { // If 'validate' is true, a runtime exception may be thrown for invalid values void update(boolean validate); } final static Updater NULL_UPDATE = validate -> {}; // Called to read values from controls into conditions Updater updater = NULL_UPDATE; @Inject public EditSelectorDialog(Shell shell, ElementSelector elementSelector, Collection currentSelection) { super(shell); this.elementSelector = elementSelector; if (elementSelector != null) { try { Simantics.getSession().sync(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { elementSelector.buildSelection(graph); } }); } catch (DatabaseException e1) { LOGGER.error("Failed to read element selector resource " + elementSelector.getResource(), e1); throw new RuntimeDatabaseException(e1); } } this.currentSelection = currentSelection; Map diagramMap = ElementSelector.findDiagrams(); diagrams = new ArrayList(diagramMap.size()); diagramNames = new ArrayList(diagramMap.size()); diagramMap.entrySet() .stream() .sorted(Comparator.comparing(e -> e.getValue())) .forEachOrdered(e -> { diagrams.add(e.getKey()); diagramNames.add(e.getValue()); }); final Map regions = new HashMap<>(); final Map routes = new HashMap<>(); try { Simantics.getSession().syncRequest(new Read() { @Override public Void perform(ReadGraph graph) throws DatabaseException { Resource model = ActiveModels.getPossibleActiveModel(graph, Simantics.getProjectResource()); List regionCollection = QueryIndexUtils.searchByType(graph, model, DiagramRegionsResource.getInstance(graph).Region); for (Resource r : regionCollection) { String name = graph.getRelatedValue(r, Layer0.getInstance(graph).HasName); regions.put(r, name); } List routeCollection = QueryIndexUtils.searchByType(graph, model, RouteResource.getInstance(graph).Route); for (Resource r : routeCollection) { String name = graph.getRelatedValue(r, Layer0.getInstance(graph).HasName); routes.put(r, name); } return null; } }); } catch (DatabaseException e) { LOGGER.error("Failed to read routes and/or regions in the model", e); } regionNames = regions.values().toArray(new String[regions.size()]); regionResources = regions.keySet().toArray(new Resource[regions.size()]); routeNames = routes.values().toArray(new String[routes.size()]); routeResources = routes.keySet().toArray(new Resource[routes.size()]); try { Simantics.getSession().syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); List types = findComponentTypes(graph); componentTypes = new ArrayList<>(types.size() + 1); componentTypeNames = new ArrayList<>(types.size() + 1); componentTypes.add(null); componentTypeNames.add("Any type"); componentTypes.addAll(types); for (Resource t : types) { componentTypeNames.add(graph.getValue2(t, L0.HasName)); } } }); } catch (DatabaseException e) { LOGGER.error("Failed to read district component types", e); } componentType = elementSelector.getSelector().componentType; propertyNames = new ArrayList<>(); propertyLabels = new ArrayList<>(); try { updatePropertyList(); } catch (DatabaseException e) { LOGGER.error("Failed to read district component properties", e); } name = elementSelector != null ? elementSelector.getName() : ""; propertyName = ""; numberOfItems = 1; generatorIndex = 0; selectorIndex = 0; diagram = null; condition = null; if (elementSelector != null) { Generator generator = elementSelector.getGenerator(); if (generator instanceof ModelGenerator) { generatorIndex = 0; } else if (generator instanceof DiagramGenerator) { generatorIndex = 1; diagram = ((DiagramGenerator)generator).diagram; } else if (generator instanceof ExplicitGenerator) { generatorIndex = 2; } else { throw new IllegalStateException("Unknown generator type " + generator.getClass().getName()); } Selector selector = elementSelector.getSelector(); if (selector instanceof All) { selectorIndex = 0; } else if (selector instanceof PropertySelector) { PropertySelector propertySelector = (PropertySelector)selector; selectorIndex = propertySelector.smallest ? 1 : 2; propertyName = propertySelector.propertyName; numberOfItems = propertySelector.resultCount; } else { throw new IllegalStateException("Unknwon selector type " + selector.getClass().getName()); } condition = elementSelector.getCondition(); } } private void updateDialog() { updater.update(false); updater = updateConditionPanel(); content.layout(true, true); getShell().pack(); } @Override protected void okPressed() { generatorIndex = sourceField.getSelectionIndex(); if (generatorIndex == 1) { int selectionIndex = diagramField.getSelectionIndex(); if (selectionIndex < 0) { ErrorDialog.openError(getShell(), "Error", "Please select a diagram", new Status(IStatus.ERROR, "org.simantics.district.selection.ui", "No diagram selected")); return; } diagram = diagrams.get(selectionIndex); } name = nameField.getText(); componentType = componentTypes.get(componentTypeField.getSelectionIndex()); selectorIndex = selectorField.getSelectionIndex(); int propertyIndex = propertyField.getSelectionIndex(); propertyName = propertyIndex >= 0 ? propertyNames.get(propertyIndex) : propertyField.getText(); // Try to parse number of items if (useNumberOfItems()) { try { numberOfItems = Integer.parseInt(nField.getText()); } catch (RuntimeException e) { nField.selectAll(); nField.forceFocus(); return; } } // To to update condition definitions try { updater.update(true); } catch (RuntimeException e) { return; } super.okPressed(); } public void writeSelection() throws DatabaseException { Simantics.getSession().syncRequest(new WriteRequest() { @Override public void perform(WriteGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); ModelingResources MOD = ModelingResources.getInstance(graph); DiagramResource DIA = DiagramResource.getInstance(graph); graph.markUndoPoint(); Layer0Utils.addCommentMetadata(graph, "Created new element selection"); Resource lib = ElementSelectionUtils.ensureSelectionLibrary(graph); // Selection Resource selection; if (elementSelector != null) { selection = elementSelector.getResource(); graph.deny(selection); } else { selection = graph.newResource(); } graph.claim(selection, L0.InstanceOf, ES.Selection); graph.claimLiteral(selection, L0.HasName, L0.String, UUID.randomUUID().toString()); graph.claimLiteral(selection, L0.HasLabel, L0.String, name); graph.claim(selection, L0.PartOf, lib); // Generator Resource generator = graph.newResource(); Resource generatorType; switch (generatorIndex) { case 0: generatorType = ES.Generator_Model; break; case 1: generatorType = ES.Generator_Diagram; Resource composite = graph.getPossibleObject(diagram, MOD.DiagramToComposite); graph.claim(generator, ES.Generator_HasDiagram, composite != null ? composite : diagram); break; case 2: generatorType = ES.Generator_Explicit; for (Resource r : currentSelection) { // No connections if (graph.isInstanceOf(r, DIA.Connection)) continue; if (!graph.isInstanceOf(r, DIA.Element)) { if (!graph.hasStatement(r, MOD.ComponentToElement)) continue; r = graph.getPossibleObject(r, MOD.ComponentToElement); if (r == null) continue; } graph.claim(generator, ES.Generator_HasSelectedElement, r); } break; default: throw new IllegalStateException("Invalid source index " + generatorIndex); } graph.claim(generator, L0.InstanceOf, generatorType); graph.claim(selection, ES.Selection_HasGenerator, generator); // Selector Resource selector = graph.newResource(); Resource selectorType; switch (selectorIndex) { case 0: selectorType = ES.Selector_All; break; case 1: selectorType = ES.Selector_NLowest; break; case 2: selectorType = ES.Selector_NHighest; break; default: throw new IllegalStateException("Invalid selector index " + selectorIndex); } graph.claim(selector, L0.InstanceOf, selectorType); graph.claim(selection, ES.Selection_HasSelector, selector); graph.deny(selector, ES.Selector_HasMapping); if (componentType != null) graph.claim(selector, ES.Selector_HasMapping, componentType); if (selectorIndex > 0) { graph.claimLiteral(selector, ES.PropertySelector_HasSelectionPropertyName, L0.String, propertyName); graph.claimLiteral(selector, ES.PropertySelector_HasResultCount, L0.Integer, numberOfItems); } // Condition if (condition != null) { Resource conditionResource = condition.update(graph); graph.claim(selection, ES.Selection_HasCondition, conditionResource); } } }); } private boolean isDiagramFieldVisible() { return generatorIndex == 1; } private boolean useNumberOfItems() { return selectorIndex != 0; } @Override protected Control createDialogArea(Composite parent) { this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent); // Set dialog title getShell().setText("Edit element selector"); content = new Composite(parent, SWT.NONE); GridLayoutFactory.swtDefaults().numColumns(2).applyTo(content); // Name Label nameLabel = new Label(content, SWT.NONE); nameLabel.setText("Name"); GridDataFactory.swtDefaults().applyTo(nameLabel); nameField = new Text(content, SWT.BORDER); nameField.setEditable(true); nameField.setText(name); GridDataFactory.swtDefaults().hint(200, SWT.DEFAULT).applyTo(nameField); // Selector Label selectorLabel = new Label(content, SWT.NONE); selectorLabel.setText("Select"); GridDataFactory.swtDefaults().applyTo(selectorLabel); Composite selectorComposite = new Composite(content, SWT.NONE); GridDataFactory.swtDefaults().applyTo(selectorComposite); RowLayoutFactory.fillDefaults().applyTo(selectorComposite); nField = new Text(selectorComposite, SWT.BORDER); RowDataFactory.swtDefaults().hint(40, SWT.DEFAULT).applyTo(nField); if (useNumberOfItems()) nField.setText(Integer.toString(numberOfItems)); nField.setEnabled(useNumberOfItems()); componentTypeField = new Combo(selectorComposite, SWT.READ_ONLY); RowDataFactory.swtDefaults().applyTo(componentTypeField); componentTypeField.setItems(componentTypeNames.toArray(new String[] {})); { int index = componentTypes.indexOf(componentType); componentTypeField.select(index >= 0 ? index : 0); } new Label(selectorComposite, SWT.NONE).setText("with"); selectorField = new Combo(selectorComposite, SWT.BORDER | SWT.READ_ONLY); selectorField.setItems("All", "Lowest", "Highest"); selectorField.select(selectorIndex); RowDataFactory.swtDefaults().hint(40, SWT.DEFAULT).applyTo(selectorField); propertyField = new Combo(selectorComposite, SWT.NONE); RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(propertyField); propertyField.setItems(propertyLabels.toArray(new String[] {})); { int index = propertyName != null ? propertyNames.indexOf(propertyName) : -1; if (index >= 0) propertyField.select(index); else propertyField.setText(propertyName != null ? propertyName : ""); } propertyField.setEnabled(useNumberOfItems()); selectorField.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { selectorIndex = selectorField.getSelectionIndex(); boolean enable = useNumberOfItems(); nField.setEnabled(enable); propertyField.setEnabled(enable); nField.setText(enable ? Integer.toString(numberOfItems) : ""); } }); // Source Label sourceLabel = new Label(content, SWT.NONE); sourceLabel.setText("from"); GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.CENTER).applyTo(sourceLabel); Composite sourceComposite = new Composite(content, SWT.NONE); GridDataFactory.swtDefaults().applyTo(sourceComposite); RowLayoutFactory.fillDefaults().applyTo(sourceComposite); sourceField = new Combo(sourceComposite, SWT.BORDER | SWT.READ_ONLY); RowDataFactory.swtDefaults().applyTo(sourceField); sourceField.setItems("Whole model", "Diagram", "Current selection"); sourceField.select(generatorIndex); diagramField = new Combo(sourceComposite, SWT.BORDER | SWT.READ_ONLY); RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(diagramField); diagramField.setItems(diagramNames.toArray(new String[diagramNames.size()])); diagramField.setEnabled(isDiagramFieldVisible()); diagramIndex = diagram != null ? diagrams.indexOf(diagram) : -1; diagramField.select(diagramIndex); sourceField.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { generatorIndex = sourceField.getSelectionIndex(); boolean enabled = isDiagramFieldVisible(); if (!enabled) { diagramIndex = diagramField.getSelectionIndex(); diagramField.clearSelection(); } else { if (diagramIndex >= 0) diagramField.select(diagramIndex); else diagramField.clearSelection(); } diagramField.setEnabled(enabled); } }); sourceField.select(generatorIndex); // Condition Label label = new Label(content, SWT.NONE); GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.CENTER).applyTo(label); label.setText("where"); conditionPanel = new Composite(content, SWT.NONE); GridDataFactory.swtDefaults().span(1, 2).minSize(400, SWT.DEFAULT).grab(true, false).applyTo(conditionPanel); GridLayoutFactory.fillDefaults().numColumns(2).applyTo(conditionPanel); updater = updateConditionPanel(); return content; } private Updater updateConditionPanel() { // Erase contents for (Widget c : conditionPanel.getChildren()) c.dispose(); return createConditionPanelFor(conditionPanel, condition, cond -> condition = cond); } private Updater createConditionPanelFor(final Composite parent, final Condition condition, final Consumer consumer) { // Create new contents Button notCheck = new Button(parent, SWT.CHECK); GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.BEGINNING).applyTo(notCheck); notCheck.setText("not"); notCheck.setSelection(condition.isInverse); Composite conditionComp = new Composite(parent, SWT.NONE); GridDataFactory.fillDefaults().applyTo(conditionComp); Combo typeCombo = new Combo(conditionComp, SWT.BORDER | SWT.READ_ONLY); typeCombo.setItems( "No condition", "Property", "In region", "On route", "All of", "Any of" ); final Updater updater; if (condition instanceof PropertyCondition) { typeCombo.select(1); updater = createPropertyConditionPanel(conditionComp, (PropertyCondition)condition); } else if (condition instanceof RegionCondition) { typeCombo.select(2); updater = createRegionConditionPanel(conditionComp, (RegionCondition)condition); } else if (condition instanceof RouteCondition) { typeCombo.select(3); updater = createRouteConditionPanel(conditionComp, (RouteCondition)condition); } else if (condition instanceof AggregateCondition) { AggregateCondition cond = (AggregateCondition) condition; typeCombo.select(cond.type.equals(Type.CONJUNCTION) ? 4 : 5); updater = createAggregateConditionPanel(conditionComp, cond); } else { ROW_LAYOUT.applyTo(conditionComp); notCheck.setEnabled(false); typeCombo.select(0); updater = validate -> {}; } typeCombo.addSelectionListener(new ConditionTypeSelectionListener(typeCombo, consumer, condition)); return validate -> { updater.update(validate); condition.isInverse = notCheck.getSelection(); }; } private final class ConditionTypeSelectionListener extends SelectionAdapter { private final Combo typeCombo; private final Consumer consumer; private final Condition finalCondition; private ConditionTypeSelectionListener(Combo typeCombo, Consumer consumer, Condition finalCondition) { this.typeCombo = typeCombo; this.consumer = consumer; this.finalCondition = finalCondition; } @Override public void widgetSelected(SelectionEvent e) { int index = typeCombo.getSelectionIndex(); Condition newCondition = finalCondition; switch (index) { case 0: newCondition = null; break; case 1: newCondition = createPropertyCondition("", null, null); break; case 2: newCondition = createRegionCondition(null); break; case 3: newCondition = createRouteCondition(null); break; case 4: if (newCondition instanceof AggregateCondition) ((AggregateCondition)newCondition).type = Type.CONJUNCTION; else newCondition = createAggregateCondition(null, new ArrayList<>(), true, false); break; case 5: if (newCondition instanceof AggregateCondition) ((AggregateCondition)newCondition).type = Type.DISJUNCTION; else newCondition = createAggregateCondition(null, new ArrayList<>(), false, false); break; } consumer.accept(newCondition); updateDialog(); } } private Updater createAggregateConditionPanel(Composite conditionComp, AggregateCondition cond) { GridLayoutFactory.fillDefaults().numColumns(2).applyTo(conditionComp); new Label(conditionComp, SWT.NONE); // Eat extra column int n = cond.conditions.size(); final Updater[] updates = new Updater[n]; for (int i = 0; i < n; i++) { updates[i] = createConditionRowPanel(conditionComp, cond, i); } Button addButton = new Button(conditionComp, SWT.PUSH); GridDataFactory.swtDefaults().applyTo(addButton); addButton.setImage(resourceManager.createImage(PLUS_IMAGE)); addButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { cond.conditions.add(createPropertyCondition("property", null, null)); updateDialog(); } }); return validate -> { for (Updater updater : updates) updater.update(validate); }; } private Updater createConditionRowPanel(Composite parent, AggregateCondition parentCondition, final int i) { GridLayoutFactory conditionLayout = GridLayoutFactory.fillDefaults().numColumns(2); GridDataFactory swtDefaults = GridDataFactory.swtDefaults(); Condition c = parentCondition.conditions.get(i); Composite row = new Composite(parent, SWT.NONE); conditionLayout.applyTo(row); swtDefaults.applyTo(row); Consumer update = cd -> { if (cd != null) parentCondition.conditions.set(i, cd); else parentCondition.conditions.remove(i); }; Updater updater = createConditionPanelFor(row, c, update); Button removeButton = new Button(parent, SWT.PUSH); swtDefaults.align(SWT.BEGINNING, SWT.BEGINNING).applyTo(removeButton); removeButton.setImage(resourceManager.createImage(CROSS_IMAGE)); removeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { parentCondition.conditions.remove(i); updateDialog(); } }); return updater; } private Updater createRouteConditionPanel(Composite conditionComp, RouteCondition condition) { ROW_LAYOUT.applyTo(conditionComp); // Create combo-box Combo routeCombo = new Combo(conditionComp, SWT.READ_ONLY); RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(routeCombo); routeCombo.setItems(routeNames); // Set current selection int index = Arrays.indexOf(routeResources, condition.routeResource); if (index >= 0) routeCombo.select(index); // Register update return validate -> { int i = routeCombo.getSelectionIndex(); condition.routeResource = i >= 0 ? routeResources[i] : null; }; } private Updater createRegionConditionPanel(Composite conditionComp, RegionCondition condition) { ROW_LAYOUT.applyTo(conditionComp); // Create combo-box Combo regionCombo = new Combo(conditionComp, SWT.READ_ONLY); RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(regionCombo); regionCombo.setItems(regionNames); // Set current selection int index = Arrays.indexOf(regionResources, condition.regionResource); if (index >= 0) regionCombo.select(index); // Register update return validate -> { int i = regionCombo.getSelectionIndex(); condition.regionResource = i >= 0 ? regionResources[i] : null; }; } private Updater createPropertyConditionPanel(Composite conditionComp, PropertyCondition condition) { ROW_LAYOUT.applyTo(conditionComp); Text lowerLimitText = new Text(conditionComp, SWT.BORDER); RowDataFactory.swtDefaults().hint(40, SWT.DEFAULT).applyTo(lowerLimitText); lowerLimitText.setText(condition.lowerLimit != null ? Double.toString(condition.lowerLimit) : ""); new Label(conditionComp, SWT.NONE).setText("\u2264"); Combo propertyNameText = new Combo(conditionComp, SWT.NONE); RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(propertyNameText); propertyNameText.setItems(propertyLabels.toArray(new String[] {})); int index = propertyNames.indexOf(condition.propertyName); if (index >= 0) propertyNameText.select(index); else propertyNameText.setText(condition.propertyName); new Label(conditionComp, SWT.NONE).setText("\u2264"); Text upperLimitText = new Text(conditionComp, SWT.BORDER); RowDataFactory.swtDefaults().hint(40, SWT.DEFAULT).applyTo(upperLimitText); upperLimitText.setText(condition.upperLimit != null ? Double.toString(condition.upperLimit) : ""); // Register update return validate -> { try { String text = lowerLimitText.getText(); condition.lowerLimit = text.isEmpty() ? null : Double.parseDouble(text); } catch (NumberFormatException e) { if (validate) { lowerLimitText.selectAll(); lowerLimitText.forceFocus(); throw e; } } try { String text = upperLimitText.getText(); condition.upperLimit = text.isEmpty() ? null : Double.parseDouble(text); } catch (NumberFormatException e) { if (validate) { upperLimitText.selectAll(); upperLimitText.forceFocus(); throw e; } } int ind = propertyNameText.getSelectionIndex(); String name; if (ind >= 0) name = propertyNames.get(ind); else name = propertyNameText.getText(); if (validate && name.isEmpty()) { propertyNameText.forceFocus(); throw new RuntimeException(); } else { condition.propertyName = name; } }; } private static Condition createPropertyCondition(String propertyName, Double lowerLimit, Double upperLimit) { return new PropertyCondition(null, propertyName, lowerLimit, upperLimit); } private static Condition createRegionCondition(Resource regionResource) { return new RegionCondition(null, regionResource, null); } private static Condition createRouteCondition(Resource route) { return new RouteCondition(null, route, null); } private static Condition createAggregateCondition(Resource existingResource, List subConditions, boolean isConjunction, boolean isInverse) { Type type = isConjunction ? Type.CONJUNCTION : Type.DISJUNCTION; AggregateCondition condition = new AggregateCondition(null, type, subConditions); condition.isInverse = isInverse; return condition; } static List findComponentTypes(ReadGraph graph) throws DatabaseException { DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); Resource project = Simantics.getProjectResource(); Resource model = ActiveModels.getPossibleActiveModel(graph, project); return QueryIndexUtils.searchByType(graph, model, DN.Mapping_Base); } void updatePropertyList() throws DatabaseException { Collection types = componentType != null ? Collections.singleton(componentType) : componentTypes; Set> properties = new HashSet<>(); Simantics.getSession().syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); for (Resource type : types) { if (type == null) continue; Resource ct = graph.getPossibleObject(type, DistrictNetworkResource.getInstance(graph).Mapping_ComponentType); if (ct == null) continue; if (graph.isInstanceOf(ct, L0.String)) { Resource indexRoot = graph.syncRequest(new IndexRoot(type)); String name = graph.getValue(ct); ct = GraphUtils.getPossibleChild(graph, indexRoot, name); if (ct == null) continue; } for (Resource prop : graph.getObjects(ct, L0.DomainOf)) { if (!graph.isInstanceOf(prop, StructuralResource2.getInstance(graph).Property)) continue; // Filter only numeric properties PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(prop)); if (info != null && info.requiredValueType != null && !isNumericValueType(info.requiredValueType)) continue; String name = graph.getRelatedValue2(prop, L0.HasName); String label = graph.getPossibleRelatedValue2(prop, L0.HasLabel); if (label == null) label = name; properties.add(Pair.make(label, name)); } } } }); propertyNames.clear(); propertyLabels.clear(); properties.stream().sorted(Comparator.comparing(p -> p.first)).forEachOrdered(p -> { propertyLabels.add(p.first); propertyNames.add(p.second); }); } static boolean isNumericValueType(String requiredValueType) { switch (requiredValueType) { case "Integer": case "Long": case "Double": case "Float": return true; default: return false; } } }