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.browsing.ui.BuiltinKeys;
51 import org.simantics.browsing.ui.Column;
52 import org.simantics.browsing.ui.ExplorerState;
53 import org.simantics.browsing.ui.GraphExplorer;
54 import org.simantics.browsing.ui.GraphExplorer.TransientExplorerState;
55 import org.simantics.browsing.ui.NodeContext;
56 import org.simantics.browsing.ui.StatePersistor;
57 import org.simantics.browsing.ui.common.AdaptableHintContext;
58 import org.simantics.browsing.ui.common.ColumnKeys;
59 import org.simantics.browsing.ui.common.EvaluatorData;
60 import org.simantics.browsing.ui.common.EvaluatorDataImpl;
61 import org.simantics.browsing.ui.common.processors.ComparableFactoryResolver;
62 import org.simantics.browsing.ui.common.processors.ComparableSelectorQueryProcessor;
63 import org.simantics.browsing.ui.common.processors.FilterSelectionRequestQueryProcessor;
64 import org.simantics.browsing.ui.common.processors.ImageDecoratorFactoryResolver;
65 import org.simantics.browsing.ui.common.processors.ImagerFactoryResolver;
66 import org.simantics.browsing.ui.common.processors.LabelDecoratorFactoryResolver;
67 import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver;
68 import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor;
69 import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor;
70 import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver;
71 import org.simantics.browsing.ui.common.state.ExplorerStates;
72 import org.simantics.browsing.ui.common.views.FilterAreaSource;
73 import org.simantics.browsing.ui.common.views.IFilterArea;
74 import org.simantics.browsing.ui.common.views.IFilterAreaProvider;
75 import org.simantics.browsing.ui.graph.impl.AsyncReadGraphDataSource;
76 import org.simantics.browsing.ui.graph.impl.Evaluators;
77 import org.simantics.browsing.ui.graph.impl.InheritsQueryProcessor;
78 import org.simantics.browsing.ui.graph.impl.ReadGraphDataSource;
79 import org.simantics.browsing.ui.graph.impl.RelatedObjectsQueryProcessor;
80 import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
81 import org.simantics.browsing.ui.model.browsecontexts.BrowseContext;
82 import org.simantics.browsing.ui.model.nodetypes.NodeType;
83 import org.simantics.browsing.ui.swt.ComparatorSelector;
84 import org.simantics.browsing.ui.swt.ContextMenuInitializer;
85 import org.simantics.browsing.ui.swt.DefaultExplorerSelectionListener;
86 import org.simantics.browsing.ui.swt.DefaultIsCheckedProcessor2;
87 import org.simantics.browsing.ui.swt.DefaultKeyListener;
88 import org.simantics.browsing.ui.swt.DefaultMouseListener;
89 import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver;
90 import org.simantics.browsing.ui.swt.FilterArea;
91 import org.simantics.browsing.ui.swt.GraphExplorerFactory;
92 import org.simantics.browsing.ui.swt.IContextMenuInitializer;
93 import org.simantics.browsing.ui.swt.RootFilterArea;
94 import org.simantics.browsing.ui.swt.StandardContextTypesQueryProcessor;
95 import org.simantics.browsing.ui.swt.TypesQueryProcessor;
96 import org.simantics.browsing.ui.swt.ViewpointSelector;
97 import org.simantics.browsing.ui.swt.widgets.impl.Widget;
98 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;
99 import org.simantics.db.AsyncReadGraph;
100 import org.simantics.db.ReadGraph;
101 import org.simantics.db.Resource;
102 import org.simantics.db.Session;
103 import org.simantics.db.exception.DatabaseException;
104 import org.simantics.db.layer0.SelectionHints;
105 import org.simantics.db.layer0.request.PossibleVariable;
106 import org.simantics.db.layer0.request.PossibleVariableRepresents;
107 import org.simantics.db.layer0.variable.Variable;
108 import org.simantics.db.management.ISessionContext;
109 import org.simantics.db.management.ISessionContextChangedListener;
110 import org.simantics.db.management.ISessionContextProvider;
111 import org.simantics.db.management.SessionContextChangedEvent;
112 import org.simantics.project.ProjectKeys;
113 import org.simantics.ui.SimanticsUI;
114 import org.simantics.ui.dnd.LocalObjectTransfer;
115 import org.simantics.ui.dnd.LocalSelectionDragSourceListener;
116 import org.simantics.ui.dnd.NoImageDragSourceEffect;
117 import org.simantics.ui.dnd.SessionContainer;
118 import org.simantics.ui.selection.AnyResource;
119 import org.simantics.ui.selection.AnyVariable;
120 import org.simantics.ui.selection.ExplorerColumnContentType;
121 import org.simantics.ui.selection.ExplorerInputContentType;
122 import org.simantics.ui.selection.WorkbenchSelectionContentType;
123 import org.simantics.ui.selection.WorkbenchSelectionElement;
124 import org.simantics.ui.selection.WorkbenchSelectionUtils;
125 import org.simantics.utils.ObjectUtils;
126 import org.simantics.utils.datastructures.Function;
127 import org.simantics.utils.datastructures.disposable.DisposeState;
128 import org.simantics.utils.datastructures.hints.HintListenerAdapter;
129 import org.simantics.utils.datastructures.hints.HintTracker;
130 import org.simantics.utils.datastructures.hints.IHintContext.Key;
131 import org.simantics.utils.datastructures.hints.IHintListener;
132 import org.simantics.utils.datastructures.hints.IHintObservable;
133 import org.simantics.utils.datastructures.hints.IHintTracker;
134 import org.simantics.utils.ui.SWTUtils;
135 import org.slf4j.Logger;
136 import org.slf4j.LoggerFactory;
139 public class GraphExplorerComposite extends Composite implements Widget, IAdaptable {
141 private static final Logger LOGGER = LoggerFactory.getLogger(GraphExplorerComposite.class);
143 protected UserSelectedComparableFactoryQueryProcessor userSelectedComparableFactoryQueryProcessor;
144 protected UserSelectedViewpointFactoryQueryProcessor userSelectedViewpointFactoryQueryProcessor;
145 protected FilterSelectionRequestQueryProcessor filterSelectionRequestQueryProcessor;
146 protected IFilterArea filterArea;
147 protected EvaluatorData evaluatorData;
149 protected LocalResourceManager resourceManager;
151 protected ISelectionListener workbenchSelectionListener;
153 private final int style;
155 final private IWorkbenchSite site;
157 protected GraphExplorer explorer;
159 protected IMenuManager menuManager;
161 private final Map<String, Object> args;
163 protected ISessionContextProvider contextProvider;
165 private ISessionContext sessionContext;
167 private Object dragSource;
169 private IHintTracker sessionContextTracker = new SessionContextProjectTracker();
171 private InputSource inputSource = new DirectInputSource();
172 private FilterAreaSource filterAreaSource = new SelectionFilterAreaSource();
174 private final TreeColumnLayout ad;
175 private String[] editingColumn = ColumnKeys.KEYS_SINGLE;
177 private StatePersistor persistor = null;
179 private final Composite toolComposite;
180 private final Composite toolComposite2;
181 private final Composite explorerComposite;
182 final private WidgetSupport support;
183 private final boolean useNodeBrowseContexts;
184 private final boolean useNodeActionContexts;
186 static class SelectionElement extends AdaptableHintContext {
188 final public WorkbenchSelectionElement wse;
189 final public Object content;
190 final public Resource resource;
191 final public Variable variable;
192 final public Object input;
193 final public TransientExplorerState explorerState;
195 private WorkbenchSelectionElement extractWse(Object content) {
196 if(content instanceof NodeContext) {
197 NodeContext context = (NodeContext)content;
198 Object input = context.getConstant(NodeType.TYPE);
199 if(input instanceof NodeType)
200 return ((NodeType)input).getWorkbenchSelectionElement(context);
205 private Resource extractResource(Object content) {
206 if(content instanceof NodeContext) {
207 NodeContext context = (NodeContext)content;
208 Object input = context.getConstant(BuiltinKeys.INPUT);
209 if(input instanceof Resource) return (Resource)input;
210 if(input instanceof IAdaptable) {
211 Resource var = (Resource)((IAdaptable)input).getAdapter(Resource.class);
212 if(var != null) return var;
218 private Variable extractVariable(Object content) {
219 if(content instanceof NodeContext) {
220 NodeContext context = (NodeContext)content;
221 Object input = context.getConstant(BuiltinKeys.INPUT);
222 if(input instanceof Variable) return (Variable)input;
223 if(input instanceof IAdaptable) {
224 Variable var = (Variable)((IAdaptable)input).getAdapter(Variable.class);
225 if(var != null) return var;
231 private Object extractInput(Object content) {
232 if(content instanceof NodeContext) {
233 NodeContext context = (NodeContext)content;
234 return context.getConstant(BuiltinKeys.INPUT);
239 public SelectionElement(GraphExplorer explorer, Key[] keys, Object content) {
241 this.content = content;
242 this.wse = extractWse(content);
243 this.resource = extractResource(content);
244 this.variable = extractVariable(content);
245 this.input = extractInput(content);
246 this.explorerState = explorer.getTransientState();
249 @SuppressWarnings("unchecked")
251 public <T> T getContent(WorkbenchSelectionContentType<T> contentType) {
253 T result = wse.getContent(contentType);
258 if (contentType instanceof AnyResource) {
259 if (resource != null)
261 if (variable == null)
264 return (T) ((AnyResource) contentType).processor.syncRequest(new PossibleVariableRepresents(variable));
265 } catch (DatabaseException e) {
266 LOGGER.error("Unexpected error occurred while resolving Resource from Variable " + variable, e);
269 else if (contentType instanceof AnyVariable) {
270 if (variable != null)
272 if (resource == null)
275 return (T) ((AnyVariable) contentType).processor.syncRequest(new PossibleVariable(resource));
276 } catch (DatabaseException e) {
277 LOGGER.error("Unexpected error occurred while resolving Variable from Resource " + resource, e);
279 } else if (contentType instanceof ExplorerInputContentType) {
281 } else if (contentType instanceof ExplorerColumnContentType) {
282 return (T) explorerState.getActiveColumn();
287 @SuppressWarnings("rawtypes")
289 public Object getAdapter(Class adapter) {
290 if(WorkbenchSelectionElement.class == adapter) {
293 if(NodeContext.class == adapter) {
294 if(content instanceof NodeContext)
295 return (NodeContext)content;
299 return super.getAdapter(adapter);
303 private BiFunction<GraphExplorer, Object[], Object[]> selectionTransformation = new BiFunction<GraphExplorer, Object[], Object[]>() {
305 private Key[] KEYS = new Key[] { SelectionHints.KEY_MAIN };
308 public Object[] apply(GraphExplorer explorer, Object[] objects) {
309 Object[] result = new Object[objects.length];
310 for (int i = 0; i < objects.length; i++) {
311 SelectionElement context = new SelectionElement(explorer, KEYS, objects[i]);
312 context.setHint(SelectionHints.KEY_MAIN, objects[i]);
320 private Set<String> browseContexts = null;
322 private DisposeState disposeState = DisposeState.Alive;
324 private boolean created = false;
326 protected String contextMenuId = null;
328 protected Set<String> uiContext = null;
330 protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {
332 public void sessionContextChanged(SessionContextChangedEvent event) {
333 sessionContext = event.getNewValue();
334 sessionContextTracker.track(sessionContext);
338 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, WidgetSupport support, int style) {
340 super(parent, SWT.NONE);
343 args = Collections.emptyMap();
348 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), this);
350 contextProvider = getSessionContextProvider(site);
352 Integer maxChildren = (Integer)args.get("maxChildren");
354 GridLayoutFactory.fillDefaults().equalWidth(false).numColumns(1).margins(0,0).spacing(0,0).applyTo(this);
356 toolComposite = new Composite(this, SWT.NONE);
357 // toolComposite.setBackground(toolComposite.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
358 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
359 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite);
360 GridLayoutFactory.fillDefaults().applyTo(toolComposite);
362 ad = new TreeColumnLayout();
363 explorerComposite = new Composite(this, SWT.NONE);
364 explorerComposite.setLayout(ad);
365 GridDataFactory.fillDefaults().grab(true, true).minSize(1, 50).applyTo(explorerComposite);
367 if (args.containsKey("treeView") && Boolean.TRUE.equals(args.get("treeView"))) {
368 explorer = createExplorerControl2(explorerComposite, maxChildren);
369 } else if (args.containsKey("natTable") && Boolean.TRUE.equals(args.get("natTable"))) {
370 explorer = createExplorerControl3(explorerComposite, maxChildren);
372 explorer = createExplorerControl(explorerComposite, maxChildren);
375 if (args.containsKey("useNodeBrowseContexts") && Boolean.TRUE.equals(args.get("useNodeBrowseContexts"))) {
376 useNodeBrowseContexts = true;
378 useNodeBrowseContexts = false;
381 if (args.containsKey("useNodeActionContexts") && Boolean.TRUE.equals(args.get("useNodeActionContexts"))) {
382 useNodeActionContexts = true;
384 useNodeActionContexts = false;
387 toolComposite2 = new Composite(this, SWT.NONE);
388 // toolComposite2.setBackground(toolComposite2.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW));
389 // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite);
390 GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite2);
391 GridLayoutFactory.fillDefaults().applyTo(toolComposite2);
393 this.support = support;
396 support.register(this);
400 public GraphExplorerComposite(Map<String, Object> args, IWorkbenchSite site, Composite parent, int style) {
402 this(args, site, parent, null, style);
406 public ISessionContextProvider getSessionContextProvider(IWorkbenchSite site) {
408 return SimanticsUI.getSessionContextProvider(site.getWorkbenchWindow());
410 return SimanticsUI.getSessionContextProvider();
413 public GraphExplorer getExplorer() {
417 public Composite getExplorerComposite() {
418 return explorerComposite;
421 public <T> T getExplorerControl() {
422 return explorer.getControl();
425 public void addListenerToControl(int eventType, Listener listener) {
426 ((Control)explorer.getControl()).addListener(eventType, listener);
429 public void finish() {
431 createControls(site);
435 IWorkbenchSite getSite() {
439 protected void activateUiContexts() {
440 Collection<String> contexts = getUiContexts();
441 if (contexts == null || contexts.isEmpty())
443 IWorkbenchSite site = getSite();
445 IContextService cs = (IContextService) getSite().getService(IContextService.class);
446 for (String context : contexts)
447 cs.activateContext(context);
451 protected void createControls(IWorkbenchSite site) {
453 // Initialize explorer control.
454 // GridDataFactory.fillDefaults().grab(true, true).applyTo(explorer.getControl());
456 Control control = explorer.getControl();
458 // Initialize context menu if an initializer is provided.
459 IContextMenuInitializer cmi = getContextMenuInitializer();
461 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
462 menuManager = cmi.createContextMenu(control, selectionProvider, site);
465 // Initialize UI contexts
466 activateUiContexts();
469 dragSource = setupDND(explorer);
471 // Listeners are only added once per listener, not every time the
472 // session context changes.
473 addListeners(explorer, menuManager);
475 userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor();
476 userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor();
477 filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor();
479 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
481 boolean hasExtraControls = false;
482 boolean hasExtraControls2 = false;
484 Boolean displaySelectors = (Boolean)args.get("displaySelectors");
485 if(displaySelectors == null || displaySelectors == true) {
487 @SuppressWarnings("unused")
488 ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
489 // comparatorSelector.moveAbove(control);
491 @SuppressWarnings("unused")
492 ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, toolComposite, SWT.READ_ONLY);
493 // viewpointSelector.moveAbove(control);
495 hasExtraControls = true;
499 Boolean displayFilter = (Boolean)args.get("displayFilter");
500 if(displayFilter == null || displayFilter == true) {
503 filterArea = filterAreaSource.getFilterArea(toolComposite, explorer);
504 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite, SWT.READ_ONLY);
505 //filterArea.moveAbove(control);
507 hasExtraControls = true;
511 Boolean displayFilter2 = (Boolean)args.get("displayFilter2");
512 if(displayFilter2 != null && displayFilter2 == true) {
514 filterArea = filterAreaSource.getFilterArea(toolComposite2, explorer);
515 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite2, SWT.READ_ONLY);
516 // //filterArea.moveAbove(control);
518 hasExtraControls2 = true;
522 // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, this, SWT.READ_ONLY);
523 // filterArea.moveAbove(control);
525 if(!hasExtraControls)
526 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite);
527 if(!hasExtraControls2)
528 GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite2);
530 GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control);
532 //tree.getTree().setLayout(new FillLayout()
533 //this.setLayout(LayoutUtils.createNoBorderGridLayout(2, false));
535 DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_DEFAULT);
536 target.setTransfer(getAcceptedDataTypes());
537 if (control instanceof Tree) {
538 target.addDropListener(new DropTargetListener() {
540 Tree tree = (Tree)explorer.getControl();
543 public void dragEnter(DropTargetEvent event) {
544 event.detail = DND.DROP_COPY;
548 public void dragLeave(DropTargetEvent event) {
552 public void dragOperationChanged(DropTargetEvent event) {
556 public void dragOver(DropTargetEvent event) {
560 public void drop(DropTargetEvent event) {
561 TreeItem item = tree.getItem(tree.toControl(event.x, event.y));
563 Object data = item.getData();
564 if (data instanceof NodeContext)
565 handleDrop(event.data, (NodeContext) data);
566 else if (data instanceof IAdaptable) {
567 IAdaptable a = (IAdaptable) data;
568 handleDrop(event.data, (NodeContext) a.getAdapter(NodeContext.class));
571 handleDrop(event.data, null);
575 public void dropAccept(DropTargetEvent event) {
581 // Add workbench listeners and make sure they are cleaned up
582 setWorkbenchListeners();
583 control.addListener(SWT.Dispose, new Listener() {
585 public void handleEvent(Event event) {
591 @SuppressWarnings({ "rawtypes", "unchecked" })
593 public Object getAdapter(Class adapter) {
594 if (GraphExplorer.class == adapter)
596 if (EvaluatorData.class == adapter)
597 return evaluatorData;
598 if (BrowseContext.class == adapter) {
599 EvaluatorData ed = evaluatorData;
600 return ed != null ? ed.getBrowseContext() : null;
602 if (adapter == IFilterAreaProvider.class)
604 return explorer.getAdapter(adapter);
607 protected void doDispose() {
608 //System.out.println(this + ".GraphExplorerComposite.doDispose()");
609 removeWorkbenchListeners();
610 userSelectedComparableFactoryQueryProcessor = null;
611 userSelectedViewpointFactoryQueryProcessor = null;
612 filterSelectionRequestQueryProcessor = null;
614 disposeState = DisposeState.Disposing;
616 //System.out.println(this + ".GraphExplorerViewBase.dispose()");
617 if (contextProvider != null) {
618 contextProvider.removeContextChangedListener(contextChangeListener);
619 contextProvider = null;
621 sessionContextTracker.untrack();
622 resourceManager = null;
624 sessionContext = null;
628 disposeState = DisposeState.Disposed;
633 public void dispose() {
638 protected StatePersistor getStatePersistor() {
642 public void setStatePersistor(StatePersistor persistor) {
643 this.persistor = persistor;
646 protected void initializeExplorer(GraphExplorer explorer, ISessionContext context) {
648 if(explorer == null || explorer.isDisposed()) return;
649 if(context == null) return;
650 if(browseContexts == null) return;
652 Session session = context != null ? context.getSession() : null;
653 setupDragSource(session);
655 if (session != null) {
656 evaluatorData = createEvaluatorData(session);
657 explorer.setDataSource(new AsyncReadGraphDataSource(session));
658 explorer.setDataSource(new ReadGraphDataSource(session));
661 evaluatorData = new EvaluatorDataImpl();
662 explorer.removeDataSource(AsyncReadGraph.class);
663 explorer.removeDataSource(ReadGraph.class);
666 explorer.setPersistor(getStatePersistor());
668 explorer.setProcessor(new ComparableFactoryResolver(evaluatorData));
669 explorer.setProcessor(new ViewpointFactoryResolver(evaluatorData));
670 explorer.setProcessor(new LabelerFactoryResolver(evaluatorData));
671 explorer.setProcessor(new ImagerFactoryResolver(evaluatorData));
672 explorer.setProcessor(new LabelDecoratorFactoryResolver(evaluatorData));
673 explorer.setProcessor(new ImageDecoratorFactoryResolver(evaluatorData));
674 explorer.setProcessor(new DefaultIsCheckedProcessor2(evaluatorData));
675 explorer.setPrimitiveProcessor(new TypesQueryProcessor());
676 explorer.setPrimitiveProcessor(new StandardContextTypesQueryProcessor());
677 explorer.setPrimitiveProcessor(new InheritsQueryProcessor());
678 explorer.setPrimitiveProcessor(new RelatedObjectsQueryProcessor());
680 explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor);
681 explorer.setProcessor(new ComparableSelectorQueryProcessor());
682 explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor);
683 explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor);
685 initializeExplorerWithEvaluator(explorer, context, evaluatorData);
688 protected void initializeExplorerWithEvaluator(GraphExplorer explorer, ISessionContext context, EvaluatorData data) {
691 protected EvaluatorData createEvaluatorData(Session context) {
693 // Set<String> browseContexts = getArgument("browseContexts");
695 return Evaluators.load(context.getSession(), browseContexts, resourceManager, useNodeBrowseContexts, useNodeActionContexts);
699 protected Transfer[] getAcceptedDataTypes() {
700 return new Transfer[] { LocalObjectTransfer.getTransfer(), FileTransfer.getInstance(), TextTransfer.getInstance() };
703 protected void handleDrop(Object data, NodeContext target) {
706 DragSourceListenerFactory dragSourceListenerFactory = new DragSourceListenerFactory() {
708 final Transfer[] transfers = new Transfer[] {LocalObjectTransfer.getTransfer(), TextTransfer.getInstance() };
711 public DragSourceListener get(ISelectionProvider selectionProvider) {
713 LocalSelectionDragSourceListener ls = new LocalSelectionDragSourceListener(selectionProvider);
715 return new DragSourceListener() {
718 public void dragStart(DragSourceEvent event) {
723 public void dragSetData(DragSourceEvent event) {
724 if(TextTransfer.getInstance().isSupportedType(event.dataType)) {
726 event.data = WorkbenchSelectionUtils.getPossibleJSON(selectionProvider.getSelection());
727 } catch (DatabaseException e) {
728 event.data = "{ type:\"Exception\" }";
729 LOGGER.error("Failed to get current selection as JSON.", e);
731 } else if (LocalObjectTransfer.getTransfer().isSupportedType(event.dataType)) {
732 ls.dragSetData(event);
737 public void dragFinished(DragSourceEvent event) {
738 ls.dragFinished(event);
744 public Transfer[] getTransfers() {
750 public void setDragSourceListenerFactory(DragSourceListenerFactory dragSourceListenerFactory) {
751 this.dragSourceListenerFactory = dragSourceListenerFactory;
754 protected DragSourceListener setupDND(GraphExplorer explorer) {
756 ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
758 DragSourceListener listener = createDragSourceListener(selectionProvider);
760 Control control = explorer.getControl();
761 DragSource source = createDragSource(control);
762 source.setTransfer(getTransfers());
763 source.addDragListener(listener);
764 source.setDragSourceEffect(new NoImageDragSourceEffect(control));
770 protected DragSourceListener createDragSourceListener(ISelectionProvider selectionProvider) {
771 return dragSourceListenerFactory.get(selectionProvider);
774 private int dragStyle = DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
776 protected void setDragStyle(int style) {
777 this.dragStyle = style;
780 protected int getDragStyle() {
784 protected DragSource createDragSource(Control control) {
785 return new DragSource(control, getDragStyle());
788 protected Transfer[] getTransfers() {
789 return dragSourceListenerFactory.getTransfers();
792 public EvaluatorData getEvaluatorData() {
793 return evaluatorData;
796 public interface InputSource {
798 * @param ctx the session context to read the input from. May be
799 * <code>null</code> if there is no session.
800 * @return the input object of a graph explorer. To indicate no input,
801 * use {@link GraphExplorerConstants#EMPTY_INPUT}. Never return
804 Object get(ISessionContext ctx, Object selection);
807 public interface FilterSource {
814 * The default hint tracker that will be active if
815 * {@link GraphExplorerComposite#setSessionContextTracker(IHintTracker) is
818 public class SessionContextProjectTracker extends HintTracker {
819 public SessionContextProjectTracker() {
820 IHintListener activeProjectListener = new HintListenerAdapter() {
822 public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
823 applySessionContext(getSessionContext());
826 addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);
830 public class DirectInputSource implements InputSource {
832 public Object get(ISessionContext ctx, Object selection) {
837 public static class SelectionFilterAreaSource implements FilterAreaSource {
840 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
841 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
842 return new FilterArea(explorer, processor, parent, SWT.READ_ONLY);
847 public static class RootFilterAreaSource implements FilterAreaSource {
850 public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) {
851 FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS);
852 return new RootFilterArea(explorer, processor, parent, SWT.READ_ONLY);
857 protected void setSessionContextTracker(IHintTracker tracker) {
858 this.sessionContextTracker = tracker;
861 public void setInputSource(InputSource source) {
862 this.inputSource = source;
865 public void setFilterAreaSource(FilterAreaSource provider) {
866 this.filterAreaSource = provider;
869 public void setSelectionTransformation(BiFunction<GraphExplorer, Object[], Object[]> transformation) {
870 this.selectionTransformation = transformation;
871 if(explorer != null) explorer.setSelectionTransformation(transformation);
874 protected Set<String> getBrowseContexts() {
875 return browseContexts;
878 public void setBrowseContexts(Set<String> contexts) {
879 this.browseContexts = contexts;
880 //initializeExplorer(explorer, getSessionContext());
883 public void setBrowseContexts(String ... contexts) {
884 this.browseContexts = new HashSet<String>();
885 for(String s : contexts) this.browseContexts.add(s);
886 initializeExplorer(explorer, getSessionContext());
889 public void setContextMenuId(String contextMenuId) {
890 this.contextMenuId = contextMenuId;
893 // protected IContextMenuInitializer getContextMenuInitializer() {
894 // String contextMenuId = getContextMenuId();
895 // if(contextMenuId != null) {
896 // return new ContextMenuInitializer(contextMenuId);
902 protected String getContextMenuId() {
903 return this.contextMenuId;
906 public void setUiContexts(Set<String> uiContext) {
907 this.uiContext = uiContext;
910 public Set<String> getUiContexts() {
914 protected InputSource getInputSource() {
918 protected Map<String, Object> getArguments() {
922 @SuppressWarnings("unchecked")
923 protected <T> T getArgument(String key) {
924 return (T) args.get(key);
927 protected DisposeState getDisposeState() {
931 public ISessionContext getSessionContext() {
932 return sessionContext;
935 public ISessionContextProvider getSessionContextProvider() {
936 return contextProvider;
940 public boolean setFocus() {
941 if (explorer != null && !explorer.isDisposed())
946 public void setWorkbenchListeners() {
947 if (workbenchSelectionListener == null && getSite() != null) {
948 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
949 getSite().setSelectionProvider(selectionProvider);
951 // Listen to the workbench selection also to propagate it to
952 // the explorer also.
953 workbenchSelectionListener = new DefaultExplorerSelectionListener(site.getPage().getActivePart(), explorer);
954 //System.out.println("ADD WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
955 getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener);
959 protected void removeWorkbenchListeners() {
960 //System.out.println("REMOVE WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener);
961 // Remember to remove the installed workbench selection listener
962 if (workbenchSelectionListener != null) {
963 getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener);
964 workbenchSelectionListener = null;
966 ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class);
967 if(getSite().getSelectionProvider() == selectionProvider) getSite().setSelectionProvider(null);
972 protected final void attachToSession() {
974 // Track active ISessionContext changes
975 //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());
976 contextProvider.addContextChangedListener(contextChangeListener);
978 // Start tracking the current session context for input changes.
979 // This will/must cause applySessionContext to get called.
980 // Doing the applySessionContext initialization this way
981 // instead of directly calling it will also make sure that
982 // applySessionContext is only called once when first initialized,
983 // and not twice like with the direct invocation.
984 this.sessionContext = contextProvider.getSessionContext();
985 sessionContextTracker.track(sessionContext);
988 // /////////////////////////////////////////////////////////////////////////
989 // Override / implement these:
992 // * Returns an ID that is used for persisting a GraphExplorer instance.
994 // * Used for </code>restoreState(IMemento)</code> and
995 // * <code>restoreState(IMemento)</code> in OntologyExplorer. Must be unique
996 // * within a workbench part.
998 // * @return a unique name for this particular graph explorer view used for
999 // * saving and restoring the state of this view part
1001 // public String getExplorerName() {
1002 // return "GraphExplorerViewBase";
1006 * Override this method to add controls to the view part. This is invoked
1007 * before attaching the view part to a database session.
1011 protected void createControls(Composite parent) {
1016 * Override this method and provide a proper context menu initializer if you
1017 * want to have this base class initialize one for you.
1019 * @return the initializer to be used by {@link #createControls(Composite)}
1021 protected IContextMenuInitializer getContextMenuInitializer() {
1022 String contextMenuId = getContextMenuId();
1023 if(contextMenuId != null) {
1024 return new ContextMenuInitializer(contextMenuId);
1034 protected GraphExplorer createExplorerControl(Composite parent, Integer maxChildren) {
1035 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1036 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1038 GraphExplorer ge = factory
1039 .selectionDataResolver(new DefaultSelectionDataResolver())
1040 .selectionTransformation(selectionTransformation)
1041 .setServiceLocator(site)
1042 .create(parent, style);
1047 protected GraphExplorer createExplorerControl2(Composite parent, Integer maxChildren) {
1048 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1049 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1051 GraphExplorer ge = factory
1052 .selectionDataResolver(new DefaultSelectionDataResolver())
1053 .selectionTransformation(selectionTransformation)
1054 .setServiceLocator(site)
1055 .create2(parent, style);
1060 protected GraphExplorer createExplorerControl3(Composite parent, Integer maxChildren) {
1061 GraphExplorerFactory factory = GraphExplorerFactory.getInstance();
1062 if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren);
1064 GraphExplorer ge = factory
1065 .selectionDataResolver(new DefaultSelectionDataResolver())
1066 .selectionTransformation(selectionTransformation)
1067 .setServiceLocator(site)
1068 .create3(parent, style);
1073 protected void setupDragSource(Session session) {
1074 if (dragSource instanceof SessionContainer) {
1075 ((SessionContainer) dragSource).setSession(session);
1080 * Override to customize the addition of listeners a newly created
1085 protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {
1086 addSelectionInputListeners(explorer, menuManager);
1089 protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {
1090 // Consider ENTER presses to simulate mouse left button double clicks
1091 explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function<String[]>() {
1093 public String[] execute(Object... obj) {
1094 return getEditingColumn((NodeContext) obj[0]);
1097 // Default double click handling
1098 explorer.addListener(new DefaultMouseListener(explorer));
1101 protected String[] getEditingColumn(NodeContext context) {
1102 return editingColumn;
1105 public void setEditingColumn(String... columnKeysInOrderOfTrial) {
1106 this.editingColumn = columnKeysInOrderOfTrial;
1109 // Needed for preventing unnecessary re-initialization of the explorer with the same input.
1110 private Object currentInput;
1111 private Object currentRoot;
1114 * Invoke this to reinitialize the explorer and reset its input. The input
1115 * will be resolved from the specified ISessionContext based on the
1116 * {@link SessionContextInputSource} that is currently in use. If the input
1117 * is identical to the previous input, nothing will be done.
1121 public final boolean applySessionContext(ISessionContext context) {
1123 // If control is not alive anymore, do nothing.
1124 //System.out.println(this + ": applySessionContext(" + context + "), explorer=" + explorer);
1125 if (disposeState != DisposeState.Alive)
1128 //System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");
1129 initializeExplorer(explorer, context);
1132 // Start tracking the session context.
1134 // If this is not the same session that is currently tracked, it will
1135 // cause IHintListeners of the sessionContextTracker to fire.
1136 // For this we need the above input equality (identity) checking.
1137 // This is here just to make sure that we are tracking the correct
1139 sessionContextTracker.track(sessionContext);
1141 this.sessionContext = context;
1142 Object root = inputSource.get(context, currentInput);
1143 if (ObjectUtils.objectEquals(root, currentRoot))
1148 //System.out.println(this + ": setRoot(" + input + ")");
1149 explorer.setUIContexts(uiContext);
1150 explorer.setRoot(root);
1156 protected boolean isImportantInput(Object previousSelection, Object selection) {
1157 return !ObjectUtils.objectEquals(previousSelection, selection);
1160 public void setInput(Object selection, boolean force) {
1166 if (sessionContext == null)
1169 // Check if this is a duplicate of the previous selection to reduce unnecessary flicker.
1170 if (!force && !isImportantInput(currentInput, selection))
1173 currentInput = selection;
1175 Object root = inputSource.get(sessionContext, selection);
1179 explorer.setUIContexts(uiContext);
1182 explorer.setRoot(GraphExplorer.EMPTY_INPUT);
1184 explorer.setRoot(root);
1189 public void setColumnsVisible(boolean visible) {
1190 explorer.setColumnsVisible(visible);
1193 private int getColumnWidth(Column column, ExplorerState state) {
1194 // Get saved width from the persistor if there is one.
1195 if (state != null && state.columnWidths != null) {
1196 Integer width = state.columnWidths.get(column.getLabel());
1200 return column.getWidth();
1203 protected void restoreColumnSizes(Map<Column, Object> columns) {
1204 if (persistor != null) {
1205 setColumnData(columns, null);
1206 ExplorerStates.scheduleRead(explorer.getRoot(), persistor).thenAccept(state -> {
1207 SWTUtils.asyncExec(GraphExplorerComposite.this, () -> {
1208 if (explorerComposite.isDisposed())
1209 setColumnData(columns, state);
1213 setColumnData(columns, null);
1217 protected void setColumnData(Map<Column, Object> columns, ExplorerState state) {
1218 columns.forEach((column, widget) -> {
1219 org.eclipse.swt.widgets.Widget columnWidget = (org.eclipse.swt.widgets.Widget) widget;
1220 ad.setColumnData(columnWidget,
1221 new ColumnWeightData(
1222 column.hasGrab() ? column.getWeight() : 0,
1223 getColumnWidth(column, state)));
1227 public void setColumns(Column[] columns) {
1228 // ColumnWeightData does not support column weight/width < 0
1229 for (Column column : columns) {
1230 if (column.getWeight() < 0)
1231 throw new IllegalArgumentException("Column weight must be >= 0, got " + column.getWeight() + " for " + column);
1232 if (column.getWidth() < 0)
1233 throw new IllegalArgumentException("Column minimum width must be >= 0, got " + column.getWidth() + " for " + column);
1235 explorer.setColumns(columns, this::restoreColumnSizes);
1239 public void setInput(ISessionContext context, Object input) {
1240 setInput(input, false);
1243 public void setMaxChildren(int maxChildren) {
1244 explorer.setMaxChildren(maxChildren);
1247 public <T> void addListener(ExplorerMouseListenerImpl<T> listener) {
1249 support.register(listener);
1250 listener.register(explorer);
1251 explorer.addListener(listener);
1256 // public Point computeSize(int wHint, int hHint) {
1257 // Point p = super.computeSize(wHint, hHint);
1258 // System.err.println("graphExplorerComposite.computeSize " + p);
1263 // public Point computeSize(int wHint, int hHint, boolean changed) {
1264 // Point p = super.computeSize(wHint, hHint, changed);
1265 // System.err.println("graphExplorerComposite.computeSize " + p);