]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/DistrictDiagramViewer.java
Move remaining profiles to visualisations for perf
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / DistrictDiagramViewer.java
1 package org.simantics.district.network.ui;
2
3 import java.awt.Color;
4 import java.awt.geom.AffineTransform;
5 import java.util.Collections;
6 import java.util.Map;
7 import java.util.Objects;
8 import java.util.concurrent.TimeUnit;
9 import java.util.function.Consumer;
10 import java.util.function.Supplier;
11
12 import org.simantics.datatypes.literal.RGB;
13 import org.simantics.db.ReadGraph;
14 import org.simantics.db.Resource;
15 import org.simantics.db.common.request.PossibleIndexRoot;
16 import org.simantics.db.common.request.UnaryRead;
17 import org.simantics.db.exception.DatabaseException;
18 import org.simantics.db.procedure.Listener;
19 import org.simantics.diagram.ui.DiagramModelHints;
20 import org.simantics.district.network.DistrictNetworkUtil;
21 import org.simantics.district.network.ontology.DistrictNetworkResource;
22 import org.simantics.district.network.ui.internal.Activator;
23 import org.simantics.district.network.ui.nodes.DistrictRenderingPreparationNode;
24 import org.simantics.district.network.ui.nodes.DistrictSelectionNode;
25 import org.simantics.district.network.ui.participants.DNPointerInteractor;
26 import org.simantics.district.network.ui.participants.DynamicVisualisationContributionsParticipant;
27 import org.simantics.district.network.ui.participants.MapRulerPainter;
28 import org.simantics.district.network.visualisations.DynamicVisualisations;
29 import org.simantics.district.network.visualisations.model.ColorBarOptions;
30 import org.simantics.district.network.visualisations.model.DynamicColorContribution;
31 import org.simantics.district.network.visualisations.model.DynamicSizeContribution;
32 import org.simantics.district.network.visualisations.model.SizeBarOptions;
33 import org.simantics.g2d.canvas.ICanvasContext;
34 import org.simantics.g2d.canvas.impl.CanvasContext;
35 import org.simantics.g2d.diagram.handler.PickRequest.PickFilter;
36 import org.simantics.g2d.diagram.participant.DelayedBatchElementPainter;
37 import org.simantics.g2d.diagram.participant.ElementPainter;
38 import org.simantics.g2d.diagram.participant.ElementPainterConfiguration;
39 import org.simantics.g2d.diagram.participant.Selection;
40 import org.simantics.g2d.diagram.participant.ZOrderHandler;
41 import org.simantics.g2d.participant.BackgroundPainter;
42 import org.simantics.g2d.participant.GridPainter;
43 import org.simantics.g2d.participant.PanZoomRotateHandler;
44 import org.simantics.g2d.participant.RenderingQualityInteractor;
45 import org.simantics.g2d.participant.TransformUtil;
46 import org.simantics.g2d.participant.ZoomToAreaHandler;
47 import org.simantics.g2d.scenegraph.SceneGraphConstants;
48 import org.simantics.maps.MapScalingTransform;
49 import org.simantics.maps.eclipse.MapPainter;
50 import org.simantics.maps.sg.commands.MapCommands;
51 import org.simantics.modeling.ui.diagramEditor.DiagramViewer;
52 import org.simantics.scenegraph.g2d.G2DParentNode;
53 import org.simantics.scenegraph.g2d.events.command.Command;
54 import org.simantics.scenegraph.g2d.events.command.CommandEvent;
55 import org.simantics.scenegraph.g2d.events.command.Commands;
56 import org.simantics.utils.datastructures.hints.IHintContext;
57 import org.simantics.utils.datastructures.hints.IHintContext.Key;
58 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 public class DistrictDiagramViewer extends DiagramViewer {
63
64         private static final Logger LOGGER = LoggerFactory.getLogger(DistrictDiagramViewer.class);
65
66     @Override
67     protected void addDiagramParticipants(ICanvasContext ctx) {
68         ctx.add(new ZOrderHandler());
69         ctx.add(new Selection());
70         ctx.add(new ElementPainter(new ElementPainterConfiguration().selectionNodeClass(DistrictSelectionNode.class)));
71         ctx.add(new DNPointerInteractor());
72         
73         AffineTransform tr = new AffineTransform(MapScalingTransform.INSTANCE);
74         ctx.add(new MapPainter(tr));
75         
76         DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant = new DynamicVisualisationContributionsParticipant(tr);
77         ctx.add(new NetworkDrawingParticipant(dynamicVisualisationContributionsParticipant, tr));
78         ctx.add(dynamicVisualisationContributionsParticipant);
79         
80         // Optimize AffineTransform memory allocations during district diagram rendering
81         G2DParentNode spatialRoot = (G2DParentNode) ctx.getSceneGraph().lookupNode(SceneGraphConstants.SPATIAL_ROOT_NODE_ID);
82         DistrictRenderingPreparationNode prepNode = new DistrictRenderingPreparationNode();
83         prepNode.setZIndex(Integer.MIN_VALUE / 2);
84         spatialRoot.addNode("districtRenderingPrepareNode", prepNode);
85     }
86     
87     protected String getPopupId() {
88         return "#DistrictDiagramPopup";
89     }
90
91     @Override
92     protected void fillInitialDiagramHints(Resource diagram, IHintContext initialHints) throws DatabaseException {
93         super.fillInitialDiagramHints(diagram, initialHints);
94         
95     }
96
97     @Override
98     public void initializeCanvasContext(CanvasContext ctx) {
99         super.initializeCanvasContext(ctx);
100         IHintContext h = ctx.getDefaultHintContext();
101         h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 10000.0);
102         h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 0.01);
103         h.setHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE, diagramResource);
104     }
105
106     @Override
107     protected void addPainterParticipants(ICanvasContext ctx) {
108         ctx.add(new RenderingQualityInteractor());
109         ctx.add(new DelayedBatchElementPainter(PickFilter.FILTER_MONITORS, 500, TimeUnit.MILLISECONDS));
110     }
111     
112     @Override
113     protected void addGridRulerBackgroundParticipants(CanvasContext ctx) {
114         ctx.add(new GridPainter());
115         ctx.add(new MapRulerPainter());
116         ctx.add(new BackgroundPainter());
117     }
118     
119     protected void addViewManipulationParticipants(CanvasContext ctx) {
120         // Let's replace with our special util
121         TransformUtil util = ctx.getAtMostOneItemOfClass(TransformUtil.class);
122         if (util != null)
123             ctx.remove(util);
124         ctx.add(new DistrictTransformUtil());
125         ctx.add(new DistrictPanZoomRotateHandler());
126         //ctx.add(new MousePanZoomInteractor());
127         //ctx.add(new MultitouchPanZoomRotateInteractor());
128         // ctx.add( new OrientationRestorer() );
129         ctx.add(new ZoomToAreaHandler());
130     }
131
132     @Override
133     protected void loadPageSettings(ICanvasContext ctx) {
134         super.loadPageSettings(ctx);
135         // this might be the wrong place to start such listening but at least
136         // super.loadPageSettings() does async-db-operations
137         setupDrawMapEnabled();
138         setupBackgroundColor();
139         setupColoringObjects();
140         setupColorBarOptions();
141         setupSizingObjects();
142         setupSizeBarOptions();
143         setupShowElevationServerBoundingBox();
144         
145         // add listeners
146         DistrictDiagramViewerListener[] listeners = Activator.getInstance().getDistrictDiagramViewerListeners();
147         if (listeners != null) {
148             for (DistrictDiagramViewerListener listener : listeners) {
149                 listener.diagramLoaded(getRuntime(), canvasContext);
150             }
151         }
152     }
153     
154     @Override
155     public void dispose() {
156         DistrictDiagramViewerListener[] listeners = Activator.getInstance().getDistrictDiagramViewerListeners();
157         if (listeners != null) {
158             Resource runtime = getRuntime();
159             for (DistrictDiagramViewerListener listener : listeners) {
160                 listener.diagramDisposed(runtime, canvasContext);
161             }
162         }
163         super.dispose();
164     }
165     
166     private void setupDrawMapEnabled() {
167         sessionContext.getSession().asyncRequest(new DrawMapEnabledRequest(getInputResource()), new DrawMapEnabledListener(
168                 result -> canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), result ? Commands.MAP_ENABLE : Commands.MAP_DISABLE)),
169                 () -> DistrictDiagramViewer.this.isDisposed()));
170     }
171
172     private void setupBackgroundColor() {
173         sessionContext.getSession().asyncRequest(new MapBackgroundColorRequest(getInputResource()), new MapBackgroundColorListener(
174                 result -> queueBackgroundColorChangeEvent(result),
175                 () -> DistrictDiagramViewer.this.isDisposed()));
176     }
177
178     private void queueBackgroundColorChangeEvent(RGB.Integer result) {
179         if (result != null) {
180             Color backgroundColor = new Color(result.red, result.green, result.blue);
181             canvasContext.getDefaultHintContext().setHint(MapCommands.KEY_MAP_BACKGROUND_COLOR, backgroundColor);
182             canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), MapCommands.MAP_BACKGROUND_COLOR_CHANGE));
183         }
184     }
185
186     private void setupColoringObjects() {
187         sessionContext.getSession().asyncRequest(new ColoringObjectsRequest(getInputResource()), new ColoringObjectsListener(
188                 result -> queueColoringObjectsChangeEvent(result),
189                 () -> DistrictDiagramViewer.this.isDisposed()));
190     }
191
192     
193     private void setupColorBarOptions() {
194         sessionContext.getSession().asyncRequest(new ColorBarOptionsRequest(getInputResource()), new ColorBarOptionsListener(
195                 result -> queueColorBarOptionsChangeEvent(result),
196                 () -> DistrictDiagramViewer.this.isDisposed()));
197     }
198
199     private void setupSizingObjects() {
200         sessionContext.getSession().asyncRequest(new SizingObjectsRequest(getInputResource()), new SizingObjectsListener(
201                 result -> queueSizingObjectsChangeEvent(result),
202                 () -> DistrictDiagramViewer.this.isDisposed()));
203     }
204
205     private void setupSizeBarOptions() {
206         sessionContext.getSession().asyncRequest(new SizeBarOptionsRequest(getInputResource()), new SizeBarOptionsListener(
207                 result -> queueSizeBarOptionsChangeEvent(result),
208                 () -> DistrictDiagramViewer.this.isDisposed()));
209     }
210
211     private void setupShowElevationServerBoundingBox() {
212         sessionContext.getSession().asyncRequest(new ShowElevationServerRequest(getInputResource()), new ShowElevationServerListener(
213                 result -> queueShowElevationServerChangeEvent(result),
214                 () -> DistrictDiagramViewer.this.isDisposed()));
215     }
216
217     public static final Key KEY_MAP_COLOR_BAR_OPTIONS = new KeyOf(ColorBarOptions.class, "colorBarOptions");
218     public static final Command MAP_COLOR_BAR_OPTIONS_CHANGE = new Command("colorBarOptionsChange");
219     public static final Key KEY_MAP_SIZE_BAR_OPTIONS = new KeyOf(SizeBarOptions.class, "sizeBarOptions");
220     public static final Command MAP_SIZE_BAR_OPTIONS_CHANGE = new Command("sizeBarOptionsChange");
221     
222     public static final Key KEY_MAP_COLORING_OBJECTS = new KeyOf(Map.class, "coloringObjects");
223     public static final Command MAP_COLORING_OBJECTS_CHANGE = new Command("coloringObjectsChange");
224     
225     public static final Key KEY_MAP_SIZING_OBJECTS = new KeyOf(Map.class, "sizingObjects");
226     public static final Command MAP_SIZING_OBJECTS_CHANGE = new Command("sizingObjectsChange");
227
228     public static final Key KEY_SHOW_ELEVATION_SERVER = new KeyOf(Boolean.class, "showElevationServer");
229     public static final Command SHOW_ELEVATION_SERVER_CHANGE = new Command("showElevationServerChange");
230
231     private void queueColoringObjectsChangeEvent(Map<String, DynamicColorContribution> result) {
232         queueEventInternal(KEY_MAP_COLORING_OBJECTS, MAP_COLORING_OBJECTS_CHANGE, result);
233     }
234
235     private void queueColorBarOptionsChangeEvent(ColorBarOptions result) {
236         queueEventInternal(KEY_MAP_COLOR_BAR_OPTIONS, MAP_COLOR_BAR_OPTIONS_CHANGE, result);
237     }
238
239     private void queueSizingObjectsChangeEvent(Map<String, DynamicSizeContribution> result) {
240         queueEventInternal(KEY_MAP_SIZING_OBJECTS, MAP_SIZING_OBJECTS_CHANGE, result);
241     }
242
243     private void queueSizeBarOptionsChangeEvent(SizeBarOptions result) {
244         queueEventInternal(KEY_MAP_SIZE_BAR_OPTIONS, MAP_SIZE_BAR_OPTIONS_CHANGE, result);
245     }
246
247     private void queueShowElevationServerChangeEvent(Boolean result) {
248         queueEventInternal(KEY_SHOW_ELEVATION_SERVER, SHOW_ELEVATION_SERVER_CHANGE, result);
249     }
250
251     private void queueEventInternal(Key key, Command command, Object result) {
252         if (result != null && !canvasContext.isDisposed()) {
253             canvasContext.getThreadAccess().asyncExec(() -> {
254                 canvasContext.getDefaultHintContext().setHint(key, result);
255                 canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), command));
256             });
257         } else {
258             LOGGER.info("Result is either null or canvasContext is disposed", String.valueOf(result));
259         }
260     }
261
262     private static class DrawMapEnabledRequest extends UnaryRead<Resource, Boolean> {
263
264         public DrawMapEnabledRequest(Resource diagram) {
265             super(diagram);
266         }
267
268         @Override
269         public Boolean perform(ReadGraph graph) throws DatabaseException {
270             return DistrictNetworkUtil.drawMapEnabled(graph, parameter);
271         }
272     }
273
274     private static class DrawMapEnabledListener implements Listener<Boolean> {
275
276         private static final Logger LOGGER = LoggerFactory.getLogger(DrawMapEnabledListener.class);
277
278         private Consumer<Boolean> callback;
279         private Supplier<Boolean> isDisposed;
280         
281         private Boolean lastResult;
282
283         public DrawMapEnabledListener(Consumer<Boolean> callback, Supplier<Boolean> isDisposed) {
284             this.callback = callback;
285             this.isDisposed = isDisposed;
286         }
287
288         @Override
289         public void execute(Boolean result) {
290             // Minor optimization
291             if (!Objects.equals(lastResult, result)) {
292                 lastResult = result;
293                 callback.accept(result);
294             }
295         }
296
297         @Override
298         public void exception(Throwable t) {
299             LOGGER.error("Could not listen if draw map is enabled", t);
300         }
301
302         @Override
303         public boolean isDisposed() {
304             return isDisposed.get();
305         }
306     }
307     
308     private static class MapBackgroundColorRequest extends UnaryRead<Resource, RGB.Integer> {
309
310         public MapBackgroundColorRequest(Resource diagram) {
311             super(diagram);
312         }
313
314         @Override
315         public RGB.Integer perform(ReadGraph graph) throws DatabaseException {
316             return DistrictNetworkUtil.backgroundColor(graph, parameter);
317         }
318     }
319
320     private static class MapBackgroundColorListener implements Listener<RGB.Integer> {
321
322         private static final Logger LOGGER = LoggerFactory.getLogger(MapBackgroundColorListener.class);
323
324         private Consumer<RGB.Integer> callback;
325         private Supplier<Boolean> isDisposed;
326         
327         private RGB.Integer lastResult;
328
329         public MapBackgroundColorListener(Consumer<RGB.Integer> callback, Supplier<Boolean> isDisposed) {
330             this.callback = callback;
331             this.isDisposed = isDisposed;
332         }
333
334         @Override
335         public void execute(RGB.Integer result) {
336             if (!Objects.equals(lastResult, result)) {
337                 lastResult = result;
338                 callback.accept(result);
339             }
340         }
341
342         @Override
343         public void exception(Throwable t) {
344             LOGGER.error("Could not listen map background color", t);
345         }
346
347         @Override
348         public boolean isDisposed() {
349             return isDisposed.get();
350         }
351     }
352
353     private static class ColorBarOptionsRequest extends UnaryRead<Resource, ColorBarOptions> {
354
355         public ColorBarOptionsRequest(Resource diagram) {
356             super(diagram);
357         }
358
359         @Override
360         public ColorBarOptions perform(ReadGraph graph) throws DatabaseException {
361             DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
362             Resource model = graph.syncRequest(new PossibleIndexRoot(parameter));
363             if (model != null) {
364                 Resource vf = DynamicVisualisations.getVisualisationFolder(graph, model);
365                 if (vf != null) {
366                     Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation);
367                     if (activeVisualisation != null) {
368                         return DynamicVisualisations.colorBarOptions(graph, activeVisualisation);
369                     }
370                 } else {
371                     LOGGER.debug("No visualisation folder available for model {}", model);
372                 }
373             }
374             return ColorBarOptions.useDefault();
375         }
376     }
377
378     private static class ColoringObjectsRequest extends UnaryRead<Resource, Map<String,DynamicColorContribution>> {
379
380         public ColoringObjectsRequest(Resource diagram) {
381             super(diagram);
382         }
383
384         @Override
385         public Map<String, DynamicColorContribution> perform(ReadGraph graph) throws DatabaseException {
386             DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
387             Resource model = graph.syncRequest(new PossibleIndexRoot(parameter));
388             if (model != null) {
389                 Resource vf = DynamicVisualisations.getVisualisationFolder(graph, model);
390                 if (vf != null) {
391                     Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation);
392                     if (activeVisualisation != null) {
393                         return DynamicVisualisations.colorContributions(graph, activeVisualisation);
394                     }
395                 } else {
396                     LOGGER.debug("No visualisation folder available for model {}", model);
397                 }
398             }
399             return Collections.emptyMap();
400         }
401     }
402     
403     private static class ColoringObjectsListener implements Listener<Map<String,DynamicColorContribution>> {
404
405         private static final Logger LOGGER = LoggerFactory.getLogger(ColoringObjectsListener.class);
406
407         private Consumer<Map<String,DynamicColorContribution>> callback;
408         private Supplier<Boolean> isDisposed;
409         
410         //private Map<String, DynamicColorContribution> lastResult
411
412         public ColoringObjectsListener(Consumer<Map<String,DynamicColorContribution>> callback, Supplier<Boolean> isDisposed) {
413             this.callback = callback;
414             this.isDisposed = isDisposed;
415         }
416
417         @Override
418         public void execute(Map<String,DynamicColorContribution> result) {
419             callback.accept(result);
420         }
421
422         @Override
423         public void exception(Throwable t) {
424             LOGGER.error("Could not listen ColoringObjects", t);
425         }
426
427         @Override
428         public boolean isDisposed() {
429             return isDisposed.get();
430         }
431     }
432     
433     private static class ColorBarOptionsListener implements Listener<ColorBarOptions> {
434
435         private static final Logger LOGGER = LoggerFactory.getLogger(ColorBarOptionsListener.class);
436
437         private Consumer<ColorBarOptions> callback;
438         private Supplier<Boolean> isDisposed;
439
440         public ColorBarOptionsListener(Consumer<ColorBarOptions> callback, Supplier<Boolean> isDisposed) {
441             this.callback = callback;
442             this.isDisposed = isDisposed;
443         }
444
445         @Override
446         public void execute(ColorBarOptions result) {
447             callback.accept(result);
448         }
449
450         @Override
451         public void exception(Throwable t) {
452             LOGGER.error("Could not listen ColorBarOptions", t);
453         }
454
455         @Override
456         public boolean isDisposed() {
457             return isDisposed.get();
458         }
459     }
460     
461     private static class SizeBarOptionsRequest extends UnaryRead<Resource, SizeBarOptions> {
462
463         public SizeBarOptionsRequest(Resource diagram) {
464             super(diagram);
465         }
466
467         @Override
468         public SizeBarOptions perform(ReadGraph graph) throws DatabaseException {
469             DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
470             Resource model = graph.syncRequest(new PossibleIndexRoot(parameter));
471             if (model != null) {
472                 Resource vf = DynamicVisualisations.getVisualisationFolder(graph, model);
473                 if (vf != null) {
474                     Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation);
475                     if (activeVisualisation != null) {
476                         return DynamicVisualisations.sizeBarOptions(graph, activeVisualisation);
477                     }
478                 } else {
479                     LOGGER.debug("No visualisation folder available for model {}", model);
480                 }
481             }
482             return SizeBarOptions.useDefault();
483         }
484     }
485
486     private static class SizeBarOptionsListener implements Listener<SizeBarOptions> {
487
488         private static final Logger LOGGER = LoggerFactory.getLogger(SizeBarOptionsListener.class);
489
490         private Consumer<SizeBarOptions> callback;
491         private Supplier<Boolean> isDisposed;
492
493         public SizeBarOptionsListener(Consumer<SizeBarOptions> callback, Supplier<Boolean> isDisposed) {
494             this.callback = callback;
495             this.isDisposed = isDisposed;
496         }
497
498         @Override
499         public void execute(SizeBarOptions result) {
500             callback.accept(result);
501         }
502
503         @Override
504         public void exception(Throwable t) {
505             LOGGER.error("Could not listen SizeBarOptions", t);
506         }
507
508         @Override
509         public boolean isDisposed() {
510             return isDisposed.get();
511         }
512     }
513     
514     private static class SizingObjectsRequest extends UnaryRead<Resource, Map<String, DynamicSizeContribution>> {
515
516         public SizingObjectsRequest(Resource diagram) {
517             super(diagram);
518         }
519
520         @Override
521         public Map<String, DynamicSizeContribution> perform(ReadGraph graph) throws DatabaseException {
522             DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
523             Resource model = graph.syncRequest(new PossibleIndexRoot(parameter));
524             if (model != null) {
525                 Resource vf = DynamicVisualisations.getVisualisationFolder(graph, model);
526                 if (vf != null) {
527                     Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation);
528                     if (activeVisualisation != null) {
529                         return DynamicVisualisations.sizeContributions(graph, activeVisualisation);
530                     }
531                 } else {
532                     LOGGER.debug("No visualisation folder available for model {}", model);
533                 }
534             }
535             return Collections.emptyMap();
536         }
537     }
538     
539     private static class SizingObjectsListener implements Listener<Map<String,DynamicSizeContribution>> {
540
541         private static final Logger LOGGER = LoggerFactory.getLogger(SizingObjectsListener.class);
542
543         private Consumer<Map<String,DynamicSizeContribution>> callback;
544         private Supplier<Boolean> isDisposed;
545
546         public SizingObjectsListener(Consumer<Map<String, DynamicSizeContribution>> callback, Supplier<Boolean> isDisposed) {
547             this.callback = callback;
548             this.isDisposed = isDisposed;
549         }
550
551         @Override
552         public void execute(Map<String, DynamicSizeContribution> result) {
553             callback.accept(result);
554         }
555
556         @Override
557         public void exception(Throwable t) {
558             LOGGER.error("Could not listen SizingObjectsOptions", t);
559         }
560
561         @Override
562         public boolean isDisposed() {
563             return isDisposed.get();
564         }
565     }
566
567     private static class ShowElevationServerRequest extends UnaryRead<Resource, Boolean> {
568
569         public ShowElevationServerRequest(Resource diagram) {
570             super(diagram);
571         }
572
573         @Override
574         public Boolean perform(ReadGraph graph) throws DatabaseException {
575             DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
576             Resource model = graph.syncRequest(new PossibleIndexRoot(parameter));
577             if (model != null) {
578                 Resource vf = DynamicVisualisations.getVisualisationFolder(graph, model);
579                 if (vf != null) {
580                     Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation);
581                     if (activeVisualisation != null) {
582                         return DynamicVisualisations.showElevationServerBoundingBox(graph, activeVisualisation);
583                     }
584                 } else {
585                     LOGGER.debug("No visualisation folder available for model {}", model);
586                 }
587             }
588             return false;
589         }
590     }
591     
592     private static class ShowElevationServerListener implements Listener<Boolean> {
593
594         private static final Logger LOGGER = LoggerFactory.getLogger(ShowElevationServerListener.class);
595
596         private Consumer<Boolean> callback;
597         private Supplier<Boolean> isDisposed;
598
599         public ShowElevationServerListener(Consumer<Boolean> callback, Supplier<Boolean> isDisposed) {
600             this.callback = callback;
601             this.isDisposed = isDisposed;
602         }
603
604         @Override
605         public void execute(Boolean result) {
606             callback.accept(result);
607         }
608
609         @Override
610         public void exception(Throwable t) {
611             LOGGER.error("Could not listen Show Elevation Server", t);
612         }
613
614         @Override
615         public boolean isDisposed() {
616             return isDisposed.get();
617         }
618     }
619 }