package org.simantics.district.network.ui; import java.awt.Color; import java.awt.geom.AffineTransform; import java.util.Collections; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Supplier; import org.simantics.datatypes.literal.RGB; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.request.IndexRoot; import org.simantics.db.common.request.UnaryRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.procedure.Listener; import org.simantics.diagram.ui.DiagramModelHints; import org.simantics.district.network.DistrictNetworkUtil; import org.simantics.district.network.ontology.DistrictNetworkResource; import org.simantics.district.network.ui.participants.DNPointerInteractor; import org.simantics.district.network.ui.participants.DynamicVisualisationContributionsParticipant; import org.simantics.district.network.ui.participants.ElevationServerParticipant; import org.simantics.district.network.ui.participants.MapRulerPainter; import org.simantics.district.network.visualisations.model.ColorBarOptions; import org.simantics.district.network.visualisations.model.DynamicColorContribution; import org.simantics.district.network.visualisations.model.DynamicSizeContribution; import org.simantics.district.network.visualisations.model.SizeBarOptions; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.impl.CanvasContext; import org.simantics.g2d.diagram.handler.PickRequest.PickFilter; import org.simantics.g2d.diagram.participant.DelayedBatchElementPainter; import org.simantics.g2d.diagram.participant.ElementPainter; import org.simantics.g2d.diagram.participant.Selection; import org.simantics.g2d.diagram.participant.ZOrderHandler; import org.simantics.g2d.participant.BackgroundPainter; import org.simantics.g2d.participant.GridPainter; import org.simantics.g2d.participant.PanZoomRotateHandler; import org.simantics.g2d.participant.RenderingQualityInteractor; import org.simantics.g2d.participant.TransformUtil; import org.simantics.g2d.participant.ZoomToAreaHandler; import org.simantics.maps.MapScalingTransform; import org.simantics.maps.eclipse.MapPainter; import org.simantics.maps.sg.commands.MapCommands; import org.simantics.modeling.ui.diagramEditor.DiagramViewer; import org.simantics.scenegraph.g2d.events.command.Command; import org.simantics.scenegraph.g2d.events.command.CommandEvent; import org.simantics.scenegraph.g2d.events.command.Commands; import org.simantics.utils.datastructures.hints.IHintContext; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DistrictDiagramViewer extends DiagramViewer { @SuppressWarnings("unused") private static final Logger LOGGER = LoggerFactory.getLogger(DistrictDiagramViewer.class); @Override protected void addDiagramParticipants(ICanvasContext ctx) { ctx.add(new ZOrderHandler()); ctx.add(new Selection()); ctx.add(new ElementPainter()); ctx.add(new DNPointerInteractor()); AffineTransform tr = new AffineTransform(MapScalingTransform.INSTANCE); ctx.add(new MapPainter(tr)); ctx.add(new NetworkDrawingParticipant(tr)); ctx.add(new ElevationServerParticipant(tr)); ctx.add(new DynamicVisualisationContributionsParticipant(tr)); } protected String getPopupId() { return "#DistrictDiagramPopup"; } @Override public void initializeCanvasContext(CanvasContext ctx) { super.initializeCanvasContext(ctx); IHintContext h = ctx.getDefaultHintContext(); h.setHint(PanZoomRotateHandler.KEY_ZOOM_IN_LIMIT, 10000.0); h.setHint(PanZoomRotateHandler.KEY_ZOOM_OUT_LIMIT, 0.01); h.setHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE, diagramResource); } @Override protected void addPainterParticipants(ICanvasContext ctx) { ctx.add(new RenderingQualityInteractor()); ctx.add(new DelayedBatchElementPainter(PickFilter.FILTER_MONITORS, 500, TimeUnit.MILLISECONDS)); } @Override protected void addGridRulerBackgroundParticipants(CanvasContext ctx) { ctx.add(new GridPainter()); ctx.add(new MapRulerPainter()); ctx.add(new BackgroundPainter()); } protected void addViewManipulationParticipants(CanvasContext ctx) { // Let's replace with our special util TransformUtil util = ctx.getAtMostOneItemOfClass(TransformUtil.class); if (util != null) ctx.remove(util); ctx.add(new DistrictTransformUtil()); ctx.add(new DistrictPanZoomRotateHandler()); //ctx.add(new MousePanZoomInteractor()); //ctx.add(new MultitouchPanZoomRotateInteractor()); // ctx.add( new OrientationRestorer() ); ctx.add(new ZoomToAreaHandler()); } @Override protected void loadPageSettings(ICanvasContext ctx) { super.loadPageSettings(ctx); // this might be the wrong place to start such listening but at least // super.loadPageSettings() does async-db-operations setupDrawMapEnabled(); setupBackgroundColor(); setupColoringObjects(); setupColorBarOptions(); setupSizingObjects(); setupSizeBarOptions(); } private void setupDrawMapEnabled() { sessionContext.getSession().asyncRequest(new DrawMapEnabledRequest(getInputResource()), new DrawMapEnabledListener( result -> canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), result ? Commands.MAP_ENABLE : Commands.MAP_DISABLE)), () -> DistrictDiagramViewer.this.isDisposed())); } private void setupBackgroundColor() { sessionContext.getSession().asyncRequest(new MapBackgroundColorRequest(getInputResource()), new MapBackgroundColorListener( result -> queueBackgroundColorChangeEvent(result), () -> DistrictDiagramViewer.this.isDisposed())); } private void queueBackgroundColorChangeEvent(RGB.Integer result) { if (result != null) { Color backgroundColor = new Color(result.red, result.green, result.blue); canvasContext.getDefaultHintContext().setHint(MapCommands.KEY_MAP_BACKGROUND_COLOR, backgroundColor); canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), MapCommands.MAP_BACKGROUND_COLOR_CHANGE)); } } private void setupColoringObjects() { sessionContext.getSession().asyncRequest(new ColoringObjectsRequest(getInputResource()), new ColoringObjectsListener( result -> queueColoringObjectsChangeEvent(result), () -> DistrictDiagramViewer.this.isDisposed())); } private void setupColorBarOptions() { sessionContext.getSession().asyncRequest(new ColorBarOptionsRequest(getInputResource()), new ColorBarOptionsListener( result -> queueColorBarOptionsChangeEvent(result), () -> DistrictDiagramViewer.this.isDisposed())); } private void setupSizingObjects() { sessionContext.getSession().asyncRequest(new SizingObjectsRequest(getInputResource()), new SizingObjectsListener( result -> queueSizingObjectsChangeEvent(result), () -> DistrictDiagramViewer.this.isDisposed())); } private void setupSizeBarOptions() { sessionContext.getSession().asyncRequest(new SizeBarOptionsRequest(getInputResource()), new SizeBarOptionsListener( result -> queueSizeBarOptionsChangeEvent(result), () -> DistrictDiagramViewer.this.isDisposed())); } public static final Key KEY_MAP_COLOR_BAR_OPTIONS = new KeyOf(ColorBarOptions.class, "colorBarOptions"); public static final Command MAP_COLOR_BAR_OPTIONS_CHANGE = new Command("colorBarOptionsChange"); public static final Key KEY_MAP_SIZE_BAR_OPTIONS = new KeyOf(SizeBarOptions.class, "sizeBarOptions"); public static final Command MAP_SIZE_BAR_OPTIONS_CHANGE = new Command("sizeBarOptionsChange"); public static final Key KEY_MAP_COLORING_OBJECTS = new KeyOf(Map.class, "coloringObjects"); public static final Command MAP_COLORING_OBJECTS_CHANGE = new Command("coloringObjectsChange"); public static final Key KEY_MAP_SIZING_OBJECTS = new KeyOf(Map.class, "sizingObjects"); public static final Command MAP_SIZING_OBJECTS_CHANGE = new Command("sizingObjectsChange"); private void queueColoringObjectsChangeEvent(Map result) { if (result != null && !canvasContext.isDisposed()) { canvasContext.getDefaultHintContext().setHint(KEY_MAP_COLORING_OBJECTS, result); canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), MAP_COLORING_OBJECTS_CHANGE)); } else { LOGGER.info("Result is either null or canvasContext is disposed", String.valueOf(result)); } } private void queueColorBarOptionsChangeEvent(ColorBarOptions result) { if (result != null && !canvasContext.isDisposed()) { canvasContext.getDefaultHintContext().setHint(KEY_MAP_COLOR_BAR_OPTIONS, result); canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), MAP_COLOR_BAR_OPTIONS_CHANGE)); } else { LOGGER.info("Result is either null or canvasContext is disposed", String.valueOf(result)); } } private void queueSizingObjectsChangeEvent(Map result) { if (result != null && !canvasContext.isDisposed()) { canvasContext.getDefaultHintContext().setHint(KEY_MAP_SIZING_OBJECTS, result); canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), MAP_SIZING_OBJECTS_CHANGE)); } else { LOGGER.info("Result is either null or canvasContext is disposed", String.valueOf(result)); } } private void queueSizeBarOptionsChangeEvent(SizeBarOptions result) { if (result != null && !canvasContext.isDisposed()) { canvasContext.getDefaultHintContext().setHint(KEY_MAP_SIZE_BAR_OPTIONS, result); canvasContext.getEventQueue().queueEvent(new CommandEvent(canvasContext, System.currentTimeMillis(), MAP_SIZE_BAR_OPTIONS_CHANGE)); } else { LOGGER.info("Result is either null or canvasContext is disposed", String.valueOf(result)); } } private static class DrawMapEnabledRequest extends UnaryRead { public DrawMapEnabledRequest(Resource diagram) { super(diagram); } @Override public Boolean perform(ReadGraph graph) throws DatabaseException { return DistrictNetworkUtil.drawMapEnabled(graph, parameter); } } private static class DrawMapEnabledListener implements Listener { private static final Logger LOGGER = LoggerFactory.getLogger(DrawMapEnabledListener.class); private Consumer callback; private Supplier isDisposed; public DrawMapEnabledListener(Consumer callback, Supplier isDisposed) { this.callback = callback; this.isDisposed = isDisposed; } @Override public void execute(Boolean result) { callback.accept(result); } @Override public void exception(Throwable t) { LOGGER.error("Could not listen if draw map is enabled", t); } @Override public boolean isDisposed() { return isDisposed.get(); } } private static class MapBackgroundColorRequest extends UnaryRead { public MapBackgroundColorRequest(Resource diagram) { super(diagram); } @Override public RGB.Integer perform(ReadGraph graph) throws DatabaseException { return DistrictNetworkUtil.backgroundColor(graph, parameter); } } private static class MapBackgroundColorListener implements Listener { private static final Logger LOGGER = LoggerFactory.getLogger(MapBackgroundColorListener.class); private Consumer callback; private Supplier isDisposed; public MapBackgroundColorListener(Consumer callback, Supplier isDisposed) { this.callback = callback; this.isDisposed = isDisposed; } @Override public void execute(RGB.Integer result) { callback.accept(result); } @Override public void exception(Throwable t) { LOGGER.error("Could not listen map background color", t); } @Override public boolean isDisposed() { return isDisposed.get(); } } private static class ColorBarOptionsRequest extends UnaryRead { public ColorBarOptionsRequest(Resource diagram) { super(diagram); } @Override public ColorBarOptions perform(ReadGraph graph) throws DatabaseException { DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); Resource model = graph.syncRequest(new IndexRoot(parameter)); Resource vf = DistrictNetworkUtil.getVisualisationFolder(graph, model); Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation); if (activeVisualisation != null) { return DistrictNetworkUtil.colorBarOptions(graph, activeVisualisation); } return ColorBarOptions.useDefault(); } } private static class ColoringObjectsRequest extends UnaryRead> { public ColoringObjectsRequest(Resource diagram) { super(diagram); } @Override public Map perform(ReadGraph graph) throws DatabaseException { DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); Resource model = graph.syncRequest(new IndexRoot(parameter)); Resource vf = DistrictNetworkUtil.getVisualisationFolder(graph, model); Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation); if (activeVisualisation != null) { return DistrictNetworkUtil.colorContributions(graph, activeVisualisation); } return Collections.emptyMap(); } } private static class ColoringObjectsListener implements Listener> { private static final Logger LOGGER = LoggerFactory.getLogger(ColoringObjectsListener.class); private Consumer> callback; private Supplier isDisposed; public ColoringObjectsListener(Consumer> callback, Supplier isDisposed) { this.callback = callback; this.isDisposed = isDisposed; } @Override public void execute(Map result) { callback.accept(result); } @Override public void exception(Throwable t) { LOGGER.error("Could not listen ColorBarOptions", t); } @Override public boolean isDisposed() { return isDisposed.get(); } } private static class ColorBarOptionsListener implements Listener { private static final Logger LOGGER = LoggerFactory.getLogger(ColorBarOptionsListener.class); private Consumer callback; private Supplier isDisposed; public ColorBarOptionsListener(Consumer callback, Supplier isDisposed) { this.callback = callback; this.isDisposed = isDisposed; } @Override public void execute(ColorBarOptions result) { callback.accept(result); } @Override public void exception(Throwable t) { LOGGER.error("Could not listen ColorBarOptions", t); } @Override public boolean isDisposed() { return isDisposed.get(); } } private static class SizeBarOptionsRequest extends UnaryRead { public SizeBarOptionsRequest(Resource diagram) { super(diagram); } @Override public SizeBarOptions perform(ReadGraph graph) throws DatabaseException { DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); Resource model = graph.syncRequest(new IndexRoot(parameter)); Resource vf = DistrictNetworkUtil.getVisualisationFolder(graph, model); Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation); if (activeVisualisation != null) { return DistrictNetworkUtil.sizeBarOptions(graph, activeVisualisation); } return SizeBarOptions.useDefault(); } } private static class SizeBarOptionsListener implements Listener { private static final Logger LOGGER = LoggerFactory.getLogger(SizeBarOptionsListener.class); private Consumer callback; private Supplier isDisposed; public SizeBarOptionsListener(Consumer callback, Supplier isDisposed) { this.callback = callback; this.isDisposed = isDisposed; } @Override public void execute(SizeBarOptions result) { callback.accept(result); } @Override public void exception(Throwable t) { LOGGER.error("Could not listen SizeBarOptions", t); } @Override public boolean isDisposed() { return isDisposed.get(); } } private static class SizingObjectsRequest extends UnaryRead> { public SizingObjectsRequest(Resource diagram) { super(diagram); } @Override public Map perform(ReadGraph graph) throws DatabaseException { DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); Resource model = graph.syncRequest(new IndexRoot(parameter)); Resource vf = DistrictNetworkUtil.getVisualisationFolder(graph, model); Resource activeVisualisation = graph.getPossibleObject(vf, DN.Diagram_hasActiveVisualisation); if (activeVisualisation != null) { return DistrictNetworkUtil.sizeContributions(graph, activeVisualisation); } return Collections.emptyMap(); } } private static class SizingObjectsListener implements Listener> { private static final Logger LOGGER = LoggerFactory.getLogger(SizingObjectsListener.class); private Consumer> callback; private Supplier isDisposed; public SizingObjectsListener(Consumer> callback, Supplier isDisposed) { this.callback = callback; this.isDisposed = isDisposed; } @Override public void execute(Map result) { callback.accept(result); } @Override public void exception(Throwable t) { LOGGER.error("Could not listen ColorBarOptions", t); } @Override public boolean isDisposed() { return isDisposed.get(); } } }