]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/visualisations/DynamicVisualisationsUI.java
First version of district visualisations
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / visualisations / DynamicVisualisationsUI.java
1 package org.simantics.district.network.ui.visualisations;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Map.Entry;
9 import java.util.Objects;
10 import java.util.function.Supplier;
11 import java.util.stream.Collectors;
12 import java.util.stream.Stream;
13
14 import org.eclipse.jface.layout.GridDataFactory;
15 import org.eclipse.jface.layout.GridLayoutFactory;
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.events.SelectionAdapter;
18 import org.eclipse.swt.events.SelectionEvent;
19 import org.eclipse.swt.widgets.Button;
20 import org.eclipse.swt.widgets.Combo;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Display;
23 import org.eclipse.swt.widgets.Group;
24 import org.eclipse.swt.widgets.Label;
25 import org.eclipse.swt.widgets.Text;
26 import org.eclipse.ui.IEditorPart;
27 import org.simantics.Simantics;
28 import org.simantics.db.ReadGraph;
29 import org.simantics.db.Resource;
30 import org.simantics.db.WriteGraph;
31 import org.simantics.db.common.request.UniqueRead;
32 import org.simantics.db.common.request.WriteRequest;
33 import org.simantics.db.exception.DatabaseException;
34 import org.simantics.db.procedure.Listener;
35 import org.simantics.district.network.DistrictNetworkUtil;
36 import org.simantics.district.network.profile.DynamicVisualisationsRequest;
37 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions;
38 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions.DynamicColoringObject;
39 import org.simantics.district.network.visualisations.DynamicVisualisationsContributions.DynamicSizingObject;
40 import org.simantics.district.network.visualisations.model.ColorBarOptions;
41 import org.simantics.district.network.visualisations.model.ColorBarOptions.ColorBarsLocation;
42 import org.simantics.district.network.visualisations.model.ColorBarOptions.ColorBarsSize;
43 import org.simantics.district.network.visualisations.model.DynamicColorContribution;
44 import org.simantics.district.network.visualisations.model.DynamicColorMap;
45 import org.simantics.district.network.visualisations.model.DynamicSizeContribution;
46 import org.simantics.district.network.visualisations.model.DynamicSizeMap;
47 import org.simantics.district.network.visualisations.model.DynamicVisualisation;
48 import org.simantics.district.network.visualisations.model.SizeBarOptions;
49 import org.simantics.district.network.visualisations.model.SizeBarOptions.SizeBarsLocation;
50 import org.simantics.district.network.visualisations.model.SizeBarOptions.SizeBarsSize;
51 import org.simantics.ui.workbench.IResourceEditorPart;
52 import org.simantics.utils.datastructures.Pair;
53 import org.simantics.utils.ui.workbench.WorkbenchUtils;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 public class DynamicVisualisationsUI extends Composite {
58
59     private static final Logger LOGGER = LoggerFactory.getLogger(DynamicVisualisationsUI.class);
60
61     private Resource diagramResource;
62     private VisualisationListener listener;
63     private DynamicVisualisation visualisation;
64
65     private Button showSizeButton;
66     private Button sizeTicksButton;
67     private Combo sizeLocationCombo;
68     private Combo sizeSizeCombo;
69     private Button showColorButton;
70     private Button colorTicksButton;
71     private Combo colorLocationCombo;
72     private Combo colorSizeCombo;
73
74     public DynamicVisualisationsUI(Composite parent, int style) {
75         super(parent, style);
76
77         defaultInitializeUI();
78     }
79
80     private void defaultInitializeUI() {
81         GridDataFactory.fillDefaults().grab(true, true).applyTo(this);
82         GridLayoutFactory.fillDefaults().numColumns(1).margins(5, 5).applyTo(this);
83         
84         Composite coloringObjectsComposite = new Composite(this, SWT.NONE);
85         GridDataFactory.fillDefaults().grab(true, false).applyTo(coloringObjectsComposite);
86         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(coloringObjectsComposite);
87         initializeColoringObjects(coloringObjectsComposite);
88         
89         Composite colorBarsComposite = new Composite(this, SWT.NONE);
90         GridDataFactory.fillDefaults().grab(true, false).applyTo(colorBarsComposite);
91         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(colorBarsComposite);
92         initializeColorBars(colorBarsComposite);
93         
94         Composite objectSizesComposite = new Composite(this, SWT.NONE);
95         GridDataFactory.fillDefaults().grab(true, false).applyTo(objectSizesComposite);
96         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(objectSizesComposite);
97         initializeObjectSizes(objectSizesComposite);
98         
99         Composite sizeBarsComposite = new Composite(this, SWT.NONE);
100         GridDataFactory.fillDefaults().grab(true, false).applyTo(sizeBarsComposite);
101         GridLayoutFactory.fillDefaults().numColumns(1).applyTo(sizeBarsComposite);
102         initializeSizeBars(sizeBarsComposite);
103         
104     }
105
106     private void initializeColoringObjects(Composite parent) {
107         Group group = new Group(parent, SWT.NONE);
108         group.setText("Coloring Objects");
109         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
110         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
111         
112         {
113             createColoringObjectHeaderRow(group);
114         }
115         List<Supplier<Pair<String, DynamicColorContribution>>> suppliers = new ArrayList<>();
116         {
117             try {
118                 Collection<DynamicColoringObject> result = Simantics.getSession().syncRequest(new UniqueRead<Collection<DynamicColoringObject>>() {
119
120                     @Override
121                     public Collection<DynamicColoringObject> perform(ReadGraph graph) throws DatabaseException {
122                         return DynamicVisualisationsContributions.dynamicColoringObjects(graph);
123                     }
124                 });
125                 
126                 for (DynamicColoringObject object : result) {
127                     suppliers.add(createColoringObjectRow(group, object));
128                 }
129
130             } catch (DatabaseException e) {
131                 e.printStackTrace();
132             }
133         }
134         {
135             Button applyButton = new Button(group, SWT.NONE);
136             applyButton.setText("Apply");
137             applyButton.addSelectionListener(new SelectionAdapter() {
138                 
139                 @Override
140                 public void widgetSelected(SelectionEvent e) {
141                     List<Pair<String, DynamicColorContribution>> collect = suppliers.stream().map(s -> s.get()).filter(Objects::nonNull).collect(Collectors.toList());
142                     Simantics.getSession().asyncRequest(new WriteRequest() {
143                         
144                         @Override
145                         public void perform(WriteGraph graph) throws DatabaseException {
146                             DistrictNetworkUtil.setColorContributions(graph, DynamicVisualisationsUI.this.diagramResource, collect);
147                         }
148                     });
149                 }
150             });
151         }
152     }
153     
154     private void createColoringObjectHeaderRow(Composite parent) {
155
156         Label label = new Label(parent, SWT.NONE);
157         label.setText("Label");
158         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
159         
160         label = new Label(parent, SWT.NONE);
161         label.setText("Used");
162         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
163         
164         label = new Label(parent, SWT.NONE);
165         label.setText("Variable");
166         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
167         
168         label = new Label(parent, SWT.NONE);
169         label.setText("Min");
170         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
171         
172         label = new Label(parent, SWT.NONE);
173         label.setText("Max");
174         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
175         
176         label = new Label(parent, SWT.NONE);
177         label.setText("Unit");
178         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
179         
180         label = new Label(parent, SWT.NONE);
181         label.setText("ColorMap");
182         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
183         
184         label = new Label(parent, SWT.NONE);
185         label.setText("Default");
186         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
187     }
188
189     private Map<String, ColoringObjectRow> coloringRows = new HashMap<>();
190     private Map<String, SizingObjectRow> sizingRows = new HashMap<>();
191
192     private static class ColoringObjectRow {
193         
194         private final Label label;
195         private final Button usedButton;
196         private final Combo variableCombo;
197         private final Text minText;
198         private final Text maxText;
199         private final Label unit;
200         private final Combo colorMapCombo;
201         private final Button defaultButton;
202         
203         public ColoringObjectRow(Label label, Button usedButton, Combo variableCombo, Text minText, Text maxText, Label unit,
204                 Combo colorMapCombo, Button defaultButton) {
205             super();
206             this.label = label;
207             this.usedButton = usedButton;
208             this.variableCombo = variableCombo;
209             this.minText = minText;
210             this.maxText = maxText;
211             this.unit = unit;
212             this.colorMapCombo = colorMapCombo;
213             this.defaultButton = defaultButton;
214         }
215
216         public void update(DynamicColorContribution colorContribution) {
217             String[] items = variableCombo.getItems();
218             for (int i = 0; i < items.length; i++) {
219                 if (colorContribution.getLabel().equals(items[i])) {
220                     variableCombo.select(i);
221                     break;
222                 }
223             }
224             minText.setText(Double.toString(colorContribution.getDefaultMin()));
225             maxText.setText(Double.toString(colorContribution.getDefaultMax()));
226             unit.setText(colorContribution.getUnit());
227             
228             // color map only supports single for now
229             colorMapCombo.setItems(colorContribution.getDefaultColorMap().getLabel());
230             colorMapCombo.select(0);
231 //            String[] colorItems = colorMapCombo.getItems();
232 //            for (int i = 0; i < colorItems.length; i++) {
233 //                
234 //                if (colorContribution.getDefaultColorMap().getLabel().equals(colorItems[i])) {
235 //                    colorMapCombo.select(i);
236 //                    break;
237 //                }
238 //            }
239         }
240     }
241
242     private static class SizingObjectRow {
243         
244         private final Label label;
245         private final Button usedButton;
246         private final Combo variableCombo;
247         private final Text minText;
248         private final Text maxText;
249         private final Label unit;
250         private final Combo sizeMapCombo;
251         private final Button defaultButton;
252         
253         public SizingObjectRow(Label label, Button usedButton, Combo variableCombo, Text minText, Text maxText, Label unit,
254                 Combo sizeMapCombo, Button defaultButton) {
255             super();
256             this.label = label;
257             this.usedButton = usedButton;
258             this.variableCombo = variableCombo;
259             this.minText = minText;
260             this.maxText = maxText;
261             this.unit = unit;
262             this.sizeMapCombo = sizeMapCombo;
263             this.defaultButton = defaultButton;
264         }
265
266         public void update(DynamicSizeContribution sizeContribution) {
267             String[] items = variableCombo.getItems();
268             for (int i = 0; i < items.length; i++) {
269                 if (sizeContribution.getLabel().equals(items[i])) {
270                     variableCombo.select(i);
271                     break;
272                 }
273             }
274             minText.setText(Double.toString(sizeContribution.getDefaultMin()));
275             maxText.setText(Double.toString(sizeContribution.getDefaultMax()));
276             unit.setText(sizeContribution.getUnit());
277             
278             // color map only supports single for now
279             sizeMapCombo.setItems(sizeContribution.getDefaultSizeMap().getLabel());
280             sizeMapCombo.select(0);
281 //            String[] colorItems = colorMapCombo.getItems();
282 //            for (int i = 0; i < colorItems.length; i++) {
283 //                
284 //                if (colorContribution.getDefaultColorMap().getLabel().equals(colorItems[i])) {
285 //                    colorMapCombo.select(i);
286 //                    break;
287 //                }
288 //            }
289         }
290     }
291
292     private Supplier<Pair<String, DynamicColorContribution>> createColoringObjectRow(Composite parent, DynamicColoringObject object) {
293         Label label = new Label(parent, SWT.NONE);
294         label.setText(object.getColoringObject().getName());
295         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(label);
296         
297         Map<String, DynamicColorContribution> colorContributions = object.getColorContributions();
298         
299         Button usedButton = new Button(parent, SWT.CHECK);
300         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(usedButton);
301         
302         Combo variableCombo = new Combo(parent, SWT.READ_ONLY);
303         variableCombo.setItems(colorContributions.keySet().toArray(new String[colorContributions.size()]));
304         
305         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(variableCombo);
306         
307         Text minText = new Text(parent, SWT.BORDER);
308         GridDataFactory.fillDefaults().grab(true, false).hint(150, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(minText);
309         
310         Text maxText = new Text(parent, SWT.BORDER);
311         GridDataFactory.fillDefaults().grab(true, false).hint(150, SWT.DEFAULT).align(SWT.CENTER, SWT.CENTER).applyTo(maxText);
312         
313         Label unit = new Label(parent, SWT.NONE);
314         unit.setText("");
315         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(unit);
316         
317         Combo colorMapCombo = new Combo(parent, SWT.READ_ONLY);
318         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(colorMapCombo);
319         
320         Button defaultButton = new Button(parent, SWT.CHECK);
321         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(defaultButton);
322         
323         variableCombo.addSelectionListener(new SelectionAdapter() {
324             
325             @Override
326             public void widgetSelected(SelectionEvent e) {
327                 // handle update for others
328                 
329                 DynamicColorContribution cont = colorContributions.get(variableCombo.getText());
330                 
331                 if (minText.getText().isEmpty()) {
332                     minText.setText(Double.toString(cont.getDefaultMin()));
333                 }
334                 if (maxText.getText().isEmpty()) {
335                     maxText.setText(Double.toString(cont.getDefaultMax()));
336                 }
337                 unit.setText(cont.getUnit());
338                 
339                 colorMapCombo.setItems(cont.getDefaultColorMap().getLabel());
340                 colorMapCombo.select(0);
341                 
342                 defaultButton.setSelection(true);
343             }
344         });
345
346         coloringRows.put(object.getColoringObject().getName(), new ColoringObjectRow(label, usedButton, variableCombo, minText, maxText, unit, colorMapCombo, defaultButton));
347
348         return new Supplier<Pair<String, DynamicColorContribution>>() {
349
350             @Override
351             public Pair<String, DynamicColorContribution> get() {
352                 DynamicColorContribution cont = colorContributions.get(variableCombo.getText());
353                 if (cont != null) {
354                     String colorMap = colorMapCombo.getItem(colorMapCombo.getSelectionIndex());
355                     try {
356                         Map<String, DynamicColorMap> colorMaps = Simantics.getSession().syncRequest(new UniqueRead<Map<String, DynamicColorMap>>() {
357     
358                             @Override
359                             public Map<String, DynamicColorMap> perform(ReadGraph graph) throws DatabaseException {
360                                 return DynamicVisualisationsContributions.dynamicColorMaps(graph);
361                             }
362                         });
363                         DynamicColorMap dColorMap = colorMaps.get(colorMap);
364                         String label = variableCombo.getItem(variableCombo.getSelectionIndex());
365                         
366                         DynamicColorContribution dcc = new DynamicColorContribution(label, cont.getModuleName(), cont.getAttributeName(), unit.getText(), cont.getVariableGain(), cont.getVariableBias(), dColorMap, Double.parseDouble(minText.getText()), Double.parseDouble(maxText.getText()));
367                         dcc.setUsed(usedButton.getSelection());
368                         dcc.setUseDefault(defaultButton.getSelection());
369                         
370                         return Pair.make(object.getColoringObject().getName(), dcc);
371                     } catch (DatabaseException e) {
372                         LOGGER.error("Could not get DynamicColorContribution", e);
373                     }
374                 }
375                 return null;
376             }
377         };
378     }
379     
380     private void createSizingObjectHeaderRow(Composite parent) {
381
382         Label label = new Label(parent, SWT.NONE);
383         label.setText("Label");
384         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
385         
386         label = new Label(parent, SWT.NONE);
387         label.setText("Used");
388         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
389         
390         label = new Label(parent, SWT.NONE);
391         label.setText("Variable");
392         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
393         
394         label = new Label(parent, SWT.NONE);
395         label.setText("Min");
396         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
397         
398         label = new Label(parent, SWT.NONE);
399         label.setText("Max");
400         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
401         
402         label = new Label(parent, SWT.NONE);
403         label.setText("Unit");
404         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
405         
406         label = new Label(parent, SWT.NONE);
407         label.setText("SizeMap");
408         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
409         
410         label = new Label(parent, SWT.NONE);
411         label.setText("Default");
412         GridDataFactory.fillDefaults().grab(true, false).align(SWT.CENTER, SWT.CENTER).applyTo(label);
413     }
414
415     private Supplier<Pair<String, DynamicSizeContribution>> createSizingObjectRow(Composite parent, DynamicSizingObject object) {
416         Label label = new Label(parent, SWT.NONE);
417         label.setText(object.getSizingObject().getName());
418         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(label);
419         
420         Map<String, DynamicSizeContribution> sizeContributions = object.getSizeContributions();
421         
422         Button usedButton = new Button(parent, SWT.CHECK);
423         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(usedButton);
424         
425         Combo variableCombo = new Combo(parent, SWT.READ_ONLY);
426         variableCombo.setItems(sizeContributions.keySet().toArray(new String[sizeContributions.size()]));
427         
428         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(variableCombo);
429         
430         Text minText = new Text(parent, SWT.BORDER);
431         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(minText);
432         
433         Text maxText = new Text(parent, SWT.BORDER);
434         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(maxText);
435         
436         Label unit = new Label(parent, SWT.NONE);
437         unit.setText("");
438         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(unit);
439         
440         Combo sizeMapCombo = new Combo(parent, SWT.READ_ONLY);
441         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(sizeMapCombo);
442         
443         Button defaultButton = new Button(parent, SWT.CHECK);
444         GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.CENTER).applyTo(defaultButton);
445         
446         variableCombo.addSelectionListener(new SelectionAdapter() {
447             
448             @Override
449             public void widgetSelected(SelectionEvent e) {
450                 // handle update for others
451                 
452                 DynamicSizeContribution cont = sizeContributions.get(variableCombo.getText());
453                 
454                 if (minText.getText().isEmpty()) {
455                     minText.setText(Double.toString(cont.getDefaultMin()));
456                 }
457                 if (maxText.getText().isEmpty()) {
458                     maxText.setText(Double.toString(cont.getDefaultMax()));
459                 }
460                 unit.setText(cont.getUnit());
461                 
462                 sizeMapCombo.setItems(cont.getDefaultSizeMap().getLabel());
463                 sizeMapCombo.select(0);
464                 
465                 defaultButton.setSelection(true);
466             }
467         });
468         
469         sizingRows.put(object.getSizingObject().getName(), new SizingObjectRow(label, usedButton, variableCombo, minText, maxText, unit, sizeMapCombo, defaultButton));
470         
471         return new Supplier<Pair<String, DynamicSizeContribution>>() {
472
473             @Override
474             public Pair<String, DynamicSizeContribution> get() {
475                 DynamicSizeContribution cont = sizeContributions.get(variableCombo.getText());
476                 if (cont != null) {
477                     String sizeMap = sizeMapCombo.getItem(sizeMapCombo.getSelectionIndex());
478                     try {
479                         Map<String, DynamicSizeMap> sizeMaps = Simantics.getSession().syncRequest(new UniqueRead<Map<String, DynamicSizeMap>>() {
480     
481                             @Override
482                             public Map<String, DynamicSizeMap> perform(ReadGraph graph) throws DatabaseException {
483                                 return DynamicVisualisationsContributions.dynamicSizeMaps(graph);
484                             }
485                         });
486                         DynamicSizeMap dColorMap = sizeMaps.get(sizeMap);
487                         String label = variableCombo.getItem(variableCombo.getSelectionIndex());
488                         
489                         DynamicSizeContribution dsc = new DynamicSizeContribution(label, cont.getModuleName(), cont.getAttributeName(), unit.getText(), cont.getVariableGain(), cont.getVariableBias(), dColorMap, Double.parseDouble(minText.getText()), Double.parseDouble(maxText.getText()));
490                         dsc.setUsed(usedButton.getSelection());
491                         dsc.setUseDefault(defaultButton.getSelection());
492                         
493                         return Pair.make(object.getSizingObject().getName(), dsc);
494                     } catch (DatabaseException e) {
495                         LOGGER.error("Could not get DynamicColorContribution", e);
496                     }
497                 }
498                 return null;
499             }
500         };
501     }
502     
503     private void initializeColorBars(Composite parent) {
504         Group group = new Group(parent, SWT.NONE);
505         group.setText("Color Bars");
506         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
507         GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(group);
508         
509         createColorBars(group);
510     }
511     
512     private void createColorBars(Composite parent) {
513         
514         showColorButton = new Button(parent, SWT.CHECK);
515         showColorButton.setText("Show");
516         
517         colorTicksButton = new Button(parent, SWT.CHECK);
518         colorTicksButton.setText("Ticks");
519         
520         Label label = new Label(parent, SWT.NONE);
521         label.setText("Location");
522         colorLocationCombo = new Combo(parent, SWT.READ_ONLY);
523         colorLocationCombo.setItems(Stream.of(ColorBarsLocation.values()).map(size -> size.toString()).toArray(String[]::new));
524         
525         label = new Label(parent, SWT.NONE);
526         label.setText("Size");
527         colorSizeCombo = new Combo(parent, SWT.READ_ONLY);
528         colorSizeCombo.setItems(Stream.of(ColorBarsSize.values()).map(size -> size.toString()).toArray(String[]::new));
529         
530         Button applyButton = new Button(parent, SWT.NONE);
531         applyButton.setText("Apply");
532         
533         applyButton.addSelectionListener(new SelectionAdapter() {
534             
535             @Override
536             public void widgetSelected(SelectionEvent e) {
537                 // persist changes
538                 IEditorPart activeEditor = WorkbenchUtils.getActiveEditor();
539                 if (activeEditor instanceof IResourceEditorPart) {
540                     Resource diagram = ((IResourceEditorPart) activeEditor).getResourceInput().getResource();
541                     ColorBarOptions options = new ColorBarOptions()
542                             .showColorBars(showColorButton.getSelection())
543                             .showColorBarsTicks(colorTicksButton.getSelection())
544                             .withLocation(ColorBarsLocation.valueOf(colorLocationCombo.getText().toUpperCase()))
545                             .withSize(ColorBarsSize.valueOf(colorSizeCombo.getText().toUpperCase()));
546
547                     Simantics.getSession().asyncRequest(new WriteRequest() {
548                         
549                         @Override
550                         public void perform(WriteGraph graph) throws DatabaseException {
551                             DistrictNetworkUtil.setColorBarOptions(graph, diagram, options);
552                         }
553                     });
554                 }
555             }
556         });
557     }
558
559     private void initializeObjectSizes(Composite parent) {
560         Group group = new Group(parent, SWT.NONE);
561         group.setText("Object Sizes");
562         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
563         GridLayoutFactory.fillDefaults().numColumns(8).margins(5, 5).applyTo(group);
564         
565         {
566             createSizingObjectHeaderRow(group);
567             createObjectSizes(group);
568         }
569     }
570     
571     private void createObjectSizes(Composite parent) {
572         
573         List<Supplier<Pair<String, DynamicSizeContribution>>> suppliers = new ArrayList<>(); 
574         try {
575             Collection<DynamicSizingObject> resultSizing = Simantics.getSession().syncRequest(new UniqueRead<Collection<DynamicSizingObject>>() {
576
577                 @Override
578                 public Collection<DynamicSizingObject> perform(ReadGraph graph) throws DatabaseException {
579                     return DynamicVisualisationsContributions.dynamicSizingObjects(graph);
580                 }
581             });
582             
583             for (DynamicSizingObject object : resultSizing) {
584                 suppliers.add(createSizingObjectRow(parent, object));
585             }
586         } catch (DatabaseException e) {
587             e.printStackTrace();
588         }
589         
590         {
591             Button applyButton = new Button(parent, SWT.NONE);
592             applyButton.setText("Apply");
593             applyButton.addSelectionListener(new SelectionAdapter() {
594                 
595                 @Override
596                 public void widgetSelected(SelectionEvent e) {
597                     List<Pair<String, DynamicSizeContribution>> collect = suppliers.stream().map(s -> s.get()).filter(Objects::nonNull).collect(Collectors.toList());
598                     Simantics.getSession().asyncRequest(new WriteRequest() {
599                         
600                         @Override
601                         public void perform(WriteGraph graph) throws DatabaseException {
602                             DistrictNetworkUtil.setSizeContributions(graph, DynamicVisualisationsUI.this.diagramResource, collect);
603                         }
604                     });
605                 }
606             });
607         }
608     }
609
610     private void initializeSizeBars(Composite parent) {
611         Group group = new Group(parent, SWT.NONE);
612         group.setText("Size Bars");
613         GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
614         GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(group);
615         
616         createSizeBars(group);
617     }
618
619     private void createSizeBars(Composite parent) {
620         showSizeButton = new Button(parent, SWT.CHECK);
621         showSizeButton.setText("Show");
622         
623         sizeTicksButton = new Button(parent, SWT.CHECK);
624         sizeTicksButton.setText("Ticks");
625         
626         Label label = new Label(parent, SWT.NONE);
627         label.setText("Location");
628         sizeLocationCombo = new Combo(parent, SWT.READ_ONLY);
629         sizeLocationCombo.setItems(Stream.of(SizeBarsLocation.values()).map(size -> size.toString()).toArray(String[]::new));
630         
631         label = new Label(parent, SWT.NONE);
632         label.setText("Size");
633         sizeSizeCombo = new Combo(parent, SWT.NONE);
634         sizeSizeCombo.setItems(Stream.of(SizeBarsSize.values()).map(size -> size.toString()).toArray(String[]::new));
635         
636         Button applyButton = new Button(parent, SWT.READ_ONLY);
637         applyButton.setText("Apply");
638         
639         applyButton.addSelectionListener(new SelectionAdapter() {
640             
641             @Override
642             public void widgetSelected(SelectionEvent e) {
643                 // persist changes
644                 IEditorPart activeEditor = WorkbenchUtils.getActiveEditor();
645                 if (activeEditor instanceof IResourceEditorPart) {
646                     Resource diagram = ((IResourceEditorPart) activeEditor).getResourceInput().getResource();
647                     SizeBarOptions options = new SizeBarOptions()
648                             .showSizeBars(showSizeButton.getSelection())
649                             .showSizeBarsTicks(sizeTicksButton.getSelection())
650                             .withLocation(SizeBarsLocation.valueOf(sizeLocationCombo.getText().toUpperCase()))
651                             .withSize(SizeBarsSize.valueOf(sizeSizeCombo.getText().toUpperCase()));
652
653                     Simantics.getSession().asyncRequest(new WriteRequest() {
654                         
655                         @Override
656                         public void perform(WriteGraph graph) throws DatabaseException {
657                             DistrictNetworkUtil.setSizeBarOptions(graph, diagram, options);
658                         }
659                     });
660                 }
661             }
662         });
663     }
664
665     public void setDiagramResource(Resource diagramResource) {
666         if (this.diagramResource != diagramResource) {
667             this.diagramResource = diagramResource;
668             updateListening();
669         }
670     }
671
672     private void updateListening() {
673         if (listener != null) {
674             listener.dispose();
675         }
676         listener = new VisualisationListener(this);
677         Simantics.getSession().asyncRequest(new DynamicVisualisationsRequest(diagramResource), listener);
678     }
679
680     private static class VisualisationListener implements Listener<DynamicVisualisation> {
681
682         private static final Logger LOGGER = LoggerFactory.getLogger(VisualisationListener.class);
683
684         private boolean disposed;
685         private DynamicVisualisationsUI ui;
686         
687         public VisualisationListener(DynamicVisualisationsUI ui) {
688             this.ui = ui;
689         }
690
691         @Override
692         public void execute(DynamicVisualisation result) {
693             ui.updateVisualisation(result);
694         }
695
696         @Override
697         public void exception(Throwable t) {
698             LOGGER.error("Could not listen visualisation", t);
699         }
700
701         @Override
702         public boolean isDisposed() {
703             return disposed || ui.isDisposed();
704         }
705
706         public void dispose() {
707             this.disposed = true;
708         }
709     }
710
711     public void updateVisualisation(DynamicVisualisation result) {
712         this.visualisation = result;
713         Display.getDefault().asyncExec(() -> {
714             if (getParent().isDisposed())
715                 return;
716             
717             Map<String, DynamicColorContribution> colorContributions = visualisation.getColorContributions();
718             for (Entry<String, DynamicColorContribution> entry : colorContributions.entrySet()) {
719                 
720                 ColoringObjectRow coloringObjectRow = coloringRows.get(entry.getKey());
721                 if (coloringObjectRow != null) {
722                     
723                     coloringObjectRow.update(entry.getValue());
724                     
725                 } else {
726                     LOGGER.info("No coloring object visualisation row for key {}", entry.getKey());
727                 }
728             }
729             ColorBarOptions colorOptions = visualisation.getColorBarOptions();
730             showColorButton.setSelection(colorOptions.isShowColorBars());
731             colorTicksButton.setSelection(colorOptions.isShowColorBarsTicks());
732             for (int i = 0; i < colorLocationCombo.getItems().length; i++) {
733                 String item = colorLocationCombo.getItem(i);
734                 if (item.equals(colorOptions.getLocation().toString())) {
735                     colorLocationCombo.select(i);
736                     break;
737                 }
738             }
739             for (int i = 0; i < colorSizeCombo.getItems().length; i++) {
740                 String item = colorSizeCombo.getItem(i);
741                 if (item.equals(colorOptions.getSize().toString())) {
742                     colorSizeCombo.select(i);
743                     break;
744                 }
745             }
746             
747             Map<String, DynamicSizeContribution> sizeContributions = visualisation.getSizeContributions();
748             for (Entry<String, DynamicSizeContribution> entry : sizeContributions.entrySet()) {
749                 
750                 SizingObjectRow sizingObjectRow = sizingRows.get(entry.getKey());
751                 if (sizingObjectRow != null) {
752                     
753                     sizingObjectRow.update(entry.getValue());
754                     
755                 } else {
756                     LOGGER.info("No sizing object visualisation row for key {}", entry.getKey());
757                 }
758             }
759             SizeBarOptions sizeOptions = visualisation.getSizeBarOptions();
760             showSizeButton.setSelection(sizeOptions.isShowSizeBars());
761             sizeTicksButton.setSelection(sizeOptions.isShowSizeBarsTicks());
762             for (int i = 0; i < sizeLocationCombo.getItems().length; i++) {
763                 String item = sizeLocationCombo.getItem(i);
764                 if (item.equals(sizeOptions.getLocation().toString())) {
765                     sizeLocationCombo.select(i);
766                     break;
767                 }
768             }
769             for (int i = 0; i < sizeSizeCombo.getItems().length; i++) {
770                 String item = sizeSizeCombo.getItem(i);
771                 if (item.equals(sizeOptions.getSize().toString())) {
772                     sizeSizeCombo.select(i);
773                     break;
774                 }
775             }
776         });
777     }
778 }