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