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