]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/visualisations/DynamicVisualisationsUI.java
Add connected components to visualisation from profiles
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / visualisations / DynamicVisualisationsUI.java
1 package org.simantics.district.network.ui.visualisations;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Map.Entry;
9 import java.util.Objects;
10 import java.util.Optional;
11 import java.util.function.Supplier;
12 import java.util.stream.Collectors;
13 import java.util.stream.Stream;
14
15 import org.eclipse.jface.dialogs.Dialog;
16 import org.eclipse.jface.dialogs.IInputValidator;
17 import org.eclipse.jface.dialogs.InputDialog;
18 import org.eclipse.jface.layout.GridDataFactory;
19 import org.eclipse.jface.layout.GridLayoutFactory;
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.custom.ScrolledComposite;
22 import org.eclipse.swt.events.FocusAdapter;
23 import org.eclipse.swt.events.FocusEvent;
24 import org.eclipse.swt.events.KeyAdapter;
25 import org.eclipse.swt.events.KeyEvent;
26 import org.eclipse.swt.events.SelectionAdapter;
27 import org.eclipse.swt.events.SelectionEvent;
28 import org.eclipse.swt.layout.GridData;
29 import org.eclipse.swt.layout.GridLayout;
30 import org.eclipse.swt.widgets.Button;
31 import org.eclipse.swt.widgets.Combo;
32 import org.eclipse.swt.widgets.Composite;
33 import org.eclipse.swt.widgets.Display;
34 import org.eclipse.swt.widgets.Group;
35 import org.eclipse.swt.widgets.Label;
36 import org.eclipse.swt.widgets.Shell;
37 import org.eclipse.swt.widgets.Text;
38 import org.eclipse.swt.widgets.Widget;
39 import org.simantics.Simantics;
40 import org.simantics.db.ReadGraph;
41 import org.simantics.db.Resource;
42 import org.simantics.db.WriteGraph;
43 import org.simantics.db.common.NamedResource;
44 import org.simantics.db.common.request.UniqueRead;
45 import org.simantics.db.common.request.WriteRequest;
46 import org.simantics.db.exception.DatabaseException;
47 import org.simantics.db.layer0.util.RemoverUtil;
48 import org.simantics.db.procedure.Listener;
49 import org.simantics.district.network.profile.ActiveDynamicVisualisationsRequest;
50 import org.simantics.district.network.profile.DynamicVisualisationsRequest;
51 import org.simantics.district.network.visualisations.DynamicVisualisations;
52 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions;
53 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions.DynamicArrowObject;
54 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions.DynamicColoringObject;
55 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions.DynamicSizingObject;
56 import org.simantics.district.network.visualisations.model.ColorBarOptions;
57 import org.simantics.district.network.visualisations.model.ColorBarOptions.ColorBarsLocation;
58 import org.simantics.district.network.visualisations.model.ColorBarOptions.ColorBarsSize;
59 import org.simantics.district.network.visualisations.model.DynamicArrowContribution;
60 import org.simantics.district.network.visualisations.model.DynamicColorContribution;
61 import org.simantics.district.network.visualisations.model.DynamicColorMap;
62 import org.simantics.district.network.visualisations.model.DynamicSizeContribution;
63 import org.simantics.district.network.visualisations.model.DynamicSizeMap;
64 import org.simantics.district.network.visualisations.model.DynamicVisualisation;
65 import org.simantics.district.network.visualisations.model.SizeBarOptions;
66 import org.simantics.district.network.visualisations.model.SizeBarOptions.SizeBarsLocation;
67 import org.simantics.district.network.visualisations.model.SizeBarOptions.SizeBarsSize;
68 import org.simantics.utils.datastructures.Pair;
69 import org.simantics.utils.ui.dialogs.ShowError;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 public class DynamicVisualisationsUI {
74
75     private static final Logger LOGGER = LoggerFactory.getLogger(DynamicVisualisationsUI.class);
76
77     private Resource parentResource;
78     private VisualisationListener listener;
79     private DynamicVisualisation visualisation;
80
81     private Button showSizeButton;
82     private Button sizeTicksButton;
83     private Button sizeGradientButton;
84     private Combo sizeLocationCombo;
85     private Combo sizeSizeCombo;
86     private Button showColorButton;
87     private Button colorTicksButton;
88     private Button colorGradientButton;
89     private Combo colorLocationCombo;
90     private Combo colorSizeCombo;
91
92     private Combo templateSelectionCombo;
93
94     private List<Supplier<Pair<String, DynamicColorContribution>>> colorSuppliers;
95
96     private Button removeVisualisationTemplateButton;
97
98     private Composite parent;
99
100     private Button disableUpdatesButton;
101     private Button resetVisualisationButton;
102     private Button hoveringVertexEnabledButton;
103     private Button hoveringEdgesEnabledButton;
104     private Button elevationServerEnabledButton;
105     private Button notInSimulationButton;
106     private Button showConnectedComponentsButton;
107
108     private List<Supplier<Pair<String, DynamicArrowContribution>>> edgeArrowSuppliers;
109
110     private Button saveVisualisationTemplateAsButton;
111
112     private Button hideEdgesButton;
113     private Button hidePointsButton;
114     private Button hideConsumersButton;
115     private Button hideProducersButton;
116     private Button hideValvesButton;
117     private Button hidePumpingStationsButton;
118
119     private Button networkBranchesStaticPropertiesButton;
120     private Button pointsStaticPropertiesButton;
121     private Button consumersStaticPropertiesButton;
122     
123     private Button dynamicSymbolsEdgesButton;
124     private Button dynamicSymbolsProducersButton;
125     private Button dynamicSymbolsValvesButton;
126     private Button dynamicSymbolsPumpingStationsButton;
127
128     private Text intervalText;
129
130     public DynamicVisualisationsUI(Composite parent) {
131         this.parent = parent;
132         ScrolledComposite scrolledComposite = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL);
133         scrolledComposite.setLayout(new GridLayout(1, false));
134         scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
135
136         Composite firstContent = new Composite(scrolledComposite, SWT.NONE);
137         firstContent.setLayout(new GridLayout(1, false));
138         firstContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
139         
140         defaultInitializeUI(firstContent);
141         
142         scrolledComposite.setContent(firstContent);
143         scrolledComposite.setExpandHorizontal(true);
144         scrolledComposite.setExpandVertical(true);
145         scrolledComposite.setMinSize(firstContent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
146     }
147
148     private void defaultInitializeUI(Composite parent) {
149         
150         GridDataFactory.fillDefaults().grab(true, true).applyTo(parent);
151         GridLayoutFactory.fillDefaults().numColumns(1).margins(5, 5).applyTo(parent);
152         
153         Composite selectionComposite = new Composite(parent, SWT.NONE);
154         GridDataFactory.fillDefaults().grab(true, false).applyTo(selectionComposite);
155         GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(selectionComposite);
156         
157         Label templateNameLabel = new Label(selectionComposite, SWT.NONE);
158         templateNameLabel.setText("Visualisation template");
159         templateSelectionCombo = new Combo(selectionComposite, SWT.READ_ONLY);
160         GridDataFactory.fillDefaults().grab(true, false).applyTo(templateSelectionCombo);
161         templateSelectionCombo.addSelectionListener(new SelectionAdapter() {
162             
163             @Override
164             public void widgetSelected(SelectionEvent e) {
165                 String item = templateSelectionCombo.getItem(templateSelectionCombo.getSelectionIndex());
166                 for (NamedResource template : visualisations) {
167                     if (item.equals(template.getName())) {
168                         if (parentResource != null) {
169                             Resource res = parentResource;
170                             Simantics.getSession().asyncRequest(new WriteRequest() {
171                                 
172                                 @Override
173                                 public void perform(WriteGraph graph) throws DatabaseException {
174                                     Resource vf = DynamicVisualisations.getVisualisationFolder(graph, res);
175                                     DynamicVisualisations.setActiveVisualisation(graph, vf, template.getResource());
176                                 }
177                             });
178                             break;
179                         }
180                     }
181                 }
182             }
183         });
184         
185         Composite intervalElementsComposite = new Composite(parent, SWT.NONE);
186         GridDataFactory.fillDefaults().grab(true, false).applyTo(intervalElementsComposite);
187         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(intervalElementsComposite);
188         initializeIntervalElements(intervalElementsComposite);
189         
190         Composite hoverElementsComposite = new Composite(parent, SWT.NONE);
191         GridDataFactory.fillDefaults().grab(true, false).applyTo(hoverElementsComposite);
192         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(hoverElementsComposite);
193         initializeHoverElements(hoverElementsComposite);
194         
195         Composite hideElementsComposite = new Composite(parent, SWT.NONE);
196         GridDataFactory.fillDefaults().grab(true, false).applyTo(hideElementsComposite);
197         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(hideElementsComposite);
198         initializeHideElements(hideElementsComposite);
199         
200         Composite staticPropertiesComposite = new Composite(parent, SWT.NONE);
201         GridDataFactory.fillDefaults().grab(true, false).applyTo(staticPropertiesComposite);
202         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(staticPropertiesComposite);
203         initializeStaticProperties(staticPropertiesComposite);
204
205         Composite dynamicSymbolsComposite = new Composite(parent, SWT.NONE);
206         GridDataFactory.fillDefaults().grab(true, false).applyTo(dynamicSymbolsComposite);
207         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(dynamicSymbolsComposite);
208         initializeDynamicSymbols(dynamicSymbolsComposite);
209
210         Composite coloringObjectsComposite = new Composite(parent, SWT.NONE);
211         GridDataFactory.fillDefaults().grab(true, false).applyTo(coloringObjectsComposite);
212         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(coloringObjectsComposite);
213         initializeColoringObjects(coloringObjectsComposite);
214         
215         Composite colorBarsComposite = new Composite(parent, SWT.NONE);
216         GridDataFactory.fillDefaults().grab(true, false).applyTo(colorBarsComposite);
217         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(colorBarsComposite);
218         initializeColorBars(colorBarsComposite);
219         
220         Composite objectSizesComposite = new Composite(parent, SWT.NONE);
221         GridDataFactory.fillDefaults().grab(true, false).applyTo(objectSizesComposite);
222         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(objectSizesComposite);
223         initializeObjectSizes(objectSizesComposite);
224         
225         Composite sizeBarsComposite = new Composite(parent, SWT.NONE);
226         GridDataFactory.fillDefaults().grab(true, false).applyTo(sizeBarsComposite);
227         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(sizeBarsComposite);
228         initializeSizeBars(sizeBarsComposite);
229         
230         Composite edgeArrowsComposite = new Composite(parent, SWT.NONE);
231         GridDataFactory.fillDefaults().grab(true, false).applyTo(edgeArrowsComposite);
232         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(edgeArrowsComposite);
233         initializeEdgeArrows(edgeArrowsComposite);
234         
235         Composite buttonBarsComposite = new Composite(parent, SWT.NONE);
236         GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonBarsComposite);
237         GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonBarsComposite);
238         
239         saveVisualisationTemplateAsButton = new Button(buttonBarsComposite, SWT.NONE);
240         saveVisualisationTemplateAsButton.setText("Save as visualisation template");
241         saveVisualisationTemplateAsButton.addSelectionListener(new SelectionAdapter() {
242             
243             @Override
244             public void widgetSelected(SelectionEvent e) {
245                 showSaveVisualisationTemplateDialog(e.widget.getDisplay().getActiveShell());
246             }
247         });
248         
249         removeVisualisationTemplateButton = new Button(buttonBarsComposite, SWT.NONE);
250         removeVisualisationTemplateButton.setText("Remove");
251         removeVisualisationTemplateButton.setEnabled(visualisation != null && visualisation.getVisualisationResource() != null);
252         removeVisualisationTemplateButton.addSelectionListener(new SelectionAdapter() {
253             
254             @Override
255             public void widgetSelected(SelectionEvent e) {
256                 removeVisualisationTemplate(visualisation.getName(), Optional.of(visualisation.getVisualisationResource()));
257             }
258         });
259     }
260     
261     private void initializeIntervalElements(Composite parent) {
262         Group group = new Group(parent, SWT.NONE);
263         group.setText("Generic");
264         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
265         GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(group);
266         
267         createIntervalElements(group);
268     }
269     
270     private void createIntervalElements(Composite parent) {
271
272         Label label = new Label(parent, SWT.NONE);
273         label.setText("Interval (seconds)");
274         intervalText = new Text(parent, SWT.BORDER);
275         GridDataFactory.fillDefaults().grab(true, false).applyTo(intervalText);
276         addSelectionListener(intervalText);
277         
278         disableUpdatesButton = new Button(parent, SWT.CHECK);
279         disableUpdatesButton.setText("Disable updates");
280         addSelectionListener(disableUpdatesButton);
281
282         resetVisualisationButton = new Button(parent, SWT.CHECK);
283         resetVisualisationButton.setText("Reset Visualisation");
284         addSelectionListener(resetVisualisationButton);
285         
286         notInSimulationButton = new Button(parent, SWT.CHECK);
287         notInSimulationButton.setText("Not in Simulation");
288         addSelectionListener(notInSimulationButton);
289
290         elevationServerEnabledButton = new Button(parent, SWT.CHECK);
291         elevationServerEnabledButton.setText("Elevation Server Bounding Box");
292         addSelectionListener(elevationServerEnabledButton);
293         
294         showConnectedComponentsButton = new Button(parent, SWT.CHECK);
295         showConnectedComponentsButton.setText("Show Connected Components");
296         addSelectionListener(showConnectedComponentsButton);
297     }
298     
299     private void initializeHoverElements(Composite parent) {
300         Group group = new Group(parent, SWT.NONE);
301         group.setText("Hover");
302         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
303         GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(group);
304         
305         createHoverElements(group);
306     }
307     
308     private void createHoverElements(Composite parent) {
309         hoveringVertexEnabledButton = new Button(parent, SWT.CHECK);
310         hoveringVertexEnabledButton.setText("Vertex Key Variables on Hover");
311         addSelectionListener(hoveringVertexEnabledButton);
312         
313         hoveringEdgesEnabledButton = new Button(parent, SWT.CHECK);
314         hoveringEdgesEnabledButton.setText("Edge Key Variables on Hover");
315         addSelectionListener(hoveringEdgesEnabledButton);
316     }
317     
318     private void initializeHideElements(Composite parent) {
319         Group group = new Group(parent, SWT.NONE);
320         group.setText("Hide Elements");
321         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
322         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
323         
324         createHideElements(group);
325     }
326     
327     private void createHideElements(Composite parent) {
328         
329         hideEdgesButton = new Button(parent, SWT.CHECK);
330         hideEdgesButton.setText("Edges");
331         addSelectionListener(hideEdgesButton);
332         
333         hidePointsButton = new Button(parent, SWT.CHECK);
334         hidePointsButton.setText("Points");
335         addSelectionListener(hidePointsButton);
336         
337         hideConsumersButton = new Button(parent, SWT.CHECK);
338         hideConsumersButton.setText("Consumers");
339         addSelectionListener(hideConsumersButton);
340         
341         hideProducersButton = new Button(parent, SWT.CHECK);
342         hideProducersButton.setText("Producers");
343         addSelectionListener(hideProducersButton);
344         
345         hideValvesButton = new Button(parent, SWT.CHECK);
346         hideValvesButton.setText("Valves");
347         addSelectionListener(hideValvesButton);
348
349         hidePumpingStationsButton = new Button(parent, SWT.CHECK);
350         hidePumpingStationsButton.setText("Pumping Stations");
351         addSelectionListener(hidePumpingStationsButton);
352     }
353
354     private void initializeStaticProperties(Composite parent) {
355         Group group = new Group(parent, SWT.NONE);
356         group.setText("Static Properties");
357         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
358         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
359         
360         createStaticProperties(group);
361     }
362     
363     private void createStaticProperties(Composite parent) {
364         
365         networkBranchesStaticPropertiesButton = new Button(parent, SWT.CHECK);
366         networkBranchesStaticPropertiesButton.setText("Network Branches");
367         addSelectionListener(networkBranchesStaticPropertiesButton);
368         
369         pointsStaticPropertiesButton = new Button(parent, SWT.CHECK);
370         pointsStaticPropertiesButton.setText("Points");
371         addSelectionListener(pointsStaticPropertiesButton);
372         
373         consumersStaticPropertiesButton = new Button(parent, SWT.CHECK);
374         consumersStaticPropertiesButton.setText("Consumers");
375         addSelectionListener(consumersStaticPropertiesButton);
376
377     }
378
379     private void initializeDynamicSymbols(Composite parent) {
380         Group group = new Group(parent, SWT.NONE);
381         group.setText("Dynamic Symbols");
382         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
383         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
384         
385         createDynamicSymbols(group);
386     }
387     
388     private void createDynamicSymbols(Composite parent) {
389         
390         dynamicSymbolsEdgesButton = new Button(parent, SWT.CHECK);
391         dynamicSymbolsEdgesButton.setText("Shutoff Valves in Pipes");
392         addSelectionListener(dynamicSymbolsEdgesButton);
393         
394         dynamicSymbolsProducersButton = new Button(parent, SWT.CHECK);
395         dynamicSymbolsProducersButton.setText("Producers");
396         addSelectionListener(dynamicSymbolsProducersButton);
397         
398         dynamicSymbolsValvesButton = new Button(parent, SWT.CHECK);
399         dynamicSymbolsValvesButton.setText("Valves");
400         addSelectionListener(dynamicSymbolsValvesButton);
401
402         dynamicSymbolsPumpingStationsButton = new Button(parent, SWT.CHECK);
403         dynamicSymbolsPumpingStationsButton.setText("Pumping Stations");
404         addSelectionListener(dynamicSymbolsPumpingStationsButton);
405     }
406
407     private void initializeEdgeArrows(Composite parent) {
408         Group group = new Group(parent, SWT.NONE);
409         group.setText("Edge Arrows");
410         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
411         GridLayoutFactory.fillDefaults().numColumns(6).margins(5, 5).applyTo(group);
412         
413         createEdgeArrowsHeaderRow(group);
414         
415         edgeArrowSuppliers = new ArrayList<>();
416         {
417             try {
418                 Collection<DynamicArrowObject> result = Simantics.getSession().syncRequest(new UniqueRead<Collection<DynamicArrowObject>>() {
419
420                     @Override
421                     public Collection<DynamicArrowObject> perform(ReadGraph graph) throws DatabaseException {
422                         return DynamicVisualisationsContributions.dynamicEdgeArrowObjects(graph);
423                     }
424                 });
425                 
426                 for (DynamicArrowObject object : result) {
427                     edgeArrowSuppliers.add(createEdgeArrowRow(group, object));
428                 }
429             } catch (DatabaseException e) {
430                 LOGGER.error("Could not create coloring objecst", e);
431             }
432         }
433     }
434
435     
436     private void createEdgeArrowsHeaderRow(Composite parent) {
437
438         Label label = new Label(parent, SWT.NONE);
439         label.setText("Label");
440         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
441         
442         label = new Label(parent, SWT.NONE);
443         label.setText("Used");
444         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
445         
446         label = new Label(parent, SWT.NONE);
447         label.setText("Variable");
448         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
449         
450         label = new Label(parent, SWT.NONE);
451         label.setText("Gain");
452         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
453         
454         label = new Label(parent, SWT.NONE);
455         label.setText("Bias");
456         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
457
458         label = new Label(parent, SWT.NONE);
459         label.setText("Default");
460         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
461     }
462     
463     private Supplier<Pair<String, DynamicArrowContribution>> createEdgeArrowRow(Composite parent, DynamicArrowObject object) {
464
465         Map<String, DynamicArrowContribution> arrowContributions = object.getArrowContributions();
466         if (arrowContributions.isEmpty()) {
467             // ok, no point in showing empty combo boxes
468             return null;
469         }
470         
471         Label label = new Label(parent, SWT.NONE);
472         label.setText(object.getArrowObject().getName());
473         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(label);
474         
475         Button usedButton = new Button(parent, SWT.CHECK);
476         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(usedButton);
477         addSelectionListener(usedButton);
478         
479         Combo variableCombo = new Combo(parent, SWT.READ_ONLY);
480         variableCombo.setItems(arrowContributions.keySet().toArray(new String[arrowContributions.size()]));
481         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(variableCombo);
482         
483         Text gainText = new Text(parent, SWT.BORDER);
484         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(gainText);
485         addSelectionListener(gainText);
486         
487         Text biasText = new Text(parent, SWT.BORDER);
488         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(biasText);
489         addSelectionListener(biasText);
490         
491         Button defaultButton = new Button(parent, SWT.CHECK);
492         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(defaultButton);
493         defaultButton.addSelectionListener(new SelectionAdapter() {
494             
495             @Override
496             public void widgetSelected(SelectionEvent e) {
497                 int index = variableCombo.getSelectionIndex();
498                 if (index >= 0) {
499                     String key = variableCombo.getItem(index);
500                     DynamicArrowContribution cont = arrowContributions.get(key);
501                     
502                     gainText.setText(Double.toString(cont.getDefaultGain()));
503                     gainText.setEnabled(!defaultButton.getSelection());
504                     biasText.setText(Double.toString(cont.getDefaultBias()));
505                     biasText.setEnabled(!defaultButton.getSelection());
506                     
507                 }
508             }
509         });
510         addSelectionListener(defaultButton);
511         
512         variableCombo.addSelectionListener(new SelectionAdapter() {
513             
514             @Override
515             public void widgetSelected(SelectionEvent e) {
516                 // handle update for others
517                 String key = variableCombo.getItem(variableCombo.getSelectionIndex());
518                 DynamicArrowContribution cont = arrowContributions.get(key);
519                 
520                 if (gainText.getText().isEmpty()) {
521                     gainText.setText(Double.toString(cont.getDefaultGain()));
522                 }
523                 if (biasText.getText().isEmpty()) {
524                     biasText.setText(Double.toString(cont.getDefaultBias()));
525                 }
526                 
527                 defaultButton.setSelection(true);
528             }
529         });
530         addSelectionListener(variableCombo);
531         
532         arrowRows.put(object.getArrowObject().getName(), new ArrowObjectRow(label, usedButton, variableCombo, gainText, biasText, defaultButton));
533         
534         return new Supplier<Pair<String, DynamicArrowContribution>>() {
535
536             @Override
537             public Pair<String, DynamicArrowContribution> get() {
538                 int selectionIndex = variableCombo.getSelectionIndex();
539                 if (selectionIndex >= 0) {
540                     String key = variableCombo.getItem(selectionIndex);
541                     DynamicArrowContribution cont = arrowContributions.get(key);
542                     if (cont != null) {
543                         String label = variableCombo.getItem(variableCombo.getSelectionIndex());
544                         
545                         double gain = cont.getDefaultGain();
546                         String gainS = gainText.getText();
547                         if (gainS != null && !gainS.isEmpty()) {
548                             gain = Double.parseDouble(gainS);
549                         }
550                         double bias = cont.getDefaultBias();
551                         String biasS = biasText.getText();
552                         if (biasS != null && !biasS.isEmpty()) {
553                             bias = Double.parseDouble(biasText.getText());
554                         }
555                         
556                         DynamicArrowContribution dsc = new DynamicArrowContribution(label, cont.getModuleName(), cont.getAttributeName(), gain, bias);
557                         dsc.setUsed(usedButton.getSelection());
558                         dsc.setUseDefault(defaultButton.getSelection());
559                         
560                         return Pair.make(object.getArrowObject().getName(), dsc);
561                     }
562                 }
563                 return null;
564             }
565         };
566     }
567
568     protected void removeVisualisationTemplate(String name, Optional<Resource> of) {
569         if (of.isPresent()) {
570             Resource visualisation = of.get();
571             Simantics.getSession().asyncRequest(new WriteRequest() {
572                 
573                 @Override
574                 public void perform(WriteGraph graph) throws DatabaseException {
575                     RemoverUtil.remove(graph, visualisation);
576                 }
577             });
578         }
579     }
580
581     private void showSaveVisualisationTemplateDialog(Shell shell) {
582         
583         InputDialog dialog = new InputDialog(shell, "Save visualisation template", "Give template a name", "", new IInputValidator() {
584             
585             @Override
586             public String isValid(String newText) {
587                 if (newText == null || newText.isEmpty())
588                     return "Name cannot be empty";
589                 return null;
590             }
591         });
592         
593         if (dialog.open() == Dialog.OK) {
594             String name = dialog.getValue();
595             try {
596                 persistVisualisationTemplate(name, Optional.empty());
597             } catch (Exception e) {
598                 LOGGER.error("Could not persist visualisation template", e);
599                 ShowError.showError("Could not persist visualisation template", e.getMessage(), e);
600             }
601         }
602     }
603
604     private void persistCurrentVisualisationTemplateIfAvailable() {
605         if (visualisation != null) {
606             try {
607                 persistVisualisationTemplate(visualisation.getName(), Optional.of(visualisation.getVisualisationResource()));
608             } catch (Exception e1) {
609                 LOGGER.error("Could not persist visualisation template", e1);
610                 ShowError.showError("Could not persist visualisation template", e1.getMessage(), e1);
611             }
612         } else {
613             LOGGER.info("No current visualisation template selected for saving");
614         }
615     }
616     
617     private void persistVisualisationTemplate(String templateName, Optional<Resource> existing) throws Exception {
618         
619         List<Pair<String, DynamicColorContribution>> colorCollect = colorSuppliers.stream().filter(Objects::nonNull).map(s -> s.get()).filter(Objects::nonNull).collect(Collectors.toList());
620
621         String colorLocation = colorLocationCombo.getItem(colorLocationCombo.getSelectionIndex());
622         String colorSize = colorSizeCombo.getItem(colorSizeCombo.getSelectionIndex());
623         
624         ColorBarOptions colorBarOptions = new ColorBarOptions()
625                 .showColorBars(showColorButton.getSelection())
626                 .showColorBarsTicks(colorTicksButton.getSelection())
627                 .useGradients(colorGradientButton.getSelection())
628                 .withLocation(ColorBarsLocation.valueOf(colorLocation))
629                 .withSize(ColorBarsSize.valueOf(colorSize));
630         
631         List<Pair<String, DynamicSizeContribution>> sizeCollect = sizeSuppliers.stream().filter(Objects::nonNull).map(s -> s.get()).filter(Objects::nonNull).collect(Collectors.toList());
632         
633         String sizeLocation = sizeLocationCombo.getItem(sizeLocationCombo.getSelectionIndex());
634         String sizeSize = sizeSizeCombo.getItem(sizeSizeCombo.getSelectionIndex());
635         
636         final SizeBarOptions sizeBarOptions = new SizeBarOptions()
637                 .showSizeBars(showSizeButton.getSelection())
638                 .showSizeBarsTicks(sizeTicksButton.getSelection())
639                 .useGradients(sizeGradientButton.getSelection())
640                 .withLocation(SizeBarsLocation.valueOf(sizeLocation))
641                 .withSize(SizeBarsSize.valueOf(sizeSize));
642         
643         List<Pair<String, DynamicArrowContribution>> edgeArrowCollect = edgeArrowSuppliers.stream().filter(Objects::nonNull).map(s -> s.get()).filter(Objects::nonNull).collect(Collectors.toList());
644         
645         boolean hideEdges = hideEdgesButton.getSelection();
646         boolean hidePoints = hidePointsButton.getSelection();
647         boolean hideConsumers = hideConsumersButton.getSelection();
648         boolean hideProducers = hideProducersButton.getSelection();
649         boolean hideValves = hideValvesButton.getSelection();
650         boolean hidePumpingStations = hidePumpingStationsButton.getSelection();
651         
652         boolean networkBranchesStaticProperties = networkBranchesStaticPropertiesButton.getSelection();
653         boolean pointsStaticProperties = pointsStaticPropertiesButton.getSelection();
654         boolean consumersStaticProperties = consumersStaticPropertiesButton.getSelection();
655         
656         boolean dynamicSymbolsEdges = dynamicSymbolsEdgesButton.getSelection();
657         boolean dynamicSymbolsProducers = dynamicSymbolsProducersButton.getSelection();
658         boolean dynamicSymbolsValves = dynamicSymbolsValvesButton.getSelection();
659         boolean dynamicSymbolsPumpingStations = dynamicSymbolsPumpingStationsButton.getSelection();
660         
661         boolean disabled = disableUpdatesButton.getSelection();
662         boolean resetVisualisation = resetVisualisationButton.getSelection();
663         Long interval;
664         try {
665             // inteval is in milliseconds but shown as seconds
666             
667             interval = (long)(Double.parseDouble(intervalText.getText()) * 1000);
668         } catch (NumberFormatException e) {
669             // ignore
670             interval = 2000L;
671         }
672         final long finalInterval = interval;
673         
674         boolean hoverVertex = hoveringVertexEnabledButton.getSelection();
675         boolean hoverEdges = hoveringEdgesEnabledButton.getSelection();
676         
677         boolean elevationServerBoundingBox = elevationServerEnabledButton.getSelection();
678         boolean notInSimulation = notInSimulationButton.getSelection();
679         boolean showConnectedComponents = showConnectedComponentsButton.getSelection();
680         
681         Simantics.getSession().asyncRequest(new WriteRequest() {
682             
683             @Override
684             public void perform(WriteGraph graph) throws DatabaseException {
685                 Resource exist;
686                 if (existing.isPresent()) {
687                     exist = existing.get();
688                 } else {
689                     exist = DynamicVisualisations.createVisualisation(graph, parentResource, templateName);
690                 }
691                 DynamicVisualisations.setIntervalAndDisabled(graph, exist, finalInterval, disabled, resetVisualisation);
692                 DynamicVisualisations.setColorContributions(graph, exist, colorCollect);
693                 DynamicVisualisations.setColorBarOptions(graph, exist, colorBarOptions);
694                 DynamicVisualisations.setSizeContributions(graph, exist, sizeCollect);
695                 DynamicVisualisations.setSizeBarOptions(graph, exist, sizeBarOptions);
696                 DynamicVisualisations.setEdgeArrowContributions(graph, exist, edgeArrowCollect);
697                 DynamicVisualisations.setHideElements(graph, exist,
698                         hideEdges,
699                         hidePoints,
700                         hideConsumers,
701                         hideProducers,
702                         hideValves,
703                         hidePumpingStations
704                     );
705                 
706                 DynamicVisualisations.setStaticProperties(graph, exist,
707                         networkBranchesStaticProperties,
708                         pointsStaticProperties,
709                         consumersStaticProperties
710                     );
711                 
712                 DynamicVisualisations.setDynamicSymbols(graph, exist,
713                         dynamicSymbolsEdges,
714                         dynamicSymbolsProducers,
715                         dynamicSymbolsValves,
716                         dynamicSymbolsPumpingStations
717                     );
718                 DynamicVisualisations.setKeyVariablesHover(graph, exist, hoverVertex, hoverEdges);
719                 
720                 DynamicVisualisations.setElevationServerBoundingBox(graph, exist, elevationServerBoundingBox);
721                 DynamicVisualisations.setNotInSimulation(graph, exist, notInSimulation);
722                 DynamicVisualisations.setShowConnectedComponents(graph, exist, showConnectedComponents);
723             }
724         });
725     }
726
727     private void initializeColoringObjects(Composite parent) {
728         Group group = new Group(parent, SWT.NONE);
729         group.setText("Coloring Objects");
730         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
731         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
732         
733         {
734             createColoringObjectHeaderRow(group);
735         }
736         colorSuppliers = new ArrayList<>();
737         {
738             try {
739                 Pair<Collection<DynamicColoringObject>, Map<String, DynamicColorMap>> result = Simantics.getSession().syncRequest(new UniqueRead<Pair<Collection<DynamicColoringObject>, Map<String, DynamicColorMap>>>() {
740
741                     @Override
742                     public Pair<Collection<DynamicColoringObject>, Map<String, DynamicColorMap>> perform(ReadGraph graph) throws DatabaseException {
743                         Map<String, DynamicColorMap> dynamicColorMaps = DynamicVisualisationsContributions.dynamicColorMaps(graph);
744                         return Pair.make(DynamicVisualisationsContributions.dynamicColoringObjects(graph), dynamicColorMaps);
745                     }
746                 });
747                 
748                 for (DynamicColoringObject object : result.first) {
749                     colorSuppliers.add(createColoringObjectRow(group, object, result.second));
750                 }
751
752             } catch (DatabaseException e) {
753                 LOGGER.error("Could not create coloring objecst", e);
754             }
755         }
756     }
757     
758     private void createColoringObjectHeaderRow(Composite parent) {
759
760         Label label = new Label(parent, SWT.NONE);
761         label.setText("Label");
762         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
763         
764         label = new Label(parent, SWT.NONE);
765         label.setText("Used");
766         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
767         
768         label = new Label(parent, SWT.NONE);
769         label.setText("Variable");
770         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
771         
772         label = new Label(parent, SWT.NONE);
773         label.setText("Min");
774         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
775         
776         label = new Label(parent, SWT.NONE);
777         label.setText("Max");
778         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
779         
780         label = new Label(parent, SWT.NONE);
781         label.setText("Unit");
782         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
783         
784         label = new Label(parent, SWT.NONE);
785         label.setText("ColorMap");
786         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
787         
788         label = new Label(parent, SWT.NONE);
789         label.setText("Default");
790         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
791     }
792
793     private Map<String, ColoringObjectRow> coloringRows = new HashMap<>();
794     private Map<String, SizingObjectRow> sizingRows = new HashMap<>();
795     private Map<String, ArrowObjectRow> arrowRows = new HashMap<>();
796
797     private VisualisationsListener visualisationsListener;
798
799     private Collection<NamedResource> visualisations;
800
801     private List<Supplier<Pair<String, DynamicSizeContribution>>> sizeSuppliers;
802
803     private static class ColoringObjectRow {
804         
805         private final Label label;
806         private final Button usedButton;
807         private final Combo variableCombo;
808         private final Text minText;
809         private final Text maxText;
810         private final Text unit;
811         private final Combo colorMapCombo;
812         private final Button defaultButton;
813         
814         public ColoringObjectRow(Label label, Button usedButton, Combo variableCombo, Text minText, Text maxText, Text unit,
815                 Combo colorMapCombo, Button defaultButton) {
816             super();
817             this.label = label;
818             this.usedButton = usedButton;
819             this.variableCombo = variableCombo;
820             this.minText = minText;
821             this.maxText = maxText;
822             this.unit = unit;
823             this.colorMapCombo = colorMapCombo;
824             this.defaultButton = defaultButton;
825         }
826
827         public void update(DynamicColorContribution colorContribution) {
828             String[] items = variableCombo.getItems();
829             for (int i = 0; i < items.length; i++) {
830                 if (colorContribution.getLabel().equals(items[i])) {
831                     variableCombo.select(i);
832                     break;
833                 }
834             }
835             minText.setText(Double.toString(colorContribution.getDefaultMin()));
836             maxText.setText(Double.toString(colorContribution.getDefaultMax()));
837             unit.setText(colorContribution.getUnit());
838             
839             String[] colorItems = colorMapCombo.getItems();
840             for (int i = 0; i < colorItems.length; i++) {
841                 
842                 if (colorContribution.getDefaultColorMap().getLabel().equals(colorItems[i])) {
843                     colorMapCombo.select(i);
844                     break;
845                 }
846             }
847             usedButton.setSelection(colorContribution.isUsed());
848             defaultButton.setSelection(colorContribution.isUseDefault());
849             
850             minText.setEnabled(!colorContribution.isUseDefault());
851             maxText.setEnabled(!colorContribution.isUseDefault());
852             colorMapCombo.setEnabled(!colorContribution.isUseDefault());
853         }
854     }
855
856     private static class SizingObjectRow {
857         
858         private final Label label;
859         private final Button usedButton;
860         private final Combo variableCombo;
861         private final Text minText;
862         private final Text maxText;
863         private final Label unit;
864         private final Combo sizeMapCombo;
865         private final Button defaultButton;
866         
867         public SizingObjectRow(Label label, Button usedButton, Combo variableCombo, Text minText, Text maxText, Label unit,
868                 Combo sizeMapCombo, Button defaultButton) {
869             super();
870             this.label = label;
871             this.usedButton = usedButton;
872             this.variableCombo = variableCombo;
873             this.minText = minText;
874             this.maxText = maxText;
875             this.unit = unit;
876             this.sizeMapCombo = sizeMapCombo;
877             this.defaultButton = defaultButton;
878         }
879
880         public void update(DynamicSizeContribution sizeContribution) {
881             String[] items = variableCombo.getItems();
882             for (int i = 0; i < items.length; i++) {
883                 if (sizeContribution.getLabel().equals(items[i])) {
884                     variableCombo.select(i);
885                     break;
886                 }
887             }
888             minText.setText(Double.toString(sizeContribution.getDefaultMin()));
889             maxText.setText(Double.toString(sizeContribution.getDefaultMax()));
890             unit.setText(sizeContribution.getUnit());
891             
892             String[] sizeItems = sizeMapCombo.getItems();
893             for (int i = 0; i < sizeItems.length; i++) {
894                 if (sizeContribution.getDefaultSizeMap().getLabel().equals(sizeItems[i])) {
895                     sizeMapCombo.select(i);
896                     break;
897                 }
898             }
899             usedButton.setSelection(sizeContribution.isUsed());
900             defaultButton.setSelection(sizeContribution.isUseDefault());
901             
902             minText.setEnabled(!sizeContribution.isUseDefault());
903             maxText.setEnabled(!sizeContribution.isUseDefault());
904             sizeMapCombo.setEnabled(!sizeContribution.isUseDefault());
905         }
906     }
907
908     private static class ArrowObjectRow {
909         
910         private final Label label;
911         private final Button usedButton;
912         private final Combo variableCombo;
913         private final Text gainText;
914         private final Text biasText;
915         private final Button defaultButton;
916         
917         public ArrowObjectRow(Label label, Button usedButton, Combo variableCombo, Text gainText, Text biasText, Button defaultButton) {
918             this.label = label;
919             this.usedButton = usedButton;
920             this.variableCombo = variableCombo;
921             this.gainText = gainText;
922             this.biasText = biasText;
923             this.defaultButton = defaultButton;
924         }
925
926         public void update(DynamicColorContribution colorContribution) {
927             String[] items = variableCombo.getItems();
928             for (int i = 0; i < items.length; i++) {
929                 if (colorContribution.getLabel().equals(items[i])) {
930                     variableCombo.select(i);
931                     break;
932                 }
933             }
934             gainText.setText(Double.toString(colorContribution.getDefaultMin()));
935             biasText.setText(Double.toString(colorContribution.getDefaultMax()));
936             
937             usedButton.setSelection(colorContribution.isUsed());
938             defaultButton.setSelection(colorContribution.isUseDefault());
939             
940             gainText.setEnabled(!colorContribution.isUseDefault());
941             biasText.setEnabled(!colorContribution.isUseDefault());
942         }
943     }
944
945     private Supplier<Pair<String, DynamicColorContribution>> createColoringObjectRow(Composite parent, DynamicColoringObject object, Map<String, DynamicColorMap> colorMaps) {
946         Label label = new Label(parent, SWT.NONE);
947         label.setText(object.getColoringObject().getName());
948         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(label);
949         
950         Map<String, DynamicColorContribution> colorContributions = object.getColorContributions();
951         
952         Button usedButton = new Button(parent, SWT.CHECK);
953         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(usedButton);
954         addSelectionListener(usedButton);
955         
956         Combo variableCombo = new Combo(parent, SWT.READ_ONLY);
957         variableCombo.setItems(colorContributions.keySet().toArray(new String[colorContributions.size()]));
958         
959         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(variableCombo);
960         
961         Text minText = new Text(parent, SWT.BORDER);
962         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(minText);
963         addSelectionListener(minText);
964         
965         Text maxText = new Text(parent, SWT.BORDER);
966         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(maxText);
967         addSelectionListener(maxText);
968         
969         Text unit = new Text(parent, SWT.READ_ONLY);
970         GridDataFactory.fillDefaults().grab(true, false).hint(30, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(unit);
971         
972         Combo colorMapCombo = new Combo(parent, SWT.READ_ONLY);
973         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(colorMapCombo);
974         colorMapCombo.setItems(colorMaps.keySet().toArray(new String[colorMaps.keySet().size()]));
975         addSelectionListener(colorMapCombo);
976         
977         Button defaultButton = new Button(parent, SWT.CHECK);
978         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(defaultButton);
979         defaultButton.addSelectionListener(new SelectionAdapter() {
980             
981             @Override
982             public void widgetSelected(SelectionEvent e) {
983                 int index = variableCombo.getSelectionIndex();
984                 if (index >= 0) {
985                     String key = variableCombo.getItem(index);
986                     DynamicColorContribution cont = colorContributions.get(key);
987                     
988                     minText.setText(Double.toString(cont.getDefaultMin()));
989                     minText.setEnabled(!defaultButton.getSelection());
990                     maxText.setText(Double.toString(cont.getDefaultMax()));
991                     maxText.setEnabled(!defaultButton.getSelection());
992                     unit.setText(cont.getUnit());
993                     
994                     String[] items = colorMapCombo.getItems();
995                     for (int i = 0; i < items.length; i++) {
996                         String item = items[i];
997                         if (item.equals(cont.getDefaultColorMap().getLabel())) {
998                             colorMapCombo.select(i);
999                             break;
1000                         }
1001                     }
1002                     colorMapCombo.setEnabled(!defaultButton.getSelection());
1003                 }
1004             }
1005         });
1006         addSelectionListener(defaultButton);
1007         
1008         variableCombo.addSelectionListener(new SelectionAdapter() {
1009             
1010             @Override
1011             public void widgetSelected(SelectionEvent e) {
1012                 // handle update for others
1013                 int index = variableCombo.getSelectionIndex();
1014                 if (index >= 0) {
1015                     String key = variableCombo.getItem(index);
1016                     DynamicColorContribution cont = colorContributions.get(key);
1017                     
1018                     if (minText.getText().isEmpty()) {
1019                         minText.setText(Double.toString(cont.getDefaultMin()));
1020                     }
1021                     if (maxText.getText().isEmpty()) {
1022                         maxText.setText(Double.toString(cont.getDefaultMax()));
1023                     }
1024                     unit.setText(cont.getUnit());
1025                     
1026                     String[] items = colorMapCombo.getItems();
1027                     for (int i = 0; i < items.length; i++) {
1028                         String item = items[i];
1029                         if (item.equals(cont.getDefaultColorMap().getLabel())) {
1030                             colorMapCombo.select(i);
1031                             break;
1032                         }
1033                     }
1034                     
1035                     defaultButton.setSelection(true);
1036                 }
1037             }
1038         });
1039         addSelectionListener(variableCombo);
1040         
1041         coloringRows.put(object.getColoringObject().getName(), new ColoringObjectRow(label, usedButton, variableCombo, minText, maxText, unit, colorMapCombo, defaultButton));
1042
1043         return new Supplier<Pair<String, DynamicColorContribution>>() {
1044
1045             @Override
1046             public Pair<String, DynamicColorContribution> get() {
1047                 int selectionIndex = variableCombo.getSelectionIndex();
1048                 if (selectionIndex >= 0) {
1049                     String key = variableCombo.getItem(selectionIndex);
1050                     DynamicColorContribution cont = colorContributions.get(key);
1051                     if (cont != null) {
1052                         
1053                         String label = variableCombo.getItem(variableCombo.getSelectionIndex());
1054                         DynamicColorContribution dcc;
1055                         if (colorMapCombo.getSelectionIndex() > -1) {
1056                             String colorMap = colorMapCombo.getItem(colorMapCombo.getSelectionIndex());
1057                             DynamicColorMap dColorMap = colorMaps.get(colorMap);
1058                             dcc = new DynamicColorContribution(label, cont.getModuleName(), cont.getAttributeName(), unit.getText(), cont.getVariableGain(), cont.getVariableBias(), dColorMap, Double.parseDouble(minText.getText()), Double.parseDouble(maxText.getText()));
1059                         } else {
1060                             dcc = colorContributions.get(label);
1061                         }
1062                         dcc.setUsed(usedButton.getSelection());
1063                         dcc.setUseDefault(defaultButton.getSelection());
1064                         
1065                         return Pair.make(object.getColoringObject().getName(), dcc);
1066                     }
1067                 }
1068                 return null;
1069             }
1070         };
1071     }
1072     
1073     private void createSizingObjectHeaderRow(Composite parent) {
1074
1075         Label label = new Label(parent, SWT.NONE);
1076         label.setText("Label");
1077         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
1078         
1079         label = new Label(parent, SWT.NONE);
1080         label.setText("Used");
1081         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
1082         
1083         label = new Label(parent, SWT.NONE);
1084         label.setText("Variable");
1085         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
1086         
1087         label = new Label(parent, SWT.NONE);
1088         label.setText("Min");
1089         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
1090         
1091         label = new Label(parent, SWT.NONE);
1092         label.setText("Max");
1093         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
1094         
1095         label = new Label(parent, SWT.NONE);
1096         label.setText("Unit");
1097         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
1098         
1099         label = new Label(parent, SWT.NONE);
1100         label.setText("SizeMap");
1101         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
1102         
1103         label = new Label(parent, SWT.NONE);
1104         label.setText("Default");
1105         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
1106     }
1107
1108     private Supplier<Pair<String, DynamicSizeContribution>> createSizingObjectRow(Composite parent, DynamicSizingObject object, Map<String, DynamicSizeMap> sizeMaps) {
1109         Label label = new Label(parent, SWT.NONE);
1110         label.setText(object.getSizingObject().getName());
1111         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(label);
1112         
1113         Map<String, DynamicSizeContribution> sizeContributions = object.getSizeContributions();
1114         
1115         Button usedButton = new Button(parent, SWT.CHECK);
1116         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(usedButton);
1117         addSelectionListener(usedButton);
1118         
1119         Combo variableCombo = new Combo(parent, SWT.READ_ONLY);
1120         variableCombo.setItems(sizeContributions.keySet().toArray(new String[sizeContributions.size()]));
1121         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(variableCombo);
1122         
1123         Text minText = new Text(parent, SWT.BORDER);
1124         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(minText);
1125         addSelectionListener(minText);
1126         
1127         Text maxText = new Text(parent, SWT.BORDER);
1128         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(maxText);
1129         addSelectionListener(maxText);
1130         
1131         Label unit = new Label(parent, SWT.NONE);
1132         GridDataFactory.fillDefaults().grab(true, false).hint(30, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(unit);
1133         
1134         Combo sizeMapCombo = new Combo(parent, SWT.READ_ONLY);
1135         GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(sizeMapCombo);
1136         sizeMapCombo.setItems(sizeMaps.keySet().toArray(new String[sizeMaps.keySet().size()]));
1137         addSelectionListener(sizeMapCombo);
1138         
1139         Button defaultButton = new Button(parent, SWT.CHECK);
1140         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(defaultButton);
1141         defaultButton.addSelectionListener(new SelectionAdapter() {
1142             
1143             @Override
1144             public void widgetSelected(SelectionEvent e) {
1145                 int index = variableCombo.getSelectionIndex();
1146                 if (index >= 0) {
1147                     String key = variableCombo.getItem(index);
1148                     DynamicSizeContribution cont = sizeContributions.get(key);
1149                     
1150                     minText.setText(Double.toString(cont.getDefaultMin()));
1151                     minText.setEnabled(!defaultButton.getSelection());
1152                     maxText.setText(Double.toString(cont.getDefaultMax()));
1153                     maxText.setEnabled(!defaultButton.getSelection());
1154                     unit.setText(cont.getUnit());
1155                     
1156                     String[] items = sizeMapCombo.getItems();
1157                     for (int i = 0; i < items.length; i++) {
1158                         String item = items[i];
1159                         if (item.equals(cont.getDefaultSizeMap().getLabel())) {
1160                             sizeMapCombo.select(i);
1161                             break;
1162                         }
1163                     }
1164                     sizeMapCombo.setEnabled(!defaultButton.getSelection());
1165                 }
1166             }
1167         });
1168         addSelectionListener(defaultButton);
1169         
1170         variableCombo.addSelectionListener(new SelectionAdapter() {
1171             
1172             @Override
1173             public void widgetSelected(SelectionEvent e) {
1174                 // handle update for others
1175                 String key = variableCombo.getItem(variableCombo.getSelectionIndex());
1176                 DynamicSizeContribution cont = sizeContributions.get(key);
1177                 
1178                 if (minText.getText().isEmpty()) {
1179                     minText.setText(Double.toString(cont.getDefaultMin()));
1180                 }
1181                 if (maxText.getText().isEmpty()) {
1182                     maxText.setText(Double.toString(cont.getDefaultMax()));
1183                 }
1184                 unit.setText(cont.getUnit());
1185                 
1186                 String[] items = sizeMapCombo.getItems();
1187                 for (int i = 0; i < items.length; i++) {
1188                     String item = items[i];
1189                     if (item.equals(cont.getDefaultSizeMap().getLabel())) {
1190                         sizeMapCombo.select(i);
1191                         break;
1192                     }
1193                 }
1194                 
1195                 defaultButton.setSelection(true);
1196             }
1197         });
1198         addSelectionListener(variableCombo);
1199         
1200         sizingRows.put(object.getSizingObject().getName(), new SizingObjectRow(label, usedButton, variableCombo, minText, maxText, unit, sizeMapCombo, defaultButton));
1201         
1202         return new Supplier<Pair<String, DynamicSizeContribution>>() {
1203
1204             @Override
1205             public Pair<String, DynamicSizeContribution> get() {
1206                 int selectionIndex = variableCombo.getSelectionIndex();
1207                 if (selectionIndex >= 0) {
1208                     String key = variableCombo.getItem(selectionIndex);
1209                     DynamicSizeContribution cont = sizeContributions.get(key);
1210                     if (cont != null) {
1211
1212                         String label = variableCombo.getItem(variableCombo.getSelectionIndex());
1213                         DynamicSizeContribution dsc;
1214                         if (sizeMapCombo.getSelectionIndex() > -1) {
1215                             String sizeMap = sizeMapCombo.getItem(sizeMapCombo.getSelectionIndex());
1216                             DynamicSizeMap dSizeMap = sizeMaps.get(sizeMap);
1217                             dsc = new DynamicSizeContribution(label, cont.getModuleName(), cont.getAttributeName(), unit.getText(), cont.getVariableGain(), cont.getVariableBias(), dSizeMap, Double.parseDouble(minText.getText()), Double.parseDouble(maxText.getText()));
1218                         } else {
1219                             dsc = sizeContributions.get(label);
1220                         }
1221                         dsc.setUsed(usedButton.getSelection());
1222                         dsc.setUseDefault(defaultButton.getSelection());
1223                         
1224                         return Pair.make(object.getSizingObject().getName(), dsc);
1225                     }
1226                 }
1227                 return null;
1228             }
1229         };
1230     }
1231     
1232     private void initializeColorBars(Composite parent) {
1233         Group group = new Group(parent, SWT.NONE);
1234         group.setText("Color Bars");
1235         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
1236         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
1237         
1238         createColorBars(group);
1239     }
1240     
1241     private void createColorBars(Composite parent) {
1242         
1243         showColorButton = new Button(parent, SWT.CHECK);
1244         showColorButton.setText("Show");
1245         addSelectionListener(showColorButton);
1246         
1247         colorTicksButton = new Button(parent, SWT.CHECK);
1248         colorTicksButton.setText("Ticks");
1249         addSelectionListener(colorTicksButton);
1250         
1251         colorGradientButton = new Button(parent, SWT.CHECK);
1252         colorGradientButton.setText("Gradients");
1253         addSelectionListener(colorGradientButton);
1254         
1255         Label label = new Label(parent, SWT.NONE);
1256         label.setText("Location");
1257         colorLocationCombo = new Combo(parent, SWT.READ_ONLY);
1258         String[] colorLocationItems = Stream.of(ColorBarsLocation.values()).map(size -> size.toString()).toArray(String[]::new);
1259         colorLocationCombo.setItems(colorLocationItems);
1260         if (colorLocationItems.length > 0) {
1261             colorLocationCombo.select(0);
1262         }
1263         addSelectionListener(colorLocationCombo);
1264         
1265         label = new Label(parent, SWT.NONE);
1266         label.setText("Size");
1267         colorSizeCombo = new Combo(parent, SWT.READ_ONLY);
1268         String[] colorSizeItems = Stream.of(ColorBarsSize.values()).map(size -> size.toString()).toArray(String[]::new);
1269         colorSizeCombo.setItems(colorSizeItems);
1270         if (colorSizeItems.length > 0) {
1271             colorSizeCombo.select(0);
1272         }
1273         addSelectionListener(colorSizeCombo);
1274     }
1275
1276     private void initializeObjectSizes(Composite parent) {
1277         Group group = new Group(parent, SWT.NONE);
1278         group.setText("Object Sizes");
1279         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
1280         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
1281         
1282         {
1283             createSizingObjectHeaderRow(group);
1284             createObjectSizes(group);
1285         }
1286     }
1287     
1288     private void createObjectSizes(Composite parent) {
1289         
1290         sizeSuppliers = new ArrayList<>(); 
1291         try {
1292             Pair<Collection<DynamicSizingObject>, Map<String, DynamicSizeMap>> resultSizing = Simantics.getSession().syncRequest(new UniqueRead<Pair<Collection<DynamicSizingObject>, Map<String, DynamicSizeMap>>>() {
1293
1294                 @Override
1295                 public Pair<Collection<DynamicSizingObject>, Map<String, DynamicSizeMap>> perform(ReadGraph graph) throws DatabaseException {
1296                     Map<String, DynamicSizeMap> dynamicSizeMaps = DynamicVisualisationsContributions.dynamicSizeMaps(graph);
1297                     return Pair.make(DynamicVisualisationsContributions.dynamicSizingObjects(graph), dynamicSizeMaps);
1298                 }
1299             });
1300             
1301             for (DynamicSizingObject object : resultSizing.first) {
1302                 sizeSuppliers.add(createSizingObjectRow(parent, object, resultSizing.second));
1303             }
1304         } catch (DatabaseException e) {
1305             LOGGER.error("Could not create object sizes", e);
1306         }
1307     }
1308
1309     private void initializeSizeBars(Composite parent) {
1310         Group group = new Group(parent, SWT.NONE);
1311         group.setText("Size Bars");
1312         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
1313         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
1314         
1315         createSizeBars(group);
1316     }
1317
1318     private void createSizeBars(Composite parent) {
1319         showSizeButton = new Button(parent, SWT.CHECK);
1320         showSizeButton.setText("Show");
1321         addSelectionListener(showSizeButton);
1322         
1323         sizeTicksButton = new Button(parent, SWT.CHECK);
1324         sizeTicksButton.setText("Ticks");
1325         addSelectionListener(sizeTicksButton);
1326         
1327         sizeGradientButton = new Button(parent, SWT.CHECK);
1328         sizeGradientButton.setText("Gradient");
1329         addSelectionListener(sizeGradientButton);
1330         
1331         Label label = new Label(parent, SWT.NONE);
1332         label.setText("Location");
1333         sizeLocationCombo = new Combo(parent, SWT.READ_ONLY);
1334         String[] sizeLocationItems = Stream.of(SizeBarsLocation.values()).map(size -> size.toString()).toArray(String[]::new);
1335         sizeLocationCombo.setItems(sizeLocationItems);
1336         if (sizeLocationItems.length > 0) {
1337             sizeLocationCombo.select(0);
1338         }
1339         addSelectionListener(sizeLocationCombo);
1340         
1341         label = new Label(parent, SWT.NONE);
1342         label.setText("Size");
1343         sizeSizeCombo = new Combo(parent, SWT.READ_ONLY);
1344         String[] sizeSizeItems = Stream.of(SizeBarsSize.values()).map(size -> size.toString()).toArray(String[]::new);
1345         sizeSizeCombo.setItems(sizeSizeItems);
1346         if (sizeSizeItems.length > 0) {
1347             sizeSizeCombo.select(0);
1348         }
1349         addSelectionListener(sizeSizeCombo);
1350     }
1351
1352     private void addSelectionListener(Widget widget) {
1353         if (widget instanceof Button) {
1354             ((Button) widget).addSelectionListener(new SelectionAdapter() {
1355
1356                 @Override
1357                 public void widgetSelected(SelectionEvent e) {
1358                     persistCurrentVisualisationTemplateIfAvailable();
1359                 }
1360             });
1361         } else if (widget instanceof Combo) {
1362             ((Combo) widget).addSelectionListener(new SelectionAdapter() {
1363
1364                 @Override
1365                 public void widgetSelected(SelectionEvent e) {
1366                     persistCurrentVisualisationTemplateIfAvailable();
1367                 }
1368             });
1369         } else if (widget instanceof Text) {
1370             ((Text) widget).addFocusListener(new FocusAdapter() {
1371                 
1372                 @Override
1373                 public void focusLost(FocusEvent e) {
1374                     persistCurrentVisualisationTemplateIfAvailable();
1375                 }
1376             });
1377             ((Text) widget).addKeyListener(new KeyAdapter() {
1378                 
1379                 @Override
1380                 public void keyReleased(KeyEvent e) {
1381                     if(e.keyCode == SWT.CR || e.keyCode == SWT.LF) {
1382                         persistCurrentVisualisationTemplateIfAvailable();
1383                     }
1384                 }
1385             });
1386         }
1387     }
1388
1389     public void setParentResource(Resource parentResource) {
1390         if (this.parentResource != parentResource) {
1391             this.parentResource = parentResource;
1392             updateListening();
1393         }
1394         saveVisualisationTemplateAsButton.setEnabled(parentResource != null);
1395     }
1396
1397     private void updateListening() {
1398         if (visualisationsListener != null)
1399             visualisationsListener.dispose();
1400         if (parentResource != null) {
1401             visualisationsListener = new VisualisationsListener(this);
1402             Simantics.getSession().asyncRequest(new DynamicVisualisationsRequest(parentResource), visualisationsListener);
1403         }
1404         
1405         if (listener != null)
1406             listener.dispose();
1407         if (parentResource != null) {
1408             listener = new VisualisationListener(this);
1409             Simantics.getSession().asyncRequest(new ActiveDynamicVisualisationsRequest(parentResource), listener);
1410         }
1411     }
1412
1413     private static class VisualisationsListener implements Listener<Collection<NamedResource>> {
1414
1415         private static final Logger LOGGER = LoggerFactory.getLogger(VisualisationsListener.class);
1416
1417         private boolean disposed;
1418         private DynamicVisualisationsUI ui;
1419         
1420         public VisualisationsListener(DynamicVisualisationsUI ui) {
1421             this.ui = ui;
1422         }
1423
1424         @Override
1425         public void execute(Collection<NamedResource> result) {
1426             ui.updateVisualisations(result);
1427         }
1428
1429         @Override
1430         public void exception(Throwable t) {
1431             LOGGER.error("Could not listen visualisation", t);
1432         }
1433
1434         @Override
1435         public boolean isDisposed() {
1436             return disposed || ui.getParent().isDisposed();
1437         }
1438
1439         public void dispose() {
1440             this.disposed = true;
1441         }
1442     }
1443     
1444     private static class VisualisationListener implements Listener<DynamicVisualisation> {
1445
1446         private static final Logger LOGGER = LoggerFactory.getLogger(VisualisationListener.class);
1447
1448         private boolean disposed;
1449         private DynamicVisualisationsUI ui;
1450         
1451         public VisualisationListener(DynamicVisualisationsUI ui) {
1452             this.ui = ui;
1453         }
1454
1455         @Override
1456         public void execute(DynamicVisualisation result) {
1457             ui.updateVisualisation(result);
1458         }
1459
1460         @Override
1461         public void exception(Throwable t) {
1462             LOGGER.error("Could not listen visualisation", t);
1463         }
1464
1465         @Override
1466         public boolean isDisposed() {
1467             return disposed ||ui.getParent().isDisposed();
1468         }
1469
1470         public void dispose() {
1471             this.disposed = true;
1472         }
1473     }
1474
1475     public void updateVisualisation(DynamicVisualisation result) {
1476         this.visualisation = result;
1477         Display.getDefault().asyncExec(() -> {
1478             if (getParent().isDisposed())
1479                 return;
1480             
1481             removeVisualisationTemplateButton.setEnabled(visualisation != null && visualisation.getVisualisationResource() != null);
1482             
1483             if (visualisation != null) {
1484                 String[] items = templateSelectionCombo.getItems();
1485                 for (int i = 0; i < items.length; i++) {
1486                     if (visualisation.getName().equals(items[i])) {
1487                         templateSelectionCombo.select(i);
1488                         break;
1489                     }
1490                 }
1491                 
1492                 intervalText.setText(Double.toString(((double)visualisation.getInterval()) / 1000.0));
1493                 disableUpdatesButton.setSelection(visualisation.disabledUpdates());
1494                 
1495                 hoveringVertexEnabledButton.setSelection(visualisation.isKeyVariablesVertexHover());
1496                 hoveringEdgesEnabledButton.setSelection(visualisation.isKeyVariablesEdgesHover());
1497                 
1498                 showConnectedComponentsButton.setSelection(visualisation.showConnectedComponents());
1499                 notInSimulationButton.setSelection(visualisation.isInSimulation());
1500                 elevationServerEnabledButton.setSelection(visualisation.isShowElevationServerBoundingBox());
1501                 
1502                 hideConsumersButton.setSelection(visualisation.isHideConsumers());
1503                 hideEdgesButton.setSelection(visualisation.isHideEdges());
1504                 hideProducersButton.setSelection(visualisation.isHideProducers());
1505                 hideValvesButton.setSelection(visualisation.isHideValves());
1506                 hidePumpingStationsButton.setSelection(visualisation.isHidePumpingStations());
1507                 hidePointsButton.setSelection(visualisation.isHidePoints());
1508                 
1509                 Map<String, DynamicColorContribution> colorContributions = visualisation.getColorContributions();
1510                 for (Entry<String, DynamicColorContribution> entry : colorContributions.entrySet()) {
1511                     
1512                     ColoringObjectRow coloringObjectRow = coloringRows.get(entry.getKey());
1513                     if (coloringObjectRow != null) {
1514                         
1515                         coloringObjectRow.update(entry.getValue());
1516                         
1517                     } else {
1518                         LOGGER.info("No coloring object visualisation row for key {}", entry.getKey());
1519                     }
1520                 }
1521                 ColorBarOptions colorOptions = visualisation.getColorBarOptions();
1522                 showColorButton.setSelection(colorOptions.isShowColorBars());
1523                 colorTicksButton.setSelection(colorOptions.isShowColorBarsTicks());
1524                 colorGradientButton.setSelection(colorOptions.isUseGradients());
1525                 for (int i = 0; i < colorLocationCombo.getItems().length; i++) {
1526                     String item = colorLocationCombo.getItem(i);
1527                     if (item.equals(colorOptions.getLocation().toString())) {
1528                         colorLocationCombo.select(i);
1529                         break;
1530                     }
1531                 }
1532                 for (int i = 0; i < colorSizeCombo.getItems().length; i++) {
1533                     String item = colorSizeCombo.getItem(i);
1534                     if (item.equals(colorOptions.getSize().toString())) {
1535                         colorSizeCombo.select(i);
1536                         break;
1537                     }
1538                 }
1539                 
1540                 Map<String, DynamicSizeContribution> sizeContributions = visualisation.getSizeContributions();
1541                 for (Entry<String, DynamicSizeContribution> entry : sizeContributions.entrySet()) {
1542                     
1543                     SizingObjectRow sizingObjectRow = sizingRows.get(entry.getKey());
1544                     if (sizingObjectRow != null) {
1545                         
1546                         sizingObjectRow.update(entry.getValue());
1547                         
1548                     } else {
1549                         LOGGER.info("No sizing object visualisation row for key {}", entry.getKey());
1550                     }
1551                 }
1552                 SizeBarOptions sizeOptions = visualisation.getSizeBarOptions();
1553                 showSizeButton.setSelection(sizeOptions.isShowSizeBars());
1554                 sizeTicksButton.setSelection(sizeOptions.isShowSizeBarsTicks());
1555                 sizeGradientButton.setSelection(sizeOptions.isUseGradients());
1556                 for (int i = 0; i < sizeLocationCombo.getItems().length; i++) {
1557                     String item = sizeLocationCombo.getItem(i);
1558                     if (item.equals(sizeOptions.getLocation().toString())) {
1559                         sizeLocationCombo.select(i);
1560                         break;
1561                     }
1562                 }
1563                 for (int i = 0; i < sizeSizeCombo.getItems().length; i++) {
1564                     String item = sizeSizeCombo.getItem(i);
1565                     if (item.equals(sizeOptions.getSize().toString())) {
1566                         sizeSizeCombo.select(i);
1567                         break;
1568                     }
1569                 }
1570                 
1571                 pointsStaticPropertiesButton.setSelection(visualisation.isStaticPropertiesPoints());
1572                 networkBranchesStaticPropertiesButton.setSelection(visualisation.isStaticPropertiesNetworkBranches());
1573                 consumersStaticPropertiesButton.setSelection(visualisation.isStaticPropertiesConsumers());
1574             }
1575         });
1576     }
1577
1578     public void updateVisualisations(Collection<NamedResource> result) {
1579         this.visualisations = result;
1580         
1581         Display.getDefault().asyncExec(() -> {
1582             if (getParent().isDisposed())
1583                 return;
1584             templateSelectionCombo.setItems(visualisations.stream().map(NamedResource::getName).collect(Collectors.toList()).toArray(new String[visualisations.size()]));
1585             
1586             if (visualisation != null) {
1587                 String[] items = templateSelectionCombo.getItems();
1588                 for (int i = 0; i < items.length; i++) {
1589                     if (visualisation.getName().equals(items[i])) {
1590                         templateSelectionCombo.select(i);
1591                         break;
1592                     }
1593                 }
1594             }
1595             
1596         });
1597     }
1598     
1599     public Composite getParent() {
1600         return parent;
1601     }
1602 }