]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/parts/EditSelectorDialog.java
Manage drop-down menu contents by context in district finder dialog
[simantics/district.git] / org.simantics.district.selection.ui / src / org / simantics / district / selection / ui / parts / EditSelectorDialog.java
index 4814124b010954cffb030c3aa39aeb3f81b31b43..b708d8e978695dc18919f05a80a824409d2b1564 100644 (file)
@@ -14,10 +14,8 @@ 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.dialogs.MessageDialog;
 import org.eclipse.jface.layout.GridDataFactory;
 import org.eclipse.jface.layout.GridLayoutFactory;
 import org.eclipse.jface.layout.RowDataFactory;
@@ -51,7 +49,6 @@ 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;
@@ -143,10 +140,18 @@ public class EditSelectorDialog extends Dialog {
 
        private LocalResourceManager resourceManager;
        
+       static class ValidationException extends Exception {
+               private static final long serialVersionUID = 1L;
+
+               public ValidationException(String message) {
+                       super(message);
+               }
+       }
+       
        // 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);
+               void update(boolean validate) throws ValidationException;
        }
        
        final static Updater NULL_UPDATE = validate -> {};
@@ -186,71 +191,6 @@ public class EditSelectorDialog extends Dialog {
                                diagramNames.add(e.getValue());
                        });
                
-               final Map<Resource, String> regions = new HashMap<>();
-               final Map<Resource, String> routes = new HashMap<>();
-               
-               try {
-                       Simantics.getSession().syncRequest(new Read<Void>() {
-                               @Override
-                               public Void perform(ReadGraph graph) throws DatabaseException {
-                                       Resource model = ActiveModels.getPossibleActiveModel(graph, Simantics.getProjectResource());
-                                       List<Resource> 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<Resource> 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<Resource> 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;
@@ -290,11 +230,107 @@ public class EditSelectorDialog extends Dialog {
                        }
                        
                        condition = elementSelector.getCondition();
+                       
+                       componentType = elementSelector.getSelector().componentType;
                }
+               
+               readRegions(diagram);
+               readRoutes();
+               readComponentTypes();
+               updatePropertyList();
+       }
+
+       private void readComponentTypes() {
+               try {
+                       Simantics.getSession().syncRequest(new ReadRequest() {
+                               @Override
+                               public void run(ReadGraph graph) throws DatabaseException {
+                                       Layer0 L0 = Layer0.getInstance(graph);
+                                       List<Resource> 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);
+               }
+       }
+
+       private void readRoutes() {
+               final Map<Resource, String> routes = new HashMap<>();
+               
+               try {
+                       Simantics.getSession().syncRequest(new ReadRequest() {
+                               @Override
+                               public void run(ReadGraph graph) throws DatabaseException {
+                                       Layer0 L0 = Layer0.getInstance(graph);
+                                       RouteResource ROUTE = RouteResource.getInstance(graph);
+                                       
+                                       Resource model = ActiveModels.getPossibleActiveModel(graph, Simantics.getProjectResource());
+                                       List<Resource> routeCollection = QueryIndexUtils.searchByType(graph, model, ROUTE.Route);
+                                       for (Resource r : routeCollection) {
+                                               String name = graph.getRelatedValue(r, L0.HasLabel);
+                                               routes.put(r, name);
+                                       }
+                               }
+                       });
+               } catch (DatabaseException e) {
+                       LOGGER.error("Failed to read routes in the model", e);
+               }
+               
+               routeNames = routes.values().toArray(new String[routes.size()]);
+               routeResources = routes.keySet().toArray(new Resource[routes.size()]);
+       }
+
+       private void readRegions(Resource diagram) {
+               final Map<Resource, String> regions = new HashMap<>();
+               
+               try {
+                       Simantics.getSession().syncRequest(new ReadRequest() {
+                               @Override
+                               public void run(ReadGraph graph) throws DatabaseException {
+                                       Layer0 L0 = Layer0.getInstance(graph);
+                                       ModelingResources MOD = ModelingResources.getInstance(graph);
+                                       DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph);
+                                       
+                                       // If a specific diagram is given, use that
+                                       Collection<Resource> ds = diagram != null ? Collections.singleton(diagram) : diagrams;
+                                       
+                                       for (Resource composite : ds) {
+                                               Resource diagram = graph.getSingleObject(composite, MOD.CompositeToDiagram);
+                                               for (Resource r : graph.getObjects(diagram, DR.hasRegion)) {
+                                                       if (!graph.isInstanceOf(r, DR.Region))
+                                                               continue;
+                                                       String name = graph.getRelatedValue(r, L0.HasLabel);
+                                                       regions.put(r, name);
+                                               }
+                                       }
+                               }
+                       });
+               } catch (DatabaseException e) {
+                       LOGGER.error("Failed to read regions in the model", e);
+               }
+               
+               regionNames = regions.values().toArray(new String[regions.size()]);
+               regionResources = regions.keySet().toArray(new Resource[regions.size()]);
        }
        
        private void updateDialog() {
-               updater.update(false);
+               try {
+                       updater.update(false);
+               } catch (ValidationException e) {
+                       // Should not happend with argument false
+                       assert(false);
+               }
+               
                updater = updateConditionPanel();
                
                content.layout(true, true);
@@ -303,38 +339,53 @@ public class EditSelectorDialog extends Dialog {
 
        @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;
+               try {
+                       generatorIndex = sourceField.getSelectionIndex();
+                       if (generatorIndex == 1) {
+                               int selectionIndex = diagramField.getSelectionIndex();
+                               if (selectionIndex < 0) {
+                                       diagramField.setFocus();
+                                       throw new ValidationException("Please select a diagram");
+                               }
+                               
+                               diagram = diagrams.get(selectionIndex);
                        }
                        
-                       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;
+                       name = nameField.getText();
+                       if (name.isEmpty()) {
+                               nameField.setFocus();
+                               throw new ValidationException("Please enter a name");
                        }
-               }
-
-               // To to update condition definitions
-               try {
+                       
+                       componentType = componentTypes.get(componentTypeField.getSelectionIndex());
+                       selectorIndex = selectorField.getSelectionIndex();
+                       int propertyIndex = propertyField.getSelectionIndex();
+                       propertyName = propertyIndex >= 0 ? propertyNames.get(propertyIndex) : propertyField.getText();
+                       if (propertyName.isEmpty()) {
+                               propertyField.setFocus();
+                               throw new ValidationException("Please select a property");
+                       }
+                       
+                       // Try to parse number of items
+                       if (useNumberOfItems()) {
+                               try {
+                                       numberOfItems = Integer.parseInt(nField.getText());
+                                       if (numberOfItems <= 0) {
+                                               nField.selectAll();
+                                               nField.setFocus();
+                                               throw new ValidationException("Number of elements must be positive");
+                                       }
+                               } catch (NumberFormatException e) {
+                                       nField.selectAll();
+                                       nField.setFocus();
+                                       throw new ValidationException("Please enter a valid number of elements");
+                               }
+                       }
+       
+                       // To to update condition definitions
                        updater.update(true);
-               } catch (RuntimeException e) {
+               } catch (ValidationException e) {
+                       MessageDialog.openError(this.getShell(), "Missing data", e.getMessage());
                        return;
                }
                
@@ -469,7 +520,7 @@ public class EditSelectorDialog extends Dialog {
 
                Composite selectorComposite = new Composite(content, SWT.NONE);
                GridDataFactory.swtDefaults().applyTo(selectorComposite);
-               RowLayoutFactory.swtDefaults().applyTo(selectorComposite);
+               RowLayoutFactory.fillDefaults().applyTo(selectorComposite);
                
                nField = new Text(selectorComposite, SWT.BORDER);
                RowDataFactory.swtDefaults().hint(40, SWT.DEFAULT).applyTo(nField);
@@ -485,6 +536,19 @@ public class EditSelectorDialog extends Dialog {
                        componentTypeField.select(index >= 0 ? index : 0);
                }
                
+               // Update property selection controls when component type changes
+               componentTypeField.addSelectionListener(new SelectionAdapter() {
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               int index = componentTypeField.getSelectionIndex();
+                               componentType = index >= 0 ? componentTypes.get(index) : null;
+                               updatePropertyList();
+                               propertyField.setItems(propertyLabels.toArray(new String[] {}));
+                               
+                               updateDialog();
+                       }
+               });
+               
                new Label(selectorComposite, SWT.NONE).setText("with");
                
                selectorField = new Combo(selectorComposite, SWT.BORDER | SWT.READ_ONLY);
@@ -493,7 +557,7 @@ public class EditSelectorDialog extends Dialog {
                RowDataFactory.swtDefaults().hint(40, SWT.DEFAULT).applyTo(selectorField);
                
                propertyField = new Combo(selectorComposite, SWT.NONE);
-               RowDataFactory.swtDefaults().hint(80, SWT.DEFAULT).applyTo(propertyField);
+               RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(propertyField);
                propertyField.setItems(propertyLabels.toArray(new String[] {}));
                {
                        int index = propertyName != null ? propertyNames.indexOf(propertyName) : -1;
@@ -524,7 +588,7 @@ public class EditSelectorDialog extends Dialog {
                
                Composite sourceComposite = new Composite(content, SWT.NONE);
                GridDataFactory.swtDefaults().applyTo(sourceComposite);
-               RowLayoutFactory.swtDefaults().applyTo(sourceComposite);
+               RowLayoutFactory.fillDefaults().applyTo(sourceComposite);
                
                sourceField = new Combo(sourceComposite, SWT.BORDER | SWT.READ_ONLY);
                RowDataFactory.swtDefaults().applyTo(sourceField);
@@ -532,7 +596,7 @@ public class EditSelectorDialog extends Dialog {
                sourceField.select(generatorIndex);
                
                diagramField = new Combo(sourceComposite, SWT.BORDER | SWT.READ_ONLY);
-               RowDataFactory.swtDefaults().applyTo(diagramField);
+               RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(diagramField);
                diagramField.setItems(diagramNames.toArray(new String[diagramNames.size()]));
                diagramField.setEnabled(isDiagramFieldVisible());
                
@@ -554,6 +618,11 @@ public class EditSelectorDialog extends Dialog {
                                                diagramField.clearSelection();
                                }
                                diagramField.setEnabled(enabled);
+
+                               // Refresh list of regions for current diagram
+                               diagram = enabled ? (diagramIndex >= 0 ? diagrams.get(diagramIndex) : null) : null;
+                               readRegions(diagram);
+                               updateDialog();
                        }
                });
                
@@ -586,7 +655,7 @@ public class EditSelectorDialog extends Dialog {
                Button notCheck = new Button(parent, SWT.CHECK);
                GridDataFactory.swtDefaults().align(SWT.BEGINNING, SWT.BEGINNING).applyTo(notCheck);
                notCheck.setText("not");
-               notCheck.setSelection(condition.isInverse);
+               notCheck.setSelection(condition != null && condition.isInverse);
                
                Composite conditionComp = new Composite(parent, SWT.NONE);
                GridDataFactory.fillDefaults().applyTo(conditionComp);
@@ -601,6 +670,8 @@ public class EditSelectorDialog extends Dialog {
                                "Any of"
                        );
                
+               typeCombo.addSelectionListener(new ConditionTypeSelectionListener(typeCombo, consumer, condition));
+
                final Updater updater;
                if (condition instanceof PropertyCondition) {
                        typeCombo.select(1);
@@ -619,11 +690,9 @@ public class EditSelectorDialog extends Dialog {
                        ROW_LAYOUT.applyTo(conditionComp);
                        notCheck.setEnabled(false);
                        typeCombo.select(0);
-                       updater = validate -> {};
+                       return NULL_UPDATE;
                }
                
-               typeCombo.addSelectionListener(new ConditionTypeSelectionListener(typeCombo, consumer, condition));
-
                return validate -> {
                        updater.update(validate);
                        condition.isInverse = notCheck.getSelection();
@@ -695,7 +764,7 @@ public class EditSelectorDialog extends Dialog {
                addButton.addSelectionListener(new SelectionAdapter() {
                        @Override
                        public void widgetSelected(SelectionEvent e) {
-                               cond.conditions.add(createPropertyCondition("property", null, null));
+                               cond.conditions.add(createPropertyCondition("", null, null));
                                updateDialog();
                        }
                });
@@ -745,7 +814,7 @@ public class EditSelectorDialog extends Dialog {
 
                // Create combo-box
                Combo routeCombo = new Combo(conditionComp, SWT.READ_ONLY);
-               RowDataFactory.swtDefaults().applyTo(routeCombo);
+               RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(routeCombo);
                routeCombo.setItems(routeNames);
                
                // Set current selection
@@ -756,6 +825,11 @@ public class EditSelectorDialog extends Dialog {
                // Register update
                return validate -> {
                        int i = routeCombo.getSelectionIndex();
+                       if (validate && i < 0) {
+                               routeCombo.forceFocus();
+                               throw new RuntimeException("Must select a route");
+                       }
+                               
                        condition.routeResource = i >= 0 ? routeResources[i] : null;
                };
        }
@@ -765,7 +839,7 @@ public class EditSelectorDialog extends Dialog {
                
                // Create combo-box
                Combo regionCombo = new Combo(conditionComp, SWT.READ_ONLY);
-               RowDataFactory.swtDefaults().applyTo(regionCombo);
+               RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(regionCombo);
                regionCombo.setItems(regionNames);
                
                // Set current selection
@@ -776,6 +850,11 @@ public class EditSelectorDialog extends Dialog {
                // Register update
                return validate -> {
                        int i = regionCombo.getSelectionIndex();
+                       if (validate && i < 0) {
+                               regionCombo.forceFocus();
+                               throw new ValidationException("Please select a region");
+                       }
+                       
                        condition.regionResource = i >= 0 ? regionResources[i] : null;
                };
        }
@@ -784,13 +863,13 @@ public class EditSelectorDialog extends Dialog {
                ROW_LAYOUT.applyTo(conditionComp);
                
                Text lowerLimitText = new Text(conditionComp, SWT.BORDER);
-               RowDataFactory.swtDefaults().applyTo(lowerLimitText);
+               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().applyTo(propertyNameText);
+               RowDataFactory.swtDefaults().hint(120, SWT.DEFAULT).applyTo(propertyNameText);
                propertyNameText.setItems(propertyLabels.toArray(new String[] {}));
                int index = propertyNames.indexOf(condition.propertyName);
                if (index >= 0)
@@ -801,7 +880,7 @@ public class EditSelectorDialog extends Dialog {
                new Label(conditionComp, SWT.NONE).setText("\u2264");
                
                Text upperLimitText = new Text(conditionComp, SWT.BORDER);
-               RowDataFactory.swtDefaults().applyTo(upperLimitText);
+               RowDataFactory.swtDefaults().hint(40, SWT.DEFAULT).applyTo(upperLimitText);
                upperLimitText.setText(condition.upperLimit != null ? Double.toString(condition.upperLimit) : "");
                
                // Register update
@@ -813,7 +892,7 @@ public class EditSelectorDialog extends Dialog {
                                if (validate) {
                                        lowerLimitText.selectAll();
                                        lowerLimitText.forceFocus();
-                                       throw e;
+                                       throw new ValidationException("Please enter a valid lower limit");
                                }
                        }
                        
@@ -824,7 +903,7 @@ public class EditSelectorDialog extends Dialog {
                                if (validate) {
                                        upperLimitText.selectAll();
                                        upperLimitText.forceFocus();
-                                       throw e;
+                                       throw new ValidationException("Please enter a valid upper limit");
                                }
                        }
                        
@@ -837,7 +916,7 @@ public class EditSelectorDialog extends Dialog {
                        
                        if (validate && name.isEmpty()) {
                                propertyNameText.forceFocus();
-                               throw new RuntimeException();
+                               throw new ValidationException("Please select a property");
                        } else {
                                condition.propertyName = name;
                        }
@@ -862,462 +941,6 @@ public class EditSelectorDialog extends Dialog {
                condition.isInverse = isInverse;
                return condition;
        }
-
-       /*
-       class ConditionDialog extends Dialog {
-               // Resource of the edited condition
-               private Resource existingResource;
-               
-               // Inverse condition button
-               private boolean isInverse;
-               private Button inverseField;
-
-               // Condition type
-               private int typeIndex;
-               private Combo typeField;
-               
-               // Type-specific control panels under a stack layout
-               private Composite stackPanel;
-               private StackLayout stack;
-               
-               private Composite propertyPanel;
-               private Composite regionPanel;
-               private Composite routePanel;
-               private Composite aggregatePanel;
-               
-               // Property condition
-               private Double lowerLimit;
-               private Double upperLimit;
-               private String propertyName;
-       
-               private Text propertyNameField;
-               private Text lowerLimitField;
-               private Text upperLimitField;
-               
-               // Region condition
-               private Resource region;
-               private Combo regionField;
-               
-               // Route condition
-               private Resource route;
-               private Combo routeField;
-               
-               // Aggregate condition
-               private List<Condition> subConditions;
-               private boolean isConjunction;
-               
-               private org.eclipse.swt.widgets.List subConditionField;
-               private Combo operatorField;
-               
-               public ConditionDialog(Shell shell, Condition condition) {
-                       super(shell);
-                       
-                       typeIndex = 0;
-                       isInverse = false;
-                       propertyName = "";
-                       upperLimit = null;
-                       lowerLimit = null;
-                       subConditions = new ArrayList<>();
-                       
-                       existingResource = condition != null ? condition.resource : null;
-
-                       if (condition != null) {
-                               if (condition instanceof PropertyCondition) {
-                                       typeIndex = 0;
-                                       PropertyCondition propertyCondition = (PropertyCondition)condition;
-                                       propertyName = propertyCondition.propertyName;
-                                       upperLimit = propertyCondition.upperLimit;
-                                       lowerLimit = propertyCondition.lowerLimit;
-                               }
-                               else if (condition instanceof RegionCondition) {
-                                       typeIndex = 1;
-                                       region = ((RegionCondition)condition).regionResource;
-                               }
-                               else if (condition instanceof RouteCondition) {
-                                       typeIndex = 2;
-                                       route = ((RouteCondition)condition).routeResource;
-                               }
-                               else if (condition instanceof AggregateCondition) {
-                                       typeIndex = 3;
-                                       subConditions = new ArrayList<>(((AggregateCondition)condition).conditions);
-                                       isConjunction = ((AggregateCondition)condition).type == Type.CONJUNCTION;
-                                       isInverse = ((AggregateCondition)condition).type == Type.NEGATION;
-                               }
-                       }
-               }
-               
-               @Override
-               protected Control createDialogArea(Composite parent) {
-                       getShell().setText("Edit selector condition");
-                       
-                       Composite content = (Composite)super.createDialogArea(parent);
-                       GridLayoutFactory.swtDefaults().numColumns(1).applyTo(content);
-                       
-                       GridDataFactory defaultWidth = GridDataFactory.swtDefaults().hint(200, SWT.DEFAULT);
-                       
-                       // Is inverse
-                       inverseField = new Button(content, SWT.CHECK);
-                       inverseField.setText("Is inverse");
-                       inverseField.setSelection(isInverse);
-                       
-                       // Condition type
-                       typeField = new Combo(content, SWT.BORDER | SWT.READ_ONLY);
-                       typeField.setItems("Property value", "In region", "On route", "Combination");
-                       typeField.select(typeIndex);
-                       
-                       // Type-dependent stacked panels
-                       stackPanel = new Composite(content, SWT.NONE);
-                       stack = new StackLayout();
-                       stackPanel.setLayout(stack);
-                       
-                       // Property condition panel
-                       propertyPanel = new Composite(stackPanel, SWT.NONE);
-                       GridLayoutFactory.swtDefaults().numColumns(2).applyTo(propertyPanel);
-                       
-                       new Label(propertyPanel, SWT.NONE).setText("Property name");
-                       propertyNameField = new Text(propertyPanel, SWT.BORDER);
-                       propertyNameField.setText(propertyName);
-                       defaultWidth.applyTo(propertyNameField);
-                       
-                       new Label(propertyPanel, SWT.NONE).setText("Lower limit");
-                       lowerLimitField = new Text(propertyPanel, SWT.BORDER);
-                       defaultWidth.applyTo(lowerLimitField);
-                       if (lowerLimit != null) lowerLimitField.setText(lowerLimit.toString());
-                       
-                       new Label(propertyPanel, SWT.NONE).setText("Upper limit");
-                       upperLimitField = new Text(propertyPanel, SWT.BORDER);
-                       defaultWidth.applyTo(upperLimitField);
-                       if (upperLimit != null) upperLimitField.setText(upperLimit.toString());
-                       
-                       // Region condition panel
-                       regionPanel = new Composite(stackPanel, SWT.NONE);
-                       GridLayoutFactory.swtDefaults().numColumns(2).applyTo(regionPanel);
-                       
-                       new Label(regionPanel, SWT.NONE).setText("Region");
-                       regionField = new Combo(regionPanel, SWT.BORDER | SWT.READ_ONLY);
-                       regionField.setItems(regionNames);
-                       defaultWidth.applyTo(regionField);
-                       
-                       if (region != null) {
-                               int regionIndex = Arrays.indexOf(regionResources, region);
-                               regionField.select(regionIndex);
-                       }
-                       else {
-                               regionField.select(0);
-                       }
-                       
-                       // Route condition panel
-                       routePanel = new Composite(stackPanel, SWT.NONE);
-                       GridLayoutFactory.swtDefaults().numColumns(2).applyTo(routePanel);
-                       
-                       new Label(routePanel, SWT.NONE).setText("Route");
-                       routeField = new Combo(routePanel, SWT.BORDER | SWT.READ_ONLY);
-                       routeField.setItems(routeNames);
-                       defaultWidth.applyTo(routeField);
-                       
-                       if (route != null) {
-                               int routeIndex = Arrays.indexOf(routeResources, route);
-                               routeField.select(routeIndex);
-                       }
-                       else {
-                               routeField.select(0);
-                       }
-                       
-                       // Aggregate condition panel
-                       aggregatePanel = new Composite(stackPanel, SWT.NONE);
-                       GridLayoutFactory.swtDefaults().numColumns(2).applyTo(aggregatePanel);
-                       
-                       new Label(aggregatePanel, SWT.NONE).setText("Operator");
-                       operatorField = new Combo(aggregatePanel, SWT.READ_ONLY);
-                       operatorField.setItems("And", "Or");
-                       operatorField.select(isConjunction ? 0 : 1);
-                       
-                       new Label(aggregatePanel, SWT.NONE).setText("Sub-conditions");
-                       Composite buttons = new Composite(aggregatePanel, SWT.NONE);
-                       RowLayoutFactory.swtDefaults().justify(true).fill(true).extendedMargins(0, 0, 0, 0).type(SWT.HORIZONTAL).applyTo(buttons);
-                       
-                       Button addButton = new Button(buttons, SWT.PUSH);
-                       addButton.setText("Add");
-                       Button removeButton = new Button(buttons, SWT.PUSH);
-                       removeButton.setText("Remove");
-                       Button editButton = new Button(buttons, SWT.PUSH);
-                       editButton.setText("Edit");
-
-                       new Label(aggregatePanel, SWT.NONE);
-                       subConditionField = new org.eclipse.swt.widgets.List(aggregatePanel, SWT.BORDER);
-                       GridDataFactory.swtDefaults().hint(200, 150).applyTo(subConditionField);
-                       if (subConditions != null) {
-                               Session session = Simantics.getSession();
-                               List<String> items = new ArrayList<>();
-                               for (Condition c : subConditions) {
-                                       try {
-                                               items.add(ElementSelector.getExpression(session, c.resource));
-                                       } catch (DatabaseException e1) {
-                                               LOGGER.error("Condition expression read failed", e1);
-                                               items.add("<Unknown expression>");
-                                       }
-                               }
-                               
-                               subConditionField.setItems(items.toArray(new String[items.size()]));
-                       }
-                       
-                       addButton.addSelectionListener(new SelectionAdapter() {
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       ConditionDialog conditionDialog = new ConditionDialog(getShell(), null);
-                                       if (conditionDialog.open() == Window.OK) {
-                                               Condition condition;
-                                               try {
-                                                       condition = conditionDialog.createCondition();
-                                                       subConditions.add(condition);
-                                                       
-                                                       try {
-                                                               subConditionField.add(ElementSelector.getExpression(Simantics.getSession(), condition.resource));
-                                                       } catch (DatabaseException e1) {
-                                                               LOGGER.error("Condition expression read failed", e1);
-                                                               subConditionField.add("<Unknown expression>");
-                                                       }
-                                               } catch (DatabaseException e2) {
-                                                       LOGGER.error("Create condition failed", e2);
-                                               }
-                                       }
-                               }
-                       });
-                       
-                       removeButton.addSelectionListener(new SelectionAdapter() {
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       int index = subConditionField.getSelectionIndex();
-                                       if (index >= 0) {
-                                               subConditionField.deselectAll();
-                                               subConditionField.remove(index);
-                                               subConditions.remove(index);
-                                               
-                                               if (index < subConditions.size())
-                                                       subConditionField.setSelection(index);
-                                       }
-                                       
-                                       boolean selected = subConditionField.getSelectionIndex() >= 0;
-                                       removeButton.setEnabled(selected);
-                                       editButton.setEnabled(selected);
-                               }
-                       });
-                       
-                       editButton.addSelectionListener(new SelectionAdapter() {
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       int index = subConditionField.getSelectionIndex();
-                                       if (index >= 0) {
-                                               Condition condition = subConditions.get(index);
-                                               ConditionDialog conditionDialog = new ConditionDialog(getShell(), condition);
-                                               if (conditionDialog.open() == Window.OK) {
-                                                       try {
-                                                               condition = conditionDialog.createCondition();
-                                                               subConditions.set(index, condition);
-                                                               
-                                                               try {
-                                                                       subConditionField.setItem(index, ElementSelector.getExpression(Simantics.getSession(), condition.resource));
-                                                               } catch (DatabaseException e1) {
-                                                                       LOGGER.error("Condition expression read failed", e1);
-                                                                       subConditionField.setItem(index, "<Unknown expression>");
-                                                               }
-                                                       } catch (DatabaseException e2) {
-                                                               LOGGER.error("Create condition failed", e2);
-                                                       }
-                                               }
-                                       }
-                               }
-                       });
-                       
-                       subConditionField.addSelectionListener(new SelectionAdapter() {
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       boolean selected = subConditionField.getSelectionIndex() >= 0;
-                                       removeButton.setEnabled(selected);
-                                       editButton.setEnabled(selected);
-                               }
-                       });
-
-                       // Stack layout update
-                       typeField.addSelectionListener(new SelectionAdapter() {
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       updateStack();
-                               }
-                       });
-                       
-                       updateStack();
-                       
-                       return content;
-               }
-               
-               @Override
-               protected void okPressed() {
-                       isInverse = inverseField.getSelection();
-                       
-                       switch (typeIndex) {
-                       case 0: // Property condition
-                               propertyName = propertyNameField.getText();
-                               try {
-                                       String lowerLimitText = lowerLimitField.getText();
-                                       lowerLimit = lowerLimitText.equals("") ? null : Double.valueOf(lowerLimitText);
-                                       String upperLimitText = upperLimitField.getText();
-                                       upperLimit = upperLimitText.equals("") ? null : Double.valueOf(upperLimitText);
-                               }
-                               catch (NumberFormatException e) {
-                                       ErrorDialog.openError(getShell(), "Error", "Invalid numeric value: " + e.getMessage(), new Status(OK, "org.simantics.district.selection.ui", e.getMessage()));
-                                       return;
-                               }
-                               break;
-                       case 1: { // Region condition
-                               int selectionIndex = regionField.getSelectionIndex();
-                               if (selectionIndex < 0) {
-                                       ErrorDialog.openError(getShell(), "Error", "Please select a region", new Status(OK, "org.simantics.district.selection.ui", "No region selection"));
-                                       return;
-                               }
-                               region = regionResources[selectionIndex];
-                               break;
-                       }
-                       case 2: // Route condition
-                               route = routeResources[routeField.getSelectionIndex()];
-                               break;
-                       case 3: // Aggregate condition
-                               isConjunction = operatorField.getSelectionIndex() == 0;
-                               break;
-                       }
-                       
-                       super.okPressed();
-               }
-       
-               protected Condition createCondition() throws DatabaseException {
-                       if (isInverse && !(typeIndex == 3 && !isConjunction)) {
-                               Resource resource0 = createCondition0(typeIndex);
-                               
-                               // Create a negation
-                               Resource resource = Simantics.getSession().syncRequest(new WriteResult<Resource>() {
-                                       @Override
-                                       public Resource perform(WriteGraph graph) throws DatabaseException {
-                                               ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
-                                               Layer0 L0 = Layer0.getInstance(graph);
-                                               
-                                               Resource r = graph.newResource();
-                                               graph.claim(r, L0.InstanceOf, ES.Negation);
-                                               graph.claim(r, ES.HasSubcondition, resource0);
-                                               return r;
-                                       }
-                               });
-                               
-                               return ElementSelector.getCondition(Simantics.getSession(), resource);
-                       }
-                       else {
-                               return ElementSelector.getCondition(Simantics.getSession(), createCondition0(typeIndex));
-                       }
-               }
-       
-               private Resource createCondition0(int index) throws DatabaseException {
-                       switch (index) {
-                       case 0: return createPropertyCondition();
-                       case 1: return createRegionCondition();
-                       case 2: return createRouteCondition();
-                       case 3: return createAggregateCondition();
-                       default: throw new IllegalStateException("Invalid condition type code " + index);
-                       }
-               }
-       
-               private Resource createPropertyCondition() throws DatabaseException {
-                       return Simantics.getSession().syncRequest(new WriteResult<Resource>() {
-                               @Override
-                               public Resource perform(WriteGraph graph) throws DatabaseException {
-                                       ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
-                                       Layer0 L0 = Layer0.getInstance(graph);
-                                       
-                                       Resource r = graph.newResource();
-                                       graph.claim(r, L0.InstanceOf, ES.PropertyCondition);
-                                       graph.claimLiteral(r, ES.PropertyCondition_HasPropertyName, propertyName);
-                                       if (lowerLimit != null)
-                                               graph.claimLiteral(r, ES.PropertyCondition_HasLowerLimit, L0.Double, lowerLimit);
-                                       if (upperLimit != null)
-                                               graph.claimLiteral(r, ES.PropertyCondition_HasUpperLimit, L0.Double, upperLimit);
-                                       
-                                       return r;
-                               }
-                       });
-               }
-               
-               private Resource createAggregateCondition() throws DatabaseException {
-                       return Simantics.getSession().syncRequest(new WriteResult<Resource>() {
-                               @Override
-                               public Resource perform(WriteGraph graph) throws DatabaseException {
-                                       ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
-                                       Layer0 L0 = Layer0.getInstance(graph);
-                                       
-                                       Resource r;
-                                       if (existingResource != null) {
-                                               // Reuse existing resource
-                                               r = existingResource;
-                                               // Clear any previous statements
-                                               graph.deny(existingResource);
-                                       }
-                                       else {
-                                               r = graph.newResource();
-                                       }
-                                       
-                                       Resource type;
-                                       type = isConjunction ? ES.Conjunction : isInverse ? ES.Negation : ES.Disjunction;
-                                       
-                                       graph.claim(r, L0.InstanceOf, type);
-                                       for (Condition c : subConditions) {
-                                               graph.claim(r, ES.HasSubcondition, c.resource);
-                                       }
-                                       
-                                       return r;
-                               }
-                       });
-               }
-       
-               private Resource createRouteCondition() throws DatabaseException {
-                       return Simantics.getSession().syncRequest(new WriteResult<Resource>() {
-                               @Override
-                               public Resource perform(WriteGraph graph) throws DatabaseException {
-                                       ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
-                                       Layer0 L0 = Layer0.getInstance(graph);
-                                       
-                                       Resource r = graph.newResource();
-                                       graph.claim(r, L0.InstanceOf, ES.RouteCondition);
-                                       graph.claim(r, ES.RouteCondition_HasRoute, route);
-                                       return r;
-                               }
-                       });
-               }
-       
-               private Resource createRegionCondition() throws DatabaseException {
-                       return Simantics.getSession().syncRequest(new WriteResult<Resource>() {
-                               @Override
-                               public Resource perform(WriteGraph graph) throws DatabaseException {
-                                       ElementSelectionResource ES = ElementSelectionResource.getInstance(graph);
-                                       Layer0 L0 = Layer0.getInstance(graph);
-                                       
-                                       Resource r = graph.newResource();
-                                       graph.claim(r, L0.InstanceOf, ES.RegionCondition);
-                                       graph.claim(r, ES.RegionCondition_HasRegion, region);
-                                       return r;
-                               }
-                       });
-               }
-
-               private void updateStack() {
-                       typeIndex = typeField.getSelectionIndex();
-                       switch (typeIndex) {
-                       case 0: stack.topControl = propertyPanel; break;
-                       case 1: stack.topControl = regionPanel; break;
-                       case 2: stack.topControl = routePanel; break;
-                       case 3: stack.topControl = aggregatePanel; break;
-                       }
-                       
-                       stackPanel.layout();
-               }
-       }
-       */
        
        static List<Resource> findComponentTypes(ReadGraph graph) throws DatabaseException {
                DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
@@ -1327,49 +950,56 @@ public class EditSelectorDialog extends Dialog {
                return QueryIndexUtils.searchByType(graph, model, DN.Mapping_Base);
        }
        
-       void updatePropertyList() throws DatabaseException {
+       void updatePropertyList() {
+               propertyNames = new ArrayList<>();
+               propertyLabels = new ArrayList<>();
+               
                Collection<Resource> types = componentType != null ? Collections.singleton(componentType) : componentTypes;
                Set<Pair<String, String>> 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;
-                                       }
+               try {
+                       Simantics.getSession().syncRequest(new ReadRequest() {
+                               @Override
+                               public void run(ReadGraph graph) throws DatabaseException {
+                                       Layer0 L0 = Layer0.getInstance(graph);
                                        
-                                       for (Resource prop : graph.getObjects(ct, L0.DomainOf)) {
-                                               if (!graph.isInstanceOf(prop, StructuralResource2.getInstance(graph).Property))
+                                       for (Resource type : types) {
+                                               if (type == null)
                                                        continue;
                                                
-                                               // Filter only numeric properties
-                                               PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(prop));
-                                               if (info != null && info.requiredValueType != null && !isNumericValueType(info.requiredValueType))
+                                               Resource ct = graph.getPossibleObject(type, DistrictNetworkResource.getInstance(graph).Mapping_ComponentType);
+                                               if (ct == null)
                                                        continue;
                                                
-                                               String name = graph.getRelatedValue2(prop, L0.HasName);
-                                               String label = graph.getPossibleRelatedValue2(prop, L0.HasLabel);
-                                               if (label == null) label = name;
+                                               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;
+                                               }
                                                
-                                               properties.add(Pair.make(label, name));
+                                               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));
+                                               }
                                        }
                                }
-                       }
-               });
+                       });
+               } catch (DatabaseException e) {
+                       LOGGER.error("Failed to read district component properties", e);
+               }
                
                propertyNames.clear();
                propertyLabels.clear();