1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2012 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.browsing.ui.swt.widgets;
\r
14 import java.util.Collection;
\r
15 import java.util.Collections;
\r
16 import java.util.HashSet;
\r
17 import java.util.Map;
\r
18 import java.util.Set;
\r
19 import java.util.function.Consumer;
\r
21 import org.eclipse.core.runtime.IAdaptable;
\r
22 import org.eclipse.core.runtime.Platform;
\r
23 import org.eclipse.jface.action.IMenuManager;
\r
24 import org.eclipse.jface.layout.GridDataFactory;
\r
25 import org.eclipse.jface.layout.GridLayoutFactory;
\r
26 import org.eclipse.jface.layout.TreeColumnLayout;
\r
27 import org.eclipse.jface.resource.JFaceResources;
\r
28 import org.eclipse.jface.resource.LocalResourceManager;
\r
29 import org.eclipse.jface.viewers.ColumnWeightData;
\r
30 import org.eclipse.jface.viewers.ISelectionProvider;
\r
31 import org.eclipse.swt.SWT;
\r
32 import org.eclipse.swt.dnd.DND;
\r
33 import org.eclipse.swt.dnd.DragSource;
\r
34 import org.eclipse.swt.dnd.DragSourceEvent;
\r
35 import org.eclipse.swt.dnd.DragSourceListener;
\r
36 import org.eclipse.swt.dnd.DropTarget;
\r
37 import org.eclipse.swt.dnd.DropTargetEvent;
\r
38 import org.eclipse.swt.dnd.DropTargetListener;
\r
39 import org.eclipse.swt.dnd.FileTransfer;
\r
40 import org.eclipse.swt.dnd.TextTransfer;
\r
41 import org.eclipse.swt.dnd.Transfer;
\r
42 import org.eclipse.swt.widgets.Composite;
\r
43 import org.eclipse.swt.widgets.Control;
\r
44 import org.eclipse.swt.widgets.Event;
\r
45 import org.eclipse.swt.widgets.Listener;
\r
46 import org.eclipse.swt.widgets.Tree;
\r
47 import org.eclipse.swt.widgets.TreeColumn;
\r
48 import org.eclipse.swt.widgets.TreeItem;
\r
49 import org.eclipse.ui.ISelectionListener;
\r
50 import org.eclipse.ui.IWorkbenchSite;
\r
51 import org.eclipse.ui.contexts.IContextService;
\r
52 import org.simantics.browsing.ui.BuiltinKeys;
\r
53 import org.simantics.browsing.ui.Column;
\r
54 import org.simantics.browsing.ui.ExplorerState;
\r
55 import org.simantics.browsing.ui.GraphExplorer;
\r
56 import org.simantics.browsing.ui.GraphExplorer.TransientExplorerState;
\r
57 import org.simantics.browsing.ui.NodeContext;
\r
58 import org.simantics.browsing.ui.StatePersistor;
\r
59 import org.simantics.browsing.ui.common.ColumnKeys;
\r
60 import org.simantics.browsing.ui.common.EvaluatorData;
\r
61 import org.simantics.browsing.ui.common.EvaluatorDataImpl;
\r
62 import org.simantics.browsing.ui.common.processors.ComparableFactoryResolver;
\r
63 import org.simantics.browsing.ui.common.processors.ComparableSelectorQueryProcessor;
\r
64 import org.simantics.browsing.ui.common.processors.FilterSelectionRequestQueryProcessor;
\r
65 import org.simantics.browsing.ui.common.processors.ImageDecoratorFactoryResolver;
\r
66 import org.simantics.browsing.ui.common.processors.ImagerFactoryResolver;
\r
67 import org.simantics.browsing.ui.common.processors.LabelDecoratorFactoryResolver;
\r
68 import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver;
\r
69 import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor;
\r
70 import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor;
\r
71 import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver;
\r
72 import org.simantics.browsing.ui.common.views.FilterAreaSource;
\r
73 import org.simantics.browsing.ui.common.views.IFilterArea;
\r
74 import org.simantics.browsing.ui.common.views.IFilterAreaProvider;
\r
75 import org.simantics.browsing.ui.graph.impl.AsyncReadGraphDataSource;
\r
76 import org.simantics.browsing.ui.graph.impl.Evaluators;
\r
77 import org.simantics.browsing.ui.graph.impl.InheritsQueryProcessor;
\r
78 import org.simantics.browsing.ui.graph.impl.ReadGraphDataSource;
\r
79 import org.simantics.browsing.ui.graph.impl.RelatedObjectsQueryProcessor;
\r
80 import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
\r
81 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
\r
82 import org.simantics.browsing.ui.model.nodetypes.NodeType;
\r
83 import org.simantics.browsing.ui.swt.Activator;
\r
84 import org.simantics.browsing.ui.swt.AdaptableHintContext;
\r
85 import org.simantics.browsing.ui.swt.ComparatorSelector;
\r
86 import org.simantics.browsing.ui.swt.ContextMenuInitializer;
\r
87 import org.simantics.browsing.ui.swt.DefaultExplorerSelectionListener;
\r
88 import org.simantics.browsing.ui.swt.DefaultIsCheckedProcessor2;
\r
89 import org.simantics.browsing.ui.swt.DefaultKeyListener;
\r
90 import org.simantics.browsing.ui.swt.DefaultMouseListener;
\r
91 import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver;
\r
92 import org.simantics.browsing.ui.swt.FilterArea;
\r
93 import org.simantics.browsing.ui.swt.GraphExplorerFactory;
\r
94 import org.simantics.browsing.ui.swt.IContextMenuInitializer;
\r
95 import org.simantics.browsing.ui.swt.RootFilterArea;
\r
96 import org.simantics.browsing.ui.swt.StandardContextTypesQueryProcessor;
\r
97 import org.simantics.browsing.ui.swt.TypesQueryProcessor;
\r
98 import org.simantics.browsing.ui.swt.ViewpointSelector;
\r
99 import org.simantics.browsing.ui.swt.widgets.impl.Widget;
\r
100 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;
\r
101 import org.simantics.db.AsyncReadGraph;
\r
102 import org.simantics.db.ReadGraph;
\r
103 import org.simantics.db.Resource;
\r
104 import org.simantics.db.Session;
\r
105 import org.simantics.db.common.request.ResourceRead;
\r
106 import org.simantics.db.common.utils.Logger;
\r
107 import org.simantics.db.exception.DatabaseException;
\r
108 import org.simantics.db.layer0.SelectionHints;
\r
109 import org.simantics.db.layer0.variable.Variable;
\r
110 import org.simantics.db.layer0.variable.Variables;
\r
111 import org.simantics.db.management.ISessionContext;
\r
112 import org.simantics.db.management.ISessionContextChangedListener;
\r
113 import org.simantics.db.management.ISessionContextProvider;
\r
114 import org.simantics.db.management.SessionContextChangedEvent;
\r
115 import org.simantics.project.ProjectKeys;
\r
116 import org.simantics.ui.SimanticsUI;
\r
117 import org.simantics.ui.dnd.LocalObjectTransfer;
\r
118 import org.simantics.ui.dnd.LocalSelectionDragSourceListener;
\r
119 import org.simantics.ui.dnd.NoImageDragSourceEffect;
\r
120 import org.simantics.ui.dnd.SessionContainer;
\r
121 import org.simantics.ui.selection.AnyResource;
\r
122 import org.simantics.ui.selection.AnyVariable;
\r
123 import org.simantics.ui.selection.ExplorerColumnContentType;
\r
124 import org.simantics.ui.selection.ExplorerInputContentType;
\r
125 import org.simantics.ui.selection.WorkbenchSelectionContentType;
\r
126 import org.simantics.ui.selection.WorkbenchSelectionElement;
\r
127 import org.simantics.ui.selection.WorkbenchSelectionUtils;
\r
128 import org.simantics.utils.ObjectUtils;
\r
129 import org.simantics.utils.datastructures.BinaryFunction;
\r
130 import org.simantics.utils.datastructures.Function;
\r
131 import org.simantics.utils.datastructures.disposable.DisposeState;
\r
132 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
\r
133 import org.simantics.utils.datastructures.hints.HintTracker;
\r
134 import org.simantics.utils.datastructures.hints.IHintContext.Key;
\r
135 import org.simantics.utils.datastructures.hints.IHintListener;
\r
136 import org.simantics.utils.datastructures.hints.IHintObservable;
\r
137 import org.simantics.utils.datastructures.hints.IHintTracker;
\r
140 public class GraphExplorerComposite extends Composite implements Widget, IAdaptable {
\r
142 protected UserSelectedComparableFactoryQueryProcessor userSelectedComparableFactoryQueryProcessor;
\r
143 protected UserSelectedViewpointFactoryQueryProcessor userSelectedViewpointFactoryQueryProcessor;
\r
144 protected FilterSelectionRequestQueryProcessor filterSelectionRequestQueryProcessor;
\r
145 protected IFilterArea filterArea;
\r
146 protected EvaluatorData evaluatorData;
\r
148 protected LocalResourceManager resourceManager;
\r
150 protected ISelectionListener workbenchSelectionListener;
\r
152 private final int style;
\r
154 final private IWorkbenchSite site;
\r
156 protected GraphExplorer explorer;
\r
158 protected IMenuManager menuManager;
\r
160 private final Map<String, Object> args;
\r
162 protected ISessionContextProvider contextProvider;
\r
164 private ISessionContext sessionContext;
\r
166 private Object dragSource;
\r
168 private IHintTracker sessionContextTracker = new SessionContextProjectTracker();
\r
170 private InputSource inputSource = new DirectInputSource();
\r
171 private FilterAreaSource filterAreaSource = new SelectionFilterAreaSource();
\r
173 private final TreeColumnLayout ad;
\r
174 private String[] editingColumn = ColumnKeys.KEYS_SINGLE;
\r
176 private StatePersistor persistor = null;
\r
178 private final Composite toolComposite;
\r
179 private final Composite toolComposite2;
\r
180 private final Composite explorerComposite;
\r
181 final private WidgetSupport support;
\r
182 private final boolean useNodeBrowseContexts;
\r
183 private final boolean useNodeActionContexts;
\r
185 static class SelectionElement extends AdaptableHintContext {
\r
187 final public WorkbenchSelectionElement wse;
\r
188 final public Object content;
\r
189 final public Resource resource;
\r
190 final public Variable variable;
\r
191 final public Object input;
\r
192 final public TransientExplorerState explorerState;
\r
194 private WorkbenchSelectionElement extractWse(Object content) {
\r
195 if(content instanceof NodeContext) {
\r
196 NodeContext context = (NodeContext)content;
\r
197 Object input = context.getConstant(NodeType.TYPE);
\r
198 if(input instanceof NodeType)
\r
199 return ((NodeType)input).getWorkbenchSelectionElement(context);
\r
204 private Resource extractResource(Object content) {
\r
205 if(content instanceof NodeContext) {
\r
206 NodeContext context = (NodeContext)content;
\r
207 Object input = context.getConstant(BuiltinKeys.INPUT);
\r
208 if(input instanceof Resource) return (Resource)input;
\r
209 if(input instanceof IAdaptable) {
\r
210 Resource var = (Resource)((IAdaptable)input).getAdapter(Resource.class);
\r
211 if(var != null) return var;
\r
217 private Variable extractVariable(Object content) {
\r
218 if(content instanceof NodeContext) {
\r
219 NodeContext context = (NodeContext)content;
\r
220 Object input = context.getConstant(BuiltinKeys.INPUT);
\r
221 if(input instanceof Variable) return (Variable)input;
\r
222 if(input instanceof IAdaptable) {
\r
223 Variable var = (Variable)((IAdaptable)input).getAdapter(Variable.class);
\r
224 if(var != null) return var;
\r
230 private Object extractInput(Object content) {
\r
231 if(content instanceof NodeContext) {
\r
232 NodeContext context = (NodeContext)content;
\r
233 return context.getConstant(BuiltinKeys.INPUT);
\r
238 public SelectionElement(GraphExplorer explorer, Key[] keys, Object content) {
\r
240 this.content = content;
\r
241 this.wse = extractWse(content);
\r
242 this.resource = extractResource(content);
\r
243 this.variable = extractVariable(content);
\r
244 this.input = extractInput(content);
\r
245 this.explorerState = explorer.getTransientState();
\r
248 @SuppressWarnings("unchecked")
\r
250 public <T> T getContent(WorkbenchSelectionContentType<T> contentType) {
\r
253 T result = wse.getContent(contentType);
\r
254 if(result != null) return result;
\r
257 if(contentType instanceof AnyResource) return (T)resource;
\r
258 else if(contentType instanceof AnyVariable) {
\r
259 AnyVariable type = (AnyVariable)contentType;
\r
262 if(variable != null) return (T)variable;
\r
264 if(resource == null) return null;
\r
266 return (T) type.processor.sync(new ResourceRead<Variable>(resource) {
\r
268 public Variable perform(ReadGraph graph) throws DatabaseException {
\r
269 return Variables.getPossibleVariable(graph, resource);
\r
273 } catch (DatabaseException e) {
\r
274 Logger.defaultLogError(e);
\r
276 } else if (contentType instanceof ExplorerInputContentType) {
\r
278 } else if (contentType instanceof ExplorerColumnContentType) {
\r
279 return (T)explorerState.getActiveColumn();
\r
284 @SuppressWarnings("rawtypes")
\r
286 public Object getAdapter(Class adapter) {
\r
287 if(WorkbenchSelectionElement.class == adapter) {
\r
290 if(NodeContext.class == adapter) {
\r
291 if(content instanceof NodeContext)
\r
292 return (NodeContext)content;
\r
296 return super.getAdapter(adapter);
\r
300 private BinaryFunction<Object[], GraphExplorer, Object[]> selectionTransformation = new BinaryFunction<Object[], GraphExplorer, Object[]>() {
\r
302 private Key[] KEYS = new Key[] { SelectionHints.KEY_MAIN };
\r
305 public Object[] call(GraphExplorer explorer, Object[] objects) {
\r
306 Object[] result = new Object[objects.length];
\r
307 for (int i = 0; i < objects.length; i++) {
\r
308 SelectionElement context = new SelectionElement(explorer, KEYS, objects[i]);
\r
309 context.setHint(SelectionHints.KEY_MAIN, objects[i]);
\r
310 result[i] = context;
\r
317 private Set<String> browseContexts = null;
\r
319 private DisposeState disposeState = DisposeState.Alive;
\r
321 private boolean created = false;
\r
323 protected String contextMenuId = null;
\r
325 protected Set<String> uiContext = null;
\r
327 protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {
\r
329 public void sessionContextChanged(SessionContextChangedEvent event) {
\r
330 sessionContext = event.getNewValue();
\r
331 sessionContextTracker.track(sessionContext);
\r
335 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, WidgetSupport support, int style) {
\r
337 super(parent, SWT.NONE);
\r
340 args = Collections.emptyMap();
\r
344 this.style = style;
\r
345 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), this);
\r
347 contextProvider = getSessionContextProvider(site);
\r
349 Integer maxChildren = (Integer)args.get("maxChildren");
\r
351 GridLayoutFactory.fillDefaults().equalWidth(false).numColumns(1).margins(0,0).spacing(0,0).applyTo(this);
\r
353 toolComposite = new Composite(this, SWT.NONE);
\r
354 // toolComposite.setBackground(toolComposite.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
\r
355 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
\r
356 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite);
\r
357 GridLayoutFactory.fillDefaults().applyTo(toolComposite);
\r
359 ad = new TreeColumnLayout();
\r
360 explorerComposite = new Composite(this, SWT.NONE);
\r
361 explorerComposite.setLayout(ad);
\r
362 GridDataFactory.fillDefaults().grab(true, true).minSize(1, 50).applyTo(explorerComposite);
\r
364 if (args.containsKey("treeView") && Boolean.TRUE.equals(args.get("treeView"))) {
\r
365 explorer = createExplorerControl2(explorerComposite, maxChildren);
\r
366 } else if (args.containsKey("natTable") && Boolean.TRUE.equals(args.get("natTable"))) {
\r
367 explorer = createExplorerControl3(explorerComposite, maxChildren);
\r
369 explorer = createExplorerControl(explorerComposite, maxChildren);
\r
372 if (args.containsKey("useNodeBrowseContexts") && Boolean.TRUE.equals(args.get("useNodeBrowseContexts"))) {
\r
373 useNodeBrowseContexts = true;
\r
375 useNodeBrowseContexts = false;
\r
378 if (args.containsKey("useNodeActionContexts") && Boolean.TRUE.equals(args.get("useNodeActionContexts"))) {
\r
379 useNodeActionContexts = true;
\r
381 useNodeActionContexts = false;
\r
384 toolComposite2 = new Composite(this, SWT.NONE);
\r
385 // toolComposite2.setBackground(toolComposite2.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
\r
386 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
\r
387 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite2);
\r
388 GridLayoutFactory.fillDefaults().applyTo(toolComposite2);
\r
390 this.support = support;
\r
392 if (support != null)
\r
393 support.register(this);
\r
397 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, int style) {
\r
399 this(args, site, parent, null, style);
\r
403 public ISessionContextProvider getSessionContextProvider(IWorkbenchSite site) {
\r
405 return SimanticsUI.getSessionContextProvider(site.getWorkbenchWindow());
\r
407 return SimanticsUI.getSessionContextProvider();
\r
410 public GraphExplorer getExplorer() {
\r
414 public Composite getExplorerComposite() {
\r
415 return explorerComposite;
\r
418 public <T> T getExplorerControl() {
\r
419 return explorer.getControl();
\r
422 public void addListenerToControl(int eventType, Listener listener) {
\r
423 ((Control)explorer.getControl()).addListener(eventType, listener);
\r
426 public void finish() {
\r
428 createControls(site);
\r
432 IWorkbenchSite getSite() {
\r
436 protected void activateUiContexts() {
\r
437 Collection<String> contexts = getUiContexts();
\r
438 if (contexts == null || contexts.isEmpty())
\r
440 IWorkbenchSite site = getSite();
\r
441 if (site != null) {
\r
442 IContextService cs = (IContextService) getSite().getService(IContextService.class);
\r
443 for (String context : contexts)
\r
444 cs.activateContext(context);
\r
448 protected void createControls(IWorkbenchSite site) {
\r
450 // Initialize explorer control.
\r
451 // GridDataFactory.fillDefaults().grab(true, true).applyTo(explorer.getControl());
\r
453 Control control = explorer.getControl();
\r
455 // Initialize context menu if an initializer is provided.
\r
456 IContextMenuInitializer cmi = getContextMenuInitializer();
\r
458 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
\r
459 menuManager = cmi.createContextMenu(control, selectionProvider, site);
\r
462 // Initialize UI contexts
\r
463 activateUiContexts();
\r
466 dragSource = setupDND(explorer);
\r
468 // Listeners are only added once per listener, not every time the
\r
469 // session context changes.
\r
470 addListeners(explorer, menuManager);
\r
472 userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor();
\r
473 userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor();
\r
474 filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor();
\r
476 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
\r
478 boolean hasExtraControls = false;
\r
479 boolean hasExtraControls2 = false;
\r
481 Boolean displaySelectors = (Boolean)args.get("displaySelectors");
\r
482 if(displaySelectors == null || displaySelectors == true) {
\r
484 @SuppressWarnings("unused")
\r
485 ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
\r
486 // comparatorSelector.moveAbove(control);
\r
488 @SuppressWarnings("unused")
\r
489 ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
\r
490 // viewpointSelector.moveAbove(control);
\r
492 hasExtraControls = true;
\r
496 Boolean displayFilter = (Boolean)args.get("displayFilter");
\r
497 if(displayFilter == null || displayFilter == true) {
\r
500 filterArea = filterAreaSource.getFilterArea(toolComposite, explorer);
\r
501 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite, SWT.READ_ONLY);
\r
502 //filterArea.moveAbove(control);
\r
504 hasExtraControls = true;
\r
508 Boolean displayFilter2 = (Boolean)args.get("displayFilter2");
\r
509 if(displayFilter2 != null && displayFilter2 == true) {
\r
511 filterArea = filterAreaSource.getFilterArea(toolComposite2, explorer);
\r
512 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite2, SWT.READ_ONLY);
\r
513 // //filterArea.moveAbove(control);
\r
515 hasExtraControls2 = true;
\r
519 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, this, SWT.READ_ONLY);
\r
520 // filterArea.moveAbove(control);
\r
522 if(!hasExtraControls)
\r
523 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite);
\r
524 if(!hasExtraControls2)
\r
525 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite2);
\r
527 GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control);
\r
529 //tree.getTree().setLayout(new FillLayout()
\r
530 //this.setLayout(LayoutUtils.createNoBorderGridLayout(2, false));
\r
532 DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_LINK);
\r
533 target.setTransfer(getAcceptedDataTypes());
\r
534 if (control instanceof Tree) {
\r
535 target.addDropListener(new DropTargetListener() {
\r
537 Tree tree = (Tree)explorer.getControl();
\r
540 public void dragEnter(DropTargetEvent event) {
\r
541 event.detail = DND.DROP_COPY;
\r
545 public void dragLeave(DropTargetEvent event) {
\r
549 public void dragOperationChanged(DropTargetEvent event) {
\r
553 public void dragOver(DropTargetEvent event) {
\r
557 public void drop(DropTargetEvent event) {
\r
558 TreeItem item = tree.getItem(tree.toControl(event.x, event.y));
\r
560 Object data = item.getData();
\r
561 if (data instanceof NodeContext)
\r
562 handleDrop(event.data, (NodeContext) data);
\r
563 else if (data instanceof IAdaptable) {
\r
564 IAdaptable a = (IAdaptable) data;
\r
565 handleDrop(event.data, (NodeContext) a.getAdapter(NodeContext.class));
\r
568 handleDrop(event.data, null);
\r
572 public void dropAccept(DropTargetEvent event) {
\r
578 // Add workbench listeners and make sure they are cleaned up
\r
579 setWorkbenchListeners();
\r
580 control.addListener(SWT.Dispose, new Listener() {
\r
582 public void handleEvent(Event event) {
\r
588 @SuppressWarnings({ "rawtypes", "unchecked" })
\r
590 public Object getAdapter(Class adapter) {
\r
591 if (GraphExplorer.class == adapter)
\r
593 if (EvaluatorData.class == adapter)
\r
594 return evaluatorData;
\r
595 if (BrowseContext.class == adapter) {
\r
596 EvaluatorData ed = evaluatorData;
\r
597 return ed != null ? ed.getBrowseContext() : null;
\r
599 if (adapter == IFilterAreaProvider.class)
\r
601 return explorer.getAdapter(adapter);
\r
604 protected void doDispose() {
\r
605 //System.out.println(this + ".GraphExplorerComposite.doDispose()");
\r
606 removeWorkbenchListeners();
\r
607 userSelectedComparableFactoryQueryProcessor = null;
\r
608 userSelectedViewpointFactoryQueryProcessor = null;
\r
609 filterSelectionRequestQueryProcessor = null;
\r
611 disposeState = DisposeState.Disposing;
\r
613 //System.out.println(this + ".GraphExplorerViewBase.dispose()");
\r
614 if (contextProvider != null) {
\r
615 contextProvider.removeContextChangedListener(contextChangeListener);
\r
616 contextProvider = null;
\r
618 sessionContextTracker.untrack();
\r
619 resourceManager = null;
\r
621 sessionContext = null;
\r
625 disposeState = DisposeState.Disposed;
\r
630 public void dispose() {
\r
635 protected StatePersistor getStatePersistor() {
\r
639 public void setStatePersistor(StatePersistor persistor) {
\r
640 this.persistor = persistor;
\r
643 protected void initializeExplorer(GraphExplorer explorer, ISessionContext context) {
\r
645 if(explorer == null || explorer.isDisposed()) return;
\r
646 if(context == null) return;
\r
647 if(browseContexts == null) return;
\r
649 Session session = context != null ? context.getSession() : null;
\r
650 setupDragSource(session);
\r
652 if (session != null) {
\r
653 evaluatorData = createEvaluatorData(session);
\r
654 explorer.setDataSource(new AsyncReadGraphDataSource(session));
\r
655 explorer.setDataSource(new ReadGraphDataSource(session));
\r
658 evaluatorData = new EvaluatorDataImpl();
\r
659 explorer.removeDataSource(AsyncReadGraph.class);
\r
660 explorer.removeDataSource(ReadGraph.class);
\r
663 explorer.setPersistor(getStatePersistor());
\r
665 explorer.setProcessor(new ComparableFactoryResolver(evaluatorData));
\r
666 explorer.setProcessor(new ViewpointFactoryResolver(evaluatorData));
\r
667 explorer.setProcessor(new LabelerFactoryResolver(evaluatorData));
\r
668 explorer.setProcessor(new ImagerFactoryResolver(evaluatorData));
\r
669 explorer.setProcessor(new LabelDecoratorFactoryResolver(evaluatorData));
\r
670 explorer.setProcessor(new ImageDecoratorFactoryResolver(evaluatorData));
\r
671 explorer.setProcessor(new DefaultIsCheckedProcessor2(evaluatorData));
\r
672 explorer.setPrimitiveProcessor(new TypesQueryProcessor());
\r
673 explorer.setPrimitiveProcessor(new StandardContextTypesQueryProcessor());
\r
674 explorer.setPrimitiveProcessor(new InheritsQueryProcessor());
\r
675 explorer.setPrimitiveProcessor(new RelatedObjectsQueryProcessor());
\r
677 explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor);
\r
678 explorer.setProcessor(new ComparableSelectorQueryProcessor());
\r
679 explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor);
\r
680 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
\r
682 initializeExplorerWithEvaluator(explorer, context, evaluatorData);
\r
685 protected void initializeExplorerWithEvaluator(GraphExplorer explorer, ISessionContext context, EvaluatorData data) {
\r
688 protected EvaluatorData createEvaluatorData(Session context) {
\r
690 // Set<String> browseContexts = getArgument("browseContexts");
\r
692 return Evaluators.load(context.getSession(), browseContexts, resourceManager, useNodeBrowseContexts, useNodeActionContexts);
\r
696 protected Transfer[] getAcceptedDataTypes() {
\r
697 return new Transfer[] { LocalObjectTransfer.getTransfer(), FileTransfer.getInstance() };
\r
700 protected void handleDrop(Object data, NodeContext target) {
\r
703 DragSourceListenerFactory dragSourceListenerFactory = new DragSourceListenerFactory() {
\r
705 final Transfer[] transfers = new Transfer[] {LocalObjectTransfer.getTransfer(), TextTransfer.getInstance() };
\r
708 public DragSourceListener get(ISelectionProvider selectionProvider) {
\r
710 LocalSelectionDragSourceListener ls = new LocalSelectionDragSourceListener(selectionProvider);
\r
712 return new DragSourceListener() {
\r
715 public void dragStart(DragSourceEvent event) {
\r
716 ls.dragStart(event);
\r
720 public void dragSetData(DragSourceEvent event) {
\r
721 if(TextTransfer.getInstance().isSupportedType(event.dataType)) {
\r
723 event.data = WorkbenchSelectionUtils.getPossibleJSON(selectionProvider.getSelection());
\r
724 } catch (DatabaseException e) {
\r
725 event.data = "{ type:\"Exception\" }";
\r
726 Logger.defaultLogError(e);
\r
728 } else if (LocalObjectTransfer.getTransfer().isSupportedType(event.dataType)) {
\r
729 ls.dragSetData(event);
\r
734 public void dragFinished(DragSourceEvent event) {
\r
735 ls.dragFinished(event);
\r
741 public Transfer[] getTransfers() {
\r
747 public void setDragSourceListenerFactory(DragSourceListenerFactory dragSourceListenerFactory) {
\r
748 this.dragSourceListenerFactory = dragSourceListenerFactory;
\r
751 protected DragSourceListener setupDND(GraphExplorer explorer) {
\r
753 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
\r
755 DragSourceListener listener = createDragSourceListener(selectionProvider);
\r
757 Control control = explorer.getControl();
\r
758 DragSource source = createDragSource(control);
\r
759 source.setTransfer(getTransfers());
\r
760 source.addDragListener(listener);
\r
761 source.setDragSourceEffect(new NoImageDragSourceEffect(control));
\r
767 protected DragSourceListener createDragSourceListener(ISelectionProvider selectionProvider) {
\r
768 return dragSourceListenerFactory.get(selectionProvider);
\r
771 private int dragStyle = DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
\r
773 protected void setDragStyle(int style) {
\r
774 this.dragStyle = style;
\r
777 protected int getDragStyle() {
\r
781 protected DragSource createDragSource(Control control) {
\r
782 return new DragSource(control, getDragStyle());
\r
785 protected Transfer[] getTransfers() {
\r
786 return dragSourceListenerFactory.getTransfers();
\r
789 public EvaluatorData getEvaluatorData() {
\r
790 return evaluatorData;
\r
793 public interface InputSource {
\r
795 * @param ctx the session context to read the input from. May be
\r
796 * <code>null</code> if there is no session.
\r
797 * @return the input object of a graph explorer. To indicate no input,
\r
798 * use {@link GraphExplorerConstants#EMPTY_INPUT}. Never return
\r
799 * <code>null</code>.
\r
801 Object get(ISessionContext ctx, Object selection);
\r
804 public interface FilterSource {
\r
811 * The default hint tracker that will be active if
\r
812 * {@link GraphExplorerComposite#setSessionContextTracker(IHintTracker) is
\r
815 public class SessionContextProjectTracker extends HintTracker {
\r
816 public SessionContextProjectTracker() {
\r
817 IHintListener activeProjectListener = new HintListenerAdapter() {
\r
819 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
\r
820 applySessionContext(getSessionContext());
\r
823 addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);
\r
827 public class DirectInputSource implements InputSource {
\r
829 public Object get(ISessionContext ctx, Object selection) {
\r
834 public static class SelectionFilterAreaSource implements FilterAreaSource {
\r
837 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
\r
838 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
\r
839 return new FilterArea(explorer, processor, parent, SWT.READ_ONLY);
\r
844 public static class RootFilterAreaSource implements FilterAreaSource {
\r
847 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
\r
848 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
\r
849 return new RootFilterArea(explorer, processor, parent, SWT.READ_ONLY);
\r
854 protected void setSessionContextTracker(IHintTracker tracker) {
\r
855 this.sessionContextTracker = tracker;
\r
858 public void setInputSource(InputSource source) {
\r
859 this.inputSource = source;
\r
862 public void setFilterAreaSource(FilterAreaSource provider) {
\r
863 this.filterAreaSource = provider;
\r
866 public void setSelectionTransformation(BinaryFunction<Object[], GraphExplorer, Object[]> transformation) {
\r
867 this.selectionTransformation = transformation;
\r
868 if(explorer != null) explorer.setSelectionTransformation(transformation);
\r
871 protected Set<String> getBrowseContexts() {
\r
872 return browseContexts;
\r
875 public void setBrowseContexts(Set<String> contexts) {
\r
876 this.browseContexts = contexts;
\r
877 //initializeExplorer(explorer, getSessionContext());
\r
880 public void setBrowseContexts(String ... contexts) {
\r
881 this.browseContexts = new HashSet<String>();
\r
882 for(String s : contexts) this.browseContexts.add(s);
\r
883 initializeExplorer(explorer, getSessionContext());
\r
886 public void setContextMenuId(String contextMenuId) {
\r
887 this.contextMenuId = contextMenuId;
\r
890 // protected IContextMenuInitializer getContextMenuInitializer() {
\r
891 // String contextMenuId = getContextMenuId();
\r
892 // if(contextMenuId != null) {
\r
893 // return new ContextMenuInitializer(contextMenuId);
\r
899 protected String getContextMenuId() {
\r
900 return this.contextMenuId;
\r
903 public void setUiContexts(Set<String> uiContext) {
\r
904 this.uiContext = uiContext;
\r
907 public Set<String> getUiContexts() {
\r
911 protected InputSource getInputSource() {
\r
912 return inputSource;
\r
915 protected Map<String, Object> getArguments() {
\r
919 @SuppressWarnings("unchecked")
\r
920 protected <T> T getArgument(String key) {
\r
921 return (T) args.get(key);
\r
924 protected DisposeState getDisposeState() {
\r
925 return disposeState;
\r
928 public ISessionContext getSessionContext() {
\r
929 return sessionContext;
\r
932 public ISessionContextProvider getSessionContextProvider() {
\r
933 return contextProvider;
\r
937 public boolean setFocus() {
\r
938 if (explorer != null && !explorer.isDisposed())
\r
939 explorer.setFocus();
\r
943 public void setWorkbenchListeners() {
\r
944 if (workbenchSelectionListener == null && getSite() != null) {
\r
945 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
\r
946 getSite().setSelectionProvider(selectionProvider);
\r
948 // Listen to the workbench selection also to propagate it to
\r
949 // the explorer also.
\r
950 workbenchSelectionListener = new DefaultExplorerSelectionListener(site.getPage().getActivePart(), explorer);
\r
951 //System.out.println("ADD WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
\r
952 getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener);
\r
956 protected void removeWorkbenchListeners() {
\r
957 //System.out.println("REMOVE WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
\r
958 // Remember to remove the installed workbench selection listener
\r
959 if (workbenchSelectionListener != null) {
\r
960 getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener);
\r
961 workbenchSelectionListener = null;
\r
963 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
\r
964 if(getSite().getSelectionProvider() == selectionProvider) getSite().setSelectionProvider(null);
\r
969 protected final void attachToSession() {
\r
971 // Track active ISessionContext changes
\r
972 //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());
\r
973 contextProvider.addContextChangedListener(contextChangeListener);
\r
975 // Start tracking the current session context for input changes.
\r
976 // This will/must cause applySessionContext to get called.
\r
977 // Doing the applySessionContext initialization this way
\r
978 // instead of directly calling it will also make sure that
\r
979 // applySessionContext is only called once when first initialized,
\r
980 // and not twice like with the direct invocation.
\r
981 this.sessionContext = contextProvider.getSessionContext();
\r
982 sessionContextTracker.track(sessionContext);
\r
985 // /////////////////////////////////////////////////////////////////////////
\r
986 // Override / implement these:
\r
989 // * Returns an ID that is used for persisting a GraphExplorer instance.
\r
991 // * Used for </code>restoreState(IMemento)</code> and
\r
992 // * <code>restoreState(IMemento)</code> in OntologyExplorer. Must be unique
\r
993 // * within a workbench part.
\r
995 // * @return a unique name for this particular graph explorer view used for
\r
996 // * saving and restoring the state of this view part
\r
998 // public String getExplorerName() {
\r
999 // return "GraphExplorerViewBase";
\r
1003 * Override this method to add controls to the view part. This is invoked
\r
1004 * before attaching the view part to a database session.
\r
1008 protected void createControls(Composite parent) {
\r
1013 * Override this method and provide a proper context menu initializer if you
\r
1014 * want to have this base class initialize one for you.
\r
1016 * @return the initializer to be used by {@link #createControls(Composite)}
\r
1018 protected IContextMenuInitializer getContextMenuInitializer() {
\r
1019 String contextMenuId = getContextMenuId();
\r
1020 if(contextMenuId != null) {
\r
1021 return new ContextMenuInitializer(contextMenuId);
\r
1031 protected GraphExplorer createExplorerControl(Composite parent, Integer maxChildren) {
\r
1032 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
\r
1033 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
\r
1035 GraphExplorer ge = factory
\r
1036 .selectionDataResolver(new DefaultSelectionDataResolver())
\r
1037 .selectionTransformation(selectionTransformation)
\r
1038 .setServiceLocator(site)
\r
1039 .create(parent, style);
\r
1044 protected GraphExplorer createExplorerControl2(Composite parent, Integer maxChildren) {
\r
1045 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
\r
1046 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
\r
1048 GraphExplorer ge = factory
\r
1049 .selectionDataResolver(new DefaultSelectionDataResolver())
\r
1050 .selectionTransformation(selectionTransformation)
\r
1051 .setServiceLocator(site)
\r
1052 .create2(parent, style);
\r
1057 protected GraphExplorer createExplorerControl3(Composite parent, Integer maxChildren) {
\r
1058 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
\r
1059 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
\r
1061 GraphExplorer ge = factory
\r
1062 .selectionDataResolver(new DefaultSelectionDataResolver())
\r
1063 .selectionTransformation(selectionTransformation)
\r
1064 .setServiceLocator(site)
\r
1065 .create3(parent, style);
\r
1070 protected void setupDragSource(Session session) {
\r
1071 if (dragSource instanceof SessionContainer) {
\r
1072 ((SessionContainer) dragSource).setSession(session);
\r
1077 * Override to customize the addition of listeners a newly created
\r
1082 protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {
\r
1083 addSelectionInputListeners(explorer, menuManager);
\r
1086 protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {
\r
1087 // Consider ENTER presses to simulate mouse left button double clicks
\r
1088 explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function<String[]>() {
\r
1090 public String[] execute(Object... obj) {
\r
1091 return getEditingColumn((NodeContext) obj[0]);
\r
1094 // Default double click handling
\r
1095 explorer.addListener(new DefaultMouseListener(explorer));
\r
1098 protected String[] getEditingColumn(NodeContext context) {
\r
1099 return editingColumn;
\r
1102 public void setEditingColumn(String... columnKeysInOrderOfTrial) {
\r
1103 this.editingColumn = columnKeysInOrderOfTrial;
\r
1106 // Needed for preventing unnecessary re-initialization of the explorer with the same input.
\r
1107 private Object currentInput;
\r
1108 private Object currentRoot;
\r
1111 * Invoke this to reinitialize the explorer and reset its input. The input
\r
1112 * will be resolved from the specified ISessionContext based on the
\r
1113 * {@link SessionContextInputSource} that is currently in use. If the input
\r
1114 * is identical to the previous input, nothing will be done.
\r
1118 public final boolean applySessionContext(ISessionContext context) {
\r
1120 // If control is not alive anymore, do nothing.
\r
1121 //System.out.println(this + ": applySessionContext(" + context + "), explorer=" + explorer);
\r
1122 if (disposeState != DisposeState.Alive)
\r
1125 //System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");
\r
1126 initializeExplorer(explorer, context);
\r
1129 // Start tracking the session context.
\r
1131 // If this is not the same session that is currently tracked, it will
\r
1132 // cause IHintListeners of the sessionContextTracker to fire.
\r
1133 // For this we need the above input equality (identity) checking.
\r
1134 // This is here just to make sure that we are tracking the correct
\r
1135 // session context.
\r
1136 sessionContextTracker.track(sessionContext);
\r
1138 this.sessionContext = context;
\r
1139 Object root = inputSource.get(context, currentInput);
\r
1140 if (ObjectUtils.objectEquals(root, currentRoot))
\r
1143 currentRoot = root;
\r
1145 //System.out.println(this + ": setRoot(" + input + ")");
\r
1146 explorer.setUIContexts(uiContext);
\r
1147 explorer.setRoot(root);
\r
1153 protected boolean isImportantInput(Object previousSelection, Object selection) {
\r
1154 return !ObjectUtils.objectEquals(previousSelection, selection);
\r
1157 public void setInput(Object selection, boolean force) {
\r
1163 if (sessionContext == null)
\r
1166 // Check if this is a duplicate of the previous selection to reduce unnecessary flicker.
\r
1167 if (!force && !isImportantInput(currentInput, selection))
\r
1170 currentInput = selection;
\r
1172 Object root = inputSource.get(sessionContext, selection);
\r
1174 currentRoot = root;
\r
1176 explorer.setUIContexts(uiContext);
\r
1178 if (root == null) {
\r
1179 explorer.setRoot(GraphExplorer.EMPTY_INPUT);
\r
1181 explorer.setRoot(root);
\r
1186 public void setColumnsVisible(boolean visible) {
\r
1187 explorer.setColumnsVisible(visible);
\r
1190 private int getColumnWidth(Column column, ExplorerState state) {
\r
1191 // Get saved width from the persistor if there is one.
\r
1192 if (state != null && state.columnWidths != null) {
\r
1193 Integer width = state.columnWidths.get(column.getLabel());
\r
1194 if (width != null)
\r
1197 return column.getWidth();
\r
1200 public void setColumns(Column[] columns) {
\r
1202 explorer.setColumns(columns, new Consumer<Map<Column, Object>>() {
\r
1205 public void accept(Map<Column, Object> objects) {
\r
1206 ExplorerState state = null;
\r
1207 if (persistor != null) {
\r
1208 state = persistor.deserialize(
\r
1209 Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
\r
1210 explorer.getRoot());
\r
1213 for(Map.Entry<Column, Object> entry : objects.entrySet()) {
\r
1214 Column column = entry.getKey();
\r
1215 TreeColumn treeColumn = (TreeColumn)entry.getValue();
\r
1217 if (column.getWidth() < 0) {
\r
1218 throw new IllegalArgumentException("Column minimum width cannot be < 0, got " + column.getWidth());
\r
1221 int width = getColumnWidth(column, state);
\r
1222 if(column.hasGrab()) {
\r
1224 ad.setColumnData(treeColumn, new ColumnWeightData(column.getWeight(), width));
\r
1228 ad.setColumnData(treeColumn, new ColumnWeightData(0, width));
\r
1240 public void setInput(ISessionContext context, Object input) {
\r
1241 setInput(input, false);
\r
1244 public void setMaxChildren(int maxChildren) {
\r
1245 explorer.setMaxChildren(maxChildren);
\r
1248 public <T> void addListener(ExplorerMouseListenerImpl<T> listener) {
\r
1250 support.register(listener);
\r
1251 listener.register(explorer);
\r
1252 explorer.addListener(listener);
\r
1257 // public Point computeSize(int wHint, int hHint) {
\r
1258 // Point p = super.computeSize(wHint, hHint);
\r
1259 // System.err.println("graphExplorerComposite.computeSize " + p);
\r
1264 // public Point computeSize(int wHint, int hHint, boolean changed) {
\r
1265 // Point p = super.computeSize(wHint, hHint, changed);
\r
1266 // System.err.println("graphExplorerComposite.computeSize " + p);
\r