From: Reino Ruusu Date: Fri, 1 Feb 2019 15:56:17 +0000 (+0200) Subject: UI for diagram element selection X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=09b78f5c26bb8b521beb6eeeb5c3f44ac1aa4d07;p=simantics%2Fdistrict.git UI for diagram element selection gitlab #28 Change-Id: Id89372d9101dc7004b9b71b8ed6769b555b7b510 --- diff --git a/org.simantics.district.selection.ui/.classpath b/org.simantics.district.selection.ui/.classpath new file mode 100644 index 00000000..eca7bdba --- /dev/null +++ b/org.simantics.district.selection.ui/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.district.selection.ui/.project b/org.simantics.district.selection.ui/.project new file mode 100644 index 00000000..491a0fbf --- /dev/null +++ b/org.simantics.district.selection.ui/.project @@ -0,0 +1,28 @@ + + + org.simantics.district.selection.ui + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.district.selection.ui/META-INF/MANIFEST.MF b/org.simantics.district.selection.ui/META-INF/MANIFEST.MF new file mode 100644 index 00000000..ee821144 --- /dev/null +++ b/org.simantics.district.selection.ui/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: org.simantics.district.selection.ui +Bundle-SymbolicName: org.simantics.district.selection.ui;singleton:=tr + ue +Bundle-Name: Diagram element selection UI +Bundle-Version: 1.0.0.qualifier +Require-Bundle: javax.inject,org.eclipse.osgi,org.eclipse.jface,org.ec + lipse.e4.ui.model.workbench,org.eclipse.e4.ui.di,org.eclipse.e4.ui.se + rvices,org.eclipse.e4.core.di.annotations,org.eclipse.e4.ui.workbench + ,org.slf4j.api,org.simantics,org.simantics.district.region,org.simant + ics.district.selection,org.simantics.db.common,org.simantics.ui,com.f + amfamfam.silk;bundle-version="1.3.0",org.simantics.browsing.ui.common + ,org.eclipse.e4.core.contexts,org.eclipse.e4.core.di;bundle-version=" + 1.6.100",org.simantics.district.region.ontology,org.simantics.distric + t.route.ontology,org.simantics.modeling.ontology,org.simantics.silk.o + ntology;bundle-version=1.1.0 +Bundle-ManifestVersion: 2 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-Vendor: Semantum oy +Import-Package: javax.annotation;version="1.2.0" + diff --git a/org.simantics.district.selection.ui/build.properties b/org.simantics.district.selection.ui/build.properties new file mode 100644 index 00000000..c8d752e6 --- /dev/null +++ b/org.simantics.district.selection.ui/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = plugin.xml,\ + META-INF/,\ + .,\ + fragment.e4xmi diff --git a/org.simantics.district.selection.ui/fragment.e4xmi b/org.simantics.district.selection.ui/fragment.e4xmi new file mode 100644 index 00000000..123c9976 --- /dev/null +++ b/org.simantics.district.selection.ui/fragment.e4xmi @@ -0,0 +1,31 @@ + + + + + View + categoryTag:District + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.simantics.district.selection.ui/plugin.xml b/org.simantics.district.selection.ui/plugin.xml new file mode 100644 index 00000000..ebc45555 --- /dev/null +++ b/org.simantics.district.selection.ui/plugin.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/org.simantics.district.selection.ui/pom.xml b/org.simantics.district.selection.ui/pom.xml new file mode 100644 index 00000000..28f0dd02 --- /dev/null +++ b/org.simantics.district.selection.ui/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + + org.simantics.district + org.simantics.district.root + 1.0.0-SNAPSHOT + + + org.simantics.district.selection.ui + eclipse-plugin + 1.0.0-SNAPSHOT + + 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 new file mode 100644 index 00000000..0786ce53 --- /dev/null +++ b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/ElementSelectorTableUI.java @@ -0,0 +1,253 @@ +package org.simantics.district.selection.ui; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.jface.viewers.Viewer; +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.Tree; +import org.simantics.Simantics; +import org.simantics.browsing.ui.common.AdaptableHintContext; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.SyncListenerAdapter; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.RuntimeDatabaseException; +import org.simantics.db.layer0.QueryIndexUtils; +import org.simantics.db.layer0.SelectionHints; +import org.simantics.db.layer0.request.ActiveModels; +import org.simantics.db.request.Read; +import org.simantics.district.selection.ElementSelectionResource; +import org.simantics.district.selection.ElementSelectionUtils; +import org.simantics.district.selection.ElementSelector; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ElementSelectorTableUI extends Composite { + + private static final Logger LOGGER = LoggerFactory.getLogger(ElementSelectorTableUI.class); + + private TreeViewer viewer; + private TreeViewerColumn column1; + private TreeViewerColumn column2; + + public ElementSelectorTableUI(ESelectionService selectionService, Composite parent, int style) { + super(parent, style); + parent.setLayout(new FillLayout()); + // GridDataFactory.fillDefaults().grab(true, true).applyTo(this); + // GridLayoutFactory.fillDefaults().numColumns(1).applyTo(this); + this.setLayout(new FillLayout()); + + viewer = new TreeViewer(this, SWT.FULL_SELECTION); + viewer.addDoubleClickListener(new IDoubleClickListener() { + @Override + public void doubleClick(DoubleClickEvent event) { + TreeSelection selection = (TreeSelection) viewer.getSelection(); + ElementSelector query = (ElementSelector) selection.getFirstElement(); + try { + List elements = Simantics.getSession().syncRequest(new Read>() { + @SuppressWarnings("unchecked") + @Override + public List perform(ReadGraph graph) throws DatabaseException { + Resource model = ActiveModels.getPossibleActiveModel(graph, Simantics.getProjectResource()); + if (model == null) { + LOGGER.warn("No active model"); + return Collections.emptyList(); + } + + List result = query.selectElementsFrom(graph, model); + return Lists.map(new FunctionImpl1() { + public AdaptableHintContext apply(Resource p0) { + AdaptableHintContext selectionElement = new SelectionElement(SelectionHints.STD_KEYS, graph); + selectionElement.setHint(SelectionHints.KEY_MAIN, p0); + selectionElement.setHint(SelectionHints.KEY_MODEL, model); + return selectionElement; + } + }, result); + } + }); + + selectionService.setPostSelection(new StructuredSelection(elements)); + } catch (DatabaseException e) { + LOGGER.error("Element selection query failed", e); + } + } + }); + + viewer.setContentProvider(new ITreeContentProvider() { + @Override + public boolean hasChildren(Object element) { + return false; + } + + @Override + public Object getParent(Object element) { + return null; + } + + @Override + public Object[] getElements(Object inputElement) { + if (inputElement == null || !(inputElement instanceof Collection)) + return new Object[0]; + + return ((Collection)inputElement).toArray(); + } + + @Override + public Object[] getChildren(Object parentElement) { + return null; + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + ITreeContentProvider.super.inputChanged(viewer, oldInput, newInput); + } + }); + + Simantics.getSession().asyncRequest(new SelectionsRequest(), new SyncListenerAdapter>() { + public void execute(ReadGraph graph, Collection result) { + parent.getDisplay().asyncExec(() -> { + viewer.setInput(result); + }); + } + + @Override + public void exception(ReadGraph graph, Throwable t) throws DatabaseException { + LOGGER.error("Error getting element selector list", t); + } + + @Override + public boolean isDisposed() { + return ElementSelectorTableUI.this.isDisposed(); + } + }); + + ColumnViewerToolTipSupport.enableFor(viewer); + + Tree table = viewer.getTree(); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + column1 = new TreeViewerColumn(viewer, SWT.NONE); + column1.getColumn().setText("Name"); + column1.getColumn().setWidth(200); + column1.getColumn().setResizable(true); + column1.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + ElementSelector selector = (ElementSelector) element; + return selector.getName(); + } + + @Override + public Image getImage(Object element) { + return null; + } + }); + + column2 = new TreeViewerColumn(viewer, SWT.NONE); + column2.getColumn().setText("Query"); + column2.getColumn().setWidth(600); + column2.getColumn().setResizable(true); + column2.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + ElementSelector selector = (ElementSelector) element; + return selector.getExpression(); + } + + @Override + public Image getImage(Object element) { + return null; + } + }); + } + + public Tree getTree() { + return viewer.getTree(); + } + + public ElementSelector getSelectedItem() { + IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); + return selection != null ? (ElementSelector) selection.getFirstElement() : null; + } + + private final class SelectionElement extends AdaptableHintContext { + private final ReadGraph graph; + + private SelectionElement(Key[] keys, ReadGraph graph) { + super(keys); + this.graph = graph; + } + + @SuppressWarnings("unchecked") + public T getContent(WorkbenchSelectionContentType contentType) { + Resource element = getHint(SelectionHints.KEY_MAIN); + if (contentType instanceof AnyResource) { + return (T)element; + } + else if (contentType instanceof AnyVariable) { + try { + return (T)ElementSelector.getVariableForElement(graph, element); + } catch (DatabaseException e) { + return null; + } + } + + return null; + } + } + + public static class SelectionsRequest implements Read> { + @Override + public Collection perform(ReadGraph graph) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); + + Resource model = ActiveModels.getPossibleActiveModel(graph, Simantics.getProjectResource()); + if (model == null) { + return Collections.emptyList(); + } + + List libs = QueryIndexUtils.searchByType(graph, model, ES.SelectionLibrary); + if (libs.isEmpty()) + return Collections.emptyList(); + + Resource lib = libs.get(0); + + List result = new ArrayList<>(); + for (Resource selection : graph.getObjects(lib, L0.ConsistsOf)) { + if (!graph.isInstanceOf(selection, ES.Selection)) + continue; + + result.add(ElementSelector.getSelector(graph, selection)); + } + + return result; + } + } +} diff --git a/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/CreateNewElementSelector.java b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/CreateNewElementSelector.java new file mode 100644 index 00000000..b9df8b84 --- /dev/null +++ b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/CreateNewElementSelector.java @@ -0,0 +1,39 @@ +package org.simantics.district.selection.ui.handlers; + +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.workbench.IWorkbench; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.exception.DatabaseException; +import org.simantics.district.selection.ui.parts.EditSelectorDialog; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CreateNewElementSelector { + + private static final Logger LOGGER = LoggerFactory.getLogger(CreateNewElementSelector.class); + + @CanExecute + public boolean canExecute(ESelectionService selectionService) { + return true; + } + + @Execute + public void createNewElementSelector(IEclipseContext context, IWorkbench workbench) { + Shell shell = context.getActive(Shell.class); + EditSelectorDialog dialog = new EditSelectorDialog(shell, null); + LOGGER.debug("Opening dialog"); + int result = dialog.open(); + LOGGER.debug("Dialog closed with result code " + result); + if (result == Window.OK) { + try { + dialog.writeSelection(); + } catch (DatabaseException e) { + LOGGER.error("Writing new element selection failed", e); + } + } + } +} diff --git a/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/DeleteElementSelector.java b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/DeleteElementSelector.java new file mode 100644 index 00000000..4382e70c --- /dev/null +++ b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/DeleteElementSelector.java @@ -0,0 +1,64 @@ +package org.simantics.district.selection.ui.handlers; + +import javax.inject.Inject; + +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.workbench.IWorkbench; +import org.eclipse.e4.ui.workbench.modeling.EPartService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.simantics.Simantics; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.district.selection.ElementSelector; +import org.simantics.district.selection.ui.parts.ElementSelectionView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DeleteElementSelector { + + private static final Logger LOGGER = LoggerFactory.getLogger(DeleteElementSelector.class); + + @Inject + EPartService partService; + + @CanExecute + public boolean canExecute(ESelectionService selectionService) { + MPart part = partService.getActivePart(); + if (part == null) return false; + + Object object = part.getObject(); + if (object == null || !(object instanceof ElementSelectionView)) + return false; + + ElementSelectionView view = (ElementSelectionView)object; + return view.getSelectedItem() != null; + } + + @Execute + public void editElementSelector(IEclipseContext context, IWorkbench workbench) { + MPart part = partService.getActivePart(); + if (part == null) return; + + Object object = part.getObject(); + if (object == null || !(object instanceof ElementSelectionView)) + return; + + ElementSelectionView view = (ElementSelectionView)object; + ElementSelector selectedItem = view.getSelectedItem(); + + if (selectedItem == null) + return; + + Simantics.getSession().async(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + graph.markUndoPoint(); + graph.deny(selectedItem.getResource()); + } + }); + } +} diff --git a/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/EditElementSelector.java b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/EditElementSelector.java new file mode 100644 index 00000000..f914d161 --- /dev/null +++ b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/EditElementSelector.java @@ -0,0 +1,66 @@ +package org.simantics.district.selection.ui.handlers; + +import javax.inject.Inject; + +import org.eclipse.e4.core.contexts.ContextInjectionFactory; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.workbench.IWorkbench; +import org.eclipse.e4.ui.workbench.modeling.EPartService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.simantics.db.exception.DatabaseException; +import org.simantics.district.selection.ui.parts.EditSelectorDialog; +import org.simantics.district.selection.ui.parts.ElementSelectionView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EditElementSelector { + + private static final Logger LOGGER = LoggerFactory.getLogger(EditElementSelector.class); + + @Inject + EPartService partService; + + @CanExecute + public boolean canExecute(ESelectionService selectionService) { + MPart part = partService.getActivePart(); + if (part == null) return false; + + Object object = part.getObject(); + if (object == null || !(object instanceof ElementSelectionView)) + return false; + + ElementSelectionView view = (ElementSelectionView)object; + return view.getSelectedItem() != null; + } + + @Execute + public void editElementSelector(IEclipseContext context, IWorkbench workbench) { + MPart part = partService.getActivePart(); + if (part == null) return; + + Object object = part.getObject(); + if (object == null || !(object instanceof ElementSelectionView)) + return; + + ElementSelectionView view = (ElementSelectionView)object; + + Shell shell = context.getActive(Shell.class); + EditSelectorDialog dialog = new EditSelectorDialog(shell, view.getSelectedItem()); + + LOGGER.debug("Opening dialog"); + int result = dialog.open(); + LOGGER.debug("Dialog closed with result code " + result); + if (result == Window.OK) { + try { + dialog.writeSelection(); + } catch (DatabaseException e) { + LOGGER.error("Writing new element selection failed", e); + } + } + } +} diff --git a/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/OpenElementSelectorTable.java b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/OpenElementSelectorTable.java new file mode 100644 index 00000000..4a9bd29f --- /dev/null +++ b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/handlers/OpenElementSelectorTable.java @@ -0,0 +1,22 @@ +package org.simantics.district.selection.ui.handlers; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.simantics.ui.workbench.e4.E4WorkbenchUtils; + +public class OpenElementSelectorTable { + + private static final String VIEW_ID = "org.simantics.diagram.selection.ui.elementSelectionView"; + + @CanExecute + public boolean canExecute(ESelectionService selectionService) { + return true; + } + + @Execute + public void openPropertyTable(ESelectionService selectionService) { + E4WorkbenchUtils.openAndShowPart(VIEW_ID); + } + +} diff --git a/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/parts/EditSelectorDialog.java b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/parts/EditSelectorDialog.java new file mode 100644 index 00000000..42270da9 --- /dev/null +++ b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/parts/EditSelectorDialog.java @@ -0,0 +1,909 @@ +package org.simantics.district.selection.ui.parts; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +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.RowLayoutFactory; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StackLayout; +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.simantics.Simantics; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.WriteGraph; +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.request.Read; +import org.simantics.db.request.WriteResult; +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.modeling.ModelingResources; +import org.simantics.utils.datastructures.Arrays; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EditSelectorDialog extends Dialog { + + private static Logger LOGGER = LoggerFactory.getLogger(EditSelectorDialog.class); + + private ElementSelector elementSelector; + + // Data for comboboxes + Map diagrams; + + private String[] regionNames; + private Resource[] regionResources; + + private String[] routeNames; + private Resource[] routeResources; + + // 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 String propertyName; + private Text propertyField; + + private int numberOfItems; + private Text nField; + + private Condition condition; + private Button removeConditionButton; + private Text conditionLabel; + + // Dialog area component + private Composite content; + + @Inject + public EditSelectorDialog(Shell shell, ElementSelector elementSelector) { + 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); + } + } + + 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()]); + + 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; + // TODO: Management of explicit lists of elements + } + 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(); + } + } + + @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 = new ArrayList(diagrams.keySet()).get(selectionIndex); + } + + name = nameField.getText(); + + selectorIndex = selectorField.getSelectionIndex(); + + propertyName = propertyField.getText(); + String text = nField.getText(); + numberOfItems = "".equals(text) ? 0 : Integer.parseInt(text); + + 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); + + graph.markUndoPoint(); + + 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, ModelingResources.getInstance(graph).DiagramToComposite); + graph.claim(generator, ES.Generator_HasDiagram, composite != null ? composite : diagram); + break; + case 2: + generatorType = ES.Generator_Explicit; + // TODO: Claim relations to current selection elements + 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); + + 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) { + graph.claim(selection, ES.Selection_HasCondition, condition.resource); + } + } + }); + } + + @Override + protected Control createDialogArea(Composite parent) { + // Set dialog title + getShell().setText("Edit element selector"); + + content = new Composite(parent, SWT.NONE); + GridLayoutFactory.swtDefaults().numColumns(3).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().span(2, 1).hint(200, SWT.DEFAULT).applyTo(nameField); + + // Source + Label sourceLabel = new Label(content, SWT.NONE); + sourceLabel.setText("Source"); + GridDataFactory.swtDefaults().applyTo(sourceLabel); + + sourceField = new Combo(content, SWT.BORDER | SWT.READ_ONLY); + sourceField.setItems("Model", "Diagram", "Current selection"); + sourceField.select(generatorIndex); + GridDataFactory.swtDefaults().span(1, 1).applyTo(sourceField); + + diagramField = new Combo(content, SWT.BORDER | SWT.READ_ONLY); + GridDataFactory.swtDefaults().span(1, 1).applyTo(diagramField); + diagrams = ElementSelector.findDiagrams(); + diagramField.setItems(diagrams.values().toArray(new String[diagrams.size()])); + + int diagramIndex = diagram != null ? new ArrayList<>(diagrams.keySet()).indexOf(diagram) : -1; + diagramField.select(diagramIndex); + + sourceField.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + generatorIndex = sourceField.getSelectionIndex(); + diagramField.setVisible(isDiagramFieldVisible()); + } + }); + + sourceField.select(generatorIndex); + diagramField.setVisible(isDiagramFieldVisible()); + + // Selector + Label selectorLabel = new Label(content, SWT.NONE); + selectorLabel.setText("Select"); + GridDataFactory.swtDefaults().span(1, 1).applyTo(selectorLabel); + + selectorField = new Combo(content, SWT.BORDER | SWT.READ_ONLY); + selectorField.setItems("All", "N lowest", "N highest"); + selectorField.select(selectorIndex); + GridDataFactory.swtDefaults().span(1, 1).applyTo(selectorField); + + Composite selectorComposite = new Composite(content, SWT.NONE); + GridDataFactory.swtDefaults().span(1, 1).applyTo(selectorComposite); + GridLayoutFactory.swtDefaults().numColumns(2).applyTo(selectorComposite); + + Label propertyLabel = new Label(selectorComposite, SWT.NONE); + propertyLabel.setText("Property name"); + GridDataFactory.swtDefaults().applyTo(propertyLabel); + + propertyField = new Text(selectorComposite, SWT.BORDER); + propertyField.setText(propertyName); + GridDataFactory.swtDefaults().hint(80, SWT.DEFAULT).applyTo(propertyField); + + Label nLabel = new Label(selectorComposite, SWT.NONE); + nLabel.setText("Number of elements"); + GridDataFactory.swtDefaults().applyTo(nLabel); + + nField = new Text(selectorComposite, SWT.BORDER); + nField.setText(Integer.toString(numberOfItems)); + GridDataFactory.swtDefaults().hint(40, SWT.DEFAULT).applyTo(nField); + + selectorField.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + selectorIndex = selectorField.getSelectionIndex(); + selectorComposite.setVisible(isSelectorCompositeVisible()); + } + }); + + selectorField.select(selectorIndex); + selectorComposite.setVisible(isSelectorCompositeVisible()); + + // Condition + new Label(content, SWT.NONE).setText("Condition"); + conditionLabel = new Text(content, SWT.READ_ONLY); + GridDataFactory.swtDefaults().span(2, 1).applyTo(conditionLabel); + + new Label(content, SWT.NONE); + Composite conditionPanel = new Composite(content, SWT.NONE); + GridDataFactory.swtDefaults().span(2, 1).applyTo(conditionPanel); + GridLayoutFactory.swtDefaults().margins(0, 0).numColumns(2).applyTo(conditionPanel); + Button conditionButton = new Button(conditionPanel, SWT.PUSH); + conditionButton.setText("Edit..."); + GridDataFactory.swtDefaults().span(1, 1).applyTo(conditionButton); + removeConditionButton = new Button(conditionPanel, SWT.PUSH); + removeConditionButton.setText("Remove"); + GridDataFactory.swtDefaults().span(1, 1).applyTo(removeConditionButton); + + updateCondition(); + + conditionButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + ConditionDialog dialog = new ConditionDialog(getShell(), condition); + if (dialog.open() == Window.OK) { + try { + condition = dialog.createCondition(); + } catch (DatabaseException e1) { + LOGGER.error("Creating a condition object failed", e1); + } + + updateCondition(); + } + } + }); + + removeConditionButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + condition = null; + updateCondition(); + } + }); + + return content; + } + + private void updateCondition() { + if (condition != null) { + removeConditionButton.setEnabled(true); + try { + conditionLabel.setText(ElementSelector.getExpression(Simantics.getSession(), condition.resource)); + } catch (DatabaseException e) { + LOGGER.error("Error getting expression string for " + condition.resource); + } + } + else { + conditionLabel.setText("No condition"); + removeConditionButton.setEnabled(false); + } + + content.layout(); + } + + private boolean isDiagramFieldVisible() { + return generatorIndex == 1; + } + + private boolean isSelectorCompositeVisible() { + return selectorIndex != 0; + } + + 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 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 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(""); + } + } + + 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(""); + } + } 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, ""); + } + } 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(); + + // Create a negation + Resource resource = Simantics.getSession().syncRequest(new WriteResult() { + @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()); + } + } + + private Resource createCondition0() throws DatabaseException { + switch (typeIndex) { + case 0: return createPropertyCondition(); + case 1: return createRegionCondition(); + case 2: return createRouteCondition(); + case 3: return createAggregateCondition(); + default: throw new IllegalStateException("Invalid condition type code " + typeIndex); + } + } + + private Resource createPropertyCondition() throws DatabaseException { + return Simantics.getSession().syncRequest(new WriteResult() { + @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() { + @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() { + @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() { + @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(); + } + } +} diff --git a/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/parts/ElementSelectionView.java b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/parts/ElementSelectionView.java new file mode 100644 index 00000000..1cddde9f --- /dev/null +++ b/org.simantics.district.selection.ui/src/org/simantics/district/selection/ui/parts/ElementSelectionView.java @@ -0,0 +1,100 @@ +package org.simantics.district.selection.ui.parts; + +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +import org.eclipse.e4.ui.di.Focus; +import org.eclipse.e4.ui.model.application.MApplication; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.menu.MHandledToolItem; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution; +import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory; +import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; +import org.eclipse.e4.ui.model.application.ui.menu.MToolBar; +import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement; +import org.eclipse.e4.ui.services.EMenuService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.simantics.district.selection.ElementSelector; +import org.simantics.district.selection.ui.ElementSelectorTableUI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ElementSelectionView { + private static final String CONTEXT_MENU_ID = "org.simantics.district.selection.ui.contextMenu"; + private static final String POPUP_ID = "org.simantics.district.selection.ui.selectiontable.popup"; + private static final String CREATE_NEW_ID = "org.simantics.district.selection.ui.command.createNewSelection"; + private static final String CREATE_NEW_LABEL = "Create New Element Selection Query"; + private static final String CREATE_NEW_ICON = "platform:/plugin/com.famfamfam.silk/icons/add.png"; + private static final String EDIT_ID = "org.simantics.district.selection.ui.command.editElementSelector"; + private static final String EDIT_LABEL = "Edit Element Selection Query"; + private static final String EDIT_ICON = "platform:/plugin/com.famfamfam.silk/icons/pencil.png"; + private static final String DELETE_ID = "org.simantics.district.selection.ui.command.deleteElementSelector"; + private static final String DELETE_LABEL = "Delete Element Selection Query"; + private static final String DELETE_ICON = "platform:/plugin/com.famfamfam.silk/icons/cross.png"; + + private static final Logger LOGGER = LoggerFactory.getLogger(ElementSelectionView.class); + + private ElementSelectorTableUI table; + + @Inject + private ESelectionService selectionService; + + @Inject + public void init(MPart part, MApplication app) { + // Command is contributed via fragment + MHandledToolItem createItem = MMenuFactory.INSTANCE.createHandledToolItem(); + createItem.setCommand(app.getCommand(CREATE_NEW_ID)); + createItem.setLabel(CREATE_NEW_LABEL); + createItem.setIconURI(CREATE_NEW_ICON); + MHandledToolItem editItem = MMenuFactory.INSTANCE.createHandledToolItem(); + editItem.setCommand(app.getCommand(EDIT_ID)); + editItem.setLabel(EDIT_LABEL); + editItem.setIconURI(EDIT_ICON); + MHandledToolItem deleteItem = MMenuFactory.INSTANCE.createHandledToolItem(); + deleteItem.setCommand(app.getCommand(DELETE_ID)); + deleteItem.setLabel(DELETE_LABEL); + deleteItem.setIconURI(DELETE_ICON); + + MToolBar toolBar = MMenuFactory.INSTANCE.createToolBar(); + toolBar.setToBeRendered(true); + + List children = toolBar.getChildren(); + children.add(createItem); + children.add(editItem); + children.add(deleteItem); + + part.setToolbar(toolBar); + + MPopupMenu popupMenu = MMenuFactory.INSTANCE.createPopupMenu(); + popupMenu.setElementId(POPUP_ID); + + List menuContributions = app.getMenuContributions(); + for (MMenuContribution menuContribution : menuContributions) { + if (CONTEXT_MENU_ID.equals(menuContribution.getParentId())) { + popupMenu.getChildren().addAll(menuContribution.getChildren()); + } + } + + part.getMenus().add(popupMenu); + } + + @PostConstruct + public void createPartControl(Composite parent, EMenuService menuService) { + table = new ElementSelectorTableUI(selectionService, parent, SWT.BORDER); + if (!(menuService.registerContextMenu(this.table.getTree(), POPUP_ID))) + LOGGER.warn("Could not register context menu {}", POPUP_ID); + } + + @Focus + public void setFocus() { + table.setFocus(); + } + + public ElementSelector getSelectedItem() { + return table.getSelectedItem(); + } +} diff --git a/org.simantics.district.selection/graph.tg b/org.simantics.district.selection/graph.tg index d7f0261e..fb07142b 100644 Binary files a/org.simantics.district.selection/graph.tg and b/org.simantics.district.selection/graph.tg differ diff --git a/org.simantics.district.selection/graph/DiagramElementSelection.pgraph b/org.simantics.district.selection/graph/DiagramElementSelection.pgraph index 5a510864..55e01958 100644 --- a/org.simantics.district.selection/graph/DiagramElementSelection.pgraph +++ b/org.simantics.district.selection/graph/DiagramElementSelection.pgraph @@ -8,6 +8,8 @@ ES = : L0.Ontology L0.Ontology.global true L0.HasResourceClass "org.simantics.district.selection.ElementSelectionResource" +ES.SelectionLibrary -- ES.Selection.HasGenerator --> ES.Generator -- ES.Selection.HasCondition --> ES.Condition () { + @Override + public Resource perform(WriteGraph graph) throws DatabaseException { + ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); + + Resource model = graph.sync(new PossibleActiveModel(Simantics.getProjectResource())); + if (model == null) return null; + + List libs = QueryIndexUtils.searchByTypeShallow(graph, model, ES.SelectionLibrary); + if (libs.isEmpty()) { + Resource lib = graph.newResource(); + Layer0 L0 = Layer0.getInstance(graph); + graph.claim(lib, L0.InstanceOf, ES.SelectionLibrary); + graph.claim(model, L0.ConsistsOf, lib); + graph.claimLiteral(lib, L0.HasName, L0.String, UUID.randomUUID().toString(), Bindings.STRING); + return lib; + } + else { + return libs.get(0); + } + } + }); + } + +} diff --git a/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java b/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java index 7d429e4e..74eaa227 100644 --- a/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java +++ b/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelector.java @@ -3,22 +3,29 @@ package org.simantics.district.selection; import java.awt.geom.Path2D; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.simantics.Simantics; import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; import org.simantics.db.common.request.ResourceRead; import org.simantics.db.common.utils.ListUtils; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.QueryIndexUtils; import org.simantics.db.layer0.request.ActiveModels; import org.simantics.db.layer0.request.ActiveRuns; import org.simantics.db.layer0.request.Configuration; +import org.simantics.db.layer0.request.PossibleActiveModel; import org.simantics.db.layer0.variable.RVI; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; +import org.simantics.db.request.Read; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.district.network.ontology.DistrictNetworkResource; import org.simantics.district.region.ontology.DiagramRegionsResource; @@ -35,7 +42,7 @@ import org.slf4j.LoggerFactory; public class ElementSelector { String name; String expression; - Integer count; + Resource resource; Generator generator; @@ -51,6 +58,8 @@ public class ElementSelector { static DiagramResource DIA; static DistrictNetworkResource DN; + private static Logger LOGGER = LoggerFactory.getLogger(ElementSelector.class); + ElementSelector(ReadGraph graph, Resource resource) throws DatabaseException { super(); @@ -62,32 +71,169 @@ public class ElementSelector { DN = DistrictNetworkResource.getInstance(graph); this.resource = resource; - this.count = -1; try { this.name = graph.getRelatedValue(resource, L0.HasLabel); - this.expression = buildExpression(graph, resource); + this.expression = getExpression(graph, resource); } catch (DatabaseException e) { LOG.error("Error reading element selector", e); throw e; } } - public static ElementSelector getSelector(ReadGraph graph, Resource resource) throws DatabaseException { + /** + * Instantiate an element selector object for an ES.Selection resource. + */ + public static ElementSelector getSelector(RequestProcessor graph, Resource resource) throws DatabaseException { return graph.syncRequest(new ElementSelectorQuery(resource)); } + + /** + * Get an SQL-like textual description of an ES.Selection resource. + */ + public static String getExpression(RequestProcessor graph, Resource resource) throws DatabaseException { + return graph.syncRequest(new SelectionExpressionRequest(resource)); + } + + /** + * Get a Java object representation of an ES.Condition resource. + */ + public static Condition getCondition(RequestProcessor graph, Resource condition) throws DatabaseException { + return graph.syncRequest(new SelectionConditionRequest(condition)); + } + /** + * Get the name of the element selector. + */ public String getName() { return name; } + /** + * Get a textual SQL-like description of the element selector. + */ public String getExpression() { return expression; } + /** + * Get the resource that this selector represents. + */ public Resource getResource() { return resource; } + /** + * Get the generator component. Use {@link #buildSelection(ReadGraph)} to make it available first. + */ + public Generator getGenerator() { + return generator; + } + + /** + * Get the selector component. Use {@link #buildSelection(ReadGraph)} to make it available first. + */ + public Selector getSelector() { + return selector; + } + + /** + * Get the condition component. Use {@link #buildSelection(ReadGraph)} to make it available first. + */ + public Condition getCondition() { + return condition; + } + + /** + * + * @param graph + * @throws DatabaseException + */ + public void buildSelection(ReadGraph graph) throws DatabaseException { + Resource selector = graph.getSingleObject(resource, ES.Selection_HasSelector); + Resource generator = graph.getSingleObject(resource, ES.Selection_HasGenerator); + Resource condition = graph.getPossibleObject(resource, ES.Selection_HasCondition); + + this.selector = buildSelector(graph, selector); + this.generator = buildGenerator(graph, generator); + this.condition = buildCondition(graph, condition); + } + + public static Map findDiagrams() { + try { + return Simantics.getSession().syncRequest(new Read>() { + @Override + public Map perform(ReadGraph graph) throws DatabaseException { + Map result = new HashMap<>(); + Resource model = graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource())); + List composites = QueryIndexUtils.searchByType(graph, model, StructuralResource2.getInstance(graph).Composite); + for (Resource r : composites) { + // Get diagram + Resource diagram = graph.getPossibleObject(r, ModelingResources.getInstance(graph).CompositeToDiagram); + if (diagram == null) continue; + + // Filter out user component diagrams + Resource parent = graph.getPossibleObject(r, Layer0.getInstance(graph).PartOf); + if (parent == null || graph.isInheritedFrom(parent, StructuralResource2.getInstance(graph).Component)) + continue; + + result.put(r, graph.getRelatedValue(r, Layer0.getInstance(graph).HasName)); + } + + return result; + } + }); + } catch (DatabaseException e) { + LOGGER.error("Query for model diagrams failed", e); + return Collections.emptyMap(); + } + } + + public static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException { + Resource component = graph.getPossibleObject(element, MOD.ElementToComponent); + if (component != null) { + Variable var = Variables.getVariable(graph, component); + RVI realRvi = var.getRVI(graph); + + for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) { + for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) { + Variable v = realRvi.resolvePossible(graph, run); + if (v != null) { + return v; + } + } + Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel); + if (configuration != null) { + Variable v = realRvi.resolvePossible(graph, configuration); + if (v != null) { + return v; + } + } + } + } + + return null; + } + + public static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) { + try { + Variable v = getVariableForElement(graph, element); + if (v != null) { + Number value = v.getPossiblePropertyValue(graph, propertyName); + if (value != null) + return value.doubleValue(); + } + + // No property found - try possible mapped element property as well + Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent); + if (mappedElement != null) + return getPropertyValue(graph, mappedElement, propertyName); + } + catch (DatabaseException e) { + } + + return null; + } + public List selectElementsFrom(ReadGraph graph, Resource model) throws DatabaseException { if (selector == null) { buildSelection(graph); @@ -147,19 +293,20 @@ public class ElementSelector { String propertyName = graph.getRelatedValue(resource, ES.PropertyCondition_HasPropertyName); Double lowerLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasLowerLimit); Double upperLimit = graph.getPossibleRelatedValue(resource, ES.PropertyCondition_HasUpperLimit); - cond = new PropertyCondition(propertyName, lowerLimit, upperLimit); + cond = new PropertyCondition(resource, propertyName, lowerLimit, upperLimit); } else if (graph.isInstanceOf(resource, ES.RegionCondition)) { DiagramRegionsResource DR = DiagramRegionsResource.getInstance(graph); - double[] region = graph.getRelatedValue(graph.getSingleObject(resource, ES.RegionCondition_HasRegion), DR.Region_area); - cond = new RegionCondition(region); + Resource regionResource = graph.getSingleObject(resource, ES.RegionCondition_HasRegion); + double[] region = graph.getRelatedValue(regionResource, DR.Region_area); + cond = new RegionCondition(resource, regionResource, region); } else if (graph.isInstanceOf(resource, ES.RouteCondition)) { - Set routePoints = new HashSet<>(ListUtils.toList(graph, graph.getSingleObject(resource, ES.RouteCondition_HasRoute))); - cond = new RouteCondition(routePoints); + Resource routeResource = graph.getSingleObject(resource, ES.RouteCondition_HasRoute); + Set routePoints = new HashSet<>(ListUtils.toList(graph, routeResource)); + cond = new RouteCondition(resource, routeResource, routePoints); } else if (graph.isInstanceOf(resource, ES.AggregateCondition)) { - boolean isDisjunction = graph.isInstanceOf(resource, ES.Disjunction); Collection conditionResources = graph.getObjects(resource, ES.HasSubcondition); List conditions = new ArrayList<>(conditionResources.size()); for (Resource c : conditionResources) { @@ -175,23 +322,22 @@ public class ElementSelector { else throw new IllegalArgumentException("Unknown aggreate condition type " + graph.getURI(graph.getSingleType(resource))); - cond = new AggregateCondition(type, conditions); + cond = new AggregateCondition(resource, type, conditions); } else { throw new IllegalArgumentException("Unknown condition type " + graph.getURI(graph.getSingleType(resource))); } - cond.isInverse = graph.hasStatement(resource, ES.Condition_IsInverse, resource); return cond; } private static String buildExpression(ReadGraph graph, Resource r) throws DatabaseException { if (graph.isInstanceOf(r, ES.Selection)) { - String exp = "select " + buildExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) + - " from " + buildExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator)); + String exp = "select " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasSelector)) + + " from " + getExpression(graph, graph.getSingleObject(r, ES.Selection_HasGenerator)); Resource cond = graph.getPossibleObject(r, ES.Selection_HasCondition); - return cond != null ? exp + " where {" + buildExpression(graph, cond) + "}" : exp; + return cond != null ? exp + " where {" + getExpression(graph, cond) + "}" : exp; } else if (graph.isInstanceOf(r, ES.Condition)) { if (graph.isInstanceOf(r, ES.PropertyCondition)) { @@ -212,7 +358,7 @@ public class ElementSelector { List exps = new ArrayList<>(); Collection objects = graph.getObjects(r, ES.HasSubcondition); for (Resource c : objects) { - String exp = buildExpression(graph, c); + String exp = getExpression(graph, c); exps.add(objects.size() > 1 ? "{" + exp + "}" : exp); } String result = String.join(op, exps); @@ -300,16 +446,6 @@ public class ElementSelector { return result; } - private void buildSelection(ReadGraph graph) throws DatabaseException { - Resource selector = graph.getSingleObject(resource, ES.Selection_HasSelector); - Resource generator = graph.getSingleObject(resource, ES.Selection_HasGenerator); - Resource condition = graph.getPossibleObject(resource, ES.Selection_HasCondition); - - this.selector = buildSelector(graph, selector); - this.generator = buildGenerator(graph, generator); - this.condition = buildCondition(graph, condition); - } - private Collection filterElementsFrom(ReadGraph graph, Collection elements) throws DatabaseException { if (condition == null) return elements; @@ -326,59 +462,13 @@ public class ElementSelector { return selector.select(graph, filterElementsFrom(graph, generator.generate(graph, model))); } - static Variable getVariableForElement(ReadGraph graph, Resource element) throws DatabaseException { - Resource component = graph.getPossibleObject(element, MOD.ElementToComponent); - if (component != null) { - Variable var = Variables.getVariable(graph, component); - RVI realRvi = var.getRVI(graph); - - for (Resource activeModel : graph.syncRequest(new ActiveModels(Simantics.getProjectResource()))) { - for (Variable run : graph.syncRequest(new ActiveRuns(activeModel))) { - Variable v = realRvi.resolvePossible(graph, run); - if (v != null) { - return v; - } - } - Variable configuration = Variables.getPossibleConfigurationContext(graph, activeModel); - if (configuration != null) { - Variable v = realRvi.resolvePossible(graph, configuration); - if (v != null) { - return v; - } - } - } - } - - return null; - } - - static Double getPropertyValue(ReadGraph graph, Resource element, String propertyName) { - try { - Variable v = getVariableForElement(graph, element); - if (v != null) { - Number value = v.getPossiblePropertyValue(graph, propertyName); - if (value != null) - return value.doubleValue(); - } - - // No property found - try possible mapped element property as well - Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent); - if (mappedElement != null) - return getPropertyValue(graph, mappedElement, propertyName); - } - catch (DatabaseException e) { - } - - return null; - } - // Generators - static abstract class Generator { + public static abstract class Generator { abstract Collection generate(ReadGraph graph, Resource model) throws DatabaseException; } - static class ModelGenerator extends Generator { + public static class ModelGenerator extends Generator { @Override Collection generate(ReadGraph graph, Resource model) throws DatabaseException { Resource conf = graph.syncRequest(new Configuration(model)); @@ -397,8 +487,8 @@ public class ElementSelector { } } - static class DiagramGenerator extends Generator { - Resource diagram; + public static class DiagramGenerator extends Generator { + public Resource diagram; public DiagramGenerator(Resource diagram) { this.diagram = diagram; @@ -410,12 +500,12 @@ public class ElementSelector { } } - static class ExplicitGenerator extends Generator { + public static class ExplicitGenerator extends Generator { public ExplicitGenerator(Collection elements) { this.elements = elements; } - Collection elements; + public Collection elements; @Override Collection generate(ReadGraph graph, Resource model) { @@ -425,11 +515,11 @@ public class ElementSelector { // Selectors - static abstract class Selector { + public static abstract class Selector { abstract Collection select(ReadGraph graph, Collection elements); } - static class All extends Selector { + public static class All extends Selector { public All() { } @@ -439,16 +529,16 @@ public class ElementSelector { } } - static class PropertySelector extends Selector { + public static class PropertySelector extends Selector { public PropertySelector(boolean smallest, String propertyName, int resultCount) { this.smallest = smallest; this.propertyName = propertyName; this.resultCount = resultCount; } - boolean smallest; - String propertyName; - int resultCount; + public boolean smallest; + public String propertyName; + public int resultCount; @SuppressWarnings("unchecked") @Override @@ -486,22 +576,28 @@ public class ElementSelector { // Conditions - static abstract class Condition { - boolean isInverse; + public static abstract class Condition { + public Resource resource; + + Condition(Resource r) { + resource = r; + } + abstract boolean match(ReadGraph graph, Resource r) throws DatabaseException; } - static class PropertyCondition extends Condition { - public PropertyCondition(String propertyName, Double lowerLimit, Double upperLimit) { - super(); + public static class PropertyCondition extends Condition { + public PropertyCondition(Resource r, String propertyName, Double lowerLimit, Double upperLimit) { + super(r); + this.propertyName = propertyName; this.lowerLimit = lowerLimit; this.upperLimit = upperLimit; } - String propertyName; - Double lowerLimit; - Double upperLimit; + public String propertyName; + public Double lowerLimit; + public Double upperLimit; @Override boolean match(ReadGraph graph, Resource r) { @@ -510,9 +606,9 @@ public class ElementSelector { } } - static class RegionCondition extends Condition { - public RegionCondition(double[] region) { - super(); + public static class RegionCondition extends Condition { + public RegionCondition(Resource r, Resource regionResoruce, double[] region) { + super(r); this.region = region; Path2D path = new Path2D.Double(); @@ -524,8 +620,10 @@ public class ElementSelector { path.closePath(); this.path = path; + this.regionResource = regionResoruce; } + public Resource regionResource; double[] region; Path2D path; @@ -538,12 +636,14 @@ public class ElementSelector { } } - static class RouteCondition extends Condition { - public RouteCondition(Set routePoints) { - super(); + public static class RouteCondition extends Condition { + public RouteCondition(Resource r, Resource routeResource, Set routePoints) { + super(r); this.routePoints = routePoints; + this.routeResource = routeResource; } + public Resource routeResource; Set routePoints; @Override @@ -552,31 +652,17 @@ public class ElementSelector { } } - static class DiagramCondition extends Condition { - public DiagramCondition(Resource diagram) { - super(); - this.diagram = diagram; - } - - Resource diagram; - - @Override - boolean match(ReadGraph graph, Resource r) throws DatabaseException { - return graph.getSingleObject(r, L0.PartOf).equals(diagram); - } - } - - static class AggregateCondition extends Condition { - static enum Type { DISJUNCTION, CONJUNCTION, NEGATION }; + public static class AggregateCondition extends Condition { + public static enum Type { DISJUNCTION, CONJUNCTION, NEGATION }; - public AggregateCondition(Type type, List conditions) { - super(); + public AggregateCondition(Resource r, Type type, List conditions) { + super(r); this.type = type; this.conditions = conditions; } - Type type; - List conditions; + public Type type; + public List conditions; @Override boolean match(ReadGraph graph, Resource r) throws DatabaseException { @@ -610,4 +696,26 @@ public class ElementSelector { return new ElementSelector(graph, resource); } } + + public final static class SelectionExpressionRequest extends ResourceRead { + public SelectionExpressionRequest(Resource condition) { + super(condition); + } + + @Override + public String perform(ReadGraph graph) throws DatabaseException { + return ElementSelector.buildExpression(graph, resource); + } + } + + public static final class SelectionConditionRequest extends ResourceRead { + public SelectionConditionRequest(Resource resource) { + super(resource); + } + + @Override + public Condition perform(ReadGraph graph) throws DatabaseException { + return buildCondition(graph, resource); + } + } } diff --git a/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelectorTest.java b/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelectorTest.java new file mode 100644 index 00000000..9dc771ad --- /dev/null +++ b/org.simantics.district.selection/src/org/simantics/district/selection/ElementSelectorTest.java @@ -0,0 +1,283 @@ +package org.simantics.district.selection; + +//import static org.junit.Assert.*; +// +//import org.eclipse.core.runtime.NullProgressMonitor; +//import org.junit.AfterClass; +//import org.junit.Before; +//import org.junit.BeforeClass; +//import org.junit.Test; +//import org.simantics.Simantics; +//import org.simantics.db.Resource; +//import org.simantics.db.WriteGraph; +//import org.simantics.db.common.request.WriteRequest; +//import org.simantics.db.exception.DatabaseException; +//import org.simantics.db.testing.common.AcornTests; +//import org.simantics.layer0.Layer0; +// +//public class ElementSelectorTest { +// +// Resource selection; +// Resource generator; +// Resource selector; +// +// @Before +// public void setUp() throws DatabaseException { +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// selection = graph.newResource(); +// graph.claim(selection, L0.InstanceOf, ES.Selection); +// graph.claimLiteral(selection, L0.HasLabel, L0.String, "My Selection"); +// generator = graph.newResource(); +// graph.claim(selection, ES.Selection_HasGenerator, generator); +// selector = graph.newResource(); +// graph.claim(selection, ES.Selection_HasSelector, selector); +// } +// }); +// } +// +// @BeforeClass +// public static void initialize0() throws Exception { +// AcornTests.newSimanticsWorkspace(null, null); +// } +// +// @AfterClass +// public static void deinitialize0() throws Exception { +// Simantics.shutdown(new NullProgressMonitor()); +// } +// +// @Test +// public void testExpressionGeneration1() throws DatabaseException { +// +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// graph.claim(generator, L0.InstanceOf, ES.Generator_Model); +// graph.claim(selector, L0.InstanceOf, ES.Selector_NHighest); +// graph.claimLiteral(selector, ES.PropertySelector_HasSelectionPropertyName, L0.String, "myProperty"); +// graph.claimLiteral(selector, ES.PropertySelector_HasResultCount, L0.Integer, 10); +// } +// }); +// +// ElementSelector sel = Simantics.sync(new ElementSelector.ElementSelectorQuery(selection)); +// assertNotNull(sel); +// String expression = sel.expression; +// assertEquals("select top 10 of myProperty from model", expression); +// System.err.println(expression); +// } +// +// @Test +// public void testExpressionGeneration2() throws DatabaseException { +// +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// graph.claim(generator, L0.InstanceOf, ES.Generator_Model); +// graph.claim(selector, L0.InstanceOf, ES.Selector_NLowest); +// graph.claimLiteral(selector, ES.PropertySelector_HasSelectionPropertyName, L0.String, "criteria1"); +// graph.claimLiteral(selector, ES.PropertySelector_HasResultCount, L0.Integer, 20); +// } +// }); +// +// ElementSelector sel = Simantics.sync(new ElementSelector.ElementSelectorQuery(selection)); +// assertNotNull(sel); +// String expression = sel.expression; +// assertEquals("select bottom 20 of criteria1 from model", expression); +// System.err.println(expression); +// } +// +// @Test +// public void testExpressionGeneration3() throws DatabaseException { +// +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// graph.claim(generator, L0.InstanceOf, ES.Generator_Model); +// graph.claim(selector, L0.InstanceOf, ES.Selector_All); +// } +// }); +// +// ElementSelector sel = Simantics.sync(new ElementSelector.ElementSelectorQuery(selection)); +// assertNotNull(sel); +// String expression = sel.expression; +// assertEquals("select all from model", expression); +// System.err.println(expression); +// } +// +// @Test +// public void testExpressionGeneration4() throws DatabaseException { +// +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// graph.claim(generator, L0.InstanceOf, ES.Generator_Model); +// graph.claim(selector, L0.InstanceOf, ES.Selector_All); +// Resource condition = graph.newResource(); +// graph.claim(condition, L0.InstanceOf, ES.PropertyCondition); +// graph.claim(condition, ES.Selection_HasCondition_Inverse, selection); +// graph.claimLiteral(condition, ES.PropertyCondition_HasPropertyName, L0.String, "myProperty"); +// graph.claimLiteral(condition, ES.PropertyCondition_HasLowerLimit, L0.Double, 20.0); +// } +// }); +// +// ElementSelector sel = Simantics.sync(new ElementSelector.ElementSelectorQuery(selection)); +// assertNotNull(sel); +// String expression = sel.expression; +// assertEquals("select all from model where {20.0 < myProperty}", expression); +// System.err.println(expression); +// } +// +// @Test +// public void testExpressionGeneration5() throws DatabaseException { +// +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// graph.claim(generator, L0.InstanceOf, ES.Generator_Model); +// graph.claim(selector, L0.InstanceOf, ES.Selector_NLowest); +// graph.claimLiteral(selector, ES.PropertySelector_HasSelectionPropertyName, L0.String, "criteria1"); +// graph.claimLiteral(selector, ES.PropertySelector_HasResultCount, L0.Integer, 20); +// Resource condition = graph.newResource(); +// graph.claim(condition, L0.InstanceOf, ES.PropertyCondition); +// graph.claim(condition, ES.Selection_HasCondition_Inverse, selection); +// graph.claimLiteral(condition, ES.PropertyCondition_HasPropertyName, L0.String, "myProperty"); +// graph.claimLiteral(condition, ES.PropertyCondition_HasLowerLimit, L0.Double, 20.0); +// } +// }); +// +// ElementSelector sel = Simantics.sync(new ElementSelector.ElementSelectorQuery(selection)); +// assertNotNull(sel); +// String expression = sel.expression; +// assertEquals("select bottom 20 of criteria1 from model where {20.0 < myProperty}", expression); +// System.err.println(expression); +// } +// +// @Test +// public void testExpressionGeneration6() throws DatabaseException { +// +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// graph.claim(generator, L0.InstanceOf, ES.Generator_Model); +// graph.claim(selector, L0.InstanceOf, ES.Selector_NLowest); +// graph.claimLiteral(selector, ES.PropertySelector_HasSelectionPropertyName, L0.String, "criteria1"); +// graph.claimLiteral(selector, ES.PropertySelector_HasResultCount, L0.Integer, 20); +// Resource condition = graph.newResource(); +// graph.claim(condition, L0.InstanceOf, ES.Disjunction); +// graph.claim(condition, ES.Selection_HasCondition_Inverse, selection); +// Resource condition1 = graph.newResource(); +// graph.claim(condition1, L0.InstanceOf, ES.PropertyCondition); +// graph.claim(condition1, ES.HasSubcondition_Inverse, condition); +// graph.claimLiteral(condition1, ES.PropertyCondition_HasPropertyName, L0.String, "myProperty1"); +// graph.claimLiteral(condition1, ES.PropertyCondition_HasLowerLimit, L0.Double, 20.0); +// Resource condition2 = graph.newResource(); +// graph.claim(condition2, L0.InstanceOf, ES.PropertyCondition); +// graph.claim(condition2, ES.HasSubcondition_Inverse, condition); +// graph.claimLiteral(condition2, ES.PropertyCondition_HasPropertyName, L0.String, "myProperty2"); +// graph.claimLiteral(condition2, ES.PropertyCondition_HasLowerLimit, L0.Double, 0.0); +// graph.claimLiteral(condition2, ES.PropertyCondition_HasUpperLimit, L0.Double, 100.0); +// } +// }); +// +// ElementSelector sel = Simantics.sync(new ElementSelector.ElementSelectorQuery(selection)); +// assertNotNull(sel); +// String expression = sel.expression; +// assertEquals("select bottom 20 of criteria1 from model where {{20.0 < myProperty1} or {0.0 < myProperty2 < 100.0}}", expression); +// System.err.println(expression); +// } +// +// @Test +// public void testExpressionGeneration7() throws DatabaseException { +// +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// graph.claim(generator, L0.InstanceOf, ES.Generator_Explicit); +// for (int i = 0; i < 15; i++) { +// graph.claim(generator, ES.Generator_HasSelectedElement, graph.newResource()); +// } +// graph.claim(selector, L0.InstanceOf, ES.Selector_All); +// Resource condition = graph.newResource(); +// graph.claim(condition, L0.InstanceOf, ES.Disjunction); +// graph.claim(condition, ES.Selection_HasCondition_Inverse, selection); +// Resource condition1 = graph.newResource(); +// graph.claim(condition1, L0.InstanceOf, ES.PropertyCondition); +// graph.claim(condition1, ES.HasSubcondition_Inverse, condition); +// graph.claimLiteral(condition1, ES.PropertyCondition_HasPropertyName, L0.String, "myProperty1"); +// graph.claimLiteral(condition1, ES.PropertyCondition_HasLowerLimit, L0.Double, 20.0); +// Resource condition2 = graph.newResource(); +// graph.claim(condition2, L0.InstanceOf, ES.PropertyCondition); +// graph.claim(condition2, ES.HasSubcondition_Inverse, condition); +// graph.claimLiteral(condition2, ES.PropertyCondition_HasPropertyName, L0.String, "myProperty2"); +// graph.claimLiteral(condition2, ES.PropertyCondition_HasLowerLimit, L0.Double, 0.0); +// graph.claimLiteral(condition2, ES.PropertyCondition_HasUpperLimit, L0.Double, 100.0); +// } +// }); +// +// ElementSelector sel = Simantics.sync(new ElementSelector.ElementSelectorQuery(selection)); +// assertNotNull(sel); +// String expression = sel.expression; +// assertEquals("select all from where {{20.0 < myProperty1} or {0.0 < myProperty2 < 100.0}}", expression); +// System.err.println(expression); +// } +// +// @Test +// public void testExpressionGeneration8() throws DatabaseException { +// +// Simantics.sync(new WriteRequest() { +// @Override +// public void perform(WriteGraph graph) throws DatabaseException { +// Layer0 L0 = Layer0.getInstance(graph); +// ElementSelectionResource ES = ElementSelectionResource.getInstance(graph); +// +// graph.claim(generator, L0.InstanceOf, ES.Generator_Model); +// graph.claim(selector, L0.InstanceOf, ES.Selector_All); +// Resource condition = graph.newResource(); +// graph.claim(condition, L0.InstanceOf, ES.Conjunction); +// graph.claim(condition, ES.Selection_HasCondition_Inverse, selection); +// Resource condition1 = graph.newResource(); +// graph.claim(condition1, L0.InstanceOf, ES.PropertyCondition); +// graph.claim(condition1, ES.HasSubcondition_Inverse, condition); +// graph.claimLiteral(condition1, ES.PropertyCondition_HasPropertyName, L0.String, "myProperty1"); +// Resource condition2 = graph.newResource(); +// graph.claim(condition2, L0.InstanceOf, ES.RegionCondition); +// graph.claim(condition2, ES.HasSubcondition_Inverse, condition); +// Resource region = graph.newResource(); +// graph.claim(condition2, ES.RegionCondition_HasRegion, region); +// graph.claim(region, L0.InstanceOf, L0.Entity); +// graph.claimLiteral(region, L0.HasLabel, L0.String, "region1"); +// } +// }); +// +// ElementSelector sel = Simantics.sync(new ElementSelector.ElementSelectorQuery(selection)); +// assertNotNull(sel); +// String expression = sel.expression; +// assertEquals("select all from model where {{has property myProperty1} and {in region region1}}", expression); +// System.err.println(expression); +// } +//} diff --git a/org.simantics.district.ui.feature/feature.xml b/org.simantics.district.ui.feature/feature.xml index d4f241b2..d563d637 100644 --- a/org.simantics.district.ui.feature/feature.xml +++ b/org.simantics.district.ui.feature/feature.xml @@ -55,4 +55,11 @@ version="0.0.0" unpack="false"/> + + diff --git a/pom.xml b/pom.xml index 50cb2866..ac49440b 100644 --- a/pom.xml +++ b/pom.xml @@ -96,6 +96,7 @@ org.simantics.district.route.ontology org.simantics.district.route.ui org.simantics.district.selection + org.simantics.district.selection.ui org.simantics.maps.server org.simantics.maps.server.ui