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.jface.window.DefaultToolTip;
13 import org.eclipse.jface.window.ToolTip;
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.custom.TableEditor;
16 import org.eclipse.swt.events.MouseAdapter;
17 import org.eclipse.swt.events.MouseEvent;
18 import org.eclipse.swt.events.SelectionAdapter;
19 import org.eclipse.swt.events.SelectionEvent;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.Point;
22 import org.eclipse.swt.graphics.Rectangle;
23 import org.eclipse.swt.layout.FillLayout;
24 import org.eclipse.swt.widgets.Button;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.Control;
27 import org.eclipse.swt.widgets.Event;
28 import org.eclipse.swt.widgets.Table;
29 import org.eclipse.swt.widgets.TableColumn;
30 import org.eclipse.swt.widgets.TableItem;
31 import org.eclipse.ui.forms.widgets.Form;
32 import org.eclipse.ui.forms.widgets.FormToolkit;
33 import org.eclipse.ui.forms.widgets.Section;
34 import org.simantics.Simantics;
35 import org.simantics.db.ReadGraph;
36 import org.simantics.db.RequestProcessor;
37 import org.simantics.db.Resource;
38 import org.simantics.db.WriteGraph;
39 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
40 import org.simantics.db.common.request.UniqueRead;
41 import org.simantics.db.common.request.WriteRequest;
42 import org.simantics.db.exception.DatabaseException;
43 import org.simantics.db.layer0.request.PropertyInfo;
44 import org.simantics.db.layer0.request.PropertyInfoRequest;
45 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
46 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
47 import org.simantics.db.layer0.variable.Variable;
48 import org.simantics.layer0.Layer0;
49 import org.simantics.modeling.scl.CompileProceduralSCLMonitorRequest;
50 import org.simantics.modeling.scl.CompileSCLMonitorRequest;
51 import org.simantics.modeling.userComponent.ComponentTypeCommands;
52 import org.simantics.scl.runtime.SCLContext;
53 import org.simantics.scl.runtime.function.Function1;
54 import org.simantics.scl.runtime.function.Function4;
55 import org.simantics.structural.stubs.StructuralResource2;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
59 public class DerivedPropertiesSection implements ComponentTypeViewerSection {
60 private static final String[] COLUMN_NAMES = {
61 Messages.DerivedPropertiesSection_Name,
62 Messages.DerivedPropertiesSection_Type,
63 Messages.DerivedPropertiesSection_Expression,
64 Messages.DerivedPropertiesSection_Unit,
65 Messages.DerivedPropertiesSection_Label,
66 Messages.DerivedPropertiesSection_Description
68 private static final int[] COLUMN_LENGTHS =
69 new int[] { 120, 100, 100, 70, 100, 100 };
70 private static final int[] COLUMN_WEIGHTS =
71 new int[] { 0, 0, 100, 0, 0, 0 };
72 private static Function4<RequestProcessor, Resource, Resource, String, String> VALIDATE_MONITOR_EXPRESSION =
73 new Function4<RequestProcessor, Resource, Resource, String, String>() {
75 public String apply(RequestProcessor p0, Resource p1, Resource p2, String p3) {
76 return validateMonitorExpression(p0, p1, p2, p3);
80 private static final Logger LOGGER = LoggerFactory.getLogger(DerivedPropertiesSection.class);
82 ComponentTypeViewerData data;
84 TableColumn[] columns;
87 Button removeProperty;
91 public DerivedPropertiesSection(ComponentTypeViewerData data) {
93 FormToolkit tk = data.tk;
94 Form form = data.form;
95 section = tk.createSection(form.getBody(), Section.TITLE_BAR | Section.EXPANDED);
96 section.setLayout(new FillLayout());
97 section.setText(Messages.DerivedPropertiesSection_DerivedProperties);
99 Composite sectionBody = tk.createComposite(section);
100 GridLayoutFactory.fillDefaults().numColumns(2).applyTo(sectionBody);
101 section.setClient(sectionBody);
103 Composite tableComposite = tk.createComposite(sectionBody);
104 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tableComposite);
105 TableColumnLayout tcl = new TableColumnLayout();
106 tableComposite.setLayout(tcl);
108 table = tk.createTable(tableComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);
109 table.setLinesVisible(true);
110 table.setHeaderVisible(true);
112 columns = new TableColumn[COLUMN_NAMES.length];
113 for(int i=0;i<COLUMN_NAMES.length;++i) {
114 TableColumn column = new TableColumn(table, SWT.NONE);
116 tcl.setColumnData(column, new ColumnWeightData(COLUMN_WEIGHTS[i], COLUMN_LENGTHS[i], true));
117 column.setText(COLUMN_NAMES[i]);
121 editor = new TableEditor(table);
122 editor.grabHorizontal = true;
123 editor.grabVertical = true;
124 editor.horizontalAlignment = SWT.LEFT;
125 table.addMouseListener(new MouseAdapter() {
127 public void mouseDown(MouseEvent e) {
128 // Clean up any previous editor control
129 Control oldEditor = editor.getEditor();
130 if (oldEditor != null) oldEditor.dispose();
136 Rectangle tableBounds = table.getClientArea();
137 int rx = e.x - tableBounds.x;
138 int ry = e.y - tableBounds.y;
141 TableItem selectedItem = null;
142 int selectedColumn = -1;
143 Rectangle selectedItemBounds = null;
144 for(TableItem item : table.getItems()) {
145 for(int column = 0;column < COLUMN_NAMES.length;++column) {
146 Rectangle bounds = item.getBounds(column);
147 if(bounds.contains(rx, ry)) {
148 selectedItemBounds = bounds;
150 selectedColumn = column;
155 if(selectedItem == null) {
160 final int column = selectedColumn;
161 final ComponentTypeViewerPropertyInfo propertyInfo = (ComponentTypeViewerPropertyInfo)selectedItem.getData();
162 final Resource resource = propertyInfo.resource;
165 data.editName(table, editor, propertyInfo, selectedItem, column, ComponentTypeViewerData.PROPERTY_NAME_PATTERN);
169 data.editType(table, editor, propertyInfo, selectedItem, column, null, false);
173 data.editValue(table, editor, propertyInfo, selectedItem, column, propertyInfo.immutable ? null : new StringWriter() {
175 public void perform(WriteGraph graph, String newValue) throws DatabaseException {
176 ComponentTypeCommands.setMonitorExpression(graph, data.componentType, resource, newValue);
178 }, VALIDATE_MONITOR_EXPRESSION);
182 data.editUnit(table, editor, propertyInfo, selectedItem, column);
186 data.editValue(table, editor, propertyInfo, selectedItem, column, propertyInfo.immutable ? null : new StringWriter() {
188 public void perform(WriteGraph graph, String newValue) throws DatabaseException {
189 graph.markUndoPoint();
190 String value = newValue.isEmpty() ? null : newValue;
191 ComponentTypeCommands.setLabel(graph, resource, value);
197 data.editMultilineText(table, editor, propertyInfo, selectedItem, selectedItemBounds, column, new StringWriter() {
199 public void perform(WriteGraph graph, String newValue) throws DatabaseException {
200 graph.markUndoPoint();
201 String value = newValue.isEmpty() ? null : newValue;
202 ComponentTypeCommands.setDescription(graph, resource, value);
213 Composite buttons = tk.createComposite(sectionBody);
214 GridDataFactory.fillDefaults().applyTo(buttons);
215 GridLayoutFactory.fillDefaults().applyTo(buttons);
217 newProperty = tk.createButton(buttons, Messages.DerivedPropertiesSection_NewProperty, SWT.PUSH);
218 GridDataFactory.fillDefaults().applyTo(newProperty);
219 removeProperty = tk.createButton(buttons, Messages.DerivedPropertiesSection_RemoveProperty, SWT.PUSH);
220 GridDataFactory.fillDefaults().applyTo(removeProperty);
224 newProperty.addSelectionListener(new SelectionAdapter() {
226 public void widgetSelected(SelectionEvent e) {
227 if(editor.getEditor() != null)
228 editor.getEditor().dispose();
229 Simantics.getSession().async(new WriteRequest() {
231 public void perform(WriteGraph graph)
232 throws DatabaseException {
233 ComponentTypeCommands.createMonitorPropertyWithDefaults(graph, data.componentType);
239 removeProperty.addSelectionListener(new SelectionAdapter() {
241 public void widgetSelected(SelectionEvent e) {
242 if(editor.getEditor() != null)
243 editor.getEditor().dispose();
244 final List<Resource> propertiesToBeRemoved =
246 for(TableItem item : table.getSelection())
247 propertiesToBeRemoved.add(((ComponentTypeViewerPropertyInfo)item.getData()).resource);
248 //System.out.println("remove " + propertiesToBeRemoved.size() + " resources");
249 if(!propertiesToBeRemoved.isEmpty())
250 Simantics.getSession().async(new WriteRequest() {
252 public void perform(WriteGraph graph)
253 throws DatabaseException {
254 graph.markUndoPoint();
255 for(Resource property : propertiesToBeRemoved)
256 ComponentTypeCommands.removeProperty(graph, data.componentType, property);
264 public void setReadOnly(boolean readOnly) {
265 boolean e = !readOnly;
266 newProperty.setEnabled(e);
267 removeProperty.setEnabled(e);
270 public static String validateMonitorExpression(final RequestProcessor processor, final Resource componentType, final Resource relation, final String expression) {
272 if (expression.trim().isEmpty()) {
273 return Messages.DerivedPropertiesSection_ExpressionIsEmpty;
276 if (expression.trim().isEmpty()) {
277 return Messages.DerivedPropertiesSection_ExpressionIsEmpty;
280 return processor.sync(new UniqueRead<String>() {
283 public String perform(ReadGraph graph) throws DatabaseException {
285 StructuralResource2 STR = StructuralResource2.getInstance(graph);
287 // TODO: this is a bit hackish but should get the job done in most parts and
288 // importantly indicates something for the user
289 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheAsyncListener.<PropertyInfo>instance());
290 Variable parent = new StandardGraphChildVariable(null, null, componentType) {
292 public Resource getType(ReadGraph graph) throws DatabaseException {
293 return componentType;
296 public Variable getPossibleProperty(ReadGraph graph, String name) throws DatabaseException {
297 Variable prop = super.getPossibleProperty(graph, name);
301 return getChild(graph, name);
306 for(Resource literal : graph.getAssertedObjects(componentType, relation)) {
309 Variable context = new StandardGraphPropertyVariable(parent, null, null, info, literal);
310 if(graph.isInstanceOf(componentType, STR.ProceduralComponentType)) {
311 CompileProceduralSCLMonitorRequest.compileAndEvaluate(graph, context);
313 compileAndEvaluate(graph, context, expression);
316 } catch (Exception e) {
317 String msg = e.getMessage();
318 int index = msg.indexOf(":"); //$NON-NLS-1$
319 if(index > 0) msg = msg.substring(index);
327 } catch (DatabaseException e) {
328 LOGGER.error("Could not validate ", e);
333 public static void compileAndEvaluate(ReadGraph graph, Variable context, String expression) throws DatabaseException {
334 SCLContext sclContext = SCLContext.getCurrent();
335 Object oldGraph = sclContext.get("graph");
337 CompileSCLMonitorRequest compileSCLMonitorRequest = new ValidationCompilationRequest(graph, context, expression);
338 Function1<Variable,Object> exp = graph.syncRequest(compileSCLMonitorRequest);
339 sclContext.put("graph", graph);
340 //return exp.apply(context.getParent(graph));
341 } catch (DatabaseException e) {
342 throw (DatabaseException)e;
343 } catch (Throwable t) {
344 throw new DatabaseException(t);
346 sclContext.put("graph", oldGraph);
351 public void update(ComponentTypePropertiesResult result) {
352 if (table.isDisposed())
355 Set<ComponentTypeViewerPropertyInfo> selected = new HashSet<>();
356 List<TableItem> selectedItems = new ArrayList<TableItem>(selected.size());
357 for (int i : table.getSelectionIndices()) {
358 TableItem item = table.getItem(i);
359 selected.add((ComponentTypeViewerPropertyInfo) item.getData());
362 int topIndex = table.getTopIndex();
364 if(editor.getEditor() != null)
365 editor.getEditor().dispose();
367 for(ComponentTypeViewerPropertyInfo info : result.getProperties()) {
368 boolean immutable = result.isImmutable() || info.immutable;
369 Color fg = immutable ? table.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY) : null;
370 if(info.sectionSpecificData != MONITOR)
373 TableItem item = new TableItem(table, SWT.NONE);
375 item.setText(0, info.valid != null ? info.name + " (!)" : info.name); //$NON-NLS-1$
376 item.setText(1, info.type);
377 item.setText(2, info.expression);
378 item.setText(3, info.unitString());
379 item.setText(4, info.label);
380 item.setText(5, info.description);
382 if (info.valid != null)
383 item.setBackground(table.getDisplay().getSystemColor(SWT.COLOR_RED));
385 item.setForeground(fg);
389 if (selected.contains(info))
390 selectedItems.add(item);
393 new DefaultToolTip(table, ToolTip.NO_RECREATE, false) {
396 protected boolean shouldCreateToolTip(Event event) {
397 TableItem item = table.getItem(new Point(event.x, event.y));
399 ComponentTypeViewerPropertyInfo info = (ComponentTypeViewerPropertyInfo) item.getData();
400 return info.valid != null;
406 protected String getText(Event event) {
407 TableItem item = table.getItem(new Point(event.x, event.y));
409 ComponentTypeViewerPropertyInfo info = (ComponentTypeViewerPropertyInfo) item.getData();
410 return info.valid.replaceAll("\n", "");
412 return super.getText(event);
416 table.setTopIndex(topIndex);
417 table.setSelection(selectedItems.toArray(new TableItem[selectedItems.size()]));
422 public Section getSection() {
427 public double getPriority() {
431 private static final Object MONITOR = new Object();
434 public Object getSectionSpecificData(ReadGraph graph,
435 ComponentTypeViewerPropertyInfo info) throws DatabaseException {
436 Layer0 L0 = Layer0.getInstance(graph);
437 StructuralResource2 STR = StructuralResource2.getInstance(graph);
438 Resource range = graph.getPossibleObject(info.resource, L0.HasRange);
439 if(range != null && graph.isInstanceOf(range, STR.MonitorValueType))
446 public double getDataPriority() {
450 private static final class ValidationCompilationRequest extends CompileSCLMonitorRequest {
451 private final String expression;
453 private ValidationCompilationRequest(ReadGraph graph, Variable context, String expression)
454 throws DatabaseException {
455 super(graph, context);
456 this.expression = expression;
460 protected String getExpressionText(ReadGraph graph) throws DatabaseException {
465 public int hashCode() {
466 return super.hashCode() + 37 * expression.hashCode();
470 public boolean equals(Object obj) {
471 return super.equals(obj) && ((ValidationCompilationRequest)obj).expression.equals(expression);