]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/RoutingMode.java
4f023c880a2968d2a3d306fff7ed685551956c47
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / participants / RoutingMode.java
1 package org.simantics.district.network.ui.participants;
2
3 import java.awt.AlphaComposite;
4 import java.awt.Cursor;
5 import java.util.Collection;
6
7 import org.eclipse.jface.dialogs.IDialogSettings;
8 import org.eclipse.jface.dialogs.IInputValidator;
9 import org.eclipse.jface.dialogs.InputDialog;
10 import org.eclipse.jface.window.Window;
11 import org.eclipse.swt.widgets.Display;
12 import org.eclipse.swt.widgets.Shell;
13 import org.eclipse.ui.PlatformUI;
14 import org.simantics.db.Resource;
15 import org.simantics.diagram.ui.DiagramModelHints;
16 import org.simantics.district.network.ui.internal.Activator;
17 import org.simantics.district.route.Route;
18 import org.simantics.district.route.RouteService;
19 import org.simantics.district.route.Waypoint;
20 import org.simantics.g2d.canvas.ICanvasContext;
21 import org.simantics.g2d.canvas.IMouseCursorContext;
22 import org.simantics.g2d.canvas.IMouseCursorHandle;
23 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
24 import org.simantics.g2d.canvas.impl.HintReflection.HintListener;
25 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup;
26 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
27 import org.simantics.g2d.diagram.handler.PickContext;
28 import org.simantics.g2d.diagram.participant.Selection;
29 import org.simantics.g2d.diagram.participant.pointertool.AbstractMode;
30 import org.simantics.g2d.element.ElementUtils;
31 import org.simantics.g2d.element.IElement;
32 import org.simantics.g2d.participant.TransformUtil;
33 import org.simantics.scenegraph.g2d.G2DParentNode;
34 import org.simantics.scenegraph.g2d.events.Event;
35 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
36 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;
37 import org.simantics.scenegraph.g2d.events.command.Command;
38 import org.simantics.scenegraph.g2d.events.command.CommandEvent;
39 import org.simantics.scenegraph.g2d.events.command.Commands;
40 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
41 import org.simantics.utils.datastructures.hints.IHintContext.Key;
42 import org.simantics.utils.datastructures.hints.IHintObservable;
43 import org.simantics.utils.ui.AdaptionUtils;
44 import org.simantics.utils.ui.SWTUtils;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * This participant creates routes on district network diagrams using
50  * {@link RouteService}.
51  *
52  * @author Tuukka Lehtonen
53  * @since 6.09
54  */
55 public class RoutingMode extends AbstractMode {
56
57     private static final Logger LOGGER = LoggerFactory.getLogger(RoutingMode.class);
58
59     @Dependency
60     protected TransformUtil        util;
61
62     @Dependency
63     protected PickContext          pickContext;
64
65     @Dependency
66     protected Selection            selection;
67
68     protected IMouseCursorHandle   cursor;
69
70     private RouteService           routeService;
71
72     private Route                  route;
73
74     /**
75      * The node under which the mutated diagram is ghosted in the scene graph.
76      */
77     protected G2DParentNode        parent;
78
79     /**
80      * This stays null until the translated diagram parts have been initialized
81      * into the scene graph. After that, only the translations of the nodes in
82      * the scene graph are modified.
83      */
84     protected SingleElementNode    node = null;
85
86     public RoutingMode(int mouseId) {
87         super(mouseId);
88     }
89
90     @Override
91     public void addedToContext(ICanvasContext ctx) {
92         super.addedToContext(ctx);
93         IMouseCursorContext mcc = getContext().getMouseCursorContext();
94         cursor = mcc == null ? null : mcc.setCursor(mouseId, new Cursor(Cursor.CROSSHAIR_CURSOR));
95         routeService = Activator.getInstance().getRouteService();
96         if (routeService != null) {
97             Resource diagramResource = getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
98             LOGGER.info("Diagram resource: " + diagramResource);
99             route = routeService.createRoute("Current", diagramResource);
100             routeService.registerRoute(route);
101         }
102     }
103
104     @Override
105     public void removedFromContext(ICanvasContext ctx) {
106         if (cursor != null) {
107             cursor.remove();
108             cursor = null;
109         }
110         // Discard route if it hasn't been persisted before this
111         if (route != null) {
112             routeService.discardRoute(route);
113             route = null;
114             routeService = null;
115         }
116         super.removedFromContext(ctx);
117     }
118
119     @HintListener(Class = Selection.class, Field = "SELECTION0")
120     public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
121         Collection<IElement> elements = AdaptionUtils.adaptToCollection(newValue, IElement.class);
122         for (IElement element : elements) {
123             addRoutePoint(element);
124         }
125     }
126
127     private void addRoutePoint(IElement element) {
128         if (route == null)
129             return;
130
131         Object o = ElementUtils.getObject(element);
132         if (o instanceof Resource) {
133             Waypoint wp = route.createWaypoint(o);
134             route.addWaypoint(wp);
135         }
136     }
137
138     @SGInit
139     public void initSG(G2DParentNode parent) {
140         this.parent = parent;
141         node = parent.addNode("route highlight", SingleElementNode.class);
142         node.setZIndex(1000);
143         node.setVisible(Boolean.TRUE);
144         node.setComposite(AlphaComposite.SrcOver.derive(0.75f));
145     }
146
147     @SGCleanup
148     public void cleanupSG() {
149         if (node != null) {
150             node.remove();
151             node = null;
152         }
153         parent = null;
154     }
155
156     @EventHandler(priority = 30)
157     public boolean handleEvent(Event e) {
158         if (e instanceof KeyPressedEvent) {
159             if (route == null)
160                 return false;
161             KeyPressedEvent kpe = (KeyPressedEvent) e;
162             if (kpe.keyCode == java.awt.event.KeyEvent.VK_ENTER) {
163                 Route committedRoute = route;
164                 route = null;
165                 SWTUtils.asyncExec(Display.getDefault(), () -> {
166                     String newName = askRouteName("Confirm Route", committedRoute.getName());
167                     if (newName != null) {
168                         committedRoute.setName(newName);
169                         routeService.persistRoute(committedRoute);
170                     } else {
171                         routeService.discardRoute(committedRoute);
172                     }
173                 });
174                 dispose();
175             }
176         } else if (e instanceof CommandEvent) {
177             Command cmd = ((CommandEvent) e).command;
178             if (cmd.equals(Commands.CANCEL)) {
179                 return dispose();
180             } else if (cmd.equals(Commands.RENAME)) {
181                 // TODO: still needs key binding contribution for the district diagram editor
182                 SWTUtils.asyncExec(Display.getDefault(), () -> {
183                     String newName = askRouteName("Rename Route", route.getName());
184                     if (newName != null) {
185                         route.setName(newName);
186                         routeService.refreshRoute(route);
187                     }
188                 });
189             }
190         }
191         return false;
192     }
193
194     private String askRouteName(String dialogTitle, String initialValue) {
195         InputDialog dialog = new InputDialog(
196                 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
197                 dialogTitle,
198                 "Route name",
199                 initialValue,
200                 s -> s.trim().length() > 0 ? null : "Name must be non-empty");
201         if (dialog.open() == Window.OK) {
202             return dialog.getValue();
203         }
204         return null;
205     }
206
207     protected boolean dispose() {
208         setDirty();
209         remove();
210         return false;
211     }
212
213     static class RenameDialog extends InputDialog {
214
215         public RenameDialog(Shell parent, String title, String message, String initialValue, IInputValidator validator) {
216             super(parent, title, message, initialValue, validator);
217         }
218
219         @Override
220         protected IDialogSettings getDialogBoundsSettings() {
221             String sectionName = getClass().getName() + "_dialogBounds"; //$NON-NLS-1$
222             IDialogSettings settings= Activator.getInstance().getDialogSettings();
223             IDialogSettings section= settings.getSection(sectionName);
224             if (section == null)
225                 section= settings.addNewSection(sectionName);
226             return section;
227         }
228
229         @Override
230         protected int getDialogBoundsStrategy() {
231             return DIALOG_PERSISTLOCATION;
232         }
233     }
234
235 }