/******************************************************************************* * Copyright (c) 2007, 2018 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.browsing.ui.swt.widgets; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.BiFunction; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.layout.TreeColumnLayout; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSource; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.DropTargetListener; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchSite; import org.eclipse.ui.contexts.IContextService; import org.simantics.Simantics; import org.simantics.browsing.ui.BuiltinKeys; import org.simantics.browsing.ui.Column; import org.simantics.browsing.ui.ExplorerState; import org.simantics.browsing.ui.GraphExplorer; import org.simantics.browsing.ui.GraphExplorer.TransientExplorerState; import org.simantics.browsing.ui.NodeContext; import org.simantics.browsing.ui.StatePersistor; import org.simantics.browsing.ui.common.AdaptableHintContext; import org.simantics.browsing.ui.common.ColumnKeys; import org.simantics.browsing.ui.common.EvaluatorData; import org.simantics.browsing.ui.common.EvaluatorDataImpl; import org.simantics.browsing.ui.common.processors.ComparableFactoryResolver; import org.simantics.browsing.ui.common.processors.ComparableSelectorQueryProcessor; import org.simantics.browsing.ui.common.processors.FilterSelectionRequestQueryProcessor; import org.simantics.browsing.ui.common.processors.ImageDecoratorFactoryResolver; import org.simantics.browsing.ui.common.processors.ImagerFactoryResolver; import org.simantics.browsing.ui.common.processors.LabelDecoratorFactoryResolver; import org.simantics.browsing.ui.common.processors.LabelerFactoryResolver; import org.simantics.browsing.ui.common.processors.UserSelectedComparableFactoryQueryProcessor; import org.simantics.browsing.ui.common.processors.UserSelectedViewpointFactoryQueryProcessor; import org.simantics.browsing.ui.common.processors.ViewpointFactoryResolver; import org.simantics.browsing.ui.common.state.ExplorerStates; import org.simantics.browsing.ui.common.views.FilterAreaSource; import org.simantics.browsing.ui.common.views.IFilterArea; import org.simantics.browsing.ui.common.views.IFilterAreaProvider; import org.simantics.browsing.ui.graph.impl.AsyncReadGraphDataSource; import org.simantics.browsing.ui.graph.impl.Evaluators; import org.simantics.browsing.ui.graph.impl.InheritsQueryProcessor; import org.simantics.browsing.ui.graph.impl.ReadGraphDataSource; import org.simantics.browsing.ui.graph.impl.RelatedObjectsQueryProcessor; import org.simantics.browsing.ui.graph.impl.SessionContextInputSource; import org.simantics.browsing.ui.model.browsecontexts.BrowseContext; import org.simantics.browsing.ui.model.nodetypes.NodeType; import org.simantics.browsing.ui.swt.ComparatorSelector; import org.simantics.browsing.ui.swt.ContextMenuInitializer; import org.simantics.browsing.ui.swt.DefaultExplorerSelectionListener; import org.simantics.browsing.ui.swt.DefaultIsCheckedProcessor2; import org.simantics.browsing.ui.swt.DefaultKeyListener; import org.simantics.browsing.ui.swt.DefaultMouseListener; import org.simantics.browsing.ui.swt.DefaultSelectionDataResolver; import org.simantics.browsing.ui.swt.FilterArea; import org.simantics.browsing.ui.swt.GraphExplorerFactory; import org.simantics.browsing.ui.swt.IContextMenuInitializer; import org.simantics.browsing.ui.swt.RootFilterArea; import org.simantics.browsing.ui.swt.StandardContextTypesQueryProcessor; import org.simantics.browsing.ui.swt.TypesQueryProcessor; import org.simantics.browsing.ui.swt.ViewpointSelector; import org.simantics.browsing.ui.swt.widgets.impl.Widget; import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.SelectionHints; import org.simantics.db.layer0.request.PossibleVariable; import org.simantics.db.layer0.request.PossibleVariableRepresents; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.management.ISessionContext; import org.simantics.db.management.ISessionContextChangedListener; import org.simantics.db.management.ISessionContextProvider; import org.simantics.db.management.SessionContextChangedEvent; import org.simantics.project.ProjectKeys; import org.simantics.ui.SimanticsUI; import org.simantics.ui.dnd.LocalObjectTransfer; import org.simantics.ui.dnd.LocalSelectionDragSourceListener; import org.simantics.ui.dnd.NoImageDragSourceEffect; import org.simantics.ui.dnd.SessionContainer; import org.simantics.ui.selection.AnyResource; import org.simantics.ui.selection.AnyVariable; import org.simantics.ui.selection.ExplorerColumnContentType; import org.simantics.ui.selection.ExplorerInputContentType; import org.simantics.ui.selection.WorkbenchSelectionContentType; import org.simantics.ui.selection.WorkbenchSelectionElement; import org.simantics.ui.selection.WorkbenchSelectionUtils; import org.simantics.utils.ObjectUtils; import org.simantics.utils.datastructures.Function; import org.simantics.utils.datastructures.disposable.DisposeState; import org.simantics.utils.datastructures.hints.HintListenerAdapter; import org.simantics.utils.datastructures.hints.HintTracker; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintListener; import org.simantics.utils.datastructures.hints.IHintObservable; import org.simantics.utils.datastructures.hints.IHintTracker; import org.simantics.utils.ui.SWTUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GraphExplorerComposite extends Composite implements Widget, IAdaptable { private static final Logger LOGGER = LoggerFactory.getLogger(GraphExplorerComposite.class); protected UserSelectedComparableFactoryQueryProcessor userSelectedComparableFactoryQueryProcessor; protected UserSelectedViewpointFactoryQueryProcessor userSelectedViewpointFactoryQueryProcessor; protected FilterSelectionRequestQueryProcessor filterSelectionRequestQueryProcessor; protected IFilterArea filterArea; protected EvaluatorData evaluatorData; protected LocalResourceManager resourceManager; protected ISelectionListener workbenchSelectionListener; private final int style; final private IWorkbenchSite site; protected GraphExplorer explorer; protected IMenuManager menuManager; private final Map args; protected ISessionContextProvider contextProvider; private ISessionContext sessionContext; private Object dragSource; private IHintTracker sessionContextTracker = new SessionContextProjectTracker(); private InputSource inputSource = new DirectInputSource(); private FilterAreaSource filterAreaSource = new SelectionFilterAreaSource(); private final TreeColumnLayout ad; private String[] editingColumn = ColumnKeys.KEYS_SINGLE; private StatePersistor persistor = null; private final Composite toolComposite; private final Composite toolComposite2; private final Composite explorerComposite; final private WidgetSupport support; private final boolean useNodeBrowseContexts; private final boolean useNodeActionContexts; static class SelectionElement extends AdaptableHintContext { final public WorkbenchSelectionElement wse; final public Object content; final public Resource resource; final public Variable variable; final public Object input; final public TransientExplorerState explorerState; private WorkbenchSelectionElement extractWse(Object content) { if(content instanceof NodeContext) { NodeContext context = (NodeContext)content; Object input = context.getConstant(NodeType.TYPE); if(input instanceof NodeType) return ((NodeType)input).getWorkbenchSelectionElement(context); } return null; } private Resource extractResource(Object content) { if(content instanceof NodeContext) { NodeContext context = (NodeContext)content; Object input = context.getConstant(BuiltinKeys.INPUT); if(input instanceof Resource) return (Resource)input; if(input instanceof IAdaptable) { Resource var = (Resource)((IAdaptable)input).getAdapter(Resource.class); if(var != null) return var; } } return null; } private Variable extractVariable(Object content) { if(content instanceof NodeContext) { NodeContext context = (NodeContext)content; Object input = context.getConstant(BuiltinKeys.INPUT); if(input instanceof Variable) return (Variable)input; if(input instanceof IAdaptable) { Variable var = (Variable)((IAdaptable)input).getAdapter(Variable.class); if(var != null) return var; } } return null; } private Object extractInput(Object content) { if(content instanceof NodeContext) { NodeContext context = (NodeContext)content; return context.getConstant(BuiltinKeys.INPUT); } return null; } public SelectionElement(GraphExplorer explorer, Key[] keys, Object content) { super(keys); this.content = content; this.wse = extractWse(content); this.resource = extractResource(content); this.variable = extractVariable(content); this.input = extractInput(content); this.explorerState = explorer.getTransientState(); } @SuppressWarnings("unchecked") @Override public T getContent(WorkbenchSelectionContentType contentType) { if (wse != null) { T result = wse.getContent(contentType); if (result != null) return result; } if (contentType instanceof AnyResource) { if (resource != null) return (T) resource; if (variable == null) return null; try { return (T) ((AnyResource) contentType).processor.syncRequest(new PossibleVariableRepresents(variable)); } catch (DatabaseException e) { LOGGER.error("Unexpected error occurred while resolving Resource from Variable " + variable, e); } } else if (contentType instanceof AnyVariable) { if (variable != null) return (T) variable; if (resource == null) return null; try { return (T) ((AnyVariable) contentType).processor.syncRequest(new PossibleVariable(resource)); } catch (DatabaseException e) { LOGGER.error("Unexpected error occurred while resolving Variable from Resource " + resource, e); } } else if (contentType instanceof ExplorerInputContentType) { return (T) input; } else if (contentType instanceof ExplorerColumnContentType) { return (T) explorerState.getActiveColumn(); } return null; } @SuppressWarnings("rawtypes") @Override public Object getAdapter(Class adapter) { if(WorkbenchSelectionElement.class == adapter) { return wse; } if(NodeContext.class == adapter) { if(content instanceof NodeContext) return (NodeContext)content; else return null; } return super.getAdapter(adapter); } } private BiFunction selectionTransformation = new BiFunction() { private Key[] KEYS = new Key[] { SelectionHints.KEY_MAIN }; @Override public Object[] apply(GraphExplorer explorer, Object[] objects) { Object[] result = new Object[objects.length]; for (int i = 0; i < objects.length; i++) { SelectionElement context = new SelectionElement(explorer, KEYS, objects[i]); context.setHint(SelectionHints.KEY_MAIN, objects[i]); result[i] = context; } return result; } }; private Set browseContexts = null; private DisposeState disposeState = DisposeState.Alive; private boolean created = false; protected String contextMenuId = null; protected Set uiContext = null; protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() { @Override public void sessionContextChanged(SessionContextChangedEvent event) { sessionContext = event.getNewValue(); sessionContextTracker.track(sessionContext); } }; public GraphExplorerComposite(Map args, IWorkbenchSite site, Composite parent, WidgetSupport support, int style) { super(parent, SWT.NONE); if (args == null) args = Collections.emptyMap(); this.args = args; this.site = site; this.style = style; this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()), this); contextProvider = getSessionContextProvider(site); Integer maxChildren = (Integer)args.get("maxChildren"); GridLayoutFactory.fillDefaults().equalWidth(false).numColumns(1).margins(0,0).spacing(0,0).applyTo(this); toolComposite = new Composite(this, SWT.NONE); // toolComposite.setBackground(toolComposite.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW)); // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite); GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite); GridLayoutFactory.fillDefaults().applyTo(toolComposite); ad = new TreeColumnLayout(); explorerComposite = new Composite(this, SWT.NONE); explorerComposite.setLayout(ad); GridDataFactory.fillDefaults().grab(true, true).minSize(1, 50).applyTo(explorerComposite); if (args.containsKey("treeView") && Boolean.TRUE.equals(args.get("treeView"))) { explorer = createExplorerControl2(explorerComposite, maxChildren); } else if (args.containsKey("natTable") && Boolean.TRUE.equals(args.get("natTable"))) { explorer = createExplorerControl3(explorerComposite, maxChildren); } else { explorer = createExplorerControl(explorerComposite, maxChildren); } if (args.containsKey("useNodeBrowseContexts") && Boolean.TRUE.equals(args.get("useNodeBrowseContexts"))) { useNodeBrowseContexts = true; } else { useNodeBrowseContexts = false; } if (args.containsKey("useNodeActionContexts") && Boolean.TRUE.equals(args.get("useNodeActionContexts"))) { useNodeActionContexts = true; } else { useNodeActionContexts = false; } toolComposite2 = new Composite(this, SWT.NONE); // toolComposite2.setBackground(toolComposite2.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW)); // GridDataFactory.fillDefaults().grab(true, false).minSize(1, 1).applyTo(toolComposite); GridDataFactory.fillDefaults().grab(true, false).applyTo(toolComposite2); GridLayoutFactory.fillDefaults().applyTo(toolComposite2); this.support = support; if (support != null) support.register(this); } public GraphExplorerComposite(Map args, IWorkbenchSite site, Composite parent, int style) { this(args, site, parent, null, style); } public ISessionContextProvider getSessionContextProvider(IWorkbenchSite site) { if(site != null) return SimanticsUI.getSessionContextProvider(site.getWorkbenchWindow()); else return Simantics.getSessionContextProvider(); } public GraphExplorer getExplorer() { return explorer; } public Composite getExplorerComposite() { return explorerComposite; } public T getExplorerControl() { return explorer.getControl(); } public void addListenerToControl(int eventType, Listener listener) { ((Control)explorer.getControl()).addListener(eventType, listener); } public void finish() { created = true; createControls(site); attachToSession(); } IWorkbenchSite getSite() { return site; } protected void activateUiContexts() { Collection contexts = getUiContexts(); if (contexts == null || contexts.isEmpty()) return; IWorkbenchSite site = getSite(); if (site != null) { IContextService cs = (IContextService) getSite().getService(IContextService.class); for (String context : contexts) cs.activateContext(context); } } protected void createControls(IWorkbenchSite site) { // Initialize explorer control. // GridDataFactory.fillDefaults().grab(true, true).applyTo(explorer.getControl()); Control control = explorer.getControl(); // Initialize context menu if an initializer is provided. IContextMenuInitializer cmi = getContextMenuInitializer(); if (cmi != null) { ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class); menuManager = cmi.createContextMenu(control, selectionProvider, site); } // Initialize UI contexts activateUiContexts(); // Initialize DND. dragSource = setupDND(explorer); // Listeners are only added once per listener, not every time the // session context changes. addListeners(explorer, menuManager); userSelectedComparableFactoryQueryProcessor = new UserSelectedComparableFactoryQueryProcessor(); userSelectedViewpointFactoryQueryProcessor = new UserSelectedViewpointFactoryQueryProcessor(); filterSelectionRequestQueryProcessor = new FilterSelectionRequestQueryProcessor(); explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor); boolean hasExtraControls = false; boolean hasExtraControls2 = false; Boolean displaySelectors = (Boolean)args.get("displaySelectors"); if(displaySelectors == null || displaySelectors == true) { @SuppressWarnings("unused") ComparatorSelector comparatorSelector = new ComparatorSelector(explorer, userSelectedComparableFactoryQueryProcessor, toolComposite, SWT.READ_ONLY); // comparatorSelector.moveAbove(control); @SuppressWarnings("unused") ViewpointSelector viewpointSelector = new ViewpointSelector(explorer, userSelectedViewpointFactoryQueryProcessor, toolComposite, SWT.READ_ONLY); // viewpointSelector.moveAbove(control); hasExtraControls = true; } Boolean displayFilter = (Boolean)args.get("displayFilter"); if(displayFilter == null || displayFilter == true) { filterArea = filterAreaSource.getFilterArea(toolComposite, explorer); // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite, SWT.READ_ONLY); //filterArea.moveAbove(control); hasExtraControls = true; } Boolean displayFilter2 = (Boolean)args.get("displayFilter2"); if(displayFilter2 != null && displayFilter2 == true) { filterArea = filterAreaSource.getFilterArea(toolComposite2, explorer); // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, toolComposite2, SWT.READ_ONLY); // //filterArea.moveAbove(control); hasExtraControls2 = true; } // filterArea = new FilterArea(explorer, filterSelectionRequestQueryProcessor, this, SWT.READ_ONLY); // filterArea.moveAbove(control); if(!hasExtraControls) GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite); if(!hasExtraControls2) GridDataFactory.fillDefaults().grab(true, false).minSize(0, 0).hint(0, 0).applyTo(toolComposite2); GridDataFactory.fillDefaults().grab(true, true).span(2,1).applyTo(control); //tree.getTree().setLayout(new FillLayout() //this.setLayout(LayoutUtils.createNoBorderGridLayout(2, false)); DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK | DND.DROP_DEFAULT); target.setTransfer(getAcceptedDataTypes()); if (control instanceof Tree) { target.addDropListener(new DropTargetListener() { Tree tree = (Tree)explorer.getControl(); @Override public void dragEnter(DropTargetEvent event) { event.detail = DND.DROP_COPY; } @Override public void dragLeave(DropTargetEvent event) { } @Override public void dragOperationChanged(DropTargetEvent event) { } @Override public void dragOver(DropTargetEvent event) { } @Override public void drop(DropTargetEvent event) { TreeItem item = tree.getItem(tree.toControl(event.x, event.y)); if(item != null) { Object data = item.getData(); if (data instanceof NodeContext) handleDrop(event.data, (NodeContext) data); else if (data instanceof IAdaptable) { IAdaptable a = (IAdaptable) data; handleDrop(event.data, (NodeContext) a.getAdapter(NodeContext.class)); } } else handleDrop(event.data, null); } @Override public void dropAccept(DropTargetEvent event) { } }); } // Add workbench listeners and make sure they are cleaned up setWorkbenchListeners(); control.addListener(SWT.Dispose, new Listener() { @Override public void handleEvent(Event event) { doDispose(); } }); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Object getAdapter(Class adapter) { if (GraphExplorer.class == adapter) return explorer; if (EvaluatorData.class == adapter) return evaluatorData; if (BrowseContext.class == adapter) { EvaluatorData ed = evaluatorData; return ed != null ? ed.getBrowseContext() : null; } if (adapter == IFilterAreaProvider.class) return filterArea; return explorer.getAdapter(adapter); } protected void doDispose() { //System.out.println(this + ".GraphExplorerComposite.doDispose()"); removeWorkbenchListeners(); userSelectedComparableFactoryQueryProcessor = null; userSelectedViewpointFactoryQueryProcessor = null; filterSelectionRequestQueryProcessor = null; disposeState = DisposeState.Disposing; try { //System.out.println(this + ".GraphExplorerViewBase.dispose()"); if (contextProvider != null) { contextProvider.removeContextChangedListener(contextChangeListener); contextProvider = null; } sessionContextTracker.untrack(); resourceManager = null; explorer = null; sessionContext = null; dragSource = null; // parent = null; } finally { disposeState = DisposeState.Disposed; } } @Override public void dispose() { doDispose(); super.dispose(); } protected StatePersistor getStatePersistor() { return persistor; } public void setStatePersistor(StatePersistor persistor) { this.persistor = persistor; } protected void initializeExplorer(GraphExplorer explorer, ISessionContext context) { if(explorer == null || explorer.isDisposed()) return; if(context == null) return; if(browseContexts == null) return; Session session = context != null ? context.getSession() : null; setupDragSource(session); if (session != null) { evaluatorData = createEvaluatorData(session); explorer.setDataSource(new AsyncReadGraphDataSource(session)); explorer.setDataSource(new ReadGraphDataSource(session)); } else { evaluatorData = new EvaluatorDataImpl(); explorer.removeDataSource(AsyncReadGraph.class); explorer.removeDataSource(ReadGraph.class); } explorer.setPersistor(getStatePersistor()); explorer.setProcessor(new ComparableFactoryResolver(evaluatorData)); explorer.setProcessor(new ViewpointFactoryResolver(evaluatorData)); explorer.setProcessor(new LabelerFactoryResolver(evaluatorData)); explorer.setProcessor(new ImagerFactoryResolver(evaluatorData)); explorer.setProcessor(new LabelDecoratorFactoryResolver(evaluatorData)); explorer.setProcessor(new ImageDecoratorFactoryResolver(evaluatorData)); explorer.setProcessor(new DefaultIsCheckedProcessor2(evaluatorData)); explorer.setPrimitiveProcessor(new TypesQueryProcessor()); explorer.setPrimitiveProcessor(new StandardContextTypesQueryProcessor()); explorer.setPrimitiveProcessor(new InheritsQueryProcessor()); explorer.setPrimitiveProcessor(new RelatedObjectsQueryProcessor()); explorer.setPrimitiveProcessor(userSelectedViewpointFactoryQueryProcessor); explorer.setProcessor(new ComparableSelectorQueryProcessor()); explorer.setPrimitiveProcessor(userSelectedComparableFactoryQueryProcessor); explorer.setPrimitiveProcessor(filterSelectionRequestQueryProcessor); initializeExplorerWithEvaluator(explorer, context, evaluatorData); } protected void initializeExplorerWithEvaluator(GraphExplorer explorer, ISessionContext context, EvaluatorData data) { } protected EvaluatorData createEvaluatorData(Session context) { // Set browseContexts = getArgument("browseContexts"); return Evaluators.load(context.getSession(), browseContexts, resourceManager, useNodeBrowseContexts, useNodeActionContexts); } protected Transfer[] getAcceptedDataTypes() { return new Transfer[] { LocalObjectTransfer.getTransfer(), FileTransfer.getInstance(), TextTransfer.getInstance() }; } protected void handleDrop(Object data, NodeContext target) { } DragSourceListenerFactory dragSourceListenerFactory = new DragSourceListenerFactory() { final Transfer[] transfers = new Transfer[] {LocalObjectTransfer.getTransfer(), TextTransfer.getInstance() }; @Override public DragSourceListener get(ISelectionProvider selectionProvider) { LocalSelectionDragSourceListener ls = new LocalSelectionDragSourceListener(selectionProvider); return new DragSourceListener() { @Override public void dragStart(DragSourceEvent event) { ls.dragStart(event); } @Override public void dragSetData(DragSourceEvent event) { if(TextTransfer.getInstance().isSupportedType(event.dataType)) { try { event.data = WorkbenchSelectionUtils.getPossibleJSON(selectionProvider.getSelection()); } catch (DatabaseException e) { event.data = "{ type:\"Exception\" }"; LOGGER.error("Failed to get current selection as JSON.", e); } } else if (LocalObjectTransfer.getTransfer().isSupportedType(event.dataType)) { ls.dragSetData(event); } } @Override public void dragFinished(DragSourceEvent event) { ls.dragFinished(event); } }; } @Override public Transfer[] getTransfers() { return transfers; } }; public void setDragSourceListenerFactory(DragSourceListenerFactory dragSourceListenerFactory) { this.dragSourceListenerFactory = dragSourceListenerFactory; } protected DragSourceListener setupDND(GraphExplorer explorer) { ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class); DragSourceListener listener = createDragSourceListener(selectionProvider); Control control = explorer.getControl(); DragSource source = createDragSource(control); source.setTransfer(getTransfers()); source.addDragListener(listener); source.setDragSourceEffect(new NoImageDragSourceEffect(control)); return listener; } protected DragSourceListener createDragSourceListener(ISelectionProvider selectionProvider) { return dragSourceListenerFactory.get(selectionProvider); } private int dragStyle = DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT; protected void setDragStyle(int style) { this.dragStyle = style; } protected int getDragStyle() { return dragStyle; } protected DragSource createDragSource(Control control) { return new DragSource(control, getDragStyle()); } protected Transfer[] getTransfers() { return dragSourceListenerFactory.getTransfers(); } public EvaluatorData getEvaluatorData() { return evaluatorData; } public interface InputSource { /** * @param ctx the session context to read the input from. May be * null if there is no session. * @return the input object of a graph explorer. To indicate no input, * use {@link GraphExplorerConstants#EMPTY_INPUT}. Never return * null. */ Object get(ISessionContext ctx, Object selection); } public interface FilterSource { } /** * The default hint tracker that will be active if * {@link GraphExplorerComposite#setSessionContextTracker(IHintTracker) is * not called. */ public class SessionContextProjectTracker extends HintTracker { public SessionContextProjectTracker() { IHintListener activeProjectListener = new HintListenerAdapter() { @Override public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { applySessionContext(getSessionContext()); } }; addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener); } } public class DirectInputSource implements InputSource { @Override public Object get(ISessionContext ctx, Object selection) { return selection; } } public static class SelectionFilterAreaSource implements FilterAreaSource { @Override public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) { FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS); return new FilterArea(explorer, processor, parent, SWT.READ_ONLY); } } public static class RootFilterAreaSource implements FilterAreaSource { @Override public IFilterArea getFilterArea(Composite parent, GraphExplorer explorer) { FilterSelectionRequestQueryProcessor processor = (FilterSelectionRequestQueryProcessor)explorer.getPrimitiveProcessor(BuiltinKeys.SELECTION_REQUESTS); return new RootFilterArea(explorer, processor, parent, SWT.READ_ONLY); } } protected void setSessionContextTracker(IHintTracker tracker) { this.sessionContextTracker = tracker; } public void setInputSource(InputSource source) { this.inputSource = source; } public void setFilterAreaSource(FilterAreaSource provider) { this.filterAreaSource = provider; } public void setSelectionTransformation(BiFunction transformation) { this.selectionTransformation = transformation; if(explorer != null) explorer.setSelectionTransformation(transformation); } protected Set getBrowseContexts() { return browseContexts; } public void setBrowseContexts(Set contexts) { this.browseContexts = contexts; //initializeExplorer(explorer, getSessionContext()); } public void setBrowseContexts(String ... contexts) { this.browseContexts = new HashSet(); for(String s : contexts) this.browseContexts.add(s); initializeExplorer(explorer, getSessionContext()); } public void setContextMenuId(String contextMenuId) { this.contextMenuId = contextMenuId; } // protected IContextMenuInitializer getContextMenuInitializer() { // String contextMenuId = getContextMenuId(); // if(contextMenuId != null) { // return new ContextMenuInitializer(contextMenuId); // } else { // return null; // } // } protected String getContextMenuId() { return this.contextMenuId; } public void setUiContexts(Set uiContext) { this.uiContext = uiContext; } public Set getUiContexts() { return uiContext; } protected InputSource getInputSource() { return inputSource; } protected Map getArguments() { return args; } @SuppressWarnings("unchecked") protected T getArgument(String key) { return (T) args.get(key); } protected DisposeState getDisposeState() { return disposeState; } public ISessionContext getSessionContext() { return sessionContext; } public ISessionContextProvider getSessionContextProvider() { return contextProvider; } @Override public boolean setFocus() { if (explorer != null && !explorer.isDisposed()) explorer.setFocus(); return true; } public void setWorkbenchListeners() { if (workbenchSelectionListener == null && getSite() != null) { ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class); getSite().setSelectionProvider(selectionProvider); // Listen to the workbench selection also to propagate it to // the explorer also. workbenchSelectionListener = new DefaultExplorerSelectionListener(site.getPage().getActivePart(), explorer); //System.out.println("ADD WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener); getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener); } } protected void removeWorkbenchListeners() { //System.out.println("REMOVE WORKBENCH SELECTION LISTENER: " + workbenchSelectionListener); // Remember to remove the installed workbench selection listener if (workbenchSelectionListener != null) { getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener); workbenchSelectionListener = null; ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class); if(getSite().getSelectionProvider() == selectionProvider) getSite().setSelectionProvider(null); } } protected final void attachToSession() { // Track active ISessionContext changes //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow()); contextProvider.addContextChangedListener(contextChangeListener); // Start tracking the current session context for input changes. // This will/must cause applySessionContext to get called. // Doing the applySessionContext initialization this way // instead of directly calling it will also make sure that // applySessionContext is only called once when first initialized, // and not twice like with the direct invocation. this.sessionContext = contextProvider.getSessionContext(); sessionContextTracker.track(sessionContext); } // ///////////////////////////////////////////////////////////////////////// // Override / implement these: // /** // * Returns an ID that is used for persisting a GraphExplorer instance. // * // * Used for restoreState(IMemento) and // * restoreState(IMemento) in OntologyExplorer. Must be unique // * within a workbench part. // * // * @return a unique name for this particular graph explorer view used for // * saving and restoring the state of this view part // */ // public String getExplorerName() { // return "GraphExplorerViewBase"; // } /** * Override this method to add controls to the view part. This is invoked * before attaching the view part to a database session. * * @param parent */ protected void createControls(Composite parent) { } /** * Override this method and provide a proper context menu initializer if you * want to have this base class initialize one for you. * * @return the initializer to be used by {@link #createControls(Composite)} */ protected IContextMenuInitializer getContextMenuInitializer() { String contextMenuId = getContextMenuId(); if(contextMenuId != null) { return new ContextMenuInitializer(contextMenuId); } else { return null; } } /** * @param parent * @return */ protected GraphExplorer createExplorerControl(Composite parent, Integer maxChildren) { GraphExplorerFactory factory = GraphExplorerFactory.getInstance(); if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren); GraphExplorer ge = factory .selectionDataResolver(new DefaultSelectionDataResolver()) .selectionTransformation(selectionTransformation) .setServiceLocator(site) .create(parent, style); return ge; } protected GraphExplorer createExplorerControl2(Composite parent, Integer maxChildren) { GraphExplorerFactory factory = GraphExplorerFactory.getInstance(); if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren); GraphExplorer ge = factory .selectionDataResolver(new DefaultSelectionDataResolver()) .selectionTransformation(selectionTransformation) .setServiceLocator(site) .create2(parent, style); return ge; } protected GraphExplorer createExplorerControl3(Composite parent, Integer maxChildren) { GraphExplorerFactory factory = GraphExplorerFactory.getInstance(); if(maxChildren != null) factory = factory.maxChildrenShown(maxChildren); GraphExplorer ge = factory .selectionDataResolver(new DefaultSelectionDataResolver()) .selectionTransformation(selectionTransformation) .setServiceLocator(site) .create3(parent, style); return ge; } protected void setupDragSource(Session session) { if (dragSource instanceof SessionContainer) { ((SessionContainer) dragSource).setSession(session); } } /** * Override to customize the addition of listeners a newly created * GraphExplorer. * * @param explorer */ protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) { addSelectionInputListeners(explorer, menuManager); } protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) { // Consider ENTER presses to simulate mouse left button double clicks explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function() { @Override public String[] execute(Object... obj) { return getEditingColumn((NodeContext) obj[0]); } })); // Default double click handling explorer.addListener(new DefaultMouseListener(explorer)); } protected String[] getEditingColumn(NodeContext context) { return editingColumn; } public void setEditingColumn(String... columnKeysInOrderOfTrial) { this.editingColumn = columnKeysInOrderOfTrial; } // Needed for preventing unnecessary re-initialization of the explorer with the same input. private Object currentInput; private Object currentRoot; /** * Invoke this to reinitialize the explorer and reset its input. The input * will be resolved from the specified ISessionContext based on the * {@link SessionContextInputSource} that is currently in use. If the input * is identical to the previous input, nothing will be done. * * @param context */ public final boolean applySessionContext(ISessionContext context) { // If control is not alive anymore, do nothing. //System.out.println(this + ": applySessionContext(" + context + "), explorer=" + explorer); if (disposeState != DisposeState.Alive) return false; //System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")"); initializeExplorer(explorer, context); // Start tracking the session context. // // If this is not the same session that is currently tracked, it will // cause IHintListeners of the sessionContextTracker to fire. // For this we need the above input equality (identity) checking. // This is here just to make sure that we are tracking the correct // session context. sessionContextTracker.track(sessionContext); this.sessionContext = context; Object root = inputSource.get(context, currentInput); if (ObjectUtils.objectEquals(root, currentRoot)) return false; currentRoot = root; //System.out.println(this + ": setRoot(" + input + ")"); explorer.setUIContexts(uiContext); explorer.setRoot(root); return true; } protected boolean isImportantInput(Object previousSelection, Object selection) { return !ObjectUtils.objectEquals(previousSelection, selection); } public void setInput(Object selection, boolean force) { assert(created); if (isDisposed()) return; if (sessionContext == null) return; // Check if this is a duplicate of the previous selection to reduce unnecessary flicker. if (!force && !isImportantInput(currentInput, selection)) return; currentInput = selection; Object root = inputSource.get(sessionContext, selection); currentRoot = root; explorer.setUIContexts(uiContext); if (root == null) { explorer.setRoot(GraphExplorer.EMPTY_INPUT); } else { explorer.setRoot(root); } } public void setColumnsVisible(boolean visible) { explorer.setColumnsVisible(visible); } private int getColumnWidth(Column column, ExplorerState state) { // Get saved width from the persistor if there is one. if (state != null && state.columnWidths != null) { Integer width = state.columnWidths.get(column.getLabel()); if (width != null) return width; } return column.getWidth(); } protected void restoreColumnSizes(Map columns) { if (persistor != null) { setColumnData(columns, null); ExplorerStates.scheduleRead(explorer.getRoot(), persistor).thenAccept(state -> { SWTUtils.asyncExec(GraphExplorerComposite.this, () -> { if (explorerComposite.isDisposed()) setColumnData(columns, state); }); }); } else { setColumnData(columns, null); } } protected void setColumnData(Map columns, ExplorerState state) { columns.forEach((column, widget) -> { org.eclipse.swt.widgets.Widget columnWidget = (org.eclipse.swt.widgets.Widget) widget; ad.setColumnData(columnWidget, new ColumnWeightData( column.hasGrab() ? column.getWeight() : 0, getColumnWidth(column, state))); }); } public void setColumns(Column[] columns) { // ColumnWeightData does not support column weight/width < 0 for (Column column : columns) { if (column.getWeight() < 0) throw new IllegalArgumentException("Column weight must be >= 0, got " + column.getWeight() + " for " + column); if (column.getWidth() < 0) throw new IllegalArgumentException("Column minimum width must be >= 0, got " + column.getWidth() + " for " + column); } explorer.setColumns(columns, this::restoreColumnSizes); } @Override public void setInput(ISessionContext context, Object input) { setInput(input, false); } public void setMaxChildren(int maxChildren) { explorer.setMaxChildren(maxChildren); } public void addListener(ExplorerMouseListenerImpl listener) { support.register(listener); listener.register(explorer); explorer.addListener(listener); } // @Override // public Point computeSize(int wHint, int hHint) { // Point p = super.computeSize(wHint, hHint); // System.err.println("graphExplorerComposite.computeSize " + p); // return p; // } // // @Override // public Point computeSize(int wHint, int hHint, boolean changed) { // Point p = super.computeSize(wHint, hHint, changed); // System.err.println("graphExplorerComposite.computeSize " + p); // return p; // } }