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