X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.views.swt%2Fsrc%2Forg%2Fsimantics%2Fviews%2Fswt%2FSimanticsView.java;fp=bundles%2Forg.simantics.views.swt%2Fsrc%2Forg%2Fsimantics%2Fviews%2Fswt%2FSimanticsView.java;h=6f424c5b07e2a5d9215e85dbf4139ff0133bce9f;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.views.swt/src/org/simantics/views/swt/SimanticsView.java b/bundles/org.simantics.views.swt/src/org/simantics/views/swt/SimanticsView.java new file mode 100644 index 000000000..6f424c5b0 --- /dev/null +++ b/bundles/org.simantics.views.swt/src/org/simantics/views/swt/SimanticsView.java @@ -0,0 +1,503 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 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.views.swt; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.resource.LocalResourceManager; +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.DragSourceListener; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.IWorkbenchSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.contexts.IContextService; +import org.eclipse.ui.part.ViewPart; +import org.simantics.browsing.ui.BuiltinKeys; +import org.simantics.browsing.ui.Column; +import org.simantics.browsing.ui.GraphExplorer; +import org.simantics.browsing.ui.NodeContext; +import org.simantics.browsing.ui.common.ColumnKeys; +import org.simantics.browsing.ui.common.node.IDropTargetNode; +import org.simantics.browsing.ui.graph.impl.GraphInputSources; +import org.simantics.browsing.ui.graph.impl.SessionContextInputSource; +import org.simantics.browsing.ui.swt.ContextMenuInitializer; +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.GraphExplorerFactory; +import org.simantics.browsing.ui.swt.IContextMenuInitializer; +import org.simantics.browsing.ui.swt.ViewArgumentUtils; +import org.simantics.browsing.ui.swt.widgets.GraphExplorerComposite; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport; +import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl; +import org.simantics.db.Disposable; +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.workbench.IPropertyPage; +import org.simantics.utils.ObjectUtils; +import org.simantics.utils.datastructures.Function; +import org.simantics.utils.datastructures.disposable.DisposeState; +import org.simantics.utils.datastructures.hints.HintContext; +import org.simantics.utils.datastructures.hints.HintListenerAdapter; +import org.simantics.utils.datastructures.hints.HintTracker; +import org.simantics.utils.datastructures.hints.IHintContext; +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.LayoutUtils; + +/** + * @author Antti Villberg + * @deprecated in favor of org.simantics.views.swt.ModelledView + */ +public abstract class SimanticsView extends ViewPart { + + private final WidgetSupportImpl widgetSupport = createSupport(); + + protected IHintContext factoryHints = new HintContext(); + + protected LocalResourceManager resourceManager; + + protected ISelectionListener workbenchSelectionListener; + + protected Composite parent; + + private Map args; + + private ISessionContextProvider contextProvider; + + private ISessionContext sessionContext; + + protected IMemento memento; + + private IHintTracker sessionContextTracker = new SessionContextProjectTracker(); + + private SessionContextInputSource inputSource = GraphInputSources.projectSource(); + + private DisposeState disposeState = DisposeState.Alive; + + protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() { + @Override + public void sessionContextChanged(SessionContextChangedEvent event) { + sessionContext = event.getNewValue(); + sessionContextTracker.track(sessionContext); + } + }; + + protected Set getBrowseContexts() { + return Collections.emptySet(); + } + + protected WidgetSupportImpl createSupport() { + return new WidgetSupportImpl(); + } + + abstract protected void createControls(Composite body, IWorkbenchSite site, ISessionContext context, WidgetSupport support); + + protected void activateUiContexts() { + Collection contexts = getUiContexts(); + if (!contexts.isEmpty()) { + IContextService cs = (IContextService) getSite().getService(IContextService.class); + for (String context : contexts) + cs.activateContext(context); + } + } + + protected Transfer[] getAcceptedDataTypes() { + return new Transfer[] { LocalObjectTransfer.getTransfer(), FileTransfer.getInstance() }; + } + + protected void handleDrop(Object data, NodeContext target) { + if (target != null) { + Object input = target.getConstant(BuiltinKeys.INPUT); + //System.out.println("DROPPED " + data + " ON " + target); + if (input instanceof IDropTargetNode) + ((IDropTargetNode) input).drop(data); + } + } + + protected Object createDragSource(GraphExplorer explorer) { + ISelectionProvider selectionProvider = (ISelectionProvider) explorer.getAdapter(ISelectionProvider.class); + + DragSourceListener listener = new LocalSelectionDragSourceListener(selectionProvider); + + Control control = explorer.getControl(); + DragSource source = new DragSource(control, DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT); + source.setTransfer(new Transfer[] {LocalObjectTransfer.getTransfer()}); + source.addDragListener(listener); + source.setDragSourceEffect(new NoImageDragSourceEffect(control)); + + return listener; + } + + /** + * @return the set of org.eclipse.ui.context contexts to + * activate for this view site + */ + protected Set getUiContexts() { + return Collections.emptySet(); + } + + /** + * The default hint tracker that will be active if + * {@link SimanticsViewBase#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); + } + } + + protected void setSessionContextTracker(IHintTracker tracker) { + this.sessionContextTracker = tracker; + } + + public void setInputSource(SessionContextInputSource source) { + this.inputSource = source; + } + + protected final SessionContextInputSource getInputSource() { + return inputSource; + } + + protected Map getViewArguments() { + return args; + } + + protected DisposeState getDisposeState() { + return disposeState; + } + + public ISessionContext getSessionContext() { + return sessionContext; + } + + public ISessionContextProvider getSessionContextProvider() { + return contextProvider; + } + + @Override + public void createPartControl(Composite parent) { + this.parent = parent; + this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay())); + + contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow()); + + parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false)); + + setWorkbenchListeners(); + activateUiContexts(); + + createControls(parent, getSite(), getSessionContext(), widgetSupport); + + attachToSession(); + + } + + /** + * Invoked when this viewpart is disposed. Unhooks the view from its + * ISessionContextProvider. Overriding is allowed but super.dispose() must + * be called. + * + * @see org.eclipse.ui.part.WorkbenchPart#dispose() + */ + @Override + public void dispose() { + removeWorkbenchListeners(); + disposeState = DisposeState.Disposing; + try { + if (inputSource instanceof Disposable) { + ((Disposable) inputSource).dispose(); + } + //System.out.println(this + ".GraphExplorerViewBase.dispose()"); + if (contextProvider != null) { + contextProvider.removeContextChangedListener(contextChangeListener); + contextProvider = null; + } + sessionContextTracker.untrack(); + resourceManager.dispose(); + if (widgetSupport instanceof Disposable) + ((Disposable) widgetSupport).dispose(); + resourceManager = null; + args = null; + sessionContext = null; + parent = null; + super.dispose(); + } finally { + disposeState = DisposeState.Disposed; + } + } + + @Override + public void setFocus() { + } + + @Override + public void init(IViewSite site) throws PartInitException { + super.init(site); + this.args = ViewArgumentUtils.parseViewArguments(this); + } + + @Override + public void init(IViewSite site, IMemento memento) throws PartInitException { + super.init(site, memento); + this.args = ViewArgumentUtils.parseViewArguments(this); + this.memento = memento; + } + + @Override + public void saveState(IMemento memento) { + if (this.memento != null) { + memento.putMemento(this.memento); + } +// if (explorer != null) +// explorer.saveState(memento); + } + + protected void setWorkbenchListeners() { + if (workbenchSelectionListener == 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(this, explorer); +// getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener); + } + } + + protected void removeWorkbenchListeners() { + // Remember to remove the installed workbench selection listener + if (workbenchSelectionListener != null) { + getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener); + workbenchSelectionListener = null; + + 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: + + protected Column[] getColumns() { + return null; + } + + /** + * 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) { + + parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false)); + + } + + /** + * 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; + } + } + + protected String getContextMenuId() { + return null; + } + + protected int getStyle() { + return SWT.MULTI; + } + + /** + * @param parent + * @return + */ + protected GraphExplorer createExplorerControl(Composite parent) { + return GraphExplorerFactory.getInstance() + .selectionDataResolver(new DefaultSelectionDataResolver()) + .create(parent, getStyle()); + } + + /** + * 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 new String[] { getEditingColumn((NodeContext) obj[0]) }; + } + })); + // Default double click handling + explorer.addListener(new DefaultMouseListener(explorer)); + } + + protected String getEditingColumn(NodeContext context) { + return ColumnKeys.SINGLE; + } + + // Needed for preventing unnecessary re-initialization of the explorer with the same input. + private Object currentInput; + + protected boolean isImportantInput(Object previousInput, Object input) { + return !ObjectUtils.objectEquals(previousInput, input); + } + + /** + * 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 + */ + protected final boolean applySessionContext(ISessionContext context) { + // If control is not alive anymore, do nothing. + //System.out.println(this + "(SimanticsView).applySessionContext(context=" + context + ")"); + if (disposeState != DisposeState.Alive) + return false; + + if(this.sessionContext == null && context == null) + return false; + + this.sessionContext = context; + Object input = getInputSource().get(context); + //System.out.println(this + "(SimanticsView).applySessionContext(input=" + input + ")"); + if (!isImportantInput(currentInput, input)) + return false; + +// System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")"); +// initializeExplorer(explorer, context); +// System.out.println(this + ": setRoot(" + input + ")"); +// explorer.setRoot(input); + + currentInput = input; + //System.out.println(this + "(SimanticsView).applySessionContext(new input=" + currentInput + ")"); + + widgetSupport.fireInput(context, input); + + // 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); + + return true; + } + + @SuppressWarnings("unchecked") + void searchControl(Control control, Class c, Set result) { + if(c.isInstance(control)) + result.add((T)control); + if(control instanceof Composite) { + for(Control child : ((Composite)control).getChildren()) { + searchControl(child, c, result); + } + } + } + + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + + if(ISessionContextProvider.class == adapter) + return (T) getSessionContextProvider(); + else if(IPropertyPage.class == adapter) + return (T) getPropertyPage(); + else if(GraphExplorer.class == adapter) { + Set composites = new HashSet<>(); + searchControl(parent, GraphExplorerComposite.class, composites); + if(composites.size() == 1) { + GraphExplorerComposite gec = composites.iterator().next(); + return (T) gec.getExplorer(); + } + return null; + } + + return super.getAdapter(adapter); + + } + + abstract protected IPropertyPage getPropertyPage(); + +// protected IPropertyPage getPropertyPage() { +// return new StandardPropertyPage(getSite(), getBrowseContexts()); +// } + +}