]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/componentTypeEditor/DerivedPropertiesSection.java
41356de318c949215b97adf970394181703af925
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / componentTypeEditor / DerivedPropertiesSection.java
1 package org.simantics.modeling.ui.componentTypeEditor;\r
2 \r
3 import java.util.ArrayList;\r
4 import java.util.HashSet;\r
5 import java.util.List;\r
6 import java.util.Set;\r
7 \r
8 import org.eclipse.jface.layout.GridDataFactory;\r
9 import org.eclipse.jface.layout.GridLayoutFactory;\r
10 import org.eclipse.jface.layout.TableColumnLayout;\r
11 import org.eclipse.jface.viewers.ColumnWeightData;\r
12 import org.eclipse.swt.SWT;\r
13 import org.eclipse.swt.custom.TableEditor;\r
14 import org.eclipse.swt.events.MouseAdapter;\r
15 import org.eclipse.swt.events.MouseEvent;\r
16 import org.eclipse.swt.events.SelectionAdapter;\r
17 import org.eclipse.swt.events.SelectionEvent;\r
18 import org.eclipse.swt.graphics.Color;\r
19 import org.eclipse.swt.graphics.Rectangle;\r
20 import org.eclipse.swt.layout.FillLayout;\r
21 import org.eclipse.swt.widgets.Button;\r
22 import org.eclipse.swt.widgets.Composite;\r
23 import org.eclipse.swt.widgets.Control;\r
24 import org.eclipse.swt.widgets.Table;\r
25 import org.eclipse.swt.widgets.TableColumn;\r
26 import org.eclipse.swt.widgets.TableItem;\r
27 import org.eclipse.ui.forms.widgets.Form;\r
28 import org.eclipse.ui.forms.widgets.FormToolkit;\r
29 import org.eclipse.ui.forms.widgets.Section;\r
30 import org.simantics.Simantics;\r
31 import org.simantics.db.ReadGraph;\r
32 import org.simantics.db.RequestProcessor;\r
33 import org.simantics.db.Resource;\r
34 import org.simantics.db.WriteGraph;\r
35 import org.simantics.db.common.request.PossibleIndexRoot;\r
36 import org.simantics.db.common.request.UniqueRead;\r
37 import org.simantics.db.common.request.WriteRequest;\r
38 import org.simantics.db.exception.DatabaseException;\r
39 import org.simantics.layer0.Layer0;\r
40 import org.simantics.modeling.userComponent.ComponentTypeCommands;\r
41 import org.simantics.scl.runtime.function.Function4;\r
42 import org.simantics.structural.stubs.StructuralResource2;\r
43 \r
44 public class DerivedPropertiesSection implements ComponentTypeViewerSection {\r
45     private static final String[] COLUMN_NAMES = \r
46             new String[] {"Name", "Type", "Expression", "Label", "Description"};\r
47     private static final int[] COLUMN_LENGTHS =\r
48             new int[] { 120, 100, 100, 100, 100 };\r
49     private static final int[] COLUMN_WEIGHTS =\r
50             new int[] { 0, 0, 100, 0, 0 };\r
51     private static Function4<RequestProcessor, Resource, Resource, String, String> VALIDATE_MONITOR_EXPRESSION =\r
52             new Function4<RequestProcessor, Resource, Resource, String, String>() {\r
53         @Override\r
54         public String apply(RequestProcessor p0, Resource p1, Resource p2, String p3) {\r
55             return validateMonitorExpression(p0, p1, p2, p3);\r
56         }\r
57     };\r
58     \r
59     ComponentTypeViewerData data;\r
60     Table table;\r
61     TableColumn[] columns;\r
62     TableEditor editor;\r
63     Button newProperty;\r
64     Button removeProperty;\r
65     \r
66     Section section;\r
67     \r
68     public DerivedPropertiesSection(ComponentTypeViewerData data) {\r
69         this.data = data;\r
70         FormToolkit tk = data.tk;\r
71         Form form = data.form;\r
72         section = tk.createSection(form.getBody(), Section.TITLE_BAR | Section.EXPANDED);\r
73         section.setLayout(new FillLayout());\r
74         section.setText("Derived properties");\r
75 \r
76         Composite sectionBody = tk.createComposite(section);\r
77         GridLayoutFactory.fillDefaults().numColumns(2).applyTo(sectionBody);\r
78         section.setClient(sectionBody);\r
79 \r
80         Composite tableComposite = tk.createComposite(sectionBody);\r
81         GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tableComposite);\r
82         TableColumnLayout tcl = new TableColumnLayout();\r
83         tableComposite.setLayout(tcl);\r
84 \r
85         table = tk.createTable(tableComposite, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);\r
86         table.setLinesVisible(true);\r
87         table.setHeaderVisible(true);\r
88 \r
89         columns = new TableColumn[COLUMN_NAMES.length];\r
90         for(int i=0;i<COLUMN_NAMES.length;++i) {\r
91             TableColumn column = new TableColumn(table, SWT.NONE);\r
92             columns[i] = column;\r
93             tcl.setColumnData(column, new ColumnWeightData(COLUMN_WEIGHTS[i], COLUMN_LENGTHS[i], true));\r
94             column.setText(COLUMN_NAMES[i]);\r
95         }\r
96 \r
97         // Table editor\r
98         editor = new TableEditor(table);\r
99         editor.grabHorizontal = true;\r
100         editor.grabVertical = true;\r
101         editor.horizontalAlignment = SWT.LEFT;\r
102         table.addMouseListener(new MouseAdapter() {\r
103             @Override\r
104             public void mouseDown(MouseEvent e) {\r
105                 // Clean up any previous editor control\r
106                 Control oldEditor = editor.getEditor();\r
107                 if (oldEditor != null) oldEditor.dispose();\r
108 \r
109                 if (data.readOnly)\r
110                     return;\r
111 \r
112                 // Relative position\r
113                 Rectangle tableBounds = table.getClientArea();\r
114                 int rx = e.x - tableBounds.x;\r
115                 int ry = e.y - tableBounds.y;\r
116 \r
117                 // Find cell\r
118                 TableItem selectedItem = null;\r
119                 int selectedColumn = -1;\r
120                 Rectangle selectedItemBounds = null;\r
121                 for(TableItem item : table.getItems()) {\r
122                     for(int column = 0;column < COLUMN_NAMES.length;++column) {\r
123                         Rectangle bounds = item.getBounds(column);\r
124                         if(bounds.contains(rx, ry)) {\r
125                             selectedItemBounds = bounds;\r
126                             selectedItem = item;\r
127                             selectedColumn = column;\r
128                             break;\r
129                         }\r
130                     }\r
131                 }\r
132                 if(selectedItem == null) {\r
133                     return;\r
134                 }\r
135 \r
136                 // Table editor\r
137                 final int column = selectedColumn; \r
138                 final ComponentTypeViewerPropertyInfo propertyInfo = (ComponentTypeViewerPropertyInfo)selectedItem.getData();\r
139                 final Resource resource = propertyInfo.resource;\r
140                 switch (column) {\r
141                 case 0:\r
142                     data.editName(table, editor, propertyInfo, selectedItem, column, ComponentTypeViewerData.PROPERTY_NAME_PATTERN);\r
143                     break;\r
144 \r
145                 case 1:\r
146                     data.editType(table, editor, propertyInfo, selectedItem, column, false);\r
147                     break;\r
148 \r
149                 case 2:\r
150                     data.editValue(table, editor, propertyInfo, selectedItem, column, propertyInfo.immutable ? null : new StringWriter() {\r
151                         @Override\r
152                         public void perform(WriteGraph graph, String newValue) throws DatabaseException {\r
153                             ComponentTypeCommands.setMonitorExpression(graph, data.componentType, resource, newValue);\r
154                         }\r
155                     }, VALIDATE_MONITOR_EXPRESSION);\r
156                     break;\r
157 \r
158 //                case 3:\r
159 //                    editUnit(table2, editor2, propertyInfo, selectedItem, column);\r
160 //                    break;\r
161 \r
162                 case 3:\r
163                     data.editValue(table, editor, propertyInfo, selectedItem, column, propertyInfo.immutable ? null : new StringWriter() {\r
164                         @Override\r
165                         public void perform(WriteGraph graph, String newValue) throws DatabaseException {\r
166                             graph.markUndoPoint();\r
167                             String value = newValue.isEmpty() ? null : newValue;\r
168                             ComponentTypeCommands.setLabel(graph, resource, value);\r
169                         }\r
170                     }, null);\r
171                     break;\r
172 \r
173                 case 4:\r
174                     data.editMultilineText(table, editor, propertyInfo, selectedItem, selectedItemBounds, column, new StringWriter() {\r
175                         @Override\r
176                         public void perform(WriteGraph graph, String newValue) throws DatabaseException {\r
177                             graph.markUndoPoint();\r
178                             String value = newValue.isEmpty() ? null : newValue;\r
179                             ComponentTypeCommands.setDescription(graph, resource, value);\r
180                         }\r
181                     });\r
182                     break;\r
183                 }\r
184             }\r
185 \r
186         });\r
187 \r
188         // Buttons\r
189 \r
190         Composite buttons = tk.createComposite(sectionBody);\r
191         GridDataFactory.fillDefaults().applyTo(buttons);\r
192         GridLayoutFactory.fillDefaults().applyTo(buttons);\r
193 \r
194         newProperty = tk.createButton(buttons, "New property", SWT.PUSH);\r
195         GridDataFactory.fillDefaults().applyTo(newProperty);\r
196         removeProperty = tk.createButton(buttons, "Remove property", SWT.PUSH);\r
197         GridDataFactory.fillDefaults().applyTo(removeProperty);\r
198 \r
199         // Actions\r
200 \r
201         newProperty.addSelectionListener(new SelectionAdapter() {\r
202             @Override\r
203             public void widgetSelected(SelectionEvent e) {\r
204                 if(editor.getEditor() != null)\r
205                     editor.getEditor().dispose();\r
206                 Simantics.getSession().async(new WriteRequest() {\r
207                     @Override\r
208                     public void perform(WriteGraph graph)\r
209                             throws DatabaseException {\r
210                         ComponentTypeCommands.createMonitorPropertyWithDefaults(graph, data.componentType);\r
211                     }\r
212                 });\r
213             }\r
214         });\r
215 \r
216         removeProperty.addSelectionListener(new SelectionAdapter() {\r
217             @Override\r
218             public void widgetSelected(SelectionEvent e) {\r
219                 if(editor.getEditor() != null)\r
220                     editor.getEditor().dispose();\r
221                 final List<Resource> propertiesToBeRemoved = \r
222                         new ArrayList<>();\r
223                 for(TableItem item : table.getSelection())\r
224                     propertiesToBeRemoved.add(((ComponentTypeViewerPropertyInfo)item.getData()).resource);\r
225                 //System.out.println("remove " + propertiesToBeRemoved.size() + " resources");\r
226                 if(!propertiesToBeRemoved.isEmpty())\r
227                     Simantics.getSession().async(new WriteRequest() {\r
228                         @Override\r
229                         public void perform(WriteGraph graph)\r
230                                 throws DatabaseException {\r
231                             graph.markUndoPoint();\r
232                             for(Resource property : propertiesToBeRemoved)\r
233                                 ComponentTypeCommands.removeProperty(graph, data.componentType, property);\r
234                         }\r
235                     });\r
236             }\r
237         });\r
238     }\r
239 \r
240     @Override\r
241     public void setReadOnly(boolean readOnly) {\r
242         boolean e = !readOnly;\r
243         newProperty.setEnabled(e);\r
244         removeProperty.setEnabled(e);\r
245     }\r
246 \r
247     public static String validateMonitorExpression(final RequestProcessor processor, final Resource componentType, final Resource relation, final String expression) {\r
248 \r
249         if (expression.trim().isEmpty()) {\r
250             return "Expression is empty.";\r
251         }\r
252 \r
253         if (expression.trim().isEmpty()) {\r
254             return "Expression is empty.";\r
255         }\r
256         try {\r
257             return processor.sync(new UniqueRead<String>() {\r
258 \r
259                 @Override\r
260                 public String perform(ReadGraph graph) throws DatabaseException {\r
261 \r
262                     StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
263 \r
264                     Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(componentType));\r
265 \r
266                     for(Resource literal : graph.getAssertedObjects(componentType, relation)) {\r
267 \r
268                         try {\r
269                             // TODO validation\r
270                             if(graph.isInstanceOf(componentType, STR.ProceduralComponentType)) {\r
271                                 //Layer0 L0 = Layer0.getInstance(graph);\r
272                                 //Resource environment = graph.getPossibleObject(literal, L0.SCLValue_environment); \r
273                                 //ContextModule context = graph.sync(new TypeMonitorContextRequest(componentType));\r
274                                 //String SCLMain = graph.syncRequest(new SCLMainModuleRequest(indexRoot));\r
275                                 //CompilationContext cc = new CompilationContext(environment, context, SCLMain);\r
276                                 //graph.syncRequest(new ActualCompileRequest(expression, cc), TransientCacheListener.<CompiledExpression>instance());\r
277                             } else {\r
278                                 //CompilationContext cc = new CompileSCLMonitorRequest(literal, componentType, indexRoot).getContext(graph);\r
279                                 //graph.syncRequest(new ActualCompileRequest(expression, cc), TransientCacheListener.<CompiledExpression>instance());\r
280                                 //graph.syncRequest(new CompileSCLMonitorRequest(graph, context));\r
281                             }\r
282                             \r
283                         } catch (Exception e) {\r
284                             String msg = e.getMessage();\r
285                             int index = msg.indexOf(":");\r
286                             if(index > 0) msg = msg.substring(index);\r
287                             return msg;\r
288                         }\r
289                         \r
290                     }\r
291                     \r
292                     return null;\r
293                     \r
294                 }\r
295                 \r
296             });\r
297         } catch (DatabaseException e) {\r
298             e.printStackTrace();\r
299         }\r
300 \r
301         return null;\r
302 \r
303     }\r
304 \r
305     @Override\r
306     public void update(ComponentTypePropertiesResult result) {\r
307         if (table.isDisposed())\r
308             return;\r
309 \r
310         Set<ComponentTypeViewerPropertyInfo> selected = new HashSet<>();\r
311         List<TableItem> selectedItems = new ArrayList<TableItem>(selected.size());\r
312         for (int i : table.getSelectionIndices()) {\r
313             TableItem item = table.getItem(i);\r
314             selected.add((ComponentTypeViewerPropertyInfo) item.getData());\r
315         }\r
316         \r
317         int topIndex = table.getTopIndex();\r
318         table.removeAll();\r
319         if(editor.getEditor() != null)\r
320             editor.getEditor().dispose();\r
321         \r
322         for(ComponentTypeViewerPropertyInfo info : result.getProperties()) {\r
323             boolean immutable = result.isImmutable() || info.immutable;\r
324             Color fg = immutable ? table.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY) : null;\r
325             if(info.sectionSpecificData != MONITOR)\r
326                 continue;\r
327 \r
328             TableItem item = new TableItem(table, SWT.NONE);\r
329 \r
330             item.setText(0, info.valid != null ? info.name + " (!)" : info.name);\r
331             item.setText(1, info.type);\r
332             item.setText(2, info.expression);\r
333             //item.setText(3, unitStr(info));\r
334             item.setText(3, info.label);\r
335             item.setText(4, info.description);\r
336 \r
337             item.setForeground(fg);\r
338 \r
339             item.setData(info);\r
340 \r
341             if (selected.contains(info))\r
342                 selectedItems.add(item);\r
343         }\r
344         \r
345         table.setTopIndex(topIndex);\r
346         table.setSelection(selectedItems.toArray(new TableItem[selectedItems.size()]));\r
347         table.redraw();\r
348     }\r
349 \r
350     @Override\r
351     public Section getSection() {\r
352         return section;\r
353     }\r
354 \r
355     @Override\r
356     public double getPriority() {\r
357         return 100.0;\r
358     }\r
359 \r
360     private static final Object MONITOR = new Object();\r
361     \r
362     @Override\r
363     public Object getSectionSpecificData(ReadGraph graph,\r
364             ComponentTypeViewerPropertyInfo info) throws DatabaseException {\r
365         Layer0 L0 = Layer0.getInstance(graph);\r
366         StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
367         Resource range = graph.getPossibleObject(info.resource, L0.HasRange);\r
368         if(range != null && graph.isInstanceOf(range, STR.MonitorValueType))\r
369             return MONITOR;\r
370         else\r
371             return null;\r
372     }\r
373     \r
374     @Override\r
375     public double getDataPriority() {\r
376         return 100.0;\r
377     }\r
378 \r
379 }\r