]> gerrit.simantics Code Review - simantics/district.git/commitdiff
Improved Routes view functionality 61/2561/1 private/psaas
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 18 Dec 2018 12:36:45 +0000 (14:36 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 18 Dec 2018 12:36:45 +0000 (14:36 +0200)
Context menu now has:
* Select Route on Diagram (actually works now)
* Discard Route
* Rename Route

Route waypoint names are resolved properly already during creation and
show address if defined.

Route rename can also be initiated with F2 from the tree.

gitlab #25

Change-Id: If5edbe63032b2a5b42a616d4c058d2ea7f3a88c1

18 files changed:
org.simantics.district.network.ui/META-INF/MANIFEST.MF
org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/RoutingMode.java
org.simantics.district.region/src/org/simantics/district/region/DiagramRegions.java
org.simantics.district.route.ui/META-INF/MANIFEST.MF
org.simantics.district.route.ui/OSGI-INF/l10n/bundle.properties
org.simantics.district.route.ui/fragment.e4xmi
org.simantics.district.route.ui/src/org/simantics/district/route/ui/RouteTree.java
org.simantics.district.route.ui/src/org/simantics/district/route/ui/RouteView.java
org.simantics.district.route.ui/src/org/simantics/district/route/ui/handlers/DiscardRoute.java [new file with mode: 0644]
org.simantics.district.route.ui/src/org/simantics/district/route/ui/handlers/RenameRoute.java [new file with mode: 0644]
org.simantics.district.route.ui/src/org/simantics/district/route/ui/handlers/SelectRouteOnDiagram.java
org.simantics.district.route/META-INF/MANIFEST.MF
org.simantics.district.route/src/org/simantics/district/route/RouteJob.java
org.simantics.district.route/src/org/simantics/district/route/RouteService.java
org.simantics.district.route/src/org/simantics/district/route/Router.java
org.simantics.district.route/src/org/simantics/district/route/internal/RouteImpl.java
org.simantics.district.route/src/org/simantics/district/route/internal/RoutePersistence.java
org.simantics.district.route/src/org/simantics/district/route/internal/RouteServiceImpl.java

index 2e77a6c4208f0b42da94b497b70181256bcd206e..ccb5ab1d844aa285eb898e2eba060ecff44eb20b 100644 (file)
@@ -30,9 +30,9 @@ Require-Bundle: org.eclipse.e4.ui.model.workbench;bundle-version="1.1.100.v20150
  org.eclipse.e4.core.contexts,
  org.eclipse.jface,
  org.simantics.scl.osgi,
- org.simantics.district.route.ui;bundle-version="1.0.0",
  org.simantics.district.route
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Import-Package: javax.annotation;version="1.0.0";resolution:=optional,
   javax.inject;version="1.0.0"
 Bundle-ActivationPolicy: lazy
+Automatic-Module-Name: org.simantics.district.network.ui
index d274a617931b11d1641149bbc722ae4826f45699..4f023c880a2968d2a3d306fff7ed685551956c47 100644 (file)
@@ -8,6 +8,7 @@ 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.Display;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.PlatformUI;
 import org.simantics.db.Resource;
@@ -40,6 +41,7 @@ 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.simantics.utils.ui.SWTUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -158,8 +160,17 @@ public class RoutingMode extends AbstractMode {
                 return false;
             KeyPressedEvent kpe = (KeyPressedEvent) e;
             if (kpe.keyCode == java.awt.event.KeyEvent.VK_ENTER) {
-                routeService.persistRoute(route);
+                Route committedRoute = route;
                 route = null;
+                SWTUtils.asyncExec(Display.getDefault(), () -> {
+                    String newName = askRouteName("Confirm Route", committedRoute.getName());
+                    if (newName != null) {
+                        committedRoute.setName(newName);
+                        routeService.persistRoute(committedRoute);
+                    } else {
+                        routeService.discardRoute(committedRoute);
+                    }
+                });
                 dispose();
             }
         } else if (e instanceof CommandEvent) {
@@ -167,20 +178,32 @@ public class RoutingMode extends AbstractMode {
             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());
-                }
+                // TODO: still needs key binding contribution for the district diagram editor
+                SWTUtils.asyncExec(Display.getDefault(), () -> {
+                    String newName = askRouteName("Rename Route", route.getName());
+                    if (newName != null) {
+                        route.setName(newName);
+                        routeService.refreshRoute(route);
+                    }
+                });
             }
         }
         return false;
     }
 
+    private String askRouteName(String dialogTitle, String initialValue) {
+        InputDialog dialog = new InputDialog(
+                PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+                dialogTitle,
+                "Route name",
+                initialValue,
+                s -> s.trim().length() > 0 ? null : "Name must be non-empty");
+        if (dialog.open() == Window.OK) {
+            return dialog.getValue();
+        }
+        return null;
+    }
+
     protected boolean dispose() {
         setDirty();
         remove();
index 98a3ea4f47aa7d78df6a4e0f864f5ccc58e082f9..175d49c242c088b9c660081c486cda66e2afa0e0 100644 (file)
@@ -7,6 +7,7 @@ import java.awt.geom.PathIterator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -87,6 +88,9 @@ public final class DiagramRegions {
     }
     
     public static Collection<DiagramRegion> findRegions(ReadGraph graph, Resource model) throws DatabaseException {
+        if (model == null)
+            return Collections.emptyList();
+
         List<Resource> diagrams = QueryIndexUtils.searchByType(graph, model, DiagramResource.getInstance(graph).Diagram);
         Set<DiagramRegion> regions = new HashSet<>();
         
index 299b2414e4431cde19551224ec64bc7bc6dbb915..3b531e707da2667c7b3ab10fd3a4a29617ced9c8 100644 (file)
@@ -5,16 +5,17 @@ Bundle-SymbolicName: org.simantics.district.route.ui;singleton:=true
 Bundle-Version: 1.0.0.qualifier
 Bundle-Activator: org.simantics.district.route.ui.internal.Activator
 Bundle-Vendor: Semantum Oy
-Require-Bundle: org.eclipse.e4.ui.di,
- org.eclipse.e4.ui.model.workbench,
+Require-Bundle: org.eclipse.e4.core.di,
  org.eclipse.e4.core.di.annotations,
  org.eclipse.e4.core.services,
+ org.eclipse.e4.ui.di,
+ org.eclipse.e4.ui.model.workbench,
+ org.eclipse.e4.ui.services,
+ org.eclipse.e4.ui.workbench,
  org.simantics.ui,
  org.simantics.district.route,
- org.slf4j.api,
- org.eclipse.e4.ui.workbench,
- org.eclipse.e4.core.di,
- org.eclipse.e4.ui.services
+ org.simantics.district.network.ui;bundle-version="1.0.0",
+ org.slf4j.api
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Automatic-Module-Name: fi.vtt.apros.district.route.ui
 Import-Package: javax.annotation;version="1.0.0";resolution:=optional,
index 6bc47b42c04e49c898804070ea9b9f158db20237..7b710bee907bec8c877981a72c51d76e346feb9c 100644 (file)
@@ -1,4 +1,2 @@
-#Properties file for fi.apros.visualization.table
+#Properties file for org.simantics.district.route.ui
 view.name = Routes
-command.commandname.1 = Open Routes View
-command.commandname.2 = Select Route on Diagram
index d737ba6ba427be1045054c39e87a783780c7a106..16c774b371847e9122cde24c406815259a984db3 100644 (file)
@@ -2,12 +2,16 @@
 <fragment:ModelFragments xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:commands="http://www.eclipse.org/ui/2010/UIModel/application/commands" xmlns:fragment="http://www.eclipse.org/ui/2010/UIModel/fragment" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_BxaXACerEeWxCPrV0pAZQQ">
   <fragments xsi:type="fragment:StringModelFragment" xmi:id="_n2jsIMq-EeeUz6Cs9kKeKg" featurename="categories" parentElementId="xpath:/"/>
   <fragments xsi:type="fragment:StringModelFragment" xmi:id="_4fyr4MqVEeeUz6Cs9kKeKg" featurename="commands" parentElementId="xpath:/">
-    <elements xsi:type="commands:Command" xmi:id="_x1nG0H4WEei74IuRct85qQ" elementId="org.simantics.district.route.ui.commands.openRouteView" commandName="%command.commandname.1"/>
-    <elements xsi:type="commands:Command" xmi:id="_k63rkP6zEeiBo8tg-6EPYA" elementId="org.simantics.district.route.ui.command.selectRouteOnDiagram" commandName="%command.commandname.2"/>
+    <elements xsi:type="commands:Command" xmi:id="_x1nG0H4WEei74IuRct85qQ" elementId="org.simantics.district.route.ui.commands.openRouteView" commandName="Open Routes View"/>
+    <elements xsi:type="commands:Command" xmi:id="_k63rkP6zEeiBo8tg-6EPYA" elementId="org.simantics.district.route.ui.command.selectRouteOnDiagram" commandName="Select Route on Diagram"/>
+    <elements xsi:type="commands:Command" xmi:id="_bA61IAI7EemGocelWS26pQ" elementId="org.simantics.district.route.ui.command.discardRoute" commandName="Discard Route"/>
+    <elements xsi:type="commands:Command" xmi:id="_bfN6sAI7EemGocelWS26pQ" elementId="org.simantics.district.route.ui.command.renameRoute" commandName="Rename Route"/>
   </fragments>
   <fragments xsi:type="fragment:StringModelFragment" xmi:id="_1Ds_gMqVEeeUz6Cs9kKeKg" featurename="handlers" parentElementId="xpath:/">
     <elements xsi:type="commands:Handler" xmi:id="_1G5RYH4WEei74IuRct85qQ" elementId="org.simantics.district.route.ui.handlers.openRouteView" contributionURI="bundleclass://org.simantics.district.route.ui/org.simantics.district.route.ui.OpenRouteView" command="_x1nG0H4WEei74IuRct85qQ"/>
     <elements xsi:type="commands:Handler" xmi:id="_O9tbQP60EeiBo8tg-6EPYA" elementId="org.simantics.district.route.ui.handlers.selectRouteOnDiagram" contributionURI="bundleclass://org.simantics.district.route.ui/org.simantics.district.route.ui.handlers.SelectRouteOnDiagram" command="_k63rkP6zEeiBo8tg-6EPYA"/>
+    <elements xsi:type="commands:Handler" xmi:id="_mRg_oAI7EemGocelWS26pQ" elementId="org.simantics.district.route.ui.handler.discardRoute" contributionURI="bundleclass://org.simantics.district.route.ui/org.simantics.district.route.ui.handlers.DiscardRoute" command="_bA61IAI7EemGocelWS26pQ"/>
+    <elements xsi:type="commands:Handler" xmi:id="_mh_EkAI7EemGocelWS26pQ" elementId="org.simantics.district.route.ui.handler.renameRoute" contributionURI="bundleclass://org.simantics.district.route.ui/org.simantics.district.route.ui.handlers.RenameRoute" command="_bfN6sAI7EemGocelWS26pQ"/>
   </fragments>
   <fragments xsi:type="fragment:StringModelFragment" xmi:id="_Fso08MrIEeeUz6Cs9kKeKg" featurename="toolBarContributions" parentElementId="xpath:/"/>
   <fragments xsi:type="fragment:StringModelFragment" xmi:id="_WNB8EH4oEei74IuRct85qQ" featurename="trimContributions" parentElementId="xpath:/">
@@ -23,6 +27,8 @@
     </elements>
     <elements xsi:type="menu:MenuContribution" xmi:id="_Y4vWcP6zEeiBo8tg-6EPYA" elementId="org.simantics.district.route.ui.menucontribution.1" parentId="org.simantics.district.route.ui.contextMenu">
       <children xsi:type="menu:HandledMenuItem" xmi:id="_fH1V8P6zEeiBo8tg-6EPYA" elementId="org.simantics.district.route.ui.handledmenuitem.selectRouteOnDiagram" command="_k63rkP6zEeiBo8tg-6EPYA"/>
+      <children xsi:type="menu:HandledMenuItem" xmi:id="_2nw1UAI7EemGocelWS26pQ" elementId="org.simantics.district.route.ui.handledmenuitem.discardRoute" command="_bA61IAI7EemGocelWS26pQ"/>
+      <children xsi:type="menu:HandledMenuItem" xmi:id="_6oh8EAI7EemGocelWS26pQ" elementId="org.simantics.district.route.ui.handledmenuitem.renameRoute" command="_bfN6sAI7EemGocelWS26pQ"/>
     </elements>
   </fragments>
 </fragment:ModelFragments>
index e58d6a68ec9d4d833c35f929e7405ab1f6c47242..04ffc2361a380f5d2b2f03a21c92dea2dd7fc9ca 100644 (file)
@@ -4,15 +4,26 @@ import java.util.List;
 
 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
 import org.eclipse.jface.layout.GridDataFactory;
-import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.layout.TreeColumnLayout;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.CellEditor;
 import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.ColumnViewerEditor;
+import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
+import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
+import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.ITreeContentProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TextCellEditor;
 import org.eclipse.jface.viewers.TreePath;
 import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.TreeViewerEditor;
+import org.eclipse.jface.viewers.TreeViewerFocusCellManager;
 import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.jface.viewers.ViewerCell;
 import org.eclipse.osgi.util.NLS;
@@ -39,7 +50,8 @@ public class RouteTree extends Composite {
 
     ESelectionService selectionService;
 
-    private final LocalResourceManager resourceManager;
+    @SuppressWarnings("unused")
+    private LocalResourceManager resourceManager;
 
     private TreeViewer tree;
 
@@ -52,7 +64,7 @@ public class RouteTree extends Composite {
     }
 
     private RouteServiceListener routeServiceListener = e -> {
-        System.out.println("Route event: " + e);
+        LOGGER.info("Route event: {}", e);
         switch (e.type) {
             case RouteEvent.TYPE_ROUTE_DISCARDED:
                 runUi(() -> tree.refresh());
@@ -77,7 +89,16 @@ public class RouteTree extends Composite {
                 break;
 
             case RouteEvent.TYPE_ROUTE_SOURCE_CHANGED:
-                runUi(() -> tree.setInput(e.service.listRoutes()));
+                runUi(() -> {
+                    tree.getTree().setRedraw(false);
+                    try {
+                        Object[] expanded = tree.getExpandedElements();
+                        tree.setInput(e.service.listRoutes());
+                        tree.setExpandedElements(expanded);
+                    } finally {
+                        tree.getTree().setRedraw(true);
+                    }
+                });
                 break;
         }
     };
@@ -93,46 +114,71 @@ public class RouteTree extends Composite {
 
     private void defaultInitializeUI() {
         GridDataFactory.fillDefaults().grab(true, true).applyTo(this);
-        GridLayoutFactory.fillDefaults().numColumns(1).applyTo(this);
-
         createTree(this);
     }
 
     private void createTree(Composite parent) {
-        tree = new TreeViewer(parent, SWT.SINGLE);
+        TreeColumnLayout columnLayout = new TreeColumnLayout(false);
+        parent.setLayout(columnLayout);
+
+        tree = new TreeViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION);
         tree.setUseHashlookup(true);
         GridDataFactory.fillDefaults().grab(true, true).applyTo(tree.getControl());
         tree.setContentProvider(new ContentProvider());
         tree.setLabelProvider(new LabelProvider());
         tree.addSelectionChangedListener(this::treeSelectionChanged);
-        //tree.addPostSelectionChangedListener(this::treeSelectionChanged);
-        tree.addDoubleClickListener(this::itemDoubleClicked);
-        // TODO: add route renaming (F2), DnD reordering support
-    }
 
-    private void itemDoubleClicked(DoubleClickEvent e) {
-        // TODO: default action, i.e. highlight route?
-        LOGGER.info("double click {}", e);
+        TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(tree, new FocusCellOwnerDrawHighlighter(tree));
+        ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(tree) {
+            @Override
+            protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
+                boolean singleSelect = tree.getStructuredSelection().size() == 1;
+                return singleSelect && (
+                        (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.F2)
+                        || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC
+                        );
+            }
+        };
+
+        int feature = ColumnViewerEditor.KEYBOARD_ACTIVATION;
+
+        TreeViewerEditor.create(tree, focusCellManager, actSupport, feature);
+        final TextCellEditor textCellEditor = new TextCellEditor(tree.getTree());
+
+        TreeViewerColumn viewerColumn = new TreeViewerColumn(tree, SWT.LEFT);
+        columnLayout.setColumnData(viewerColumn.getColumn(), new ColumnWeightData(1));
+        viewerColumn.setLabelProvider(new LabelProvider());
+        viewerColumn.setEditingSupport(new EditingSupport(tree) {
+            @Override
+            protected void setValue(Object element, Object value) {
+                LOGGER.info("set value {} for {}", value, element);
+                Route r = (Route) element;
+                r.setName((String) value);
+                Activator.getDefault().getRouteService().persistRoute(r);
+                getViewer().update(element, null);
+            }
+
+            @Override
+            protected Object getValue(Object element) {
+                return ((Route) element).getName();
+            }
+
+            @Override
+            protected CellEditor getCellEditor(Object element) {
+                return textCellEditor;
+            }
+
+            @Override
+            protected boolean canEdit(Object element) {
+                return element instanceof Route;
+            }
+        });
+
+        // TODO: add DnD reordering support
     }
 
     private void treeSelectionChanged(SelectionChangedEvent e) {
         selectionService.setSelection(e.getSelection());
-        /*
-        IStructuredSelection ss = (IStructuredSelection) e.getSelection();
-        Object[] arr = ss.toArray();
-        if (arr.length == 1) {
-            Object o = arr[0];
-            if (o instanceof Route) {
-                CompletableFuture<List<Resource>> callback = new CompletableFuture<>();
-                callback.thenAccept(dnElements -> {
-                    runUi(() -> selectionService.setSelection(new StructuredSelection(dnElements)));
-                });
-                new RouteJob((Route) o, callback).schedule();
-            } else if (o instanceof Waypoint) {
-                selectionService.setSelection(new StructuredSelection(((Waypoint) o).<Object>getObject()));
-            }
-        }
-        */
     }
 
     protected void setInput(List<Route> result) {
@@ -217,4 +263,11 @@ public class RouteTree extends Composite {
         return tree.getTree();
     }
 
-}
+    public void editCurrentSelection() {
+        IStructuredSelection s = tree.getStructuredSelection();
+        if (s.size() == 1) {
+            tree.editElement(s.getFirstElement(), 0);
+        }
+    }
+
+}
\ No newline at end of file
index 0d99b37486fdf557e813e720ce9812b80f2bece5..4499782d100860411da25f878a6ee1c9da8074be 100644 (file)
@@ -71,4 +71,8 @@ public class RouteView {
         ui.setFocus();
     }
 
+    public void editCurrentSelection() {
+        ui.editCurrentSelection();
+    }
+
 }
\ No newline at end of file
diff --git a/org.simantics.district.route.ui/src/org/simantics/district/route/ui/handlers/DiscardRoute.java b/org.simantics.district.route.ui/src/org/simantics/district/route/ui/handlers/DiscardRoute.java
new file mode 100644 (file)
index 0000000..3312b7d
--- /dev/null
@@ -0,0 +1,35 @@
+package org.simantics.district.route.ui.handlers;
+
+import javax.inject.Named;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Shell;
+import org.simantics.district.route.Route;
+import org.simantics.district.route.ui.internal.Activator;
+import org.simantics.utils.ui.ISelectionUtils;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class DiscardRoute {
+
+    @CanExecute
+    public boolean canExecute(@Named(IServiceConstants.ACTIVE_SELECTION) ISelection selection) {
+        return ISelectionUtils.filterSingleSelection(selection, Route.class) != null;
+    }
+
+    @Execute
+    public void execute(@Named(IServiceConstants.ACTIVE_SHELL) Shell activeShell,
+            @Named(IServiceConstants.ACTIVE_PART) MPart part,
+            @Named(IServiceConstants.ACTIVE_SELECTION) ISelection selection) {
+        // get selected route
+        Route route = ISelectionUtils.filterSingleSelection(selection, Route.class);
+        if (route != null)
+            Activator.getDefault().getRouteService().discardRoute(route);
+    }
+
+}
\ No newline at end of file
diff --git a/org.simantics.district.route.ui/src/org/simantics/district/route/ui/handlers/RenameRoute.java b/org.simantics.district.route.ui/src/org/simantics/district/route/ui/handlers/RenameRoute.java
new file mode 100644 (file)
index 0000000..d6af099
--- /dev/null
@@ -0,0 +1,39 @@
+package org.simantics.district.route.ui.handlers;
+
+import javax.inject.Named;
+
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Shell;
+import org.simantics.district.route.Route;
+import org.simantics.district.route.ui.RouteView;
+import org.simantics.utils.ui.ISelectionUtils;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class RenameRoute {
+
+    @CanExecute
+    public boolean canExecute(@Named(IServiceConstants.ACTIVE_SELECTION) ISelection selection) {
+        return ISelectionUtils.filterSingleSelection(selection, Route.class) != null;
+    }
+
+    @Execute
+    public void execute(@Named(IServiceConstants.ACTIVE_SHELL) Shell activeShell,
+            @Named(IServiceConstants.ACTIVE_PART) MPart part,
+            @Named(IServiceConstants.ACTIVE_SELECTION) ISelection selection) {
+        // get selected route
+        Route route = ISelectionUtils.filterSingleSelection(selection, Route.class);
+        if (route != null) {
+            Object obj = part.getObject();
+            if (obj instanceof RouteView) {
+                ((RouteView)obj).editCurrentSelection();
+            }
+        }
+    }
+
+}
\ No newline at end of file
index 7568ea308d7b6e975cb3564ee28c6674092e5355..36d14fc6427167b3c102469e4623f9a77e7af294 100644 (file)
@@ -5,22 +5,37 @@ import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Named;
 
+import org.eclipse.e4.core.di.annotations.CanExecute;
 import org.eclipse.e4.core.di.annotations.Execute;
 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
 import org.eclipse.e4.ui.services.IServiceConstants;
 import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Shell;
-import org.simantics.db.layer0.variable.Variable;
+import org.simantics.Simantics;
+import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.district.network.ui.DistrictNetworkUIUtil;
 import org.simantics.district.route.Route;
 import org.simantics.district.route.RouteJob;
 import org.simantics.district.route.RouterConfiguration;
 import org.simantics.utils.ui.ISelectionUtils;
+import org.simantics.utils.ui.SWTUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * @author Tuukka Lehtonen
  */
 public class SelectRouteOnDiagram {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(SelectRouteOnDiagram.class);
+
+    @CanExecute
+    public boolean canExecute(@Named(IServiceConstants.ACTIVE_SELECTION) ISelection selection) {
+        return ISelectionUtils.filterSingleSelection(selection, Route.class) != null;
+    }
+
     @Execute
     public void execute(@Named(IServiceConstants.ACTIVE_SHELL) Shell activeShell,
             @Named(IServiceConstants.ACTIVE_PART) MPart part,
@@ -30,9 +45,32 @@ public class SelectRouteOnDiagram {
         if (route == null)
             return;
 
-        CompletableFuture<List<Variable>> result = new CompletableFuture<>();
+        Display display = activeShell.getDisplay();
+        CompletableFuture<List<Resource>> result = new CompletableFuture<>();
+        result.thenAccept(dnElements -> {
+            try {
+                openDiagram(display, dnElements);
+            } catch (DatabaseException e) {
+                LOGGER.error("Failed to open district network diagram with selection {}", dnElements);
+            }
+        });
+
         RouterConfiguration config = new RouterConfiguration();
         new RouteJob(config, route, result).schedule();
     }
 
+    public static boolean openDiagram(Display display, List<Resource> dnElements) throws DatabaseException {
+        if (dnElements.isEmpty())
+            return false;
+
+        DistrictNetworkUIUtil.Input in = Simantics.getSession().syncRequest(
+                new DistrictNetworkUIUtil.ElementToInput(dnElements.get(0)));
+        if (in == null)
+            return false;
+
+        SWTUtils.asyncExec(display,
+                () -> DistrictNetworkUIUtil.openDNDiagramEditorWithSelection(in, dnElements.toArray()));
+        return true;
+    }
+
 }
\ No newline at end of file
index 48dce696d5709d4179a33aff43a9684788e8ec84..118f8157da6da73c44ef4e2d40890a6282d1c25e 100644 (file)
@@ -15,4 +15,5 @@ Require-Bundle: org.eclipse.core.runtime,
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Automatic-Module-Name: fi.vtt.apros.district.route
 Bundle-ActivationPolicy: lazy
-Export-Package: org.simantics.district.route
+Export-Package: org.simantics.district.route,
+ org.simantics.district.route.internal;x-friends:="org.simantics.district.route.ui"
index 84414937d7344aa1f22c89f705b8d3ca4949672a..897366ada886f17308fee48caeda0c8e3a043fee 100644 (file)
@@ -10,7 +10,6 @@ import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
 import org.simantics.ObjectIdentitySchedulingRule;
 import org.simantics.db.Resource;
-import org.simantics.db.layer0.variable.Variable;
 import org.simantics.district.route.internal.Activator;
 import org.simantics.district.route.internal.RoutePersistence;
 import org.slf4j.Logger;
@@ -26,9 +25,9 @@ public class RouteJob extends Job {
 
     private RouterConfiguration config;
     private List<Resource> waypoints;
-    private CompletableFuture<List<Variable>> callback;
+    private CompletableFuture<List<Resource>> callback;
 
-    public RouteJob(RouterConfiguration config, Route route, CompletableFuture<List<Variable>> callback) {
+    public RouteJob(RouterConfiguration config, Route route, CompletableFuture<List<Resource>> callback) {
         super("Compute route");
         Objects.requireNonNull(callback, "Callback must be non-null");
         setUser(true);
@@ -43,7 +42,7 @@ public class RouteJob extends Job {
         List<Router> routers = Activator.getInstance().getRouteService().routers();
         for (Router router : routers) {
             try {
-                List<Variable> path = router.findShortestPath(config, waypoints);
+                List<Resource> path = router.findShortestPath(config, waypoints);
                 if (!path.isEmpty()) {
                     callback.complete(path);
                     return Status.OK_STATUS;
index 5c7180b62f254364e736cff3eb8d1ab8a955f2bc..5d3f63dc2499d471bdb40978a7a537b3b053bebc 100644 (file)
@@ -16,6 +16,8 @@ public interface RouteService {
 
     void registerRoute(Route route);
 
+    void refreshRoute(Route route);
+
     CompletableFuture<Route> persistRoute(Route route);
 
     CompletableFuture<?> discardRoute(Route route);
index 1d2423221440b43706e5b8336949b2718c7412d7..5f73c9679b12d5b388c5ad6d1694a2d7dee4935d 100644 (file)
@@ -3,7 +3,6 @@ package org.simantics.district.route;
 import java.util.List;
 
 import org.simantics.db.Resource;
-import org.simantics.db.layer0.variable.Variable;
 
 /**
  * @author Tuukka Lehtonen
@@ -20,13 +19,14 @@ public interface Router {
     /**
      * Must be invoked outside of any transaction realm, like a database request or
      * experiment thread, preferably from a background job thread.
-     * 
+     *
+     * @param config reserved for future use, may be <code>null</code>
      * @param wayPoints waypoints for the route to find in visiting order. The
      *            resources must represents district network diagram elements.
      * @return the piece-wise shortest path between the specified waypoints as a
      *         fully baked path of district network diagram element resources
      * @throws RoutingException in case of any problems in routing
      */
-    List<Variable> findShortestPath(RouterConfiguration config, List<Resource> wayPoints) throws RoutingException;
+    List<Resource> findShortestPath(RouterConfiguration config, List<Resource> wayPoints) throws RoutingException;
 
 }
index 3619b602143a4c0be0c7c897df625acd3512829e..224f4af0392084adea8d168f215c10ace4c6b30e 100644 (file)
@@ -4,13 +4,21 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.simantics.Simantics;
 import org.simantics.db.Resource;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.request.Read;
 import org.simantics.district.route.Route;
 import org.simantics.district.route.RouteEvent;
 import org.simantics.district.route.Waypoint;
+import org.simantics.utils.threads.ThreadUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class RouteImpl implements Route {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(RouteImpl.class);
+
     private String name;
     private Resource model;
     private Resource backend;
@@ -68,8 +76,26 @@ public class RouteImpl implements Route {
 
     @Override
     public Waypoint createWaypoint(Object backend) {
-        if (backend instanceof Resource)
-            return new WaypointImpl((Resource) backend, "Point 1");
+        if (backend instanceof Resource) {
+            Resource waypoint = (Resource) backend;
+            WaypointImpl wp = new WaypointImpl(waypoint, "");
+
+            // Read real label in background
+            ThreadUtils.getBlockingWorkExecutor().submit(() -> {
+                try {
+                    Waypoint p = Simantics.getSession().syncRequest(
+                            (Read<Waypoint>) graph -> RoutePersistence.toWaypoint(graph, waypoint));
+                    if (p != null) {
+                        wp.setLabel(p.getLabel());
+                        rs.fireEvent(RouteEvent.TYPE_ROUTE_MODIFIED, RouteImpl.this);
+                    }
+                } catch (DatabaseException e) {
+                    LOGGER.error("Failed to read waypoint {} label", backend, e);
+                }
+            });
+
+            return wp;
+        }
         throw new IllegalArgumentException("only Resource type waypoints supported, got " + backend); //$NON-NLS-1$
     }
 
index c3ba7571e82c3af15c96c4534a45a3d55c3965a4..fceb6612cb521fd2d81e3d5759046c4daee2f120 100644 (file)
@@ -16,6 +16,7 @@ import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
 import org.simantics.db.WriteGraph;
 import org.simantics.db.common.request.ObjectsWithType;
+import org.simantics.db.common.request.ResourceRead;
 import org.simantics.db.common.request.UniqueRead;
 import org.simantics.db.common.utils.ListUtils;
 import org.simantics.db.common.utils.NameUtils;
@@ -78,7 +79,7 @@ public class RoutePersistence {
         Layer0 L0 = Layer0.getInstance(graph);
 
         String existingLabel = graph.getPossibleRelatedValue(route, L0.HasLabel, Bindings.STRING);
-        if (ObjectUtils.objectEquals(existingLabel, label)) {
+        if (!ObjectUtils.objectEquals(existingLabel, label)) {
             graph.claimLiteral(route, L0.HasLabel, label, Bindings.STRING);
         }
 
@@ -124,7 +125,7 @@ public class RoutePersistence {
     }
 
     public static List<RouteImpl> findRoutes(ReadGraph graph, Resource model) throws DatabaseException {
-        Resource rf = getRouteFolder(graph, model);
+        Resource rf = model != null ? getRouteFolder(graph, model) : null;
         if (rf == null)
             return Collections.emptyList();
 
@@ -144,6 +145,16 @@ public class RoutePersistence {
         return routes;
     }
 
+    public static class ModelRoutesRequest extends ResourceRead<List<RouteImpl>> {
+        public ModelRoutesRequest(Resource model) {
+            super(model);
+        }
+        @Override
+        public List<RouteImpl> perform(ReadGraph graph) throws DatabaseException {
+            return findRoutes(graph, resource);
+        }
+    }
+
     public static class ActiveModelRoutesRequest extends UniqueRead<List<RouteImpl>> {
         @Override
         public List<RouteImpl> perform(ReadGraph graph) throws DatabaseException {
index e37a803b6fa76b96cb84cd8c48200b19d5b4f48b..6817ea3282843de3f70531c69d47889c71786bcc 100644 (file)
@@ -11,12 +11,12 @@ import org.simantics.Simantics;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
 import org.simantics.db.Session;
-import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.common.procedure.adapter.DisposableListener;
+import org.simantics.db.common.procedure.adapter.DisposableSyncListener;
 import org.simantics.db.layer0.request.PossibleActiveModel;
 import org.simantics.db.management.ISessionContext;
 import org.simantics.db.management.ISessionContextChangedListener;
 import org.simantics.db.management.SessionContextChangedEvent;
-import org.simantics.db.procedure.SyncListener;
 import org.simantics.district.route.Route;
 import org.simantics.district.route.RouteEvent;
 import org.simantics.district.route.RouteService;
@@ -38,42 +38,46 @@ public class RouteServiceImpl implements RouteService, ISessionContextChangedLis
     private List<Router> routers = new ArrayList<>();
     private List<Router> unmodifiableRouters = Collections.unmodifiableList(routers);
 
-    private class StoreListener implements SyncListener<Resource> {
-        private boolean disposed = false;
-
+    private class StoreRoutesListener extends DisposableListener<List<RouteImpl>> {
         @Override
-        public void execute(ReadGraph graph, Resource activeModel) {
-            try {
-                if (activeModel != null) {
-                    resetRoutes(RoutePersistence.findRoutes(graph, activeModel));
-                } else {
-                    resetRoutes(Collections.emptyList());
-                }
-                fireEvent(RouteEvent.TYPE_ROUTE_SOURCE_CHANGED, this);
-            } catch (DatabaseException e) {
-                LOGGER.error("Failed to read routes from model {}", activeModel, e);
-            }
+        public void execute(List<RouteImpl> result) {
+            resetRoutes(result);
+            fireEvent(RouteEvent.TYPE_ROUTE_SOURCE_CHANGED, RouteServiceImpl.this);
         }
 
         @Override
-        public void exception(ReadGraph graph, Throwable t) {
-            LOGGER.error("Failed to listen to current route service storage", t);
+        public void exception(Throwable t) {
+            LOGGER.error("Failed to listen to current route store routes", t);
         }
+    }
 
-        public void dispose() {
-            disposed = true;
+    private class StoreListener extends DisposableSyncListener<Resource> {
+        @Override
+        public void execute(ReadGraph graph, Resource activeModel) {
+            if (activeModel != null) {
+                StoreRoutesListener srl = storeRoutesListener;
+                if (srl != null)
+                    srl.dispose();
+                Simantics.getSession().asyncRequest(
+                        new RoutePersistence.ModelRoutesRequest(activeModel),
+                        storeRoutesListener = new StoreRoutesListener());
+            } else {
+                resetRoutes(Collections.emptyList());
+                fireEvent(RouteEvent.TYPE_ROUTE_SOURCE_CHANGED, RouteServiceImpl.this);
+            }
         }
 
         @Override
-        public boolean isDisposed() {
-            return disposed;
+        public void exception(ReadGraph graph, Throwable t) {
+            LOGGER.error("Failed to listen to current route service storage", t);
         }
     }
 
+    private StoreRoutesListener storeRoutesListener;
     private StoreListener storeListener;
 
     private synchronized void listenToActiveModels(Session s) {
-        StoreListener sl =  storeListener;
+        StoreListener sl = storeListener;
         if (sl != null)
             sl.dispose();
         if (s != null) {
@@ -133,6 +137,11 @@ public class RouteServiceImpl implements RouteService, ISessionContextChangedLis
         fireEvent(RouteEvent.TYPE_ROUTE_REGISTERED, route);
     }
 
+    @Override
+    public void refreshRoute(Route route) {
+        fireEvent(RouteEvent.TYPE_ROUTE_MODIFIED, route);
+    }
+
     @Override
     public CompletableFuture<Route> persistRoute(Route route) {
         fireEvent(RouteEvent.TYPE_ROUTE_PERSISTING, route);