1 package org.simantics.modeling.ui.componentTypeEditor;
3 import java.util.ArrayList;
4 import java.util.HashSet;
8 import org.eclipse.jface.layout.GridDataFactory;
9 import org.eclipse.jface.layout.GridLayoutFactory;
10 import org.eclipse.jface.layout.TableColumnLayout;
11 import org.eclipse.jface.viewers.ColumnWeightData;
12 import org.eclipse.swt.SWT;
13 import org.eclipse.swt.custom.TableEditor;
14 import org.eclipse.swt.events.MouseAdapter;
15 import org.eclipse.swt.events.MouseEvent;
16 import org.eclipse.swt.events.SelectionAdapter;
17 import org.eclipse.swt.events.SelectionEvent;
18 import org.eclipse.swt.graphics.Color;
19 import org.eclipse.swt.graphics.Rectangle;
20 import org.eclipse.swt.layout.FillLayout;
21 import org.eclipse.swt.widgets.Button;
22 import org.eclipse.swt.widgets.Composite;
23 import org.eclipse.swt.widgets.Control;
24 import org.eclipse.swt.widgets.Table;
25 import org.eclipse.swt.widgets.TableColumn;
26 import org.eclipse.swt.widgets.TableItem;
27 import org.eclipse.ui.forms.widgets.Form;
28 import org.eclipse.ui.forms.widgets.FormToolkit;
29 import org.eclipse.ui.forms.widgets.Section;
30 import org.simantics.Simantics;
31 import org.simantics.db.ReadGraph;
32 import org.simantics.db.RequestProcessor;
33 import org.simantics.db.Resource;
34 import org.simantics.db.WriteGraph;
35 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
36 import org.simantics.db.common.request.UniqueRead;
37 import org.simantics.db.common.request.WriteRequest;
38 import org.simantics.db.exception.DatabaseException;
39 import org.simantics.db.layer0.request.PropertyInfo;
40 import org.simantics.db.layer0.request.PropertyInfoRequest;
41 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
42 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
43 import org.simantics.db.layer0.variable.Variable;
44 import org.simantics.layer0.Layer0;
45 import org.simantics.modeling.scl.CompileProceduralSCLMonitorRequest;
46 import org.simantics.modeling.scl.CompileSCLMonitorRequest;
47 import org.simantics.modeling.userComponent.ComponentTypeCommands;
48 import org.simantics.scl.runtime.SCLContext;
49 import org.simantics.scl.runtime.function.Function1;
50 import org.simantics.scl.runtime.function.Function4;
51 import org.simantics.structural.stubs.StructuralResource2;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 public class DerivedPropertiesSection implements ComponentTypeViewerSection {
56 private static final String[] COLUMN_NAMES =
57 new String[] {"Name", "Type", "Expression", "Unit", "Label", "Description"};
58 private static final int[] COLUMN_LENGTHS =
59 new int[] { 120, 100, 100, 70, 100, 100 };
60 private static final int[] COLUMN_WEIGHTS =
61 new int[] { 0, 0, 100, 0, 0, 0 };
62 private static Function4<RequestProcessor, Resource, Resource, String, String> VALIDATE_MONITOR_EXPRESSION =
63 new Function4<RequestProcessor, Resource, Resource, String, String>() {
65 public String apply(RequestProcessor p0, Resource p1, Resource p2, String p3) {
66 return validateMonitorExpression(p0, p1, p2, p3);
70 private static final Logger LOGGER = LoggerFactory.getLogger(DerivedPropertiesSection.class);
72 ComponentTypeViewerData data;
74 TableColumn[] columns;
77 Button removeProperty;
81 public DerivedPropertiesSection(ComponentTypeViewerData data) {
83 FormToolkit tk = data.tk;
84 Form form = data.form;
85 section = tk.createSection(form.getBody(), Section.TITLE_BAR | Section.EXPANDED);
86 section.setLayout(new FillLayout());
87 section.setText("Derived properties");
89 Composite sectionBody = tk.createComposite(section);
90 GridLayoutFactory.fillDefaults().numColumns(2).applyTo(sectionBody);
91 section.setClient(sectionBody);
93 Composite tableComposite = tk.createComposite(sectionBody);
94 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tableComposite);
95 TableColumnLayout tcl = new TableColumnLayout();
96 tableComposite.setLayout(tcl);
98 table = tk.createTable(tableComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);
99 table.setLinesVisible(true);
100 table.setHeaderVisible(true);
102 columns = new TableColumn[COLUMN_NAMES.length];
103 for(int i=0;i<COLUMN_NAMES.length;++i) {
104 TableColumn column = new TableColumn(table, SWT.NONE);
106 tcl.setColumnData(column, new ColumnWeightData(COLUMN_WEIGHTS[i], COLUMN_LENGTHS[i], true));
107 column.setText(COLUMN_NAMES[i]);
111 editor = new TableEditor(table);
112 editor.grabHorizontal = true;
113 editor.grabVertical = true;
114 editor.horizontalAlignment = SWT.LEFT;
115 table.addMouseListener(new MouseAdapter() {
117 public void mouseDown(MouseEvent e) {
118 // Clean up any previous editor control
119 Control oldEditor = editor.getEditor();
120 if (oldEditor != null) oldEditor.dispose();
126 Rectangle tableBounds = table.getClientArea();
127 int rx = e.x - tableBounds.x;
128 int ry = e.y - tableBounds.y;
131 TableItem selectedItem = null;
132 int selectedColumn = -1;
133 Rectangle selectedItemBounds = null;
134 for(TableItem item : table.getItems()) {
135 for(int column = 0;column < COLUMN_NAMES.length;++column) {
136 Rectangle bounds = item.getBounds(column);
137 if(bounds.contains(rx, ry)) {
138 selectedItemBounds = bounds;
140 selectedColumn = column;
145 if(selectedItem == null) {
150 final int column = selectedColumn;
151 final ComponentTypeViewerPropertyInfo propertyInfo = (ComponentTypeViewerPropertyInfo)selectedItem.getData();
152 final Resource resource = propertyInfo.resource;
155 data.editName(table, editor, propertyInfo, selectedItem, column, ComponentTypeViewerData.PROPERTY_NAME_PATTERN);
159 data.editType(table, editor, propertyInfo, selectedItem, column, false);
163 data.editValue(table, editor, propertyInfo, selectedItem, column, propertyInfo.immutable ? null : new StringWriter() {
165 public void perform(WriteGraph graph, String newValue) throws DatabaseException {
166 ComponentTypeCommands.setMonitorExpression(graph, data.componentType, resource, newValue);
168 }, VALIDATE_MONITOR_EXPRESSION);
172 data.editUnit(table, editor, propertyInfo, selectedItem, column);
176 data.editValue(table, editor, propertyInfo, selectedItem, column, propertyInfo.immutable ? null : new StringWriter() {
178 public void perform(WriteGraph graph, String newValue) throws DatabaseException {
179 graph.markUndoPoint();
180 String value = newValue.isEmpty() ? null : newValue;
181 ComponentTypeCommands.setLabel(graph, resource, value);
187 data.editMultilineText(table, editor, propertyInfo, selectedItem, selectedItemBounds, column, new StringWriter() {
189 public void perform(WriteGraph graph, String newValue) throws DatabaseException {
190 graph.markUndoPoint();
191 String value = newValue.isEmpty() ? null : newValue;
192 ComponentTypeCommands.setDescription(graph, resource, value);
203 Composite buttons = tk.createComposite(sectionBody);
204 GridDataFactory.fillDefaults().applyTo(buttons);
205 GridLayoutFactory.fillDefaults().applyTo(buttons);
207 newProperty = tk.createButton(buttons, "New property", SWT.PUSH);
208 GridDataFactory.fillDefaults().applyTo(newProperty);
209 removeProperty = tk.createButton(buttons, "Remove property", SWT.PUSH);
210 GridDataFactory.fillDefaults().applyTo(removeProperty);
214 newProperty.addSelectionListener(new SelectionAdapter() {
216 public void widgetSelected(SelectionEvent e) {
217 if(editor.getEditor() != null)
218 editor.getEditor().dispose();
219 Simantics.getSession().async(new WriteRequest() {
221 public void perform(WriteGraph graph)
222 throws DatabaseException {
223 ComponentTypeCommands.createMonitorPropertyWithDefaults(graph, data.componentType);
229 removeProperty.addSelectionListener(new SelectionAdapter() {
231 public void widgetSelected(SelectionEvent e) {
232 if(editor.getEditor() != null)
233 editor.getEditor().dispose();
234 final List<Resource> propertiesToBeRemoved =
236 for(TableItem item : table.getSelection())
237 propertiesToBeRemoved.add(((ComponentTypeViewerPropertyInfo)item.getData()).resource);
238 //System.out.println("remove " + propertiesToBeRemoved.size() + " resources");
239 if(!propertiesToBeRemoved.isEmpty())
240 Simantics.getSession().async(new WriteRequest() {
242 public void perform(WriteGraph graph)
243 throws DatabaseException {
244 graph.markUndoPoint();
245 for(Resource property : propertiesToBeRemoved)
246 ComponentTypeCommands.removeProperty(graph, data.componentType, property);
254 public void setReadOnly(boolean readOnly) {
255 boolean e = !readOnly;
256 newProperty.setEnabled(e);
257 removeProperty.setEnabled(e);
260 public static String validateMonitorExpression(final RequestProcessor processor, final Resource componentType, final Resource relation, final String expression) {
262 if (expression.trim().isEmpty()) {
263 return "Expression is empty.";
266 if (expression.trim().isEmpty()) {
267 return "Expression is empty.";
270 return processor.sync(new UniqueRead<String>() {
273 public String perform(ReadGraph graph) throws DatabaseException {
275 StructuralResource2 STR = StructuralResource2.getInstance(graph);
277 // TODO: this is a bit hackish but should get the job done in most parts and
278 // importantly indicates something for the user
279 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheAsyncListener.<PropertyInfo>instance());
280 Variable parent = new StandardGraphChildVariable(null, null, componentType) {
282 public Resource getType(ReadGraph graph) throws DatabaseException {
283 return componentType;
286 public Variable getPossibleProperty(ReadGraph graph, String name) throws DatabaseException {
287 Variable prop = super.getPossibleProperty(graph, name);
291 return getChild(graph, name);
296 for(Resource literal : graph.getAssertedObjects(componentType, relation)) {
299 Variable context = new StandardGraphPropertyVariable(parent, null, null, info, literal);
300 if(graph.isInstanceOf(componentType, STR.ProceduralComponentType)) {
301 CompileProceduralSCLMonitorRequest.compileAndEvaluate(graph, context);
303 compileAndEvaluate(graph, context, expression);
306 } catch (Exception e) {
307 String msg = e.getMessage();
308 int index = msg.indexOf(":");
309 if(index > 0) msg = msg.substring(index);
317 } catch (DatabaseException e) {
318 LOGGER.error("Could not validate ", e);
323 public static void compileAndEvaluate(ReadGraph graph, Variable context, String expression) throws DatabaseException {
324 SCLContext sclContext = SCLContext.getCurrent();
325 Object oldGraph = sclContext.get("graph");
327 CompileSCLMonitorRequest compileSCLMonitorRequest = new CompileSCLMonitorRequest(graph, context) {
329 protected String getExpressionText(ReadGraph graph) throws DatabaseException {
333 Function1<Variable,Object> exp = graph.syncRequest(compileSCLMonitorRequest);
334 sclContext.put("graph", graph);
335 //return exp.apply(context.getParent(graph));
336 } catch (DatabaseException e) {
337 throw (DatabaseException)e;
338 } catch (Throwable t) {
339 throw new DatabaseException(t);
341 sclContext.put("graph", oldGraph);
346 public void update(ComponentTypePropertiesResult result) {
347 if (table.isDisposed())
350 Set<ComponentTypeViewerPropertyInfo> selected = new HashSet<>();
351 List<TableItem> selectedItems = new ArrayList<TableItem>(selected.size());
352 for (int i : table.getSelectionIndices()) {
353 TableItem item = table.getItem(i);
354 selected.add((ComponentTypeViewerPropertyInfo) item.getData());
357 int topIndex = table.getTopIndex();
359 if(editor.getEditor() != null)
360 editor.getEditor().dispose();
362 for(ComponentTypeViewerPropertyInfo info : result.getProperties()) {
363 boolean immutable = result.isImmutable() || info.immutable;
364 Color fg = immutable ? table.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY) : null;
365 if(info.sectionSpecificData != MONITOR)
368 TableItem item = new TableItem(table, SWT.NONE);
370 item.setText(0, info.valid != null ? info.name + " (!)" : info.name);
371 item.setText(1, info.type);
372 item.setText(2, info.expression);
373 item.setText(3, info.unitString());
374 item.setText(4, info.label);
375 item.setText(5, info.description);
377 item.setForeground(fg);
381 if (selected.contains(info))
382 selectedItems.add(item);
385 table.setTopIndex(topIndex);
386 table.setSelection(selectedItems.toArray(new TableItem[selectedItems.size()]));
391 public Section getSection() {
396 public double getPriority() {
400 private static final Object MONITOR = new Object();
403 public Object getSectionSpecificData(ReadGraph graph,
404 ComponentTypeViewerPropertyInfo info) throws DatabaseException {
405 Layer0 L0 = Layer0.getInstance(graph);
406 StructuralResource2 STR = StructuralResource2.getInstance(graph);
407 Resource range = graph.getPossibleObject(info.resource, L0.HasRange);
408 if(range != null && graph.isInstanceOf(range, STR.MonitorValueType))
415 public double getDataPriority() {