--- /dev/null
+package org.simantics.district.network.ui.participants;
+
+import java.awt.AlphaComposite;
+import java.awt.Cursor;
+import java.util.Collection;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.simantics.db.Resource;
+import org.simantics.diagram.ui.DiagramModelHints;
+import org.simantics.district.network.ui.internal.Activator;
+import org.simantics.district.route.Route;
+import org.simantics.district.route.RouteService;
+import org.simantics.district.route.Waypoint;
+import org.simantics.g2d.canvas.ICanvasContext;
+import org.simantics.g2d.canvas.IMouseCursorContext;
+import org.simantics.g2d.canvas.IMouseCursorHandle;
+import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
+import org.simantics.g2d.canvas.impl.HintReflection.HintListener;
+import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup;
+import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
+import org.simantics.g2d.diagram.handler.PickContext;
+import org.simantics.g2d.diagram.participant.Selection;
+import org.simantics.g2d.diagram.participant.pointertool.AbstractMode;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.participant.TransformUtil;
+import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.scenegraph.g2d.events.Event;
+import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
+import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;
+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.scenegraph.g2d.nodes.SingleElementNode;
+import org.simantics.utils.datastructures.hints.IHintContext.Key;
+import org.simantics.utils.datastructures.hints.IHintObservable;
+import org.simantics.utils.ui.AdaptionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This participant creates routes on district network diagrams using
+ * {@link RouteService}.
+ *
+ * @author Tuukka Lehtonen
+ * @since 6.09
+ */
+public class RoutingMode extends AbstractMode {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RoutingMode.class);
+
+ @Dependency
+ protected TransformUtil util;
+
+ @Dependency
+ protected PickContext pickContext;
+
+ @Dependency
+ protected Selection selection;
+
+ protected IMouseCursorHandle cursor;
+
+ private RouteService routeService;
+
+ private Route route;
+
+ /**
+ * The node under which the mutated diagram is ghosted in the scene graph.
+ */
+ protected G2DParentNode parent;
+
+ /**
+ * This stays null until the translated diagram parts have been initialized
+ * into the scene graph. After that, only the translations of the nodes in
+ * the scene graph are modified.
+ */
+ protected SingleElementNode node = null;
+
+ public RoutingMode(int mouseId) {
+ super(mouseId);
+ }
+
+ @Override
+ public void addedToContext(ICanvasContext ctx) {
+ super.addedToContext(ctx);
+ IMouseCursorContext mcc = getContext().getMouseCursorContext();
+ cursor = mcc == null ? null : mcc.setCursor(mouseId, new Cursor(Cursor.CROSSHAIR_CURSOR));
+ routeService = Activator.getInstance().getRouteService();
+ if (routeService != null) {
+ Resource diagramResource = getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
+ LOGGER.info("Diagram resource: " + diagramResource);
+ route = routeService.createRoute("Current", diagramResource);
+ routeService.registerRoute(route);
+ }
+ }
+
+ @Override
+ public void removedFromContext(ICanvasContext ctx) {
+ if (cursor != null) {
+ cursor.remove();
+ cursor = null;
+ }
+ // Discard route if it hasn't been persisted before this
+ if (route != null) {
+ routeService.discardRoute(route);
+ route = null;
+ routeService = null;
+ }
+ super.removedFromContext(ctx);
+ }
+
+ @HintListener(Class = Selection.class, Field = "SELECTION0")
+ public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
+ Collection<IElement> elements = AdaptionUtils.adaptToCollection(newValue, IElement.class);
+ for (IElement element : elements) {
+ addRoutePoint(element);
+ }
+ }
+
+ private void addRoutePoint(IElement element) {
+ if (route == null)
+ return;
+
+ Object o = ElementUtils.getObject(element);
+ if (o instanceof Resource) {
+ Waypoint wp = route.createWaypoint(o);
+ route.addWaypoint(wp);
+ }
+ }
+
+ @SGInit
+ public void initSG(G2DParentNode parent) {
+ this.parent = parent;
+ node = parent.addNode("route highlight", SingleElementNode.class);
+ node.setZIndex(1000);
+ node.setVisible(Boolean.TRUE);
+ node.setComposite(AlphaComposite.SrcOver.derive(0.75f));
+ }
+
+ @SGCleanup
+ public void cleanupSG() {
+ if (node != null) {
+ node.remove();
+ node = null;
+ }
+ parent = null;
+ }
+
+ @EventHandler(priority = 30)
+ public boolean handleEvent(Event e) {
+ if (e instanceof KeyPressedEvent) {
+ if (route == null)
+ return false;
+ KeyPressedEvent kpe = (KeyPressedEvent) e;
+ if (kpe.keyCode == java.awt.event.KeyEvent.VK_ENTER) {
+ routeService.persistRoute(route);
+ route = null;
+ dispose();
+ }
+ } else if (e instanceof CommandEvent) {
+ Command cmd = ((CommandEvent) e).command;
+ if (cmd.equals(Commands.CANCEL)) {
+ return dispose();
+ } else if (cmd.equals(Commands.RENAME)) {
+ InputDialog dialog = new InputDialog(
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ "Rename Route",
+ "Route name",
+ route.getName(),
+ s -> s.trim().length() > 0 ? null : "Name must be non-empty");
+ if (dialog.open() == Window.OK) {
+ route.setName(dialog.getValue());
+ }
+ }
+ }
+ return false;
+ }
+
+ protected boolean dispose() {
+ setDirty();
+ remove();
+ return false;
+ }
+
+ static class RenameDialog extends InputDialog {
+
+ public RenameDialog(Shell parent, String title, String message, String initialValue, IInputValidator validator) {
+ super(parent, title, message, initialValue, validator);
+ }
+
+ @Override
+ protected IDialogSettings getDialogBoundsSettings() {
+ String sectionName = getClass().getName() + "_dialogBounds"; //$NON-NLS-1$
+ IDialogSettings settings= Activator.getInstance().getDialogSettings();
+ IDialogSettings section= settings.getSection(sectionName);
+ if (section == null)
+ section= settings.addNewSection(sectionName);
+ return section;
+ }
+
+ @Override
+ protected int getDialogBoundsStrategy() {
+ return DIALOG_PERSISTLOCATION;
+ }
+ }
+
+}