1 package org.simantics.district.route.ui;
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;
44 * @author Tuukka Lehtonen
47 public class RouteTree extends Composite {
49 private static final Logger LOGGER = LoggerFactory.getLogger(RouteTree.class);
51 ESelectionService selectionService;
53 @SuppressWarnings("unused")
54 private LocalResourceManager resourceManager;
56 private TreeViewer tree;
58 public RouteTree(Composite parent, int style, ESelectionService selectionService) {
60 this.selectionService = selectionService;
61 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
62 defaultInitializeUI();
66 private RouteServiceListener routeServiceListener = e -> {
67 LOGGER.info("Route event: {}", e);
69 case RouteEvent.TYPE_ROUTE_DISCARDED:
70 runUi(() -> tree.refresh());
73 case RouteEvent.TYPE_ROUTE_REGISTERED:
76 tree.setExpandedState(e.obj, true);
80 case RouteEvent.TYPE_ROUTE_MODIFIED:
83 tree.setExpandedState(e.obj, true);
87 case RouteEvent.TYPE_ROUTE_RENAMED:
88 runUi(() -> tree.refresh(e.obj));
91 case RouteEvent.TYPE_ROUTE_SOURCE_CHANGED:
93 tree.getTree().setRedraw(false);
95 Object[] expanded = tree.getExpandedElements();
96 tree.setInput(e.service.listRoutes());
97 tree.setExpandedElements(expanded);
99 tree.getTree().setRedraw(true);
106 private void trackRouteInput() {
107 RouteService rs = Activator.getDefault().getRouteService();
109 rs.addListener(routeServiceListener);
110 addDisposeListener(e -> rs.removeListener(routeServiceListener));
111 setInput(rs.listRoutes());
115 private void defaultInitializeUI() {
116 GridDataFactory.fillDefaults().grab(true, true).applyTo(this);
120 private void createTree(Composite parent) {
121 TreeColumnLayout columnLayout = new TreeColumnLayout(false);
122 parent.setLayout(columnLayout);
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);
131 TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(tree, new FocusCellOwnerDrawHighlighter(tree));
132 ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(tree) {
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
143 int feature = ColumnViewerEditor.KEYBOARD_ACTIVATION;
145 TreeViewerEditor.create(tree, focusCellManager, actSupport, feature);
146 final TextCellEditor textCellEditor = new TextCellEditor(tree.getTree());
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) {
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);
162 protected Object getValue(Object element) {
163 return ((Route) element).getName();
167 protected CellEditor getCellEditor(Object element) {
168 return textCellEditor;
172 protected boolean canEdit(Object element) {
173 return element instanceof Route;
177 // TODO: add DnD reordering support
180 private void treeSelectionChanged(SelectionChangedEvent e) {
181 selectionService.setSelection(e.getSelection());
184 protected void setInput(List<Route> result) {
186 TreePath[] paths = tree.getExpandedTreePaths();
187 tree.setInput(result);
188 tree.setExpandedTreePaths(paths);
192 protected void runUi(Runnable r) {
193 SWTUtils.asyncExec(getDisplay(), () -> {
194 if (!tree.getControl().isDisposed())
199 private static class ContentProvider implements ITreeContentProvider {
201 private static final Object[] NONE = {};
202 @SuppressWarnings("unused")
203 private List<?> input;
206 public void dispose() {
211 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
212 input = newInput instanceof List ? (List<?>) newInput : null;
216 public Object[] getElements(Object inputElement) {
217 if (inputElement instanceof List)
218 return ((List<?>) inputElement).toArray();
223 public Object[] getChildren(Object parentElement) {
224 if (parentElement instanceof Route) {
225 return ((Route) parentElement).waypoints().toArray();
231 public Object getParent(Object element) {
236 public boolean hasChildren(Object element) {
237 if (element instanceof Route) {
238 return !((Route) element).waypoints().isEmpty();
245 private static class LabelProvider extends ColumnLabelProvider {
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) {
253 return element.toString();
256 public void update(ViewerCell cell) {
257 Object element = cell.getElement();
258 cell.setText(getText(element));
262 public Tree getTree() {
263 return tree.getTree();
266 public void editCurrentSelection() {
267 IStructuredSelection s = tree.getStructuredSelection();
269 tree.editElement(s.getFirstElement(), 0);