]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/visualisations/DynamicVisualisationsUI.java
5cb80a15d5fca59c50a72827a1bcbad7ac0dc94e
[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.events.SelectionAdapter;
22 import org.eclipse.swt.events.SelectionEvent;
23 import org.eclipse.swt.widgets.Button;
24 import org.eclipse.swt.widgets.Combo;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.Display;
27 import org.eclipse.swt.widgets.Group;
28 import org.eclipse.swt.widgets.Label;
29 import org.eclipse.swt.widgets.Shell;
30 import org.eclipse.swt.widgets.Text;
31 import org.simantics.Simantics;
32 import org.simantics.db.ReadGraph;
33 import org.simantics.db.Resource;
34 import org.simantics.db.WriteGraph;
35 import org.simantics.db.common.NamedResource;
36 import org.simantics.db.common.request.UniqueRead;
37 import org.simantics.db.common.request.WriteRequest;
38 import org.simantics.db.exception.DatabaseException;
39 import org.simantics.db.layer0.util.RemoverUtil;
40 import org.simantics.db.procedure.Listener;
41 import org.simantics.district.network.DistrictNetworkUtil;
42 import org.simantics.district.network.ontology.DistrictNetworkResource;
43 import org.simantics.district.network.profile.ActiveDynamicVisualisationsRequest;
44 import org.simantics.district.network.profile.DynamicVisualisationsRequest;
45 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions;
46 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions.DynamicColoringObject;
47 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions.DynamicSizingObject;
48 import org.simantics.district.network.visualisations.model.ColorBarOptions;
49 import org.simantics.district.network.visualisations.model.ColorBarOptions.ColorBarsLocation;
50 import org.simantics.district.network.visualisations.model.ColorBarOptions.ColorBarsSize;
51 import org.simantics.district.network.visualisations.model.DynamicColorContribution;
52 import org.simantics.district.network.visualisations.model.DynamicColorMap;
53 import org.simantics.district.network.visualisations.model.DynamicSizeContribution;
54 import org.simantics.district.network.visualisations.model.DynamicSizeMap;
55 import org.simantics.district.network.visualisations.model.DynamicVisualisation;
56 import org.simantics.district.network.visualisations.model.SizeBarOptions;
57 import org.simantics.district.network.visualisations.model.SizeBarOptions.SizeBarsLocation;
58 import org.simantics.district.network.visualisations.model.SizeBarOptions.SizeBarsSize;
59 import org.simantics.utils.datastructures.Pair;
60 import org.simantics.utils.ui.dialogs.ShowError;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 public class DynamicVisualisationsUI extends Composite {
65
66     private static final Logger LOGGER = LoggerFactory.getLogger(DynamicVisualisationsUI.class);
67
68     private Resource diagramResource;
69     private VisualisationListener listener;
70     private DynamicVisualisation visualisation;
71
72     private Button showSizeButton;
73     private Button sizeTicksButton;
74     private Button sizeGradientButton;
75     private Combo sizeLocationCombo;
76     private Combo sizeSizeCombo;
77     private Button showColorButton;
78     private Button colorTicksButton;
79     private Button colorGradientButton;
80     private Combo colorLocationCombo;
81     private Combo colorSizeCombo;
82
83     private Combo templateSelectionCombo;
84
85     private List<Supplier<Pair<String, DynamicColorContribution>>> colorSuppliers;
86
87     private Button removeVisualisationTemplateButton;
88
89         private Button applyButton;
90
91     public DynamicVisualisationsUI(Composite parent, int style) {
92         super(parent, style);
93 //        ScrolledComposite scrolledComposite = new ScrolledComposite(this, SWT.V_SCROLL);
94 //        scrolledComposite.setLayout(new GridLayout(1, false));
95 //        scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
96 //
97 //        Composite firstContent = new Composite(scrolledComposite, SWT.NONE);
98 //        firstContent.setLayout(new GridLayout(1, false));
99 //        firstContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
100         
101         defaultInitializeUI(this);
102         
103 //        scrolledComposite.setContent(firstContent);
104 //        scrolledComposite.setExpandHorizontal(true);
105 //        scrolledComposite.setExpandVertical(true);
106 //        scrolledComposite.setMinSize(firstContent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
107         
108     }
109
110     private void defaultInitializeUI(Composite parent) {
111         
112         GridDataFactory.fillDefaults().grab(true, true).applyTo(parent);
113         GridLayoutFactory.fillDefaults().numColumns(1).margins(5, 5).applyTo(parent);
114         
115         Composite selectionComposite = new Composite(parent, SWT.NONE);
116         GridDataFactory.fillDefaults().grab(true, false).applyTo(selectionComposite);
117         GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(selectionComposite);
118         
119         Label templateNameLabel = new Label(selectionComposite, SWT.NONE);
120         templateNameLabel.setText("Visualisation template");
121         templateSelectionCombo = new Combo(selectionComposite, SWT.READ_ONLY);
122         GridDataFactory.fillDefaults().grab(true, false).applyTo(templateSelectionCombo);
123         templateSelectionCombo.addSelectionListener(new SelectionAdapter() {
124             
125             @Override
126             public void widgetSelected(SelectionEvent e) {
127                 String item = templateSelectionCombo.getItem(templateSelectionCombo.getSelectionIndex());
128                 for (NamedResource template : visualisations) {
129                     if (item.equals(template.getName())) {
130                         Simantics.getSession().asyncRequest(new WriteRequest() {
131                             
132                             @Override
133                             public void perform(WriteGraph graph) throws DatabaseException {
134                                 DistrictNetworkUtil.setActiveVisualisation(graph, diagramResource, template.getResource());
135                             }
136                         });
137                         break;
138                     }
139                 }
140             }
141         });
142         
143         Composite coloringObjectsComposite = new Composite(parent, SWT.NONE);
144         GridDataFactory.fillDefaults().grab(true, false).applyTo(coloringObjectsComposite);
145         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(coloringObjectsComposite);
146         initializeColoringObjects(coloringObjectsComposite);
147         
148         Composite colorBarsComposite = new Composite(parent, SWT.NONE);
149         GridDataFactory.fillDefaults().grab(true, false).applyTo(colorBarsComposite);
150         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(colorBarsComposite);
151         initializeColorBars(colorBarsComposite);
152         
153         Composite objectSizesComposite = new Composite(parent, SWT.NONE);
154         GridDataFactory.fillDefaults().grab(true, false).applyTo(objectSizesComposite);
155         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(objectSizesComposite);
156         initializeObjectSizes(objectSizesComposite);
157         
158         Composite sizeBarsComposite = new Composite(parent, SWT.NONE);
159         GridDataFactory.fillDefaults().grab(true, false).applyTo(sizeBarsComposite);
160         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(sizeBarsComposite);
161         initializeSizeBars(sizeBarsComposite);
162         
163         Composite buttonBarsComposite = new Composite(parent, SWT.NONE);
164         GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonBarsComposite);
165         GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonBarsComposite);
166         
167         Button saveVisualisationTemplateAsButton = new Button(buttonBarsComposite, SWT.NONE);
168         saveVisualisationTemplateAsButton.setText("Save as visualisation template");
169         saveVisualisationTemplateAsButton.addSelectionListener(new SelectionAdapter() {
170             
171             @Override
172             public void widgetSelected(SelectionEvent e) {
173                 showSaveVisualisationTemplateDialog(e.widget.getDisplay().getActiveShell());
174             }
175         });
176         
177         applyButton = new Button(buttonBarsComposite, SWT.NONE);
178         applyButton.setText("Apply");
179         applyButton.setEnabled(visualisation != null);
180         applyButton.addSelectionListener(new SelectionAdapter() {
181             
182             @Override
183             public void widgetSelected(SelectionEvent e) {
184                 try {
185                     persistVisualisationTemplate(visualisation.getName(), Optional.of(visualisation.getVisualisationResource()));
186                 } catch (Exception e1) {
187                     LOGGER.error("Could not persist visualisation template", e1);
188                     ShowError.showError("Could not persist visualisation template", e1.getMessage(), e1);
189                 }
190             }
191         });
192         
193         removeVisualisationTemplateButton = new Button(buttonBarsComposite, SWT.NONE);
194         removeVisualisationTemplateButton.setText("Remove");
195         removeVisualisationTemplateButton.setEnabled(visualisation != null && visualisation.getVisualisationResource() != null);
196         removeVisualisationTemplateButton.addSelectionListener(new SelectionAdapter() {
197             
198             @Override
199             public void widgetSelected(SelectionEvent e) {
200                 removeVisualisationTemplate(visualisation.getName(), Optional.of(visualisation.getVisualisationResource()));
201             }
202         });
203         
204     }
205     
206     protected void removeVisualisationTemplate(String name, Optional<Resource> of) {
207         if (of.isPresent()) {
208             Resource visualisation = of.get();
209             Simantics.getSession().asyncRequest(new WriteRequest() {
210                 
211                 @Override
212                 public void perform(WriteGraph graph) throws DatabaseException {
213                     RemoverUtil.remove(graph, visualisation);
214                 }
215             });
216         }
217     }
218
219     private void showSaveVisualisationTemplateDialog(Shell shell) {
220         
221         InputDialog dialog = new InputDialog(shell, "Save visualisation template", "Give template a name", "", new IInputValidator() {
222             
223             @Override
224             public String isValid(String newText) {
225                 if (newText == null || newText.isEmpty())
226                     return "Name cannot be empty";
227                 return null;
228             }
229         });
230         
231         if (dialog.open() == Dialog.OK) {
232             String name = dialog.getValue();
233             try {
234                 persistVisualisationTemplate(name, Optional.empty());
235             } catch (Exception e) {
236                 LOGGER.error("Could not persist visualisation template", e);
237                 ShowError.showError("Could not persist visualisation template", e.getMessage(), e);
238             }
239         }
240     }
241
242     private void persistVisualisationTemplate(String templateName, Optional<Resource> existing) throws Exception {
243         
244         List<Pair<String, DynamicColorContribution>> colorCollect = colorSuppliers.stream().map(s -> s.get()).filter(Objects::nonNull).collect(Collectors.toList());
245
246         String colorLocation = colorLocationCombo.getItem(colorLocationCombo.getSelectionIndex());
247         String colorSize = colorSizeCombo.getItem(colorSizeCombo.getSelectionIndex());
248         
249         ColorBarOptions colorBarOptions = new ColorBarOptions()
250                 .showColorBars(showColorButton.getSelection())
251                 .showColorBarsTicks(colorTicksButton.getSelection())
252                 .useGradients(colorGradientButton.getSelection())
253                 .withLocation(ColorBarsLocation.valueOf(colorLocation))
254                 .withSize(ColorBarsSize.valueOf(colorSize));
255         
256         List<Pair<String, DynamicSizeContribution>> sizeCollect = sizeSuppliers.stream().map(s -> s.get()).filter(Objects::nonNull).collect(Collectors.toList());
257         
258         String sizeLocation = sizeLocationCombo.getItem(sizeLocationCombo.getSelectionIndex());
259         String sizeSize = sizeSizeCombo.getItem(sizeSizeCombo.getSelectionIndex());
260         
261         SizeBarOptions sizeBarOptions = new SizeBarOptions()
262                 .showSizeBars(showSizeButton.getSelection())
263                 .showSizeBarsTicks(sizeTicksButton.getSelection())
264                 .useGradients(sizeGradientButton.getSelection())
265                 .withLocation(SizeBarsLocation.valueOf(sizeLocation))
266                 .withSize(SizeBarsSize.valueOf(sizeSize));
267         
268         Simantics.getSession().asyncRequest(new WriteRequest() {
269             
270             @Override
271             public void perform(WriteGraph graph) throws DatabaseException {
272                 DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
273                 Resource exist;
274                 if (existing.isPresent()) {
275                     exist = existing.get();
276                 } else {
277                     exist = DistrictNetworkUtil.createVisualisation(graph, diagramResource, templateName);
278                 }
279                 
280                 DistrictNetworkUtil.setColorContributions(graph, exist, colorCollect);
281                 
282                 DistrictNetworkUtil.setColorBarOptions(graph, exist, colorBarOptions);
283                 DistrictNetworkUtil.setSizeContributions(graph, exist, sizeCollect);
284                 DistrictNetworkUtil.setSizeBarOptions(graph, exist, sizeBarOptions);
285             }
286         });
287     }
288
289     private void initializeColoringObjects(Composite parent) {
290         Group group = new Group(parent, SWT.NONE);
291         group.setText("Coloring Objects");
292         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
293         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
294         
295         {
296             createColoringObjectHeaderRow(group);
297         }
298         colorSuppliers = new ArrayList<>();
299         {
300             try {
301                 Collection<DynamicColoringObject> result = Simantics.getSession().syncRequest(new UniqueRead<Collection<DynamicColoringObject>>() {
302
303                     @Override
304                     public Collection<DynamicColoringObject> perform(ReadGraph graph) throws DatabaseException {
305                         return DynamicVisualisationsContributions.dynamicColoringObjects(graph);
306                     }
307                 });
308                 
309                 for (DynamicColoringObject object : result) {
310                     colorSuppliers.add(createColoringObjectRow(group, object));
311                 }
312
313             } catch (DatabaseException e) {
314                 LOGGER.error("Could not create coloring objecst", e);
315             }
316         }
317     }
318     
319     private void createColoringObjectHeaderRow(Composite parent) {
320
321         Label label = new Label(parent, SWT.NONE);
322         label.setText("Label");
323         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
324         
325         label = new Label(parent, SWT.NONE);
326         label.setText("Used");
327         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
328         
329         label = new Label(parent, SWT.NONE);
330         label.setText("Variable");
331         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
332         
333         label = new Label(parent, SWT.NONE);
334         label.setText("Min");
335         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
336         
337         label = new Label(parent, SWT.NONE);
338         label.setText("Max");
339         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
340         
341         label = new Label(parent, SWT.NONE);
342         label.setText("Unit");
343         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
344         
345         label = new Label(parent, SWT.NONE);
346         label.setText("ColorMap");
347         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
348         
349         label = new Label(parent, SWT.NONE);
350         label.setText("Default");
351         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
352     }
353
354     private Map<String, ColoringObjectRow> coloringRows = new HashMap<>();
355     private Map<String, SizingObjectRow> sizingRows = new HashMap<>();
356
357     private VisualisationsListener visualisationsListener;
358
359     private Collection<NamedResource> visualisations;
360
361     private List<Supplier<Pair<String, DynamicSizeContribution>>> sizeSuppliers;
362
363     private static class ColoringObjectRow {
364         
365         private final Label label;
366         private final Button usedButton;
367         private final Combo variableCombo;
368         private final Text minText;
369         private final Text maxText;
370         private final Label unit;
371         private final Combo colorMapCombo;
372         private final Button defaultButton;
373         
374         public ColoringObjectRow(Label label, Button usedButton, Combo variableCombo, Text minText, Text maxText, Label unit,
375                 Combo colorMapCombo, Button defaultButton) {
376             super();
377             this.label = label;
378             this.usedButton = usedButton;
379             this.variableCombo = variableCombo;
380             this.minText = minText;
381             this.maxText = maxText;
382             this.unit = unit;
383             this.colorMapCombo = colorMapCombo;
384             this.defaultButton = defaultButton;
385         }
386
387         public void update(DynamicColorContribution colorContribution) {
388             String[] items = variableCombo.getItems();
389             for (int i = 0; i < items.length; i++) {
390                 if (colorContribution.getLabel().equals(items[i])) {
391                     variableCombo.select(i);
392                     break;
393                 }
394             }
395             minText.setText(Double.toString(colorContribution.getDefaultMin()));
396             maxText.setText(Double.toString(colorContribution.getDefaultMax()));
397             unit.setText(colorContribution.getUnit());
398             
399             // color map only supports single for now
400             colorMapCombo.setItems(colorContribution.getDefaultColorMap().getLabel());
401             colorMapCombo.select(0);
402 //            String[] colorItems = colorMapCombo.getItems();
403 //            for (int i = 0; i < colorItems.length; i++) {
404 //                
405 //                if (colorContribution.getDefaultColorMap().getLabel().equals(colorItems[i])) {
406 //                    colorMapCombo.select(i);
407 //                    break;
408 //                }
409 //            }
410             usedButton.setSelection(colorContribution.isUsed());
411             defaultButton.setSelection(colorContribution.isUseDefault());
412             
413             minText.setEnabled(!colorContribution.isUseDefault());
414             maxText.setEnabled(!colorContribution.isUseDefault());
415             colorMapCombo.setEnabled(!colorContribution.isUseDefault());
416         }
417     }
418
419     private static class SizingObjectRow {
420         
421         private final Label label;
422         private final Button usedButton;
423         private final Combo variableCombo;
424         private final Text minText;
425         private final Text maxText;
426         private final Label unit;
427         private final Combo sizeMapCombo;
428         private final Button defaultButton;
429         
430         public SizingObjectRow(Label label, Button usedButton, Combo variableCombo, Text minText, Text maxText, Label unit,
431                 Combo sizeMapCombo, Button defaultButton) {
432             super();
433             this.label = label;
434             this.usedButton = usedButton;
435             this.variableCombo = variableCombo;
436             this.minText = minText;
437             this.maxText = maxText;
438             this.unit = unit;
439             this.sizeMapCombo = sizeMapCombo;
440             this.defaultButton = defaultButton;
441         }
442
443         public void update(DynamicSizeContribution sizeContribution) {
444             String[] items = variableCombo.getItems();
445             for (int i = 0; i < items.length; i++) {
446                 if (sizeContribution.getLabel().equals(items[i])) {
447                     variableCombo.select(i);
448                     break;
449                 }
450             }
451             minText.setText(Double.toString(sizeContribution.getDefaultMin()));
452             maxText.setText(Double.toString(sizeContribution.getDefaultMax()));
453             unit.setText(sizeContribution.getUnit());
454             
455             // color map only supports single for now
456             sizeMapCombo.setItems(sizeContribution.getDefaultSizeMap().getLabel());
457             sizeMapCombo.select(0);
458 //            String[] colorItems = colorMapCombo.getItems();
459 //            for (int i = 0; i < colorItems.length; i++) {
460 //                
461 //                if (colorContribution.getDefaultColorMap().getLabel().equals(colorItems[i])) {
462 //                    colorMapCombo.select(i);
463 //                    break;
464 //                }
465 //            }
466             usedButton.setSelection(sizeContribution.isUsed());
467             defaultButton.setSelection(sizeContribution.isUseDefault());
468             
469             minText.setEnabled(!sizeContribution.isUseDefault());
470             maxText.setEnabled(!sizeContribution.isUseDefault());
471             sizeMapCombo.setEnabled(!sizeContribution.isUseDefault());
472         }
473     }
474
475     private Supplier<Pair<String, DynamicColorContribution>> createColoringObjectRow(Composite parent, DynamicColoringObject object) {
476         Label label = new Label(parent, SWT.NONE);
477         label.setText(object.getColoringObject().getName());
478         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(label);
479         
480         Map<String, DynamicColorContribution> colorContributions = object.getColorContributions();
481         
482         Button usedButton = new Button(parent, SWT.CHECK);
483         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(usedButton);
484         
485         Combo variableCombo = new Combo(parent, SWT.READ_ONLY);
486         variableCombo.setItems(colorContributions.keySet().toArray(new String[colorContributions.size()]));
487         
488         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(variableCombo);
489         
490         Text minText = new Text(parent, SWT.BORDER);
491         GridDataFactory.fillDefaults().grab(true, false).hint(150, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(minText);
492         
493         Text maxText = new Text(parent, SWT.BORDER);
494         GridDataFactory.fillDefaults().grab(true, false).hint(150, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(maxText);
495         
496         Label unit = new Label(parent, SWT.NONE);
497         unit.setText("");
498         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(unit);
499         
500         Combo colorMapCombo = new Combo(parent, SWT.READ_ONLY);
501         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(colorMapCombo);
502         
503         Button defaultButton = new Button(parent, SWT.CHECK);
504         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(defaultButton);
505         defaultButton.addSelectionListener(new SelectionAdapter() {
506             
507             @Override
508             public void widgetSelected(SelectionEvent e) {
509                 int index = variableCombo.getSelectionIndex();
510                 if (index >= 0) {
511                     String key = variableCombo.getItem(index);
512                     DynamicColorContribution cont = colorContributions.get(key);
513                     
514                     minText.setText(Double.toString(cont.getDefaultMin()));
515                     minText.setEnabled(!defaultButton.getSelection());
516                     maxText.setText(Double.toString(cont.getDefaultMax()));
517                     maxText.setEnabled(!defaultButton.getSelection());
518                     unit.setText(cont.getUnit());
519                     
520                     colorMapCombo.setItems(cont.getDefaultColorMap().getLabel());
521                     colorMapCombo.select(0);
522                     colorMapCombo.setEnabled(!defaultButton.getSelection());
523                 }
524             }
525         });
526         
527         variableCombo.addSelectionListener(new SelectionAdapter() {
528             
529             @Override
530             public void widgetSelected(SelectionEvent e) {
531                 // handle update for others
532                 int index = variableCombo.getSelectionIndex();
533                 if (index >= 0) {
534                     String key = variableCombo.getItem(index);
535                     DynamicColorContribution cont = colorContributions.get(key);
536                     
537                     if (minText.getText().isEmpty()) {
538                         minText.setText(Double.toString(cont.getDefaultMin()));
539                     }
540                     if (maxText.getText().isEmpty()) {
541                         maxText.setText(Double.toString(cont.getDefaultMax()));
542                     }
543                     unit.setText(cont.getUnit());
544                     
545                     colorMapCombo.setItems(cont.getDefaultColorMap().getLabel());
546                     colorMapCombo.select(0);
547                     
548                     defaultButton.setSelection(true);
549                 }
550             }
551         });
552         
553         coloringRows.put(object.getColoringObject().getName(), new ColoringObjectRow(label, usedButton, variableCombo, minText, maxText, unit, colorMapCombo, defaultButton));
554
555         return new Supplier<Pair<String, DynamicColorContribution>>() {
556
557             @Override
558             public Pair<String, DynamicColorContribution> get() {
559                 int selectionIndex = variableCombo.getSelectionIndex();
560                 if (selectionIndex >= 0) {
561                     String key = variableCombo.getItem(selectionIndex);
562                     DynamicColorContribution cont = colorContributions.get(key);
563                     if (cont != null) {
564                         String colorMap = colorMapCombo.getItem(colorMapCombo.getSelectionIndex());
565                         try {
566                             Map<String, DynamicColorMap> colorMaps = Simantics.getSession().syncRequest(new UniqueRead<Map<String, DynamicColorMap>>() {
567         
568                                 @Override
569                                 public Map<String, DynamicColorMap> perform(ReadGraph graph) throws DatabaseException {
570                                     return DynamicVisualisationsContributions.dynamicColorMaps(graph);
571                                 }
572                             });
573                             DynamicColorMap dColorMap = colorMaps.get(colorMap);
574                             String label = variableCombo.getItem(variableCombo.getSelectionIndex());
575                             
576                             DynamicColorContribution dcc = new DynamicColorContribution(label, cont.getModuleName(), cont.getAttributeName(), unit.getText(), cont.getVariableGain(), cont.getVariableBias(), dColorMap, Double.parseDouble(minText.getText()), Double.parseDouble(maxText.getText()));
577                             dcc.setUsed(usedButton.getSelection());
578                             dcc.setUseDefault(defaultButton.getSelection());
579                             
580                             return Pair.make(object.getColoringObject().getName(), dcc);
581                         } catch (DatabaseException e) {
582                             LOGGER.error("Could not get DynamicColorContribution", e);
583                         }
584                     }
585                 }
586                 return null;
587             }
588         };
589     }
590     
591     private void createSizingObjectHeaderRow(Composite parent) {
592
593         Label label = new Label(parent, SWT.NONE);
594         label.setText("Label");
595         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
596         
597         label = new Label(parent, SWT.NONE);
598         label.setText("Used");
599         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
600         
601         label = new Label(parent, SWT.NONE);
602         label.setText("Variable");
603         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
604         
605         label = new Label(parent, SWT.NONE);
606         label.setText("Min");
607         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
608         
609         label = new Label(parent, SWT.NONE);
610         label.setText("Max");
611         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
612         
613         label = new Label(parent, SWT.NONE);
614         label.setText("Unit");
615         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
616         
617         label = new Label(parent, SWT.NONE);
618         label.setText("SizeMap");
619         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
620         
621         label = new Label(parent, SWT.NONE);
622         label.setText("Default");
623         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
624     }
625
626     private Supplier<Pair<String, DynamicSizeContribution>> createSizingObjectRow(Composite parent, DynamicSizingObject object) {
627         Label label = new Label(parent, SWT.NONE);
628         label.setText(object.getSizingObject().getName());
629         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(label);
630         
631         Map<String, DynamicSizeContribution> sizeContributions = object.getSizeContributions();
632         
633         Button usedButton = new Button(parent, SWT.CHECK);
634         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(usedButton);
635         
636         Combo variableCombo = new Combo(parent, SWT.READ_ONLY);
637         variableCombo.setItems(sizeContributions.keySet().toArray(new String[sizeContributions.size()]));
638         
639         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(variableCombo);
640         
641         Text minText = new Text(parent, SWT.BORDER);
642         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(minText);
643         
644         Text maxText = new Text(parent, SWT.BORDER);
645         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(maxText);
646         
647         Label unit = new Label(parent, SWT.NONE);
648         unit.setText("");
649         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(unit);
650         
651         Combo sizeMapCombo = new Combo(parent, SWT.READ_ONLY);
652         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(sizeMapCombo);
653         
654         Button defaultButton = new Button(parent, SWT.CHECK);
655         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(defaultButton);
656         
657         variableCombo.addSelectionListener(new SelectionAdapter() {
658             
659             @Override
660             public void widgetSelected(SelectionEvent e) {
661                 // handle update for others
662                 String key = variableCombo.getItem(variableCombo.getSelectionIndex());
663                 DynamicSizeContribution cont = sizeContributions.get(key);
664                 
665                 if (minText.getText().isEmpty()) {
666                     minText.setText(Double.toString(cont.getDefaultMin()));
667                 }
668                 if (maxText.getText().isEmpty()) {
669                     maxText.setText(Double.toString(cont.getDefaultMax()));
670                 }
671                 unit.setText(cont.getUnit());
672                 
673                 sizeMapCombo.setItems(cont.getDefaultSizeMap().getLabel());
674                 sizeMapCombo.select(0);
675                 
676                 defaultButton.setSelection(true);
677             }
678         });
679         
680         sizingRows.put(object.getSizingObject().getName(), new SizingObjectRow(label, usedButton, variableCombo, minText, maxText, unit, sizeMapCombo, defaultButton));
681         
682         return new Supplier<Pair<String, DynamicSizeContribution>>() {
683
684             @Override
685             public Pair<String, DynamicSizeContribution> get() {
686                 int selectionIndex = variableCombo.getSelectionIndex();
687                 if (selectionIndex >= 0) {
688                     String key = variableCombo.getItem(selectionIndex);
689                     DynamicSizeContribution cont = sizeContributions.get(key);
690                     if (cont != null) {
691                         String sizeMap = sizeMapCombo.getItem(sizeMapCombo.getSelectionIndex());
692                         try {
693                             Map<String, DynamicSizeMap> sizeMaps = Simantics.getSession().syncRequest(new UniqueRead<Map<String, DynamicSizeMap>>() {
694         
695                                 @Override
696                                 public Map<String, DynamicSizeMap> perform(ReadGraph graph) throws DatabaseException {
697                                     return DynamicVisualisationsContributions.dynamicSizeMaps(graph);
698                                 }
699                             });
700                             DynamicSizeMap dColorMap = sizeMaps.get(sizeMap);
701                             String label = variableCombo.getItem(variableCombo.getSelectionIndex());
702                             
703                             DynamicSizeContribution dsc = new DynamicSizeContribution(label, cont.getModuleName(), cont.getAttributeName(), unit.getText(), cont.getVariableGain(), cont.getVariableBias(), dColorMap, Double.parseDouble(minText.getText()), Double.parseDouble(maxText.getText()));
704                             dsc.setUsed(usedButton.getSelection());
705                             dsc.setUseDefault(defaultButton.getSelection());
706                             
707                             return Pair.make(object.getSizingObject().getName(), dsc);
708                         } catch (DatabaseException e) {
709                             LOGGER.error("Could not get DynamicColorContribution", e);
710                         }
711                     }
712                 }
713                 return null;
714             }
715         };
716     }
717     
718     private void initializeColorBars(Composite parent) {
719         Group group = new Group(parent, SWT.NONE);
720         group.setText("Color Bars");
721         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
722         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
723         
724         createColorBars(group);
725     }
726     
727     private void createColorBars(Composite parent) {
728         
729         showColorButton = new Button(parent, SWT.CHECK);
730         showColorButton.setText("Show");
731         
732         colorTicksButton = new Button(parent, SWT.CHECK);
733         colorTicksButton.setText("Ticks");
734         
735         colorGradientButton = new Button(parent, SWT.CHECK);
736         colorGradientButton.setText("Gradients");
737         
738         Label label = new Label(parent, SWT.NONE);
739         label.setText("Location");
740         colorLocationCombo = new Combo(parent, SWT.READ_ONLY);
741         String[] colorLocationItems = Stream.of(ColorBarsLocation.values()).map(size -> size.toString()).toArray(String[]::new);
742         colorLocationCombo.setItems(colorLocationItems);
743         if (colorLocationItems.length > 0) {
744             colorLocationCombo.select(0);
745         }
746         
747         label = new Label(parent, SWT.NONE);
748         label.setText("Size");
749         colorSizeCombo = new Combo(parent, SWT.READ_ONLY);
750         String[] colorSizeItems = Stream.of(ColorBarsSize.values()).map(size -> size.toString()).toArray(String[]::new);
751         colorSizeCombo.setItems(colorSizeItems);
752         if (colorSizeItems.length > 0) {
753             colorSizeCombo.select(0);
754         }
755     }
756
757     private void initializeObjectSizes(Composite parent) {
758         Group group = new Group(parent, SWT.NONE);
759         group.setText("Object Sizes");
760         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
761         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
762         
763         {
764             createSizingObjectHeaderRow(group);
765             createObjectSizes(group);
766         }
767     }
768     
769     private void createObjectSizes(Composite parent) {
770         
771         sizeSuppliers = new ArrayList<>(); 
772         try {
773             Collection<DynamicSizingObject> resultSizing = Simantics.getSession().syncRequest(new UniqueRead<Collection<DynamicSizingObject>>() {
774
775                 @Override
776                 public Collection<DynamicSizingObject> perform(ReadGraph graph) throws DatabaseException {
777                     return DynamicVisualisationsContributions.dynamicSizingObjects(graph);
778                 }
779             });
780             
781             for (DynamicSizingObject object : resultSizing) {
782                 sizeSuppliers.add(createSizingObjectRow(parent, object));
783             }
784         } catch (DatabaseException e) {
785             LOGGER.error("Could not create object sizes", e);
786         }
787     }
788
789     private void initializeSizeBars(Composite parent) {
790         Group group = new Group(parent, SWT.NONE);
791         group.setText("Size Bars");
792         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
793         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
794         
795         createSizeBars(group);
796     }
797
798     private void createSizeBars(Composite parent) {
799         showSizeButton = new Button(parent, SWT.CHECK);
800         showSizeButton.setText("Show");
801         
802         sizeTicksButton = new Button(parent, SWT.CHECK);
803         sizeTicksButton.setText("Ticks");
804         
805         sizeGradientButton = new Button(parent, SWT.CHECK);
806         sizeGradientButton.setText("Gradient");
807         
808         Label label = new Label(parent, SWT.NONE);
809         label.setText("Location");
810         sizeLocationCombo = new Combo(parent, SWT.READ_ONLY);
811         String[] sizeLocationItems = Stream.of(SizeBarsLocation.values()).map(size -> size.toString()).toArray(String[]::new);
812         sizeLocationCombo.setItems(sizeLocationItems);
813         if (sizeLocationItems.length > 0) {
814             sizeLocationCombo.select(0);
815         }
816         
817         label = new Label(parent, SWT.NONE);
818         label.setText("Size");
819         sizeSizeCombo = new Combo(parent, SWT.READ_ONLY);
820         String[] sizeSizeItems = Stream.of(SizeBarsSize.values()).map(size -> size.toString()).toArray(String[]::new);
821         sizeSizeCombo.setItems(sizeSizeItems);
822         if (sizeSizeItems.length > 0) {
823             sizeSizeCombo.select(0);
824         }
825     }
826
827     public void setDiagramResource(Resource diagramResource) {
828         if (this.diagramResource != diagramResource) {
829             this.diagramResource = diagramResource;
830             updateListening();
831         }
832     }
833
834     private void updateListening() {
835         if (visualisationsListener != null)
836             visualisationsListener.dispose();
837         visualisationsListener = new VisualisationsListener(this);
838         Simantics.getSession().asyncRequest(new DynamicVisualisationsRequest(diagramResource), visualisationsListener);
839         
840         if (listener != null)
841             listener.dispose();
842         listener = new VisualisationListener(this);
843         Simantics.getSession().asyncRequest(new ActiveDynamicVisualisationsRequest(diagramResource), listener);
844     }
845
846     private static class VisualisationsListener implements Listener<Collection<NamedResource>> {
847
848         private static final Logger LOGGER = LoggerFactory.getLogger(VisualisationsListener.class);
849
850         private boolean disposed;
851         private DynamicVisualisationsUI ui;
852         
853         public VisualisationsListener(DynamicVisualisationsUI ui) {
854             this.ui = ui;
855         }
856
857         @Override
858         public void execute(Collection<NamedResource> result) {
859             ui.updateVisualisations(result);
860         }
861
862         @Override
863         public void exception(Throwable t) {
864             LOGGER.error("Could not listen visualisation", t);
865         }
866
867         @Override
868         public boolean isDisposed() {
869             return disposed || ui.isDisposed();
870         }
871
872         public void dispose() {
873             this.disposed = true;
874         }
875     }
876     
877     private static class VisualisationListener implements Listener<DynamicVisualisation> {
878
879         private static final Logger LOGGER = LoggerFactory.getLogger(VisualisationListener.class);
880
881         private boolean disposed;
882         private DynamicVisualisationsUI ui;
883         
884         public VisualisationListener(DynamicVisualisationsUI ui) {
885             this.ui = ui;
886         }
887
888         @Override
889         public void execute(DynamicVisualisation result) {
890             ui.updateVisualisation(result);
891         }
892
893         @Override
894         public void exception(Throwable t) {
895             LOGGER.error("Could not listen visualisation", t);
896         }
897
898         @Override
899         public boolean isDisposed() {
900             return disposed || ui.isDisposed();
901         }
902
903         public void dispose() {
904             this.disposed = true;
905         }
906     }
907
908     public void updateVisualisation(DynamicVisualisation result) {
909         this.visualisation = result;
910         Display.getDefault().asyncExec(() -> {
911             if (getParent().isDisposed())
912                 return;
913             
914             applyButton.setEnabled(visualisation != null && visualisation.getVisualisationResource() != null);
915             removeVisualisationTemplateButton.setEnabled(visualisation != null && visualisation.getVisualisationResource() != null);
916             
917             if (visualisation != null) {
918                 String[] items = templateSelectionCombo.getItems();
919                 for (int i = 0; i < items.length; i++) {
920                     if (visualisation.getName().equals(items[i])) {
921                         templateSelectionCombo.select(i);
922                         break;
923                     }
924                 }
925                 
926                 Map<String, DynamicColorContribution> colorContributions = visualisation.getColorContributions();
927                 for (Entry<String, DynamicColorContribution> entry : colorContributions.entrySet()) {
928                     
929                     ColoringObjectRow coloringObjectRow = coloringRows.get(entry.getKey());
930                     if (coloringObjectRow != null) {
931                         
932                         coloringObjectRow.update(entry.getValue());
933                         
934                     } else {
935                         LOGGER.info("No coloring object visualisation row for key {}", entry.getKey());
936                     }
937                 }
938                 ColorBarOptions colorOptions = visualisation.getColorBarOptions();
939                 showColorButton.setSelection(colorOptions.isShowColorBars());
940                 colorTicksButton.setSelection(colorOptions.isShowColorBarsTicks());
941                 for (int i = 0; i < colorLocationCombo.getItems().length; i++) {
942                     String item = colorLocationCombo.getItem(i);
943                     if (item.equals(colorOptions.getLocation().toString())) {
944                         colorLocationCombo.select(i);
945                         break;
946                     }
947                 }
948                 for (int i = 0; i < colorSizeCombo.getItems().length; i++) {
949                     String item = colorSizeCombo.getItem(i);
950                     if (item.equals(colorOptions.getSize().toString())) {
951                         colorSizeCombo.select(i);
952                         break;
953                     }
954                 }
955                 
956                 Map<String, DynamicSizeContribution> sizeContributions = visualisation.getSizeContributions();
957                 for (Entry<String, DynamicSizeContribution> entry : sizeContributions.entrySet()) {
958                     
959                     SizingObjectRow sizingObjectRow = sizingRows.get(entry.getKey());
960                     if (sizingObjectRow != null) {
961                         
962                         sizingObjectRow.update(entry.getValue());
963                         
964                     } else {
965                         LOGGER.info("No sizing object visualisation row for key {}", entry.getKey());
966                     }
967                 }
968                 SizeBarOptions sizeOptions = visualisation.getSizeBarOptions();
969                 showSizeButton.setSelection(sizeOptions.isShowSizeBars());
970                 sizeTicksButton.setSelection(sizeOptions.isShowSizeBarsTicks());
971                 for (int i = 0; i < sizeLocationCombo.getItems().length; i++) {
972                     String item = sizeLocationCombo.getItem(i);
973                     if (item.equals(sizeOptions.getLocation().toString())) {
974                         sizeLocationCombo.select(i);
975                         break;
976                     }
977                 }
978                 for (int i = 0; i < sizeSizeCombo.getItems().length; i++) {
979                     String item = sizeSizeCombo.getItem(i);
980                     if (item.equals(sizeOptions.getSize().toString())) {
981                         sizeSizeCombo.select(i);
982                         break;
983                     }
984                 }
985             }
986         });
987     }
988
989     public void updateVisualisations(Collection<NamedResource> result) {
990         this.visualisations = result;
991         
992         Display.getDefault().asyncExec(() -> {
993             if (getParent().isDisposed())
994                 return;
995             templateSelectionCombo.setItems(visualisations.stream().map(NamedResource::getName).collect(Collectors.toList()).toArray(new String[visualisations.size()]));
996             
997             if (visualisation != null) {
998                 String[] items = templateSelectionCombo.getItems();
999                 for (int i = 0; i < items.length; i++) {
1000                     if (visualisation.getName().equals(items[i])) {
1001                         templateSelectionCombo.select(i);
1002                         break;
1003                     }
1004                 }
1005             }
1006             
1007         });
1008     }
1009 }