1 /*******************************************************************************
2 * Copyright (c) 2007, 2018 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;
21 import org.eclipse.core.runtime.IAdaptable;
22 import org.eclipse.jface.action.IMenuManager;
23 import org.eclipse.jface.layout.GridDataFactory;
24 import org.eclipse.jface.layout.GridLayoutFactory;
25 import org.eclipse.jface.layout.TreeColumnLayout;
26 import org.eclipse.jface.resource.JFaceResources;
27 import org.eclipse.jface.resource.LocalResourceManager;
28 import org.eclipse.jface.viewers.ColumnWeightData;
29 import org.eclipse.jface.viewers.ISelectionProvider;
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.dnd.DND;
32 import org.eclipse.swt.dnd.DragSource;
33 import org.eclipse.swt.dnd.DragSourceEvent;
34 import org.eclipse.swt.dnd.DragSourceListener;
35 import org.eclipse.swt.dnd.DropTarget;
36 import org.eclipse.swt.dnd.DropTargetEvent;
37 import org.eclipse.swt.dnd.DropTargetListener;
38 import org.eclipse.swt.dnd.FileTransfer;
39 import org.eclipse.swt.dnd.TextTransfer;
40 import org.eclipse.swt.dnd.Transfer;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Control;
43 import org.eclipse.swt.widgets.Event;
44 import org.eclipse.swt.widgets.Listener;
45 import org.eclipse.swt.widgets.Tree;
46 import org.eclipse.swt.widgets.TreeItem;
47 import org.eclipse.ui.ISelectionListener;
48 import org.eclipse.ui.IWorkbenchSite;
49 import org.eclipse.ui.contexts.IContextService;
50 import org.simantics.Simantics;
51 import org.simantics.browsing.ui.BuiltinKeys;
52 import org.simantics.browsing.ui.Column;
53 import org.simantics.browsing.ui.ExplorerState;
54 import org.simantics.browsing.ui.GraphExplorer;
55 import org.simantics.browsing.ui.GraphExplorer.TransientExplorerState;
56 import org.simantics.browsing.ui.NodeContext;
57 import org.simantics.browsing.ui.StatePersistor;
58 import org.simantics.browsing.ui.common.AdaptableHintContext;
59 import org.simantics.browsing.ui.common.ColumnKeys;
60 import org.simantics.browsing.ui.common.EvaluatorData;
61 import org.simantics.browsing.ui.common.EvaluatorDataImpl;
62 import org.simantics.browsing.ui.common.processors.ComparableFactoryResolver;
63 import org.simantics.browsing.ui.common.processors.ComparableSelectorQueryProcessor;
64 import org.simantics.browsing.ui.common.processors.FilterSelectionRequestQueryProcessor;
65 import org.simantics.browsing.ui.common.processors.ImageDecoratorFactoryResolver;
66 import org.simantics.browsing.ui.common.processors.ImagerFactoryResolver;
67 import org.simantics.browsing.ui.common.processors.LabelDecoratorFactoryResolver;
68 import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver;
69 import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor;
70 import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor;
71 import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver;
72 import org.simantics.browsing.ui.common.state.ExplorerStates;
73 import org.simantics.browsing.ui.common.views.FilterAreaSource;
74 import org.simantics.browsing.ui.common.views.IFilterArea;
75 import org.simantics.browsing.ui.common.views.IFilterAreaProvider;
76 import org.simantics.browsing.ui.graph.impl.AsyncReadGraphDataSource;
77 import org.simantics.browsing.ui.graph.impl.Evaluators;
78 import org.simantics.browsing.ui.graph.impl.InheritsQueryProcessor;
79 import org.simantics.browsing.ui.graph.impl.ReadGraphDataSource;
80 import org.simantics.browsing.ui.graph.impl.RelatedObjectsQueryProcessor;
81 import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
82 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
83 import org.simantics.browsing.ui.model.nodetypes.NodeType;
84 import org.simantics.browsing.ui.swt.ComparatorSelector;
85 import org.simantics.browsing.ui.swt.ContextMenuInitializer;
86 import org.simantics.browsing.ui.swt.DefaultExplorerSelectionListener;
87 import org.simantics.browsing.ui.swt.DefaultIsCheckedProcessor2;
88 import org.simantics.browsing.ui.swt.DefaultKeyListener;
89 import org.simantics.browsing.ui.swt.DefaultMouseListener;
90 import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver;
91 import org.simantics.browsing.ui.swt.FilterArea;
92 import org.simantics.browsing.ui.swt.GraphExplorerFactory;
93 import org.simantics.browsing.ui.swt.IContextMenuInitializer;
94 import org.simantics.browsing.ui.swt.RootFilterArea;
95 import org.simantics.browsing.ui.swt.StandardContextTypesQueryProcessor;
96 import org.simantics.browsing.ui.swt.TypesQueryProcessor;
97 import org.simantics.browsing.ui.swt.ViewpointSelector;
98 import org.simantics.browsing.ui.swt.widgets.impl.Widget;
99 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;
100 import org.simantics.db.AsyncReadGraph;
101 import org.simantics.db.ReadGraph;
102 import org.simantics.db.Resource;
103 import org.simantics.db.Session;
104 import org.simantics.db.exception.DatabaseException;
105 import org.simantics.db.layer0.SelectionHints;
106 import org.simantics.db.layer0.request.PossibleVariable;
107 import org.simantics.db.layer0.request.PossibleVariableRepresents;
108 import org.simantics.db.layer0.variable.Variable;
109 import org.simantics.db.management.ISessionContext;
110 import org.simantics.db.management.ISessionContextChangedListener;
111 import org.simantics.db.management.ISessionContextProvider;
112 import org.simantics.db.management.SessionContextChangedEvent;
113 import org.simantics.project.ProjectKeys;
114 import org.simantics.ui.SimanticsUI;
115 import org.simantics.ui.dnd.LocalObjectTransfer;
116 import org.simantics.ui.dnd.LocalSelectionDragSourceListener;
117 import org.simantics.ui.dnd.NoImageDragSourceEffect;
118 import org.simantics.ui.dnd.SessionContainer;
119 import org.simantics.ui.selection.AnyResource;
120 import org.simantics.ui.selection.AnyVariable;
121 import org.simantics.ui.selection.ExplorerColumnContentType;
122 import org.simantics.ui.selection.ExplorerInputContentType;
123 import org.simantics.ui.selection.WorkbenchSelectionContentType;
124 import org.simantics.ui.selection.WorkbenchSelectionElement;
125 import org.simantics.ui.selection.WorkbenchSelectionUtils;
126 import org.simantics.utils.ObjectUtils;
127 import org.simantics.utils.datastructures.Function;
128 import org.simantics.utils.datastructures.disposable.DisposeState;
129 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
130 import org.simantics.utils.datastructures.hints.HintTracker;
131 import org.simantics.utils.datastructures.hints.IHintContext.Key;
132 import org.simantics.utils.datastructures.hints.IHintListener;
133 import org.simantics.utils.datastructures.hints.IHintObservable;
134 import org.simantics.utils.datastructures.hints.IHintTracker;
135 import org.simantics.utils.ui.SWTUtils;
136 import org.slf4j.Logger;
137 import org.slf4j.LoggerFactory;
140 public class GraphExplorerComposite extends Composite implements Widget, IAdaptable {
142 private static final Logger LOGGER = LoggerFactory.getLogger(GraphExplorerComposite.class);
144 protected UserSelectedComparableFactoryQueryProcessor userSelectedComparableFactoryQueryProcessor;
145 protected UserSelectedViewpointFactoryQueryProcessor userSelectedViewpointFactoryQueryProcessor;
146 protected FilterSelectionRequestQueryProcessor filterSelectionRequestQueryProcessor;
147 protected IFilterArea filterArea;
148 protected EvaluatorData evaluatorData;
150 protected LocalResourceManager resourceManager;
152 protected ISelectionListener workbenchSelectionListener;
154 private final int style;
156 final private IWorkbenchSite site;
158 protected GraphExplorer explorer;
160 protected IMenuManager menuManager;
162 private final Map<String, Object> args;
164 protected ISessionContextProvider contextProvider;
166 private ISessionContext sessionContext;
168 private Object dragSource;
170 private IHintTracker sessionContextTracker = new SessionContextProjectTracker();
172 private InputSource inputSource = new DirectInputSource();
173 private FilterAreaSource filterAreaSource = new SelectionFilterAreaSource();
175 private final TreeColumnLayout ad;
176 private String[] editingColumn = ColumnKeys.KEYS_SINGLE;
178 private StatePersistor persistor = null;
180 private final Composite toolComposite;
181 private final Composite toolComposite2;
182 private final Composite explorerComposite;
183 final private WidgetSupport support;
184 private final boolean useNodeBrowseContexts;
185 private final boolean useNodeActionContexts;
187 static class SelectionElement extends AdaptableHintContext {
189 final public WorkbenchSelectionElement wse;
190 final public Object content;
191 final public Resource resource;
192 final public Variable variable;
193 final public Object input;
194 final public TransientExplorerState explorerState;
196 private WorkbenchSelectionElement extractWse(Object content) {
197 if(content instanceof NodeContext) {
198 NodeContext context = (NodeContext)content;
199 Object input = context.getConstant(NodeType.TYPE);
200 if(input instanceof NodeType)
201 return ((NodeType)input).getWorkbenchSelectionElement(context);
206 private Resource extractResource(Object content) {
207 if(content instanceof NodeContext) {
208 NodeContext context = (NodeContext)content;
209 Object input = context.getConstant(BuiltinKeys.INPUT);
210 if(input instanceof Resource) return (Resource)input;
211 if(input instanceof IAdaptable) {
212 Resource var = (Resource)((IAdaptable)input).getAdapter(Resource.class);
213 if(var != null) return var;
219 private Variable extractVariable(Object content) {
220 if(content instanceof NodeContext) {
221 NodeContext context = (NodeContext)content;
222 Object input = context.getConstant(BuiltinKeys.INPUT);
223 if(input instanceof Variable) return (Variable)input;
224 if(input instanceof IAdaptable) {
225 Variable var = (Variable)((IAdaptable)input).getAdapter(Variable.class);
226 if(var != null) return var;
232 private Object extractInput(Object content) {
233 if(content instanceof NodeContext) {
234 NodeContext context = (NodeContext)content;
235 return context.getConstant(BuiltinKeys.INPUT);
240 public SelectionElement(GraphExplorer explorer, Key[] keys, Object content) {
242 this.content = content;
243 this.wse = extractWse(content);
244 this.resource = extractResource(content);
245 this.variable = extractVariable(content);
246 this.input = extractInput(content);
247 this.explorerState = explorer.getTransientState();
250 @SuppressWarnings("unchecked")
252 public <T> T getContent(WorkbenchSelectionContentType<T> contentType) {
254 T result = wse.getContent(contentType);
259 if (contentType instanceof AnyResource) {
260 if (resource != null)
262 if (variable == null)
265 return (T) ((AnyResource) contentType).processor.syncRequest(new PossibleVariableRepresents(variable));
266 } catch (DatabaseException e) {
267 LOGGER.error("Unexpected error occurred while resolving Resource from Variable " + variable, e);
270 else if (contentType instanceof AnyVariable) {
271 if (variable != null)
273 if (resource == null)
276 return (T) ((AnyVariable) contentType).processor.syncRequest(new PossibleVariable(resource));
277 } catch (DatabaseException e) {
278 LOGGER.error("Unexpected error occurred while resolving Variable from Resource " + resource, e);
280 } else if (contentType instanceof ExplorerInputContentType) {
282 } else if (contentType instanceof ExplorerColumnContentType) {
283 return (T) explorerState.getActiveColumn();
288 @SuppressWarnings("rawtypes")
290 public Object getAdapter(Class adapter) {
291 if(WorkbenchSelectionElement.class == adapter) {
294 if(NodeContext.class == adapter) {
295 if(content instanceof NodeContext)
296 return (NodeContext)content;
300 return super.getAdapter(adapter);
304 private BiFunction<GraphExplorer, Object[], Object[]> selectionTransformation = new BiFunction<GraphExplorer, Object[], Object[]>() {
306 private Key[] KEYS = new Key[] { SelectionHints.KEY_MAIN };
309 public Object[] apply(GraphExplorer explorer, Object[] objects) {
310 Object[] result = new Object[objects.length];
311 for (int i = 0; i < objects.length; i++) {
312 SelectionElement context = new SelectionElement(explorer, KEYS, objects[i]);
313 context.setHint(SelectionHints.KEY_MAIN, objects[i]);
321 private Set<String> browseContexts = null;
323 private DisposeState disposeState = DisposeState.Alive;
325 private boolean created = false;
327 protected String contextMenuId = null;
329 protected Set<String> uiContext = null;
331 protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {
333 public void sessionContextChanged(SessionContextChangedEvent event) {
334 sessionContext = event.getNewValue();
335 sessionContextTracker.track(sessionContext);
339 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, WidgetSupport support, int style) {
341 super(parent, SWT.NONE);
344 args = Collections.emptyMap();
349 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), this);
351 contextProvider = getSessionContextProvider(site);
353 Integer maxChildren = (Integer)args.get("maxChildren");
355 GridLayoutFactory.fillDefaults().equalWidth(false).numColumns(1).margins(0,0).spacing(0,0).applyTo(this);
357 toolComposite = new Composite(this, SWT.NONE);
358 // toolComposite.setBackground(toolComposite.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
359 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
360 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite);
361 GridLayoutFactory.fillDefaults().applyTo(toolComposite);
363 ad = new TreeColumnLayout();
364 explorerComposite = new Composite(this, SWT.NONE);
365 explorerComposite.setLayout(ad);
366 GridDataFactory.fillDefaults().grab(true, true).minSize(1, 50).applyTo(explorerComposite);
368 if (args.containsKey("treeView") && Boolean.TRUE.equals(args.get("treeView"))) {
369 explorer = createExplorerControl2(explorerComposite, maxChildren);
370 } else if (args.containsKey("natTable") && Boolean.TRUE.equals(args.get("natTable"))) {
371 explorer = createExplorerControl3(explorerComposite, maxChildren);
373 explorer = createExplorerControl(explorerComposite, maxChildren);
376 if (args.containsKey("useNodeBrowseContexts") && Boolean.TRUE.equals(args.get("useNodeBrowseContexts"))) {
377 useNodeBrowseContexts = true;
379 useNodeBrowseContexts = false;
382 if (args.containsKey("useNodeActionContexts") && Boolean.TRUE.equals(args.get("useNodeActionContexts"))) {
383 useNodeActionContexts = true;
385 useNodeActionContexts = false;
388 toolComposite2 = new Composite(this, SWT.NONE);
389 // toolComposite2.setBackground(toolComposite2.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
390 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
391 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite2);
392 GridLayoutFactory.fillDefaults().applyTo(toolComposite2);
394 this.support = support;
397 support.register(this);
401 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, int style) {
403 this(args, site, parent, null, style);
407 public ISessionContextProvider getSessionContextProvider(IWorkbenchSite site) {
409 return SimanticsUI.getSessionContextProvider(site.getWorkbenchWindow());
411 return Simantics.getSessionContextProvider();
414 public GraphExplorer getExplorer() {
418 public Composite getExplorerComposite() {
419 return explorerComposite;
422 public <T> T getExplorerControl() {
423 return explorer.getControl();
426 public void addListenerToControl(int eventType, Listener listener) {
427 ((Control)explorer.getControl()).addListener(eventType, listener);
430 public void removeListenerFromControl(int eventType, Listener listener) {
431 ((Control)explorer.getControl()).removeListener(eventType, listener);
434 public void finish() {
436 createControls(site);
440 IWorkbenchSite getSite() {
444 protected void activateUiContexts() {
445 Collection<String> contexts = getUiContexts();
446 if (contexts == null || contexts.isEmpty())
448 IWorkbenchSite site = getSite();
450 IContextService cs = (IContextService) getSite().getService(IContextService.class);
451 for (String context : contexts)
452 cs.activateContext(context);
456 protected void createControls(IWorkbenchSite site) {
458 // Initialize explorer control.
459 // GridDataFactory.fillDefaults().grab(true, true).applyTo(explorer.getControl());
461 Control control = explorer.getControl();
463 // Initialize context menu if an initializer is provided.
464 IContextMenuInitializer cmi = getContextMenuInitializer();
466 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
467 menuManager = cmi.createContextMenu(control, selectionProvider, site);
470 // Initialize UI contexts
471 activateUiContexts();
474 dragSource = setupDND(explorer);
476 // Listeners are only added once per listener, not every time the
477 // session context changes.
478 addListeners(explorer, menuManager);
480 userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor();
481 userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor();
482 filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor();
484 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
486 boolean hasExtraControls = false;
487 boolean hasExtraControls2 = false;
489 Boolean displaySelectors = (Boolean)args.get("displaySelectors");
490 if(displaySelectors == null || displaySelectors == true) {
492 @SuppressWarnings("unused")
493 ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
494 // comparatorSelector.moveAbove(control);
496 @SuppressWarnings("unused")
497 ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
498 // viewpointSelector.moveAbove(control);
500 hasExtraControls = true;
504 Boolean displayFilter = (Boolean)args.get("displayFilter");
505 if(displayFilter == null || displayFilter == true) {
508 filterArea = filterAreaSource.getFilterArea(toolComposite, explorer);
509 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite, SWT.READ_ONLY);
510 //filterArea.moveAbove(control);
512 hasExtraControls = true;
516 Boolean displayFilter2 = (Boolean)args.get("displayFilter2");
517 if(displayFilter2 != null && displayFilter2 == true) {
519 filterArea = filterAreaSource.getFilterArea(toolComposite2, explorer);
520 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite2, SWT.READ_ONLY);
521 // //filterArea.moveAbove(control);
523 hasExtraControls2 = true;
527 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, this, SWT.READ_ONLY);
528 // filterArea.moveAbove(control);
530 if(!hasExtraControls)
531 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite);
532 if(!hasExtraControls2)
533 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite2);
535 GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control);
537 //tree.getTree().setLayout(new FillLayout()
538 //this.setLayout(LayoutUtils.createNoBorderGridLayout(2, false));
540 DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_DEFAULT);
541 target.setTransfer(getAcceptedDataTypes());
542 if (control instanceof Tree) {
543 target.addDropListener(new DropTargetListener() {
545 Tree tree = (Tree)explorer.getControl();
548 public void dragEnter(DropTargetEvent event) {
549 event.detail = DND.DROP_COPY;
553 public void dragLeave(DropTargetEvent event) {
557 public void dragOperationChanged(DropTargetEvent event) {
561 public void dragOver(DropTargetEvent event) {
565 public void drop(DropTargetEvent event) {
566 TreeItem item = tree.getItem(tree.toControl(event.x, event.y));
568 Object data = item.getData();
569 if (data instanceof NodeContext)
570 handleDrop(event.data, (NodeContext) data);
571 else if (data instanceof IAdaptable) {
572 IAdaptable a = (IAdaptable) data;
573 handleDrop(event.data, (NodeContext) a.getAdapter(NodeContext.class));
576 handleDrop(event.data, null);
580 public void dropAccept(DropTargetEvent event) {
586 // Add workbench listeners and make sure they are cleaned up
587 setWorkbenchListeners();
588 control.addListener(SWT.Dispose, new Listener() {
590 public void handleEvent(Event event) {
596 @SuppressWarnings({ "rawtypes", "unchecked" })
598 public Object getAdapter(Class adapter) {
599 if (GraphExplorer.class == adapter)
601 if (EvaluatorData.class == adapter)
602 return evaluatorData;
603 if (BrowseContext.class == adapter) {
604 EvaluatorData ed = evaluatorData;
605 return ed != null ? ed.getBrowseContext() : null;
607 if (adapter == IFilterAreaProvider.class)
609 return explorer.getAdapter(adapter);
612 protected void doDispose() {
613 //System.out.println(this + ".GraphExplorerComposite.doDispose()");
614 removeWorkbenchListeners();
615 userSelectedComparableFactoryQueryProcessor = null;
616 userSelectedViewpointFactoryQueryProcessor = null;
617 filterSelectionRequestQueryProcessor = null;
619 disposeState = DisposeState.Disposing;
621 //System.out.println(this + ".GraphExplorerViewBase.dispose()");
622 if (contextProvider != null) {
623 contextProvider.removeContextChangedListener(contextChangeListener);
624 contextProvider = null;
626 sessionContextTracker.untrack();
627 resourceManager = null;
629 sessionContext = null;
633 disposeState = DisposeState.Disposed;
638 public void dispose() {
643 protected StatePersistor getStatePersistor() {
647 public void setStatePersistor(StatePersistor persistor) {
648 this.persistor = persistor;
651 protected void initializeExplorer(GraphExplorer explorer, ISessionContext context) {
653 if(explorer == null || explorer.isDisposed()) return;
654 if(context == null) return;
655 if(browseContexts == null) return;
657 Session session = context != null ? context.getSession() : null;
658 setupDragSource(session);
660 if (session != null) {
661 evaluatorData = createEvaluatorData(session);
662 explorer.setDataSource(new AsyncReadGraphDataSource(session));
663 explorer.setDataSource(new ReadGraphDataSource(session));
666 evaluatorData = new EvaluatorDataImpl();
667 explorer.removeDataSource(AsyncReadGraph.class);
668 explorer.removeDataSource(ReadGraph.class);
671 explorer.setPersistor(getStatePersistor());
673 explorer.setProcessor(new ComparableFactoryResolver(evaluatorData));
674 explorer.setProcessor(new ViewpointFactoryResolver(evaluatorData));
675 explorer.setProcessor(new LabelerFactoryResolver(evaluatorData));
676 explorer.setProcessor(new ImagerFactoryResolver(evaluatorData));
677 explorer.setProcessor(new LabelDecoratorFactoryResolver(evaluatorData));
678 explorer.setProcessor(new ImageDecoratorFactoryResolver(evaluatorData));
679 explorer.setProcessor(new DefaultIsCheckedProcessor2(evaluatorData));
680 explorer.setPrimitiveProcessor(new TypesQueryProcessor());
681 explorer.setPrimitiveProcessor(new StandardContextTypesQueryProcessor());
682 explorer.setPrimitiveProcessor(new InheritsQueryProcessor());
683 explorer.setPrimitiveProcessor(new RelatedObjectsQueryProcessor());
685 explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor);
686 explorer.setProcessor(new ComparableSelectorQueryProcessor());
687 explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor);
688 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
690 initializeExplorerWithEvaluator(explorer, context, evaluatorData);
693 protected void initializeExplorerWithEvaluator(GraphExplorer explorer, ISessionContext context, EvaluatorData data) {
696 protected EvaluatorData createEvaluatorData(Session context) {
698 // Set<String> browseContexts = getArgument("browseContexts");
700 return Evaluators.load(context.getSession(), browseContexts, resourceManager, useNodeBrowseContexts, useNodeActionContexts);
704 protected Transfer[] getAcceptedDataTypes() {
705 return new Transfer[] { LocalObjectTransfer.getTransfer(), FileTransfer.getInstance(), TextTransfer.getInstance() };
708 protected void handleDrop(Object data, NodeContext target) {
711 DragSourceListenerFactory dragSourceListenerFactory = new DragSourceListenerFactory() {
713 final Transfer[] transfers = new Transfer[] {LocalObjectTransfer.getTransfer(), TextTransfer.getInstance() };
716 public DragSourceListener get(ISelectionProvider selectionProvider) {
718 LocalSelectionDragSourceListener ls = new LocalSelectionDragSourceListener(selectionProvider);
720 return new DragSourceListener() {
723 public void dragStart(DragSourceEvent event) {
728 public void dragSetData(DragSourceEvent event) {
729 if(TextTransfer.getInstance().isSupportedType(event.dataType)) {
731 event.data = WorkbenchSelectionUtils.getPossibleJSON(selectionProvider.getSelection());
732 } catch (DatabaseException e) {
733 event.data = "{ type:\"Exception\" }";
734 LOGGER.error("Failed to get current selection as JSON.", e);
736 } else if (LocalObjectTransfer.getTransfer().isSupportedType(event.dataType)) {
737 ls.dragSetData(event);
742 public void dragFinished(DragSourceEvent event) {
743 ls.dragFinished(event);
749 public Transfer[] getTransfers() {
755 public void setDragSourceListenerFactory(DragSourceListenerFactory dragSourceListenerFactory) {
756 this.dragSourceListenerFactory = dragSourceListenerFactory;
759 protected DragSourceListener setupDND(GraphExplorer explorer) {
761 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
763 DragSourceListener listener = createDragSourceListener(selectionProvider);
765 Control control = explorer.getControl();
766 DragSource source = createDragSource(control);
767 source.setTransfer(getTransfers());
768 source.addDragListener(listener);
769 source.setDragSourceEffect(new NoImageDragSourceEffect(control));
775 protected DragSourceListener createDragSourceListener(ISelectionProvider selectionProvider) {
776 return dragSourceListenerFactory.get(selectionProvider);
779 private int dragStyle = DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
781 protected void setDragStyle(int style) {
782 this.dragStyle = style;
785 protected int getDragStyle() {
789 protected DragSource createDragSource(Control control) {
790 return new DragSource(control, getDragStyle());
793 protected Transfer[] getTransfers() {
794 return dragSourceListenerFactory.getTransfers();
797 public EvaluatorData getEvaluatorData() {
798 return evaluatorData;
801 public interface InputSource {
803 * @param ctx the session context to read the input from. May be
804 * <code>null</code> if there is no session.
805 * @return the input object of a graph explorer. To indicate no input,
806 * use {@link GraphExplorerConstants#EMPTY_INPUT}. Never return
809 Object get(ISessionContext ctx, Object selection);
812 public interface FilterSource {
819 * The default hint tracker that will be active if
820 * {@link GraphExplorerComposite#setSessionContextTracker(IHintTracker) is
823 public class SessionContextProjectTracker extends HintTracker {
824 public SessionContextProjectTracker() {
825 IHintListener activeProjectListener = new HintListenerAdapter() {
827 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
828 applySessionContext(getSessionContext());
831 addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);
835 public class DirectInputSource implements InputSource {
837 public Object get(ISessionContext ctx, Object selection) {
842 public static class SelectionFilterAreaSource implements FilterAreaSource {
845 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
846 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
847 return new FilterArea(explorer, processor, parent, SWT.READ_ONLY);
852 public static class RootFilterAreaSource implements FilterAreaSource {
855 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
856 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
857 return new RootFilterArea(explorer, processor, parent, SWT.READ_ONLY);
862 protected void setSessionContextTracker(IHintTracker tracker) {
863 this.sessionContextTracker = tracker;
866 public void setInputSource(InputSource source) {
867 this.inputSource = source;
870 public void setFilterAreaSource(FilterAreaSource provider) {
871 this.filterAreaSource = provider;
874 public void setSelectionTransformation(BiFunction<GraphExplorer, Object[], Object[]> transformation) {
875 this.selectionTransformation = transformation;
876 if(explorer != null) explorer.setSelectionTransformation(transformation);
879 protected Set<String> getBrowseContexts() {
880 return browseContexts;
883 public void setBrowseContexts(Set<String> contexts) {
884 this.browseContexts = contexts;
885 //initializeExplorer(explorer, getSessionContext());
888 public void setBrowseContexts(String ... contexts) {
889 this.browseContexts = new HashSet<String>();
890 for(String s : contexts) this.browseContexts.add(s);
891 initializeExplorer(explorer, getSessionContext());
894 public void setContextMenuId(String contextMenuId) {
895 this.contextMenuId = contextMenuId;
898 // protected IContextMenuInitializer getContextMenuInitializer() {
899 // String contextMenuId = getContextMenuId();
900 // if(contextMenuId != null) {
901 // return new ContextMenuInitializer(contextMenuId);
907 protected String getContextMenuId() {
908 return this.contextMenuId;
911 public void setUiContexts(Set<String> uiContext) {
912 this.uiContext = uiContext;
915 public Set<String> getUiContexts() {
919 protected InputSource getInputSource() {
923 protected Map<String, Object> getArguments() {
927 @SuppressWarnings("unchecked")
928 protected <T> T getArgument(String key) {
929 return (T) args.get(key);
932 protected DisposeState getDisposeState() {
936 public ISessionContext getSessionContext() {
937 return sessionContext;
940 public ISessionContextProvider getSessionContextProvider() {
941 return contextProvider;
945 public boolean setFocus() {
946 if (explorer != null && !explorer.isDisposed())
951 public void setWorkbenchListeners() {
952 if (workbenchSelectionListener == null && getSite() != null) {
953 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
954 getSite().setSelectionProvider(selectionProvider);
956 // Listen to the workbench selection also to propagate it to
957 // the explorer also.
958 workbenchSelectionListener = new DefaultExplorerSelectionListener(site.getPage().getActivePart(), explorer);
959 //System.out.println("ADD WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
960 getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener);
964 protected void removeWorkbenchListeners() {
965 //System.out.println("REMOVE WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
966 // Remember to remove the installed workbench selection listener
967 if (workbenchSelectionListener != null) {
968 getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener);
969 workbenchSelectionListener = null;
971 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
972 if(getSite().getSelectionProvider() == selectionProvider) getSite().setSelectionProvider(null);
977 protected final void attachToSession() {
979 // Track active ISessionContext changes
980 //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());
981 contextProvider.addContextChangedListener(contextChangeListener);
983 // Start tracking the current session context for input changes.
984 // This will/must cause applySessionContext to get called.
985 // Doing the applySessionContext initialization this way
986 // instead of directly calling it will also make sure that
987 // applySessionContext is only called once when first initialized,
988 // and not twice like with the direct invocation.
989 this.sessionContext = contextProvider.getSessionContext();
990 sessionContextTracker.track(sessionContext);
993 // /////////////////////////////////////////////////////////////////////////
994 // Override / implement these:
997 // * Returns an ID that is used for persisting a GraphExplorer instance.
999 // * Used for </code>restoreState(IMemento)</code> and
1000 // * <code>restoreState(IMemento)</code> in OntologyExplorer. Must be unique
1001 // * within a workbench part.
1003 // * @return a unique name for this particular graph explorer view used for
1004 // * saving and restoring the state of this view part
1006 // public String getExplorerName() {
1007 // return "GraphExplorerViewBase";
1011 * Override this method to add controls to the view part. This is invoked
1012 * before attaching the view part to a database session.
1016 protected void createControls(Composite parent) {
1021 * Override this method and provide a proper context menu initializer if you
1022 * want to have this base class initialize one for you.
1024 * @return the initializer to be used by {@link #createControls(Composite)}
1026 protected IContextMenuInitializer getContextMenuInitializer() {
1027 String contextMenuId = getContextMenuId();
1028 if(contextMenuId != null) {
1029 return new ContextMenuInitializer(contextMenuId);
1039 protected GraphExplorer createExplorerControl(Composite parent, Integer maxChildren) {
1040 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1041 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1043 GraphExplorer ge = factory
1044 .selectionDataResolver(new DefaultSelectionDataResolver())
1045 .selectionTransformation(selectionTransformation)
1046 .setServiceLocator(site)
1047 .create(parent, style);
1052 protected GraphExplorer createExplorerControl2(Composite parent, Integer maxChildren) {
1053 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1054 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1056 GraphExplorer ge = factory
1057 .selectionDataResolver(new DefaultSelectionDataResolver())
1058 .selectionTransformation(selectionTransformation)
1059 .setServiceLocator(site)
1060 .create2(parent, style);
1065 protected GraphExplorer createExplorerControl3(Composite parent, Integer maxChildren) {
1066 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1067 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1069 GraphExplorer ge = factory
1070 .selectionDataResolver(new DefaultSelectionDataResolver())
1071 .selectionTransformation(selectionTransformation)
1072 .setServiceLocator(site)
1073 .create3(parent, style);
1078 protected void setupDragSource(Session session) {
1079 if (dragSource instanceof SessionContainer) {
1080 ((SessionContainer) dragSource).setSession(session);
1085 * Override to customize the addition of listeners a newly created
1090 protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {
1091 addSelectionInputListeners(explorer, menuManager);
1094 protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {
1095 // Consider ENTER presses to simulate mouse left button double clicks
1096 explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function<String[]>() {
1098 public String[] execute(Object... obj) {
1099 return getEditingColumn((NodeContext) obj[0]);
1102 // Default double click handling
1103 explorer.addListener(new DefaultMouseListener(explorer));
1106 protected String[] getEditingColumn(NodeContext context) {
1107 return editingColumn;
1110 public void setEditingColumn(String... columnKeysInOrderOfTrial) {
1111 this.editingColumn = columnKeysInOrderOfTrial;
1114 // Needed for preventing unnecessary re-initialization of the explorer with the same input.
1115 private Object currentInput;
1116 private Object currentRoot;
1119 * Invoke this to reinitialize the explorer and reset its input. The input
1120 * will be resolved from the specified ISessionContext based on the
1121 * {@link SessionContextInputSource} that is currently in use. If the input
1122 * is identical to the previous input, nothing will be done.
1126 public final boolean applySessionContext(ISessionContext context) {
1128 // If control is not alive anymore, do nothing.
1129 //System.out.println(this + ": applySessionContext(" + context + "), explorer=" + explorer);
1130 if (disposeState != DisposeState.Alive)
1133 //System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");
1134 initializeExplorer(explorer, context);
1137 // Start tracking the session context.
1139 // If this is not the same session that is currently tracked, it will
1140 // cause IHintListeners of the sessionContextTracker to fire.
1141 // For this we need the above input equality (identity) checking.
1142 // This is here just to make sure that we are tracking the correct
1144 sessionContextTracker.track(sessionContext);
1146 this.sessionContext = context;
1147 Object root = inputSource.get(context, currentInput);
1148 if (ObjectUtils.objectEquals(root, currentRoot))
1153 //System.out.println(this + ": setRoot(" + input + ")");
1154 explorer.setUIContexts(uiContext);
1155 explorer.setRoot(root);
1161 protected boolean isImportantInput(Object previousSelection, Object selection) {
1162 return !ObjectUtils.objectEquals(previousSelection, selection);
1165 public void setInput(Object selection, boolean force) {
1171 if (sessionContext == null)
1174 // Check if this is a duplicate of the previous selection to reduce unnecessary flicker.
1175 if (!force && !isImportantInput(currentInput, selection))
1178 currentInput = selection;
1180 Object root = inputSource.get(sessionContext, selection);
1184 explorer.setUIContexts(uiContext);
1187 explorer.setRoot(GraphExplorer.EMPTY_INPUT);
1189 explorer.setRoot(root);
1194 public void setColumnsVisible(boolean visible) {
1195 explorer.setColumnsVisible(visible);
1198 private int getColumnWidth(Column column, ExplorerState state) {
1199 // Get saved width from the persistor if there is one.
1200 if (state != null && state.columnWidths != null) {
1201 Integer width = state.columnWidths.get(column.getLabel());
1205 return column.getWidth();
1208 protected void restoreColumnSizes(Map<Column, Object> columns) {
1209 if (persistor != null) {
1210 setColumnData(columns, null);
1211 ExplorerStates.scheduleRead(explorer.getRoot(), persistor).thenAccept(state -> {
1212 SWTUtils.asyncExec(GraphExplorerComposite.this, () -> {
1213 if (explorerComposite.isDisposed())
1214 setColumnData(columns, state);
1218 setColumnData(columns, null);
1222 protected void setColumnData(Map<Column, Object> columns, ExplorerState state) {
1223 columns.forEach((column, widget) -> {
1224 org.eclipse.swt.widgets.Widget columnWidget = (org.eclipse.swt.widgets.Widget) widget;
1225 ad.setColumnData(columnWidget,
1226 new ColumnWeightData(
1227 column.hasGrab() ? column.getWeight() : 0,
1228 getColumnWidth(column, state)));
1232 public void setColumns(Column[] columns) {
1233 // ColumnWeightData does not support column weight/width < 0
1234 for (Column column : columns) {
1235 if (column.getWeight() < 0)
1236 throw new IllegalArgumentException("Column weight must be >= 0, got " + column.getWeight() + " for " + column);
1237 if (column.getWidth() < 0)
1238 throw new IllegalArgumentException("Column minimum width must be >= 0, got " + column.getWidth() + " for " + column);
1240 explorer.setColumns(columns, this::restoreColumnSizes);
1244 public void setInput(ISessionContext context, Object input) {
1245 setInput(input, false);
1248 public void setMaxChildren(int maxChildren) {
1249 explorer.setMaxChildren(maxChildren);
1252 public <T> void addListener(ExplorerMouseListenerImpl<T> listener) {
1254 support.register(listener);
1255 listener.register(explorer);
1256 explorer.addListener(listener);
1261 // public Point computeSize(int wHint, int hHint) {
1262 // Point p = super.computeSize(wHint, hHint);
1263 // System.err.println("graphExplorerComposite.computeSize " + p);
1268 // public Point computeSize(int wHint, int hHint, boolean changed) {
1269 // Point p = super.computeSize(wHint, hHint, changed);
1270 // System.err.println("graphExplorerComposite.computeSize " + p);