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
367 explorer = createExplorerControl(explorerComposite, maxChildren);
\r
370 if (args.containsKey("useNodeBrowseContexts") && Boolean.TRUE.equals(args.get("useNodeBrowseContexts"))) {
\r
371 useNodeBrowseContexts = true;
\r
373 useNodeBrowseContexts = false;
\r
376 if (args.containsKey("useNodeActionContexts") && Boolean.TRUE.equals(args.get("useNodeActionContexts"))) {
\r
377 useNodeActionContexts = true;
\r
379 useNodeActionContexts = false;
\r
382 toolComposite2 = new Composite(this, SWT.NONE);
\r
383 // toolComposite2.setBackground(toolComposite2.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
\r
384 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
\r
385 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite2);
\r
386 GridLayoutFactory.fillDefaults().applyTo(toolComposite2);
\r
388 this.support = support;
\r
390 if (support != null)
\r
391 support.register(this);
\r
395 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, int style) {
\r
397 this(args, site, parent, null, style);
\r
401 public ISessionContextProvider getSessionContextProvider(IWorkbenchSite site) {
\r
403 return SimanticsUI.getSessionContextProvider(site.getWorkbenchWindow());
\r
405 return SimanticsUI.getSessionContextProvider();
\r
408 public GraphExplorer getExplorer() {
\r
412 public Composite getExplorerComposite() {
\r
413 return explorerComposite;
\r
416 public <T> T getExplorerControl() {
\r
417 return explorer.getControl();
\r
420 public void addListenerToControl(int eventType, Listener listener) {
\r
421 ((Tree)explorer.getControl()).addListener(eventType, listener);
\r
424 public void finish() {
\r
426 createControls(site);
\r
430 IWorkbenchSite getSite() {
\r
434 protected void activateUiContexts() {
\r
435 Collection<String> contexts = getUiContexts();
\r
436 if (contexts == null || contexts.isEmpty())
\r
438 IWorkbenchSite site = getSite();
\r
439 if (site != null) {
\r
440 IContextService cs = (IContextService) getSite().getService(IContextService.class);
\r
441 for (String context : contexts)
\r
442 cs.activateContext(context);
\r
446 protected void createControls(IWorkbenchSite site) {
\r
448 // Initialize explorer control.
\r
449 // GridDataFactory.fillDefaults().grab(true, true).applyTo(explorer.getControl());
\r
451 Control control = explorer.getControl();
\r
453 // Initialize context menu if an initializer is provided.
\r
454 IContextMenuInitializer cmi = getContextMenuInitializer();
\r
456 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
\r
457 menuManager = cmi.createContextMenu(control, selectionProvider, site);
\r
460 // Initialize UI contexts
\r
461 activateUiContexts();
\r
464 dragSource = setupDND(explorer);
\r
466 // Listeners are only added once per listener, not every time the
\r
467 // session context changes.
\r
468 addListeners(explorer, menuManager);
\r
470 userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor();
\r
471 userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor();
\r
472 filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor();
\r
474 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
\r
476 boolean hasExtraControls = false;
\r
477 boolean hasExtraControls2 = false;
\r
479 Boolean displaySelectors = (Boolean)args.get("displaySelectors");
\r
480 if(displaySelectors == null || displaySelectors == true) {
\r
482 @SuppressWarnings("unused")
\r
483 ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
\r
484 // comparatorSelector.moveAbove(control);
\r
486 @SuppressWarnings("unused")
\r
487 ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
\r
488 // viewpointSelector.moveAbove(control);
\r
490 hasExtraControls = true;
\r
494 Boolean displayFilter = (Boolean)args.get("displayFilter");
\r
495 if(displayFilter == null || displayFilter == true) {
\r
498 filterArea = filterAreaSource.getFilterArea(toolComposite, explorer);
\r
499 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite, SWT.READ_ONLY);
\r
500 //filterArea.moveAbove(control);
\r
502 hasExtraControls = true;
\r
506 Boolean displayFilter2 = (Boolean)args.get("displayFilter2");
\r
507 if(displayFilter2 != null && displayFilter2 == true) {
\r
509 filterArea = filterAreaSource.getFilterArea(toolComposite2, explorer);
\r
510 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite2, SWT.READ_ONLY);
\r
511 // //filterArea.moveAbove(control);
\r
513 hasExtraControls2 = true;
\r
517 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, this, SWT.READ_ONLY);
\r
518 // filterArea.moveAbove(control);
\r
520 if(!hasExtraControls)
\r
521 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite);
\r
522 if(!hasExtraControls2)
\r
523 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite2);
\r
525 GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control);
\r
527 //tree.getTree().setLayout(new FillLayout()
\r
528 //this.setLayout(LayoutUtils.createNoBorderGridLayout(2, false));
\r
530 DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_LINK);
\r
531 target.setTransfer(getAcceptedDataTypes());
\r
532 target.addDropListener(new DropTargetListener() {
\r
534 Tree tree = (Tree)explorer.getControl();
\r
537 public void dragEnter(DropTargetEvent event) {
\r
538 event.detail = DND.DROP_COPY;
\r
542 public void dragLeave(DropTargetEvent event) {
\r
546 public void dragOperationChanged(DropTargetEvent event) {
\r
550 public void dragOver(DropTargetEvent event) {
\r
554 public void drop(DropTargetEvent event) {
\r
555 TreeItem item = tree.getItem(tree.toControl(event.x, event.y));
\r
557 Object data = item.getData();
\r
558 if (data instanceof NodeContext)
\r
559 handleDrop(event.data, (NodeContext) data);
\r
560 else if (data instanceof IAdaptable) {
\r
561 IAdaptable a = (IAdaptable) data;
\r
562 handleDrop(event.data, (NodeContext) a.getAdapter(NodeContext.class));
\r
565 handleDrop(event.data, null);
\r
569 public void dropAccept(DropTargetEvent event) {
\r
574 // Add workbench listeners and make sure they are cleaned up
\r
575 setWorkbenchListeners();
\r
576 control.addListener(SWT.Dispose, new Listener() {
\r
578 public void handleEvent(Event event) {
\r
584 @SuppressWarnings({ "rawtypes", "unchecked" })
\r
586 public Object getAdapter(Class adapter) {
\r
587 if (GraphExplorer.class == adapter)
\r
589 if (EvaluatorData.class == adapter)
\r
590 return evaluatorData;
\r
591 if (BrowseContext.class == adapter) {
\r
592 EvaluatorData ed = evaluatorData;
\r
593 return ed != null ? ed.getBrowseContext() : null;
\r
595 if (adapter == IFilterAreaProvider.class)
\r
597 return explorer.getAdapter(adapter);
\r
600 protected void doDispose() {
\r
601 //System.out.println(this + ".GraphExplorerComposite.doDispose()");
\r
602 removeWorkbenchListeners();
\r
603 userSelectedComparableFactoryQueryProcessor = null;
\r
604 userSelectedViewpointFactoryQueryProcessor = null;
\r
605 filterSelectionRequestQueryProcessor = null;
\r
607 disposeState = DisposeState.Disposing;
\r
609 //System.out.println(this + ".GraphExplorerViewBase.dispose()");
\r
610 if (contextProvider != null) {
\r
611 contextProvider.removeContextChangedListener(contextChangeListener);
\r
612 contextProvider = null;
\r
614 sessionContextTracker.untrack();
\r
615 resourceManager = null;
\r
617 sessionContext = null;
\r
621 disposeState = DisposeState.Disposed;
\r
626 public void dispose() {
\r
631 protected StatePersistor getStatePersistor() {
\r
635 public void setStatePersistor(StatePersistor persistor) {
\r
636 this.persistor = persistor;
\r
639 protected void initializeExplorer(GraphExplorer explorer, ISessionContext context) {
\r
641 if(explorer == null || explorer.isDisposed()) return;
\r
642 if(context == null) return;
\r
643 if(browseContexts == null) return;
\r
645 Session session = context != null ? context.getSession() : null;
\r
646 setupDragSource(session);
\r
648 if (session != null) {
\r
649 evaluatorData = createEvaluatorData(session);
\r
650 explorer.setDataSource(new AsyncReadGraphDataSource(session));
\r
651 explorer.setDataSource(new ReadGraphDataSource(session));
\r
654 evaluatorData = new EvaluatorDataImpl();
\r
655 explorer.removeDataSource(AsyncReadGraph.class);
\r
656 explorer.removeDataSource(ReadGraph.class);
\r
659 explorer.setPersistor(getStatePersistor());
\r
661 explorer.setProcessor(new ComparableFactoryResolver(evaluatorData));
\r
662 explorer.setProcessor(new ViewpointFactoryResolver(evaluatorData));
\r
663 explorer.setProcessor(new LabelerFactoryResolver(evaluatorData));
\r
664 explorer.setProcessor(new ImagerFactoryResolver(evaluatorData));
\r
665 explorer.setProcessor(new LabelDecoratorFactoryResolver(evaluatorData));
\r
666 explorer.setProcessor(new ImageDecoratorFactoryResolver(evaluatorData));
\r
667 explorer.setProcessor(new DefaultIsCheckedProcessor2(evaluatorData));
\r
668 explorer.setPrimitiveProcessor(new TypesQueryProcessor());
\r
669 explorer.setPrimitiveProcessor(new StandardContextTypesQueryProcessor());
\r
670 explorer.setPrimitiveProcessor(new InheritsQueryProcessor());
\r
671 explorer.setPrimitiveProcessor(new RelatedObjectsQueryProcessor());
\r
673 explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor);
\r
674 explorer.setProcessor(new ComparableSelectorQueryProcessor());
\r
675 explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor);
\r
676 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
\r
678 initializeExplorerWithEvaluator(explorer, context, evaluatorData);
\r
681 protected void initializeExplorerWithEvaluator(GraphExplorer explorer, ISessionContext context, EvaluatorData data) {
\r
684 protected EvaluatorData createEvaluatorData(Session context) {
\r
686 // Set<String> browseContexts = getArgument("browseContexts");
\r
688 return Evaluators.load(context.getSession(), browseContexts, resourceManager, useNodeBrowseContexts, useNodeActionContexts);
\r
692 protected Transfer[] getAcceptedDataTypes() {
\r
693 return new Transfer[] { LocalObjectTransfer.getTransfer(), FileTransfer.getInstance() };
\r
696 protected void handleDrop(Object data, NodeContext target) {
\r
699 DragSourceListenerFactory dragSourceListenerFactory = new DragSourceListenerFactory() {
\r
701 final Transfer[] transfers = new Transfer[] {LocalObjectTransfer.getTransfer(), TextTransfer.getInstance() };
\r
704 public DragSourceListener get(ISelectionProvider selectionProvider) {
\r
706 LocalSelectionDragSourceListener ls = new LocalSelectionDragSourceListener(selectionProvider);
\r
708 return new DragSourceListener() {
\r
711 public void dragStart(DragSourceEvent event) {
\r
712 ls.dragStart(event);
\r
716 public void dragSetData(DragSourceEvent event) {
\r
717 if(TextTransfer.getInstance().isSupportedType(event.dataType)) {
\r
719 event.data = WorkbenchSelectionUtils.getPossibleJSON(selectionProvider.getSelection());
\r
720 } catch (DatabaseException e) {
\r
721 event.data = "{ type:\"Exception\" }";
\r
722 Logger.defaultLogError(e);
\r
724 } else if (LocalObjectTransfer.getTransfer().isSupportedType(event.dataType)) {
\r
725 ls.dragSetData(event);
\r
730 public void dragFinished(DragSourceEvent event) {
\r
731 ls.dragFinished(event);
\r
737 public Transfer[] getTransfers() {
\r
743 public void setDragSourceListenerFactory(DragSourceListenerFactory dragSourceListenerFactory) {
\r
744 this.dragSourceListenerFactory = dragSourceListenerFactory;
\r
747 protected DragSourceListener setupDND(GraphExplorer explorer) {
\r
749 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
\r
751 DragSourceListener listener = createDragSourceListener(selectionProvider);
\r
753 Control control = explorer.getControl();
\r
754 DragSource source = createDragSource(control);
\r
755 source.setTransfer(getTransfers());
\r
756 source.addDragListener(listener);
\r
757 source.setDragSourceEffect(new NoImageDragSourceEffect(control));
\r
763 protected DragSourceListener createDragSourceListener(ISelectionProvider selectionProvider) {
\r
764 return dragSourceListenerFactory.get(selectionProvider);
\r
767 private int dragStyle = DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
\r
769 protected void setDragStyle(int style) {
\r
770 this.dragStyle = style;
\r
773 protected int getDragStyle() {
\r
777 protected DragSource createDragSource(Control control) {
\r
778 return new DragSource(control, getDragStyle());
\r
781 protected Transfer[] getTransfers() {
\r
782 return dragSourceListenerFactory.getTransfers();
\r
785 public EvaluatorData getEvaluatorData() {
\r
786 return evaluatorData;
\r
789 public interface InputSource {
\r
791 * @param ctx the session context to read the input from. May be
\r
792 * <code>null</code> if there is no session.
\r
793 * @return the input object of a graph explorer. To indicate no input,
\r
794 * use {@link GraphExplorerConstants#EMPTY_INPUT}. Never return
\r
795 * <code>null</code>.
\r
797 Object get(ISessionContext ctx, Object selection);
\r
800 public interface FilterSource {
\r
807 * The default hint tracker that will be active if
\r
808 * {@link GraphExplorerComposite#setSessionContextTracker(IHintTracker) is
\r
811 public class SessionContextProjectTracker extends HintTracker {
\r
812 public SessionContextProjectTracker() {
\r
813 IHintListener activeProjectListener = new HintListenerAdapter() {
\r
815 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
\r
816 applySessionContext(getSessionContext());
\r
819 addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);
\r
823 public class DirectInputSource implements InputSource {
\r
825 public Object get(ISessionContext ctx, Object selection) {
\r
830 public static class SelectionFilterAreaSource implements FilterAreaSource {
\r
833 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
\r
834 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
\r
835 return new FilterArea(explorer, processor, parent, SWT.READ_ONLY);
\r
840 public static class RootFilterAreaSource implements FilterAreaSource {
\r
843 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
\r
844 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
\r
845 return new RootFilterArea(explorer, processor, parent, SWT.READ_ONLY);
\r
850 protected void setSessionContextTracker(IHintTracker tracker) {
\r
851 this.sessionContextTracker = tracker;
\r
854 public void setInputSource(InputSource source) {
\r
855 this.inputSource = source;
\r
858 public void setFilterAreaSource(FilterAreaSource provider) {
\r
859 this.filterAreaSource = provider;
\r
862 public void setSelectionTransformation(BinaryFunction<Object[], GraphExplorer, Object[]> transformation) {
\r
863 this.selectionTransformation = transformation;
\r
864 if(explorer != null) explorer.setSelectionTransformation(transformation);
\r
867 protected Set<String> getBrowseContexts() {
\r
868 return browseContexts;
\r
871 public void setBrowseContexts(Set<String> contexts) {
\r
872 this.browseContexts = contexts;
\r
873 //initializeExplorer(explorer, getSessionContext());
\r
876 public void setBrowseContexts(String ... contexts) {
\r
877 this.browseContexts = new HashSet<String>();
\r
878 for(String s : contexts) this.browseContexts.add(s);
\r
879 initializeExplorer(explorer, getSessionContext());
\r
882 public void setContextMenuId(String contextMenuId) {
\r
883 this.contextMenuId = contextMenuId;
\r
886 // protected IContextMenuInitializer getContextMenuInitializer() {
\r
887 // String contextMenuId = getContextMenuId();
\r
888 // if(contextMenuId != null) {
\r
889 // return new ContextMenuInitializer(contextMenuId);
\r
895 protected String getContextMenuId() {
\r
896 return this.contextMenuId;
\r
899 public void setUiContexts(Set<String> uiContext) {
\r
900 this.uiContext = uiContext;
\r
903 public Set<String> getUiContexts() {
\r
907 protected InputSource getInputSource() {
\r
908 return inputSource;
\r
911 protected Map<String, Object> getArguments() {
\r
915 @SuppressWarnings("unchecked")
\r
916 protected <T> T getArgument(String key) {
\r
917 return (T) args.get(key);
\r
920 protected DisposeState getDisposeState() {
\r
921 return disposeState;
\r
924 public ISessionContext getSessionContext() {
\r
925 return sessionContext;
\r
928 public ISessionContextProvider getSessionContextProvider() {
\r
929 return contextProvider;
\r
933 public boolean setFocus() {
\r
934 if (explorer != null && !explorer.isDisposed())
\r
935 explorer.setFocus();
\r
939 public void setWorkbenchListeners() {
\r
940 if (workbenchSelectionListener == null && getSite() != null) {
\r
941 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
\r
942 getSite().setSelectionProvider(selectionProvider);
\r
944 // Listen to the workbench selection also to propagate it to
\r
945 // the explorer also.
\r
946 workbenchSelectionListener = new DefaultExplorerSelectionListener(site.getPage().getActivePart(), explorer);
\r
947 //System.out.println("ADD WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
\r
948 getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener);
\r
952 protected void removeWorkbenchListeners() {
\r
953 //System.out.println("REMOVE WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
\r
954 // Remember to remove the installed workbench selection listener
\r
955 if (workbenchSelectionListener != null) {
\r
956 getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener);
\r
957 workbenchSelectionListener = null;
\r
959 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
\r
960 if(getSite().getSelectionProvider() == selectionProvider) getSite().setSelectionProvider(null);
\r
965 protected final void attachToSession() {
\r
967 // Track active ISessionContext changes
\r
968 //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());
\r
969 contextProvider.addContextChangedListener(contextChangeListener);
\r
971 // Start tracking the current session context for input changes.
\r
972 // This will/must cause applySessionContext to get called.
\r
973 // Doing the applySessionContext initialization this way
\r
974 // instead of directly calling it will also make sure that
\r
975 // applySessionContext is only called once when first initialized,
\r
976 // and not twice like with the direct invocation.
\r
977 this.sessionContext = contextProvider.getSessionContext();
\r
978 sessionContextTracker.track(sessionContext);
\r
981 // /////////////////////////////////////////////////////////////////////////
\r
982 // Override / implement these:
\r
985 // * Returns an ID that is used for persisting a GraphExplorer instance.
\r
987 // * Used for </code>restoreState(IMemento)</code> and
\r
988 // * <code>restoreState(IMemento)</code> in OntologyExplorer. Must be unique
\r
989 // * within a workbench part.
\r
991 // * @return a unique name for this particular graph explorer view used for
\r
992 // * saving and restoring the state of this view part
\r
994 // public String getExplorerName() {
\r
995 // return "GraphExplorerViewBase";
\r
999 * Override this method to add controls to the view part. This is invoked
\r
1000 * before attaching the view part to a database session.
\r
1004 protected void createControls(Composite parent) {
\r
1009 * Override this method and provide a proper context menu initializer if you
\r
1010 * want to have this base class initialize one for you.
\r
1012 * @return the initializer to be used by {@link #createControls(Composite)}
\r
1014 protected IContextMenuInitializer getContextMenuInitializer() {
\r
1015 String contextMenuId = getContextMenuId();
\r
1016 if(contextMenuId != null) {
\r
1017 return new ContextMenuInitializer(contextMenuId);
\r
1027 protected GraphExplorer createExplorerControl(Composite parent, Integer maxChildren) {
\r
1028 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
\r
1029 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
\r
1031 GraphExplorer ge = factory
\r
1032 .selectionDataResolver(new DefaultSelectionDataResolver())
\r
1033 .selectionTransformation(selectionTransformation)
\r
1034 .setServiceLocator(site)
\r
1035 .create(parent, style);
\r
1040 protected GraphExplorer createExplorerControl2(Composite parent, Integer maxChildren) {
\r
1041 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
\r
1042 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
\r
1044 GraphExplorer ge = factory
\r
1045 .selectionDataResolver(new DefaultSelectionDataResolver())
\r
1046 .selectionTransformation(selectionTransformation)
\r
1047 .setServiceLocator(site)
\r
1048 .create2(parent, style);
\r
1053 protected void setupDragSource(Session session) {
\r
1054 if (dragSource instanceof SessionContainer) {
\r
1055 ((SessionContainer) dragSource).setSession(session);
\r
1060 * Override to customize the addition of listeners a newly created
\r
1065 protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {
\r
1066 addSelectionInputListeners(explorer, menuManager);
\r
1069 protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {
\r
1070 // Consider ENTER presses to simulate mouse left button double clicks
\r
1071 explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function<String[]>() {
\r
1073 public String[] execute(Object... obj) {
\r
1074 return getEditingColumn((NodeContext) obj[0]);
\r
1077 // Default double click handling
\r
1078 explorer.addListener(new DefaultMouseListener(explorer));
\r
1081 protected String[] getEditingColumn(NodeContext context) {
\r
1082 return editingColumn;
\r
1085 public void setEditingColumn(String... columnKeysInOrderOfTrial) {
\r
1086 this.editingColumn = columnKeysInOrderOfTrial;
\r
1089 // Needed for preventing unnecessary re-initialization of the explorer with the same input.
\r
1090 private Object currentInput;
\r
1091 private Object currentRoot;
\r
1094 * Invoke this to reinitialize the explorer and reset its input. The input
\r
1095 * will be resolved from the specified ISessionContext based on the
\r
1096 * {@link SessionContextInputSource} that is currently in use. If the input
\r
1097 * is identical to the previous input, nothing will be done.
\r
1101 public final boolean applySessionContext(ISessionContext context) {
\r
1103 // If control is not alive anymore, do nothing.
\r
1104 //System.out.println(this + ": applySessionContext(" + context + "), explorer=" + explorer);
\r
1105 if (disposeState != DisposeState.Alive)
\r
1108 //System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");
\r
1109 initializeExplorer(explorer, context);
\r
1112 // Start tracking the session context.
\r
1114 // If this is not the same session that is currently tracked, it will
\r
1115 // cause IHintListeners of the sessionContextTracker to fire.
\r
1116 // For this we need the above input equality (identity) checking.
\r
1117 // This is here just to make sure that we are tracking the correct
\r
1118 // session context.
\r
1119 sessionContextTracker.track(sessionContext);
\r
1121 this.sessionContext = context;
\r
1122 Object root = inputSource.get(context, currentInput);
\r
1123 if (ObjectUtils.objectEquals(root, currentRoot))
\r
1126 currentRoot = root;
\r
1128 //System.out.println(this + ": setRoot(" + input + ")");
\r
1129 explorer.setUIContexts(uiContext);
\r
1130 explorer.setRoot(root);
\r
1136 protected boolean isImportantInput(Object previousSelection, Object selection) {
\r
1137 return !ObjectUtils.objectEquals(previousSelection, selection);
\r
1140 public void setInput(Object selection, boolean force) {
\r
1146 if (sessionContext == null)
\r
1149 // Check if this is a duplicate of the previous selection to reduce unnecessary flicker.
\r
1150 if (!force && !isImportantInput(currentInput, selection))
\r
1153 currentInput = selection;
\r
1155 Object root = inputSource.get(sessionContext, selection);
\r
1157 currentRoot = root;
\r
1159 explorer.setUIContexts(uiContext);
\r
1161 if (root == null) {
\r
1162 explorer.setRoot(GraphExplorer.EMPTY_INPUT);
\r
1164 explorer.setRoot(root);
\r
1169 public void setColumnsVisible(boolean visible) {
\r
1170 explorer.setColumnsVisible(visible);
\r
1173 private int getColumnWidth(Column column, ExplorerState state) {
\r
1174 // Get saved width from the persistor if there is one.
\r
1175 if (state != null && state.columnWidths != null) {
\r
1176 Integer width = state.columnWidths.get(column.getLabel());
\r
1177 if (width != null)
\r
1180 return column.getWidth();
\r
1183 public void setColumns(Column[] columns) {
\r
1185 explorer.setColumns(columns, new Consumer<Map<Column, Object>>() {
\r
1188 public void accept(Map<Column, Object> objects) {
\r
1189 ExplorerState state = null;
\r
1190 if (persistor != null) {
\r
1191 state = persistor.deserialize(
\r
1192 Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
\r
1193 explorer.getRoot());
\r
1196 for(Map.Entry<Column, Object> entry : objects.entrySet()) {
\r
1197 Column column = entry.getKey();
\r
1198 TreeColumn treeColumn = (TreeColumn)entry.getValue();
\r
1200 if (column.getWidth() < 0) {
\r
1201 throw new IllegalArgumentException("Column minimum width cannot be < 0, got " + column.getWidth());
\r
1204 int width = getColumnWidth(column, state);
\r
1205 if(column.hasGrab()) {
\r
1207 ad.setColumnData(treeColumn, new ColumnWeightData(column.getWeight(), width));
\r
1211 ad.setColumnData(treeColumn, new ColumnWeightData(0, width));
\r
1223 public void setInput(ISessionContext context, Object input) {
\r
1224 setInput(input, false);
\r
1227 public void setMaxChildren(int maxChildren) {
\r
1228 explorer.setMaxChildren(maxChildren);
\r
1231 public <T> void addListener(ExplorerMouseListenerImpl<T> listener) {
\r
1233 support.register(listener);
\r
1234 listener.register(explorer);
\r
1235 explorer.addListener(listener);
\r
1240 // public Point computeSize(int wHint, int hHint) {
\r
1241 // Point p = super.computeSize(wHint, hHint);
\r
1242 // System.err.println("graphExplorerComposite.computeSize " + p);
\r
1247 // public Point computeSize(int wHint, int hHint, boolean changed) {
\r
1248 // Point p = super.computeSize(wHint, hHint, changed);
\r
1249 // System.err.println("graphExplorerComposite.computeSize " + p);
\r