1 /*******************************************************************************
2 * Copyright (c) 2007, 2012 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.browsing.ui.swt.widgets;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.HashSet;
19 import java.util.function.BiFunction;
20 import java.util.function.Consumer;
22 import org.eclipse.core.runtime.IAdaptable;
23 import org.eclipse.core.runtime.Platform;
24 import org.eclipse.jface.action.IMenuManager;
25 import org.eclipse.jface.layout.GridDataFactory;
26 import org.eclipse.jface.layout.GridLayoutFactory;
27 import org.eclipse.jface.layout.TreeColumnLayout;
28 import org.eclipse.jface.resource.JFaceResources;
29 import org.eclipse.jface.resource.LocalResourceManager;
30 import org.eclipse.jface.viewers.ColumnWeightData;
31 import org.eclipse.jface.viewers.ISelectionProvider;
32 import org.eclipse.swt.SWT;
33 import org.eclipse.swt.dnd.DND;
34 import org.eclipse.swt.dnd.DragSource;
35 import org.eclipse.swt.dnd.DragSourceEvent;
36 import org.eclipse.swt.dnd.DragSourceListener;
37 import org.eclipse.swt.dnd.DropTarget;
38 import org.eclipse.swt.dnd.DropTargetEvent;
39 import org.eclipse.swt.dnd.DropTargetListener;
40 import org.eclipse.swt.dnd.FileTransfer;
41 import org.eclipse.swt.dnd.TextTransfer;
42 import org.eclipse.swt.dnd.Transfer;
43 import org.eclipse.swt.widgets.Composite;
44 import org.eclipse.swt.widgets.Control;
45 import org.eclipse.swt.widgets.Event;
46 import org.eclipse.swt.widgets.Listener;
47 import org.eclipse.swt.widgets.Tree;
48 import org.eclipse.swt.widgets.TreeColumn;
49 import org.eclipse.swt.widgets.TreeItem;
50 import org.eclipse.ui.ISelectionListener;
51 import org.eclipse.ui.IWorkbenchSite;
52 import org.eclipse.ui.contexts.IContextService;
53 import org.simantics.browsing.ui.BuiltinKeys;
54 import org.simantics.browsing.ui.Column;
55 import org.simantics.browsing.ui.ExplorerState;
56 import org.simantics.browsing.ui.GraphExplorer;
57 import org.simantics.browsing.ui.GraphExplorer.TransientExplorerState;
58 import org.simantics.browsing.ui.NodeContext;
59 import org.simantics.browsing.ui.StatePersistor;
60 import org.simantics.browsing.ui.common.AdaptableHintContext;
61 import org.simantics.browsing.ui.common.ColumnKeys;
62 import org.simantics.browsing.ui.common.EvaluatorData;
63 import org.simantics.browsing.ui.common.EvaluatorDataImpl;
64 import org.simantics.browsing.ui.common.processors.ComparableFactoryResolver;
65 import org.simantics.browsing.ui.common.processors.ComparableSelectorQueryProcessor;
66 import org.simantics.browsing.ui.common.processors.FilterSelectionRequestQueryProcessor;
67 import org.simantics.browsing.ui.common.processors.ImageDecoratorFactoryResolver;
68 import org.simantics.browsing.ui.common.processors.ImagerFactoryResolver;
69 import org.simantics.browsing.ui.common.processors.LabelDecoratorFactoryResolver;
70 import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver;
71 import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor;
72 import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor;
73 import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver;
74 import org.simantics.browsing.ui.common.views.FilterAreaSource;
75 import org.simantics.browsing.ui.common.views.IFilterArea;
76 import org.simantics.browsing.ui.common.views.IFilterAreaProvider;
77 import org.simantics.browsing.ui.graph.impl.AsyncReadGraphDataSource;
78 import org.simantics.browsing.ui.graph.impl.Evaluators;
79 import org.simantics.browsing.ui.graph.impl.InheritsQueryProcessor;
80 import org.simantics.browsing.ui.graph.impl.ReadGraphDataSource;
81 import org.simantics.browsing.ui.graph.impl.RelatedObjectsQueryProcessor;
82 import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
83 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
84 import org.simantics.browsing.ui.model.nodetypes.NodeType;
85 import org.simantics.browsing.ui.swt.Activator;
86 import org.simantics.browsing.ui.swt.ComparatorSelector;
87 import org.simantics.browsing.ui.swt.ContextMenuInitializer;
88 import org.simantics.browsing.ui.swt.DefaultExplorerSelectionListener;
89 import org.simantics.browsing.ui.swt.DefaultIsCheckedProcessor2;
90 import org.simantics.browsing.ui.swt.DefaultKeyListener;
91 import org.simantics.browsing.ui.swt.DefaultMouseListener;
92 import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver;
93 import org.simantics.browsing.ui.swt.FilterArea;
94 import org.simantics.browsing.ui.swt.GraphExplorerFactory;
95 import org.simantics.browsing.ui.swt.IContextMenuInitializer;
96 import org.simantics.browsing.ui.swt.RootFilterArea;
97 import org.simantics.browsing.ui.swt.StandardContextTypesQueryProcessor;
98 import org.simantics.browsing.ui.swt.TypesQueryProcessor;
99 import org.simantics.browsing.ui.swt.ViewpointSelector;
100 import org.simantics.browsing.ui.swt.widgets.impl.Widget;
101 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;
102 import org.simantics.db.AsyncReadGraph;
103 import org.simantics.db.ReadGraph;
104 import org.simantics.db.Resource;
105 import org.simantics.db.Session;
106 import org.simantics.db.exception.DatabaseException;
107 import org.simantics.db.layer0.SelectionHints;
108 import org.simantics.db.layer0.request.PossibleVariable;
109 import org.simantics.db.layer0.request.PossibleVariableRepresents;
110 import org.simantics.db.layer0.variable.Variable;
111 import org.simantics.db.management.ISessionContext;
112 import org.simantics.db.management.ISessionContextChangedListener;
113 import org.simantics.db.management.ISessionContextProvider;
114 import org.simantics.db.management.SessionContextChangedEvent;
115 import org.simantics.project.ProjectKeys;
116 import org.simantics.ui.SimanticsUI;
117 import org.simantics.ui.dnd.LocalObjectTransfer;
118 import org.simantics.ui.dnd.LocalSelectionDragSourceListener;
119 import org.simantics.ui.dnd.NoImageDragSourceEffect;
120 import org.simantics.ui.dnd.SessionContainer;
121 import org.simantics.ui.selection.AnyResource;
122 import org.simantics.ui.selection.AnyVariable;
123 import org.simantics.ui.selection.ExplorerColumnContentType;
124 import org.simantics.ui.selection.ExplorerInputContentType;
125 import org.simantics.ui.selection.WorkbenchSelectionContentType;
126 import org.simantics.ui.selection.WorkbenchSelectionElement;
127 import org.simantics.ui.selection.WorkbenchSelectionUtils;
128 import org.simantics.utils.ObjectUtils;
129 import org.simantics.utils.datastructures.Function;
130 import org.simantics.utils.datastructures.disposable.DisposeState;
131 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
132 import org.simantics.utils.datastructures.hints.HintTracker;
133 import org.simantics.utils.datastructures.hints.IHintContext.Key;
134 import org.simantics.utils.datastructures.hints.IHintListener;
135 import org.simantics.utils.datastructures.hints.IHintObservable;
136 import org.simantics.utils.datastructures.hints.IHintTracker;
137 import org.slf4j.Logger;
138 import org.slf4j.LoggerFactory;
141 public class GraphExplorerComposite extends Composite implements Widget, IAdaptable {
143 private static final Logger LOGGER = LoggerFactory.getLogger(GraphExplorerComposite.class);
145 protected UserSelectedComparableFactoryQueryProcessor userSelectedComparableFactoryQueryProcessor;
146 protected UserSelectedViewpointFactoryQueryProcessor userSelectedViewpointFactoryQueryProcessor;
147 protected FilterSelectionRequestQueryProcessor filterSelectionRequestQueryProcessor;
148 protected IFilterArea filterArea;
149 protected EvaluatorData evaluatorData;
151 protected LocalResourceManager resourceManager;
153 protected ISelectionListener workbenchSelectionListener;
155 private final int style;
157 final private IWorkbenchSite site;
159 protected GraphExplorer explorer;
161 protected IMenuManager menuManager;
163 private final Map<String, Object> args;
165 protected ISessionContextProvider contextProvider;
167 private ISessionContext sessionContext;
169 private Object dragSource;
171 private IHintTracker sessionContextTracker = new SessionContextProjectTracker();
173 private InputSource inputSource = new DirectInputSource();
174 private FilterAreaSource filterAreaSource = new SelectionFilterAreaSource();
176 private final TreeColumnLayout ad;
177 private String[] editingColumn = ColumnKeys.KEYS_SINGLE;
179 private StatePersistor persistor = null;
181 private final Composite toolComposite;
182 private final Composite toolComposite2;
183 private final Composite explorerComposite;
184 final private WidgetSupport support;
185 private final boolean useNodeBrowseContexts;
186 private final boolean useNodeActionContexts;
188 static class SelectionElement extends AdaptableHintContext {
190 final public WorkbenchSelectionElement wse;
191 final public Object content;
192 final public Resource resource;
193 final public Variable variable;
194 final public Object input;
195 final public TransientExplorerState explorerState;
197 private WorkbenchSelectionElement extractWse(Object content) {
198 if(content instanceof NodeContext) {
199 NodeContext context = (NodeContext)content;
200 Object input = context.getConstant(NodeType.TYPE);
201 if(input instanceof NodeType)
202 return ((NodeType)input).getWorkbenchSelectionElement(context);
207 private Resource extractResource(Object content) {
208 if(content instanceof NodeContext) {
209 NodeContext context = (NodeContext)content;
210 Object input = context.getConstant(BuiltinKeys.INPUT);
211 if(input instanceof Resource) return (Resource)input;
212 if(input instanceof IAdaptable) {
213 Resource var = (Resource)((IAdaptable)input).getAdapter(Resource.class);
214 if(var != null) return var;
220 private Variable extractVariable(Object content) {
221 if(content instanceof NodeContext) {
222 NodeContext context = (NodeContext)content;
223 Object input = context.getConstant(BuiltinKeys.INPUT);
224 if(input instanceof Variable) return (Variable)input;
225 if(input instanceof IAdaptable) {
226 Variable var = (Variable)((IAdaptable)input).getAdapter(Variable.class);
227 if(var != null) return var;
233 private Object extractInput(Object content) {
234 if(content instanceof NodeContext) {
235 NodeContext context = (NodeContext)content;
236 return context.getConstant(BuiltinKeys.INPUT);
241 public SelectionElement(GraphExplorer explorer, Key[] keys, Object content) {
243 this.content = content;
244 this.wse = extractWse(content);
245 this.resource = extractResource(content);
246 this.variable = extractVariable(content);
247 this.input = extractInput(content);
248 this.explorerState = explorer.getTransientState();
251 @SuppressWarnings("unchecked")
253 public <T> T getContent(WorkbenchSelectionContentType<T> contentType) {
255 T result = wse.getContent(contentType);
260 if (contentType instanceof AnyResource) {
261 if (resource != null)
263 if (variable == null)
266 return (T) ((AnyResource) contentType).processor.syncRequest(new PossibleVariableRepresents(variable));
267 } catch (DatabaseException e) {
268 LOGGER.error("Unexpected error occurred while resolving Resource from Variable " + variable, e);
271 else if (contentType instanceof AnyVariable) {
272 if (variable != null)
274 if (resource == null)
277 return (T) ((AnyVariable) contentType).processor.syncRequest(new PossibleVariable(resource));
278 } catch (DatabaseException e) {
279 LOGGER.error("Unexpected error occurred while resolving Variable from Resource " + resource, e);
281 } else if (contentType instanceof ExplorerInputContentType) {
283 } else if (contentType instanceof ExplorerColumnContentType) {
284 return (T) explorerState.getActiveColumn();
289 @SuppressWarnings("rawtypes")
291 public Object getAdapter(Class adapter) {
292 if(WorkbenchSelectionElement.class == adapter) {
295 if(NodeContext.class == adapter) {
296 if(content instanceof NodeContext)
297 return (NodeContext)content;
301 return super.getAdapter(adapter);
305 private BiFunction<GraphExplorer, Object[], Object[]> selectionTransformation = new BiFunction<GraphExplorer, Object[], Object[]>() {
307 private Key[] KEYS = new Key[] { SelectionHints.KEY_MAIN };
310 public Object[] apply(GraphExplorer explorer, Object[] objects) {
311 Object[] result = new Object[objects.length];
312 for (int i = 0; i < objects.length; i++) {
313 SelectionElement context = new SelectionElement(explorer, KEYS, objects[i]);
314 context.setHint(SelectionHints.KEY_MAIN, objects[i]);
322 private Set<String> browseContexts = null;
324 private DisposeState disposeState = DisposeState.Alive;
326 private boolean created = false;
328 protected String contextMenuId = null;
330 protected Set<String> uiContext = null;
332 protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {
334 public void sessionContextChanged(SessionContextChangedEvent event) {
335 sessionContext = event.getNewValue();
336 sessionContextTracker.track(sessionContext);
340 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, WidgetSupport support, int style) {
342 super(parent, SWT.NONE);
345 args = Collections.emptyMap();
350 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), this);
352 contextProvider = getSessionContextProvider(site);
354 Integer maxChildren = (Integer)args.get("maxChildren");
356 GridLayoutFactory.fillDefaults().equalWidth(false).numColumns(1).margins(0,0).spacing(0,0).applyTo(this);
358 toolComposite = new Composite(this, SWT.NONE);
359 // toolComposite.setBackground(toolComposite.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
360 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
361 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite);
362 GridLayoutFactory.fillDefaults().applyTo(toolComposite);
364 ad = new TreeColumnLayout();
365 explorerComposite = new Composite(this, SWT.NONE);
366 explorerComposite.setLayout(ad);
367 GridDataFactory.fillDefaults().grab(true, true).minSize(1, 50).applyTo(explorerComposite);
369 if (args.containsKey("treeView") && Boolean.TRUE.equals(args.get("treeView"))) {
370 explorer = createExplorerControl2(explorerComposite, maxChildren);
371 } else if (args.containsKey("natTable") && Boolean.TRUE.equals(args.get("natTable"))) {
372 explorer = createExplorerControl3(explorerComposite, maxChildren);
374 explorer = createExplorerControl(explorerComposite, maxChildren);
377 if (args.containsKey("useNodeBrowseContexts") && Boolean.TRUE.equals(args.get("useNodeBrowseContexts"))) {
378 useNodeBrowseContexts = true;
380 useNodeBrowseContexts = false;
383 if (args.containsKey("useNodeActionContexts") && Boolean.TRUE.equals(args.get("useNodeActionContexts"))) {
384 useNodeActionContexts = true;
386 useNodeActionContexts = false;
389 toolComposite2 = new Composite(this, SWT.NONE);
390 // toolComposite2.setBackground(toolComposite2.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
391 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
392 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite2);
393 GridLayoutFactory.fillDefaults().applyTo(toolComposite2);
395 this.support = support;
398 support.register(this);
402 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, int style) {
404 this(args, site, parent, null, style);
408 public ISessionContextProvider getSessionContextProvider(IWorkbenchSite site) {
410 return SimanticsUI.getSessionContextProvider(site.getWorkbenchWindow());
412 return SimanticsUI.getSessionContextProvider();
415 public GraphExplorer getExplorer() {
419 public Composite getExplorerComposite() {
420 return explorerComposite;
423 public <T> T getExplorerControl() {
424 return explorer.getControl();
427 public void addListenerToControl(int eventType, Listener listener) {
428 ((Control)explorer.getControl()).addListener(eventType, listener);
431 public void finish() {
433 createControls(site);
437 IWorkbenchSite getSite() {
441 protected void activateUiContexts() {
442 Collection<String> contexts = getUiContexts();
443 if (contexts == null || contexts.isEmpty())
445 IWorkbenchSite site = getSite();
447 IContextService cs = (IContextService) getSite().getService(IContextService.class);
448 for (String context : contexts)
449 cs.activateContext(context);
453 protected void createControls(IWorkbenchSite site) {
455 // Initialize explorer control.
456 // GridDataFactory.fillDefaults().grab(true, true).applyTo(explorer.getControl());
458 Control control = explorer.getControl();
460 // Initialize context menu if an initializer is provided.
461 IContextMenuInitializer cmi = getContextMenuInitializer();
463 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
464 menuManager = cmi.createContextMenu(control, selectionProvider, site);
467 // Initialize UI contexts
468 activateUiContexts();
471 dragSource = setupDND(explorer);
473 // Listeners are only added once per listener, not every time the
474 // session context changes.
475 addListeners(explorer, menuManager);
477 userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor();
478 userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor();
479 filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor();
481 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
483 boolean hasExtraControls = false;
484 boolean hasExtraControls2 = false;
486 Boolean displaySelectors = (Boolean)args.get("displaySelectors");
487 if(displaySelectors == null || displaySelectors == true) {
489 @SuppressWarnings("unused")
490 ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
491 // comparatorSelector.moveAbove(control);
493 @SuppressWarnings("unused")
494 ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
495 // viewpointSelector.moveAbove(control);
497 hasExtraControls = true;
501 Boolean displayFilter = (Boolean)args.get("displayFilter");
502 if(displayFilter == null || displayFilter == true) {
505 filterArea = filterAreaSource.getFilterArea(toolComposite, explorer);
506 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite, SWT.READ_ONLY);
507 //filterArea.moveAbove(control);
509 hasExtraControls = true;
513 Boolean displayFilter2 = (Boolean)args.get("displayFilter2");
514 if(displayFilter2 != null && displayFilter2 == true) {
516 filterArea = filterAreaSource.getFilterArea(toolComposite2, explorer);
517 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite2, SWT.READ_ONLY);
518 // //filterArea.moveAbove(control);
520 hasExtraControls2 = true;
524 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, this, SWT.READ_ONLY);
525 // filterArea.moveAbove(control);
527 if(!hasExtraControls)
528 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite);
529 if(!hasExtraControls2)
530 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite2);
532 GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control);
534 //tree.getTree().setLayout(new FillLayout()
535 //this.setLayout(LayoutUtils.createNoBorderGridLayout(2, false));
537 DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_DEFAULT);
538 target.setTransfer(getAcceptedDataTypes());
539 if (control instanceof Tree) {
540 target.addDropListener(new DropTargetListener() {
542 Tree tree = (Tree)explorer.getControl();
545 public void dragEnter(DropTargetEvent event) {
546 event.detail = DND.DROP_COPY;
550 public void dragLeave(DropTargetEvent event) {
554 public void dragOperationChanged(DropTargetEvent event) {
558 public void dragOver(DropTargetEvent event) {
562 public void drop(DropTargetEvent event) {
563 TreeItem item = tree.getItem(tree.toControl(event.x, event.y));
565 Object data = item.getData();
566 if (data instanceof NodeContext)
567 handleDrop(event.data, (NodeContext) data);
568 else if (data instanceof IAdaptable) {
569 IAdaptable a = (IAdaptable) data;
570 handleDrop(event.data, (NodeContext) a.getAdapter(NodeContext.class));
573 handleDrop(event.data, null);
577 public void dropAccept(DropTargetEvent event) {
583 // Add workbench listeners and make sure they are cleaned up
584 setWorkbenchListeners();
585 control.addListener(SWT.Dispose, new Listener() {
587 public void handleEvent(Event event) {
593 @SuppressWarnings({ "rawtypes", "unchecked" })
595 public Object getAdapter(Class adapter) {
596 if (GraphExplorer.class == adapter)
598 if (EvaluatorData.class == adapter)
599 return evaluatorData;
600 if (BrowseContext.class == adapter) {
601 EvaluatorData ed = evaluatorData;
602 return ed != null ? ed.getBrowseContext() : null;
604 if (adapter == IFilterAreaProvider.class)
606 return explorer.getAdapter(adapter);
609 protected void doDispose() {
610 //System.out.println(this + ".GraphExplorerComposite.doDispose()");
611 removeWorkbenchListeners();
612 userSelectedComparableFactoryQueryProcessor = null;
613 userSelectedViewpointFactoryQueryProcessor = null;
614 filterSelectionRequestQueryProcessor = null;
616 disposeState = DisposeState.Disposing;
618 //System.out.println(this + ".GraphExplorerViewBase.dispose()");
619 if (contextProvider != null) {
620 contextProvider.removeContextChangedListener(contextChangeListener);
621 contextProvider = null;
623 sessionContextTracker.untrack();
624 resourceManager = null;
626 sessionContext = null;
630 disposeState = DisposeState.Disposed;
635 public void dispose() {
640 protected StatePersistor getStatePersistor() {
644 public void setStatePersistor(StatePersistor persistor) {
645 this.persistor = persistor;
648 protected void initializeExplorer(GraphExplorer explorer, ISessionContext context) {
650 if(explorer == null || explorer.isDisposed()) return;
651 if(context == null) return;
652 if(browseContexts == null) return;
654 Session session = context != null ? context.getSession() : null;
655 setupDragSource(session);
657 if (session != null) {
658 evaluatorData = createEvaluatorData(session);
659 explorer.setDataSource(new AsyncReadGraphDataSource(session));
660 explorer.setDataSource(new ReadGraphDataSource(session));
663 evaluatorData = new EvaluatorDataImpl();
664 explorer.removeDataSource(AsyncReadGraph.class);
665 explorer.removeDataSource(ReadGraph.class);
668 explorer.setPersistor(getStatePersistor());
670 explorer.setProcessor(new ComparableFactoryResolver(evaluatorData));
671 explorer.setProcessor(new ViewpointFactoryResolver(evaluatorData));
672 explorer.setProcessor(new LabelerFactoryResolver(evaluatorData));
673 explorer.setProcessor(new ImagerFactoryResolver(evaluatorData));
674 explorer.setProcessor(new LabelDecoratorFactoryResolver(evaluatorData));
675 explorer.setProcessor(new ImageDecoratorFactoryResolver(evaluatorData));
676 explorer.setProcessor(new DefaultIsCheckedProcessor2(evaluatorData));
677 explorer.setPrimitiveProcessor(new TypesQueryProcessor());
678 explorer.setPrimitiveProcessor(new StandardContextTypesQueryProcessor());
679 explorer.setPrimitiveProcessor(new InheritsQueryProcessor());
680 explorer.setPrimitiveProcessor(new RelatedObjectsQueryProcessor());
682 explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor);
683 explorer.setProcessor(new ComparableSelectorQueryProcessor());
684 explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor);
685 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
687 initializeExplorerWithEvaluator(explorer, context, evaluatorData);
690 protected void initializeExplorerWithEvaluator(GraphExplorer explorer, ISessionContext context, EvaluatorData data) {
693 protected EvaluatorData createEvaluatorData(Session context) {
695 // Set<String> browseContexts = getArgument("browseContexts");
697 return Evaluators.load(context.getSession(), browseContexts, resourceManager, useNodeBrowseContexts, useNodeActionContexts);
701 protected Transfer[] getAcceptedDataTypes() {
702 return new Transfer[] { LocalObjectTransfer.getTransfer(), FileTransfer.getInstance(), TextTransfer.getInstance() };
705 protected void handleDrop(Object data, NodeContext target) {
708 DragSourceListenerFactory dragSourceListenerFactory = new DragSourceListenerFactory() {
710 final Transfer[] transfers = new Transfer[] {LocalObjectTransfer.getTransfer(), TextTransfer.getInstance() };
713 public DragSourceListener get(ISelectionProvider selectionProvider) {
715 LocalSelectionDragSourceListener ls = new LocalSelectionDragSourceListener(selectionProvider);
717 return new DragSourceListener() {
720 public void dragStart(DragSourceEvent event) {
725 public void dragSetData(DragSourceEvent event) {
726 if(TextTransfer.getInstance().isSupportedType(event.dataType)) {
728 event.data = WorkbenchSelectionUtils.getPossibleJSON(selectionProvider.getSelection());
729 } catch (DatabaseException e) {
730 event.data = "{ type:\"Exception\" }";
731 LOGGER.error("Failed to get current selection as JSON.", e);
733 } else if (LocalObjectTransfer.getTransfer().isSupportedType(event.dataType)) {
734 ls.dragSetData(event);
739 public void dragFinished(DragSourceEvent event) {
740 ls.dragFinished(event);
746 public Transfer[] getTransfers() {
752 public void setDragSourceListenerFactory(DragSourceListenerFactory dragSourceListenerFactory) {
753 this.dragSourceListenerFactory = dragSourceListenerFactory;
756 protected DragSourceListener setupDND(GraphExplorer explorer) {
758 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
760 DragSourceListener listener = createDragSourceListener(selectionProvider);
762 Control control = explorer.getControl();
763 DragSource source = createDragSource(control);
764 source.setTransfer(getTransfers());
765 source.addDragListener(listener);
766 source.setDragSourceEffect(new NoImageDragSourceEffect(control));
772 protected DragSourceListener createDragSourceListener(ISelectionProvider selectionProvider) {
773 return dragSourceListenerFactory.get(selectionProvider);
776 private int dragStyle = DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
778 protected void setDragStyle(int style) {
779 this.dragStyle = style;
782 protected int getDragStyle() {
786 protected DragSource createDragSource(Control control) {
787 return new DragSource(control, getDragStyle());
790 protected Transfer[] getTransfers() {
791 return dragSourceListenerFactory.getTransfers();
794 public EvaluatorData getEvaluatorData() {
795 return evaluatorData;
798 public interface InputSource {
800 * @param ctx the session context to read the input from. May be
801 * <code>null</code> if there is no session.
802 * @return the input object of a graph explorer. To indicate no input,
803 * use {@link GraphExplorerConstants#EMPTY_INPUT}. Never return
806 Object get(ISessionContext ctx, Object selection);
809 public interface FilterSource {
816 * The default hint tracker that will be active if
817 * {@link GraphExplorerComposite#setSessionContextTracker(IHintTracker) is
820 public class SessionContextProjectTracker extends HintTracker {
821 public SessionContextProjectTracker() {
822 IHintListener activeProjectListener = new HintListenerAdapter() {
824 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
825 applySessionContext(getSessionContext());
828 addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);
832 public class DirectInputSource implements InputSource {
834 public Object get(ISessionContext ctx, Object selection) {
839 public static class SelectionFilterAreaSource implements FilterAreaSource {
842 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
843 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
844 return new FilterArea(explorer, processor, parent, SWT.READ_ONLY);
849 public static class RootFilterAreaSource implements FilterAreaSource {
852 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
853 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
854 return new RootFilterArea(explorer, processor, parent, SWT.READ_ONLY);
859 protected void setSessionContextTracker(IHintTracker tracker) {
860 this.sessionContextTracker = tracker;
863 public void setInputSource(InputSource source) {
864 this.inputSource = source;
867 public void setFilterAreaSource(FilterAreaSource provider) {
868 this.filterAreaSource = provider;
871 public void setSelectionTransformation(BiFunction<GraphExplorer, Object[], Object[]> transformation) {
872 this.selectionTransformation = transformation;
873 if(explorer != null) explorer.setSelectionTransformation(transformation);
876 protected Set<String> getBrowseContexts() {
877 return browseContexts;
880 public void setBrowseContexts(Set<String> contexts) {
881 this.browseContexts = contexts;
882 //initializeExplorer(explorer, getSessionContext());
885 public void setBrowseContexts(String ... contexts) {
886 this.browseContexts = new HashSet<String>();
887 for(String s : contexts) this.browseContexts.add(s);
888 initializeExplorer(explorer, getSessionContext());
891 public void setContextMenuId(String contextMenuId) {
892 this.contextMenuId = contextMenuId;
895 // protected IContextMenuInitializer getContextMenuInitializer() {
896 // String contextMenuId = getContextMenuId();
897 // if(contextMenuId != null) {
898 // return new ContextMenuInitializer(contextMenuId);
904 protected String getContextMenuId() {
905 return this.contextMenuId;
908 public void setUiContexts(Set<String> uiContext) {
909 this.uiContext = uiContext;
912 public Set<String> getUiContexts() {
916 protected InputSource getInputSource() {
920 protected Map<String, Object> getArguments() {
924 @SuppressWarnings("unchecked")
925 protected <T> T getArgument(String key) {
926 return (T) args.get(key);
929 protected DisposeState getDisposeState() {
933 public ISessionContext getSessionContext() {
934 return sessionContext;
937 public ISessionContextProvider getSessionContextProvider() {
938 return contextProvider;
942 public boolean setFocus() {
943 if (explorer != null && !explorer.isDisposed())
948 public void setWorkbenchListeners() {
949 if (workbenchSelectionListener == null && getSite() != null) {
950 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
951 getSite().setSelectionProvider(selectionProvider);
953 // Listen to the workbench selection also to propagate it to
954 // the explorer also.
955 workbenchSelectionListener = new DefaultExplorerSelectionListener(site.getPage().getActivePart(), explorer);
956 //System.out.println("ADD WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
957 getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener);
961 protected void removeWorkbenchListeners() {
962 //System.out.println("REMOVE WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
963 // Remember to remove the installed workbench selection listener
964 if (workbenchSelectionListener != null) {
965 getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener);
966 workbenchSelectionListener = null;
968 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
969 if(getSite().getSelectionProvider() == selectionProvider) getSite().setSelectionProvider(null);
974 protected final void attachToSession() {
976 // Track active ISessionContext changes
977 //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());
978 contextProvider.addContextChangedListener(contextChangeListener);
980 // Start tracking the current session context for input changes.
981 // This will/must cause applySessionContext to get called.
982 // Doing the applySessionContext initialization this way
983 // instead of directly calling it will also make sure that
984 // applySessionContext is only called once when first initialized,
985 // and not twice like with the direct invocation.
986 this.sessionContext = contextProvider.getSessionContext();
987 sessionContextTracker.track(sessionContext);
990 // /////////////////////////////////////////////////////////////////////////
991 // Override / implement these:
994 // * Returns an ID that is used for persisting a GraphExplorer instance.
996 // * Used for </code>restoreState(IMemento)</code> and
997 // * <code>restoreState(IMemento)</code> in OntologyExplorer. Must be unique
998 // * within a workbench part.
1000 // * @return a unique name for this particular graph explorer view used for
1001 // * saving and restoring the state of this view part
1003 // public String getExplorerName() {
1004 // return "GraphExplorerViewBase";
1008 * Override this method to add controls to the view part. This is invoked
1009 * before attaching the view part to a database session.
1013 protected void createControls(Composite parent) {
1018 * Override this method and provide a proper context menu initializer if you
1019 * want to have this base class initialize one for you.
1021 * @return the initializer to be used by {@link #createControls(Composite)}
1023 protected IContextMenuInitializer getContextMenuInitializer() {
1024 String contextMenuId = getContextMenuId();
1025 if(contextMenuId != null) {
1026 return new ContextMenuInitializer(contextMenuId);
1036 protected GraphExplorer createExplorerControl(Composite parent, Integer maxChildren) {
1037 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1038 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1040 GraphExplorer ge = factory
1041 .selectionDataResolver(new DefaultSelectionDataResolver())
1042 .selectionTransformation(selectionTransformation)
1043 .setServiceLocator(site)
1044 .create(parent, style);
1049 protected GraphExplorer createExplorerControl2(Composite parent, Integer maxChildren) {
1050 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1051 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1053 GraphExplorer ge = factory
1054 .selectionDataResolver(new DefaultSelectionDataResolver())
1055 .selectionTransformation(selectionTransformation)
1056 .setServiceLocator(site)
1057 .create2(parent, style);
1062 protected GraphExplorer createExplorerControl3(Composite parent, Integer maxChildren) {
1063 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1064 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1066 GraphExplorer ge = factory
1067 .selectionDataResolver(new DefaultSelectionDataResolver())
1068 .selectionTransformation(selectionTransformation)
1069 .setServiceLocator(site)
1070 .create3(parent, style);
1075 protected void setupDragSource(Session session) {
1076 if (dragSource instanceof SessionContainer) {
1077 ((SessionContainer) dragSource).setSession(session);
1082 * Override to customize the addition of listeners a newly created
1087 protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {
1088 addSelectionInputListeners(explorer, menuManager);
1091 protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {
1092 // Consider ENTER presses to simulate mouse left button double clicks
1093 explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function<String[]>() {
1095 public String[] execute(Object... obj) {
1096 return getEditingColumn((NodeContext) obj[0]);
1099 // Default double click handling
1100 explorer.addListener(new DefaultMouseListener(explorer));
1103 protected String[] getEditingColumn(NodeContext context) {
1104 return editingColumn;
1107 public void setEditingColumn(String... columnKeysInOrderOfTrial) {
1108 this.editingColumn = columnKeysInOrderOfTrial;
1111 // Needed for preventing unnecessary re-initialization of the explorer with the same input.
1112 private Object currentInput;
1113 private Object currentRoot;
1116 * Invoke this to reinitialize the explorer and reset its input. The input
1117 * will be resolved from the specified ISessionContext based on the
1118 * {@link SessionContextInputSource} that is currently in use. If the input
1119 * is identical to the previous input, nothing will be done.
1123 public final boolean applySessionContext(ISessionContext context) {
1125 // If control is not alive anymore, do nothing.
1126 //System.out.println(this + ": applySessionContext(" + context + "), explorer=" + explorer);
1127 if (disposeState != DisposeState.Alive)
1130 //System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");
1131 initializeExplorer(explorer, context);
1134 // Start tracking the session context.
1136 // If this is not the same session that is currently tracked, it will
1137 // cause IHintListeners of the sessionContextTracker to fire.
1138 // For this we need the above input equality (identity) checking.
1139 // This is here just to make sure that we are tracking the correct
1141 sessionContextTracker.track(sessionContext);
1143 this.sessionContext = context;
1144 Object root = inputSource.get(context, currentInput);
1145 if (ObjectUtils.objectEquals(root, currentRoot))
1150 //System.out.println(this + ": setRoot(" + input + ")");
1151 explorer.setUIContexts(uiContext);
1152 explorer.setRoot(root);
1158 protected boolean isImportantInput(Object previousSelection, Object selection) {
1159 return !ObjectUtils.objectEquals(previousSelection, selection);
1162 public void setInput(Object selection, boolean force) {
1168 if (sessionContext == null)
1171 // Check if this is a duplicate of the previous selection to reduce unnecessary flicker.
1172 if (!force && !isImportantInput(currentInput, selection))
1175 currentInput = selection;
1177 Object root = inputSource.get(sessionContext, selection);
1181 explorer.setUIContexts(uiContext);
1184 explorer.setRoot(GraphExplorer.EMPTY_INPUT);
1186 explorer.setRoot(root);
1191 public void setColumnsVisible(boolean visible) {
1192 explorer.setColumnsVisible(visible);
1195 private int getColumnWidth(Column column, ExplorerState state) {
1196 // Get saved width from the persistor if there is one.
1197 if (state != null && state.columnWidths != null) {
1198 Integer width = state.columnWidths.get(column.getLabel());
1202 return column.getWidth();
1205 public void setColumns(Column[] columns) {
1207 explorer.setColumns(columns, new Consumer<Map<Column, Object>>() {
1210 public void accept(Map<Column, Object> objects) {
1211 ExplorerState state = null;
1212 if (persistor != null) {
1213 state = persistor.deserialize(
1214 Platform.getStateLocation(Activator.getDefault().getBundle()).toFile(),
1215 explorer.getRoot());
1218 for(Map.Entry<Column, Object> entry : objects.entrySet()) {
1219 Column column = entry.getKey();
1220 TreeColumn treeColumn = (TreeColumn)entry.getValue();
1222 if (column.getWidth() < 0) {
1223 throw new IllegalArgumentException("Column minimum width cannot be < 0, got " + column.getWidth());
1226 int width = getColumnWidth(column, state);
1227 if(column.hasGrab()) {
1229 ad.setColumnData(treeColumn, new ColumnWeightData(column.getWeight(), width));
1233 ad.setColumnData(treeColumn, new ColumnWeightData(0, width));
1245 public void setInput(ISessionContext context, Object input) {
1246 setInput(input, false);
1249 public void setMaxChildren(int maxChildren) {
1250 explorer.setMaxChildren(maxChildren);
1253 public <T> void addListener(ExplorerMouseListenerImpl<T> listener) {
1255 support.register(listener);
1256 listener.register(explorer);
1257 explorer.addListener(listener);
1262 // public Point computeSize(int wHint, int hHint) {
1263 // Point p = super.computeSize(wHint, hHint);
1264 // System.err.println("graphExplorerComposite.computeSize " + p);
1269 // public Point computeSize(int wHint, int hHint, boolean changed) {
1270 // Point p = super.computeSize(wHint, hHint, changed);
1271 // System.err.println("graphExplorerComposite.computeSize " + p);