]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.route.ui/src/org/simantics/district/route/ui/RouteTree.java
Improved Routes view functionality
[simantics/district.git] / org.simantics.district.route.ui / src / org / simantics / district / route / ui / RouteTree.java
1 package org.simantics.district.route.ui;
2
3 import java.util.List;
4
5 import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
6 import org.eclipse.jface.layout.GridDataFactory;
7 import org.eclipse.jface.layout.TreeColumnLayout;
8 import org.eclipse.jface.resource.JFaceResources;
9 import org.eclipse.jface.resource.LocalResourceManager;
10 import org.eclipse.jface.viewers.CellEditor;
11 import org.eclipse.jface.viewers.ColumnLabelProvider;
12 import org.eclipse.jface.viewers.ColumnViewerEditor;
13 import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
14 import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
15 import org.eclipse.jface.viewers.ColumnWeightData;
16 import org.eclipse.jface.viewers.EditingSupport;
17 import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter;
18 import org.eclipse.jface.viewers.IStructuredSelection;
19 import org.eclipse.jface.viewers.ITreeContentProvider;
20 import org.eclipse.jface.viewers.SelectionChangedEvent;
21 import org.eclipse.jface.viewers.TextCellEditor;
22 import org.eclipse.jface.viewers.TreePath;
23 import org.eclipse.jface.viewers.TreeViewer;
24 import org.eclipse.jface.viewers.TreeViewerColumn;
25 import org.eclipse.jface.viewers.TreeViewerEditor;
26 import org.eclipse.jface.viewers.TreeViewerFocusCellManager;
27 import org.eclipse.jface.viewers.Viewer;
28 import org.eclipse.jface.viewers.ViewerCell;
29 import org.eclipse.osgi.util.NLS;
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.widgets.Composite;
32 import org.eclipse.swt.widgets.Tree;
33 import org.simantics.district.route.Route;
34 import org.simantics.district.route.RouteEvent;
35 import org.simantics.district.route.RouteService;
36 import org.simantics.district.route.RouteServiceListener;
37 import org.simantics.district.route.Waypoint;
38 import org.simantics.district.route.ui.internal.Activator;
39 import org.simantics.utils.ui.SWTUtils;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * @author Tuukka Lehtonen
45  * @since 6.09
46  */
47 public class RouteTree extends Composite {
48
49     private static final Logger LOGGER = LoggerFactory.getLogger(RouteTree.class);
50
51     ESelectionService selectionService;
52
53     @SuppressWarnings("unused")
54     private LocalResourceManager resourceManager;
55
56     private TreeViewer tree;
57
58     public RouteTree(Composite parent, int style, ESelectionService selectionService) {
59         super(parent, style);
60         this.selectionService = selectionService;
61         this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
62         defaultInitializeUI();
63         trackRouteInput();
64     }
65
66     private RouteServiceListener routeServiceListener = e -> {
67         LOGGER.info("Route event: {}", e);
68         switch (e.type) {
69             case RouteEvent.TYPE_ROUTE_DISCARDED:
70                 runUi(() -> tree.refresh());
71                 break;
72
73             case RouteEvent.TYPE_ROUTE_REGISTERED:
74                 runUi(() -> {
75                     tree.refresh();
76                     tree.setExpandedState(e.obj, true);
77                 });
78                 break;
79
80             case RouteEvent.TYPE_ROUTE_MODIFIED:
81                 runUi(() -> {
82                     tree.refresh(e.obj);
83                     tree.setExpandedState(e.obj, true);
84                 });
85                 break;
86
87             case RouteEvent.TYPE_ROUTE_RENAMED:
88                 runUi(() -> tree.refresh(e.obj));
89                 break;
90
91             case RouteEvent.TYPE_ROUTE_SOURCE_CHANGED:
92                 runUi(() -> {
93                     tree.getTree().setRedraw(false);
94                     try {
95                         Object[] expanded = tree.getExpandedElements();
96                         tree.setInput(e.service.listRoutes());
97                         tree.setExpandedElements(expanded);
98                     } finally {
99                         tree.getTree().setRedraw(true);
100                     }
101                 });
102                 break;
103         }
104     };
105
106     private void trackRouteInput() {
107         RouteService rs = Activator.getDefault().getRouteService();
108         if (rs != null) {
109             rs.addListener(routeServiceListener);
110             addDisposeListener(e -> rs.removeListener(routeServiceListener));
111             setInput(rs.listRoutes());
112         }
113     }
114
115     private void defaultInitializeUI() {
116         GridDataFactory.fillDefaults().grab(true, true).applyTo(this);
117         createTree(this);
118     }
119
120     private void createTree(Composite parent) {
121         TreeColumnLayout columnLayout = new TreeColumnLayout(false);
122         parent.setLayout(columnLayout);
123
124         tree = new TreeViewer(parent, SWT.SINGLE | SWT.FULL_SELECTION);
125         tree.setUseHashlookup(true);
126         GridDataFactory.fillDefaults().grab(true, true).applyTo(tree.getControl());
127         tree.setContentProvider(new ContentProvider());
128         tree.setLabelProvider(new LabelProvider());
129         tree.addSelectionChangedListener(this::treeSelectionChanged);
130
131         TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(tree, new FocusCellOwnerDrawHighlighter(tree));
132         ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(tree) {
133             @Override
134             protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
135                 boolean singleSelect = tree.getStructuredSelection().size() == 1;
136                 return singleSelect && (
137                         (event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.F2)
138                         || event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC
139                         );
140             }
141         };
142
143         int feature = ColumnViewerEditor.KEYBOARD_ACTIVATION;
144
145         TreeViewerEditor.create(tree, focusCellManager, actSupport, feature);
146         final TextCellEditor textCellEditor = new TextCellEditor(tree.getTree());
147
148         TreeViewerColumn viewerColumn = new TreeViewerColumn(tree, SWT.LEFT);
149         columnLayout.setColumnData(viewerColumn.getColumn(), new ColumnWeightData(1));
150         viewerColumn.setLabelProvider(new LabelProvider());
151         viewerColumn.setEditingSupport(new EditingSupport(tree) {
152             @Override
153             protected void setValue(Object element, Object value) {
154                 LOGGER.info("set value {} for {}", value, element);
155                 Route r = (Route) element;
156                 r.setName((String) value);
157                 Activator.getDefault().getRouteService().persistRoute(r);
158                 getViewer().update(element, null);
159             }
160
161             @Override
162             protected Object getValue(Object element) {
163                 return ((Route) element).getName();
164             }
165
166             @Override
167             protected CellEditor getCellEditor(Object element) {
168                 return textCellEditor;
169             }
170
171             @Override
172             protected boolean canEdit(Object element) {
173                 return element instanceof Route;
174             }
175         });
176
177         // TODO: add DnD reordering support
178     }
179
180     private void treeSelectionChanged(SelectionChangedEvent e) {
181         selectionService.setSelection(e.getSelection());
182     }
183
184     protected void setInput(List<Route> result) {
185         runUi(() -> {
186             TreePath[] paths = tree.getExpandedTreePaths();
187             tree.setInput(result);
188             tree.setExpandedTreePaths(paths);
189         });
190     }
191
192     protected void runUi(Runnable r) {
193         SWTUtils.asyncExec(getDisplay(), () -> {
194             if (!tree.getControl().isDisposed())
195                 r.run();
196         });
197     }
198
199     private static class ContentProvider implements ITreeContentProvider {
200
201         private static final Object[] NONE = {};
202         @SuppressWarnings("unused")
203         private List<?> input;
204
205         @Override
206         public void dispose() {
207             input = null;
208         }
209
210         @Override
211         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
212             input = newInput instanceof List ? (List<?>) newInput : null;
213         }
214
215         @Override
216         public Object[] getElements(Object inputElement) {
217             if (inputElement instanceof List)
218                 return ((List<?>) inputElement).toArray();
219             return NONE;
220         }
221
222         @Override
223         public Object[] getChildren(Object parentElement) {
224             if (parentElement instanceof Route) {
225                 return ((Route) parentElement).waypoints().toArray();
226             }
227             return NONE;
228         }
229
230         @Override
231         public Object getParent(Object element) {
232             return null;
233         }
234
235         @Override
236         public boolean hasChildren(Object element) {
237             if (element instanceof Route) {
238                 return !((Route) element).waypoints().isEmpty();
239             }
240             return false;
241         }
242
243     }
244
245     private static class LabelProvider extends ColumnLabelProvider {
246         @Override
247         public String getText(Object element) {
248             if (element instanceof Route) {
249                 Route r = (Route) element;
250                 return NLS.bind("{0} ({1} waypoints)", r.getName(), r.count());
251             } else if (element instanceof Waypoint) {
252             }
253             return element.toString();
254         }
255         @Override
256         public void update(ViewerCell cell) {
257             Object element = cell.getElement();
258             cell.setText(getText(element));
259         }
260     }
261
262     public Tree getTree() {
263         return tree.getTree();
264     }
265
266     public void editCurrentSelection() {
267         IStructuredSelection s = tree.getStructuredSelection();
268         if (s.size() == 1) {
269             tree.editElement(s.getFirstElement(), 0);
270         }
271     }
272
273 }