]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/GraphExplorerViewBase.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.browsing.ui.swt / src / org / simantics / browsing / ui / swt / GraphExplorerViewBase.java
index f748656a5ba10f484a1dd9701f7c4f24b185c7b7..72307b32f22ec8371841ed96ef4c469e7d85453a 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.browsing.ui.swt;\r
-\r
-import java.util.Map;\r
-\r
-import org.eclipse.jface.action.IMenuManager;\r
-import org.eclipse.jface.layout.GridDataFactory;\r
-import org.eclipse.jface.resource.JFaceResources;\r
-import org.eclipse.jface.resource.LocalResourceManager;\r
-import org.eclipse.jface.viewers.ISelectionProvider;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-import org.eclipse.ui.IMemento;\r
-import org.eclipse.ui.ISelectionListener;\r
-import org.eclipse.ui.IViewSite;\r
-import org.eclipse.ui.IWorkbenchPart;\r
-import org.eclipse.ui.PartInitException;\r
-import org.eclipse.ui.part.ViewPart;\r
-import org.simantics.browsing.ui.Column;\r
-import org.simantics.browsing.ui.GraphExplorer;\r
-import org.simantics.browsing.ui.NodeContext;\r
-import org.simantics.browsing.ui.common.ColumnKeys;\r
-import org.simantics.browsing.ui.common.views.IViewArguments;\r
-import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.common.request.Queries;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.management.ISessionContext;\r
-import org.simantics.db.management.ISessionContextChangedListener;\r
-import org.simantics.db.management.ISessionContextProvider;\r
-import org.simantics.db.management.SessionContextChangedEvent;\r
-import org.simantics.project.IProject;\r
-import org.simantics.project.ProjectKeys;\r
-import org.simantics.ui.SimanticsUI;\r
-import org.simantics.ui.dnd.BasicDragSource;\r
-import org.simantics.ui.dnd.SessionContainer;\r
-import org.simantics.ui.workbench.IPropertyPage;\r
-import org.simantics.utils.ObjectUtils;\r
-import org.simantics.utils.datastructures.Function;\r
-import org.simantics.utils.datastructures.disposable.DisposeState;\r
-import org.simantics.utils.datastructures.hints.HintListenerAdapter;\r
-import org.simantics.utils.datastructures.hints.HintTracker;\r
-import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
-import org.simantics.utils.datastructures.hints.IHintListener;\r
-import org.simantics.utils.datastructures.hints.IHintObservable;\r
-import org.simantics.utils.datastructures.hints.IHintTracker;\r
-import org.simantics.utils.ui.LayoutUtils;\r
-\r
-/**\r
- * An abstract base Eclipse workbench ViewPart for use in situations where a\r
- * tree-based GraphExplorer graph model browser is needed.\r
- * \r
- * <p>\r
- * Override to customize behavior:\r
- * <ul>\r
- * <li>{@link #createControls(Composite)}</li>\r
- * <li>{@link #createExplorerControl(Composite)}</li>\r
- * <li>{@link #createDragSource(GraphExplorer)}</li>\r
- * <li>{@link #getContextMenuId()}</li>\r
- * <li>{@link #getContextMenuInitializer()}</li>\r
- * <li>{@link #addListeners(GraphExplorer, IMenuManager)}</li>\r
- * </ul>\r
- * </p>\r
- * \r
- * <p>\r
- * You can invoke the following methods from within\r
- * {@link #createControls(Composite)} to customize how the view keeps track of\r
- * the active ISessionContext and how the view resolves the input object of the\r
- * GraphExplorer control.\r
- * <ul>\r
- * <li>{@link #setSessionContextTracker(IHintTracker)}</li>\r
- * <li>{@link #setInputSource(SessionContextInputSource)}</li>\r
- * </ul>\r
- * </p>\r
- * \r
- * @author Tuukka Lehtonen\r
- * @deprecated in favor of org.simantics.views.swt.ModelledView \r
- */\r
-public abstract class GraphExplorerViewBase extends ViewPart {\r
-\r
-    /**\r
-     * The default hint tracker that will be active if\r
-     * {@link GraphExplorerViewBase#setSessionContextTracker(IHintTracker) is\r
-     * not called.\r
-     */\r
-    public class SessionContextProjectTracker extends HintTracker {\r
-        public SessionContextProjectTracker() {\r
-            IHintListener activeProjectListener = new HintListenerAdapter() {\r
-                @Override\r
-                public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
-                    applySessionContext(getSessionContext());\r
-                }\r
-            };\r
-            addKeyHintListener(ProjectKeys.KEY_PROJECT, activeProjectListener);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * The default implementation of a {@link SessionContextInputSource} that\r
-     * will be active if\r
-     * {@link GraphExplorerViewBase#setInputSource(SessionContextInputSource)}\r
-     * is not called.\r
-     */\r
-    public class SessionContextProjectSource implements SessionContextInputSource {\r
-        /**\r
-         * Returns the input object used by this GraphExplorer view. This object\r
-         * will be the starting point for all content shown in this explorer tree.\r
-         * \r
-         * @param sessionContext a valid database session context\r
-         * @return the root object of the graph explorer tree or <code>null</code>\r
-         *         to indicate that there is no input and nothing should be shown.\r
-         */\r
-        @Override\r
-        public Object get(ISessionContext ctx) {\r
-            if (ctx == null)\r
-                return GraphExplorer.EMPTY_INPUT;\r
-\r
-            String inputId = getViewArguments().get(IViewArguments.INPUT);\r
-            if (inputId != null) {\r
-                try {\r
-                    return ctx.getSession().syncRequest(Queries.resource(inputId));\r
-                } catch (DatabaseException e) {\r
-                    // Ok, the view argument was invalid. Just continue to the next\r
-                    // method.\r
-                }\r
-            }\r
-\r
-            Object input = GraphExplorer.EMPTY_INPUT;\r
-            IProject project2 = ctx.getHint(ProjectKeys.KEY_PROJECT);\r
-            if (project2 != null)\r
-                input = project2.get();\r
-            return input;\r
-        }\r
-        \r
-        @Override\r
-        public IWorkbenchPart getProvider() {\r
-               return null;\r
-        }\r
-        \r
-    }\r
-\r
-    protected LocalResourceManager           resourceManager;\r
-\r
-    protected ISelectionListener             workbenchSelectionListener;\r
-\r
-    protected Composite                      parent;\r
-\r
-    protected GraphExplorer                 explorer;\r
-\r
-    protected IMenuManager                   menuManager;\r
-\r
-    private Map<String, String>              args;\r
-\r
-    private ISessionContextProvider          contextProvider;\r
-\r
-    private ISessionContext                  sessionContext;\r
-\r
-    private Object                           dragSource;\r
-\r
-    protected IMemento                       memento;\r
-\r
-    private IHintTracker                     sessionContextTracker = new SessionContextProjectTracker();\r
-\r
-    private SessionContextInputSource        inputSource           = new SessionContextProjectSource();\r
-\r
-    private DisposeState                     disposeState          = DisposeState.Alive;\r
-\r
-    protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {\r
-        @Override\r
-        public void sessionContextChanged(SessionContextChangedEvent event) {\r
-            sessionContext = event.getNewValue();\r
-            sessionContextTracker.track(sessionContext);\r
-        }\r
-    };\r
-\r
-    protected void setSessionContextTracker(IHintTracker tracker) {\r
-        this.sessionContextTracker = tracker;\r
-    }\r
-\r
-    protected void setInputSource(SessionContextInputSource source) {\r
-        this.inputSource = source;\r
-    }\r
-\r
-    protected SessionContextInputSource getInputSource() {\r
-        return inputSource;\r
-    }\r
-\r
-    protected Map<String, String> getViewArguments() {\r
-        return args;\r
-    }\r
-\r
-    protected DisposeState getDisposeState() {\r
-        return disposeState;\r
-    }\r
-\r
-    public ISessionContext getSessionContext() {\r
-        return sessionContext;\r
-    }\r
-\r
-    public ISessionContextProvider getSessionContextProvider() {\r
-        return contextProvider;\r
-    }\r
-\r
-    @Override\r
-    public void createPartControl(Composite parent) {\r
-        this.parent = parent;\r
-        this.resourceManager = new LocalResourceManager(JFaceResources.getResources(parent.getDisplay()));\r
-\r
-        contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());\r
-        createControls(parent);\r
-        attachToSession();\r
-    }\r
-\r
-    /**\r
-     * Invoked when this viewpart is disposed. Unhooks the view from its\r
-     * ISessionContextProvider. Overriding is allowed but super.dispose() must\r
-     * be called.\r
-     * \r
-     * @see org.eclipse.ui.part.WorkbenchPart#dispose()\r
-     */\r
-    @Override\r
-    public void dispose() {\r
-        disposeState = DisposeState.Disposing;\r
-        try {\r
-            //System.out.println(this + ".GraphExplorerViewBase.dispose()");\r
-            if (contextProvider != null) {\r
-                contextProvider.removeContextChangedListener(contextChangeListener);\r
-                contextProvider = null;\r
-            }\r
-            sessionContextTracker.untrack();\r
-            resourceManager.dispose();\r
-            resourceManager = null;\r
-            args = null;\r
-            explorer = null;\r
-            sessionContext = null;\r
-            dragSource = null;\r
-            parent = null;\r
-            super.dispose();\r
-        } finally {\r
-            disposeState = DisposeState.Disposed;\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void setFocus() {\r
-        if (explorer != null && !explorer.isDisposed())\r
-            explorer.setFocus();\r
-    }\r
-\r
-    @Override\r
-    public void init(IViewSite site) throws PartInitException {\r
-        super.init(site);\r
-        this.args = ViewArgumentUtils.parseViewArguments(this);\r
-    }\r
-\r
-    @Override\r
-    public void init(IViewSite site, IMemento memento) throws PartInitException {\r
-        super.init(site, memento);\r
-        this.args = ViewArgumentUtils.parseViewArguments(this);\r
-        this.memento = memento;\r
-    }\r
-\r
-    @Override\r
-    public void saveState(IMemento memento) {\r
-        if (this.memento != null) {\r
-            memento.putMemento(this.memento);\r
-        }\r
-//        if (explorer != null)\r
-//            explorer.saveState(memento);\r
-    }\r
-\r
-    protected void setWorkbenchListeners() {\r
-        if (workbenchSelectionListener == null) {\r
-\r
-            ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);\r
-\r
-            getSite().setSelectionProvider(selectionProvider);\r
-\r
-            // Listen to the workbench selection also to propagate it to\r
-            // the explorer also.\r
-            workbenchSelectionListener = new DefaultExplorerSelectionListener(this, explorer);\r
-            getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(workbenchSelectionListener);\r
-        }\r
-    }\r
-\r
-    protected void removeWorkbenchListeners() {\r
-        // Remember to remove the installed workbench selection listener\r
-        if (workbenchSelectionListener != null) {\r
-            getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener(workbenchSelectionListener);\r
-            workbenchSelectionListener = null;\r
-\r
-            getSite().setSelectionProvider(null);\r
-        }\r
-    }\r
-\r
-    protected final void attachToSession() {\r
-        // Track active ISessionContext changes\r
-        //contextProvider = SimanticsUI.getSessionContextProvider(getViewSite().getWorkbenchWindow());\r
-        contextProvider.addContextChangedListener(contextChangeListener);\r
-\r
-        // Start tracking the current session context for input changes.\r
-        // This will/must cause applySessionContext to get called.\r
-        // Doing the applySessionContext initialization this way\r
-        // instead of directly calling it will also make sure that\r
-        // applySessionContext is only called once when first initialized,\r
-        // and not twice like with the direct invocation.\r
-        this.sessionContext = contextProvider.getSessionContext();\r
-        sessionContextTracker.track(sessionContext);\r
-    }\r
-\r
-    // /////////////////////////////////////////////////////////////////////////\r
-    // Override / implement these:\r
-\r
-//    /**\r
-//     * Returns an ID that is used for persisting a GraphExplorer instance.\r
-//     *\r
-//     * Used for </code>restoreState(IMemento)</code> and\r
-//     * <code>restoreState(IMemento)</code> in OntologyExplorer. Must be unique\r
-//     * within a workbench part.\r
-//     *\r
-//     * @return a unique name for this particular graph explorer view used for\r
-//     *         saving and restoring the state of this view part\r
-//     */\r
-//    public String getExplorerName() {\r
-//        return "GraphExplorerViewBase";\r
-//    }\r
-\r
-    protected Column[] getColumns() {\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * Override this method to add controls to the view part. This is invoked\r
-     * before attaching the view part to a database session.\r
-     * \r
-     * @param parent\r
-     */\r
-    protected void createControls(Composite parent) {\r
-\r
-        parent.setLayout(LayoutUtils.createNoBorderGridLayout(1, false));\r
-\r
-        // Initialize explorer control.\r
-        explorer = createExplorerControl(parent);\r
-\r
-        ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);\r
-        Control control = explorer.getControl();\r
-\r
-        Column[] columns = getColumns();\r
-        if(columns != null)\r
-            explorer.setColumns(columns);\r
-\r
-        GridDataFactory.fillDefaults().grab(true, true).applyTo(control);\r
-\r
-        // Initialize context menu if an initializer is provided.\r
-        IContextMenuInitializer cmi = getContextMenuInitializer();\r
-        if (cmi != null) {\r
-            menuManager = cmi.createContextMenu(control, selectionProvider, getSite());\r
-        }\r
-\r
-        // Initialize DND.\r
-        dragSource = createDragSource(explorer);\r
-\r
-        // Listeners are only added once per listener, not every time the\r
-        // session context changes.\r
-        addListeners(explorer, menuManager);\r
-    }\r
-\r
-    /**\r
-     * Override this method and provide a proper context menu initializer if you\r
-     * want to have this base class initialize one for you.\r
-     * \r
-     * @return the initializer to be used by {@link #createControls(Composite)}\r
-     */\r
-    protected IContextMenuInitializer getContextMenuInitializer() {\r
-        String contextMenuId = getContextMenuId();\r
-        if(contextMenuId != null) {\r
-            return new ContextMenuInitializer(contextMenuId);\r
-        } else {\r
-            return null;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * @return the ID of the context menu to initialize for this this graph\r
-     *         explorer view or <code>null</code> to not initialize a context\r
-     *         menu\r
-     */\r
-    protected String getContextMenuId() {\r
-        return null;\r
-    }\r
-\r
-    protected int getStyle() {\r
-        return SWT.MULTI;\r
-    }\r
-\r
-    /**\r
-     * @param parent\r
-     * @return\r
-     */\r
-    protected GraphExplorer createExplorerControl(Composite parent) {\r
-        return GraphExplorerFactory.getInstance()\r
-        .selectionDataResolver(new DefaultSelectionDataResolver())\r
-        .create(parent, getStyle());\r
-    }\r
-\r
-    /**\r
-     * Override to customize drag source initialization. This default\r
-     * implementation creates a {@link BasicDragSource}. The drag source is\r
-     * initialized when the active database session is set.\r
-     * \r
-     * @param explorer\r
-     * @return the object representing the drag source. If the object implements\r
-     *         {@link SessionContainer}, its\r
-     *         {@link SessionContainer#setSession(Session)} will be invoked\r
-     *         every time the active database session changes.\r
-     */\r
-    protected Object createDragSource(GraphExplorer explorer) {\r
-        ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);\r
-        Control control = explorer.getControl();\r
-        return new BasicDragSource(selectionProvider, control, null);\r
-    }\r
-\r
-    protected void setupDragSource(Session session) {\r
-        if (dragSource instanceof SessionContainer) {\r
-            ((SessionContainer) dragSource).setSession(session);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Override to customize the addition of listeners a newly created\r
-     * GraphExplorer.\r
-     * \r
-     * @param explorer\r
-     */\r
-    protected void addListeners(GraphExplorer explorer, IMenuManager menuManager) {\r
-        addSelectionInputListeners(explorer, menuManager);\r
-    }\r
-\r
-    protected void addSelectionInputListeners(GraphExplorer explorer, IMenuManager menuManager) {\r
-        // Consider ENTER presses to simulate mouse left button double clicks\r
-        explorer.addListener(new DefaultKeyListener(contextProvider, explorer, new Function<String[]>() {\r
-            @Override\r
-            public String[] execute(Object... obj) {\r
-                return new String[] { getEditingColumn((NodeContext) obj[0]) };\r
-            }\r
-        }));\r
-        // Default double click handling\r
-        explorer.addListener(new DefaultMouseListener(explorer));\r
-    }\r
-\r
-    protected String getEditingColumn(NodeContext context) {\r
-        return ColumnKeys.SINGLE;\r
-    }\r
-\r
-    /**\r
-     * Override to customize the initialization of the content provision and\r
-     * presentation of a GraphExplorer. This is called every time the input\r
-     * database session changes.\r
-     * \r
-     * @param explorer\r
-     * @param context may be <code>null</code> if there is no session\r
-     */\r
-    protected void initializeExplorer(final GraphExplorer explorer, ISessionContext context) {\r
-        setupDragSource((context != null) ? context.getSession() : null);\r
-    }\r
-\r
-    // Needed for preventing unnecessary re-initialization of the explorer with the same input.\r
-    private Object currentInput;\r
-\r
-    protected boolean isImportantInput(Object previousInput, Object input) {\r
-        return !ObjectUtils.objectEquals(previousInput, input);\r
-    }\r
-\r
-    /**\r
-     * Invoke this to reinitialize the explorer and reset its input. The input\r
-     * will be resolved from the specified ISessionContext based on the\r
-     * {@link SessionContextInputSource} that is currently in use. If the input\r
-     * is identical to the previous input, nothing will be done.\r
-     * \r
-     * @param context\r
-     */\r
-    protected final boolean applySessionContext(ISessionContext context) {\r
-        // If control is not alive anymore, do nothing.\r
-//        System.out.println(this + ": applySessionContext(" + context + "), explorer="  + explorer);\r
-        if (disposeState != DisposeState.Alive)\r
-            return false;\r
-\r
-        this.sessionContext = context;\r
-        Object input = inputSource.get(context);\r
-        if (!isImportantInput(currentInput, input))\r
-            return false;\r
-\r
-//        System.out.println(this + ": initializeExplorer(" + explorer + ", " + context + ")");\r
-        initializeExplorer(explorer, context);\r
-//        System.out.println(this + ": setRoot(" + input + ")");\r
-        explorer.setRoot(input);\r
-\r
-        currentInput = input;\r
-\r
-        // Start tracking the session context.\r
-        //\r
-        // If this is not the same session that is currently tracked, it will\r
-        // cause IHintListeners of the sessionContextTracker to fire.\r
-        // For this we need the above input equality (identity) checking.\r
-        // This is here just to make sure that we are tracking the correct\r
-        // session context.\r
-        sessionContextTracker.track(sessionContext);\r
-\r
-        return true;\r
-    }\r
-\r
-    @SuppressWarnings("rawtypes")\r
-    @Override\r
-    public Object getAdapter(Class adapter) {\r
-\r
-        if (GraphExplorer.class == adapter)\r
-            return explorer;\r
-        else if(ISessionContextProvider.class == adapter)\r
-            return getSessionContextProvider();\r
-        else if(IPropertyPage.class == adapter)\r
-            return getPropertyPage();\r
-\r
-        return super.getAdapter(adapter);\r
-\r
-    }\r
-\r
-    protected IPropertyPage getPropertyPage() {\r
-        return null;\r
-    }\r
-\r
-\r
-\r
-}\r
+/*******************************************************************************
+ * 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.browsing.ui.swt;
+
+import java.util.Map;
+
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.layout.GridDataFactory;
+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.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.IWorkbenchPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.part.ViewPart;
+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.views.IViewArguments;
+import org.simantics.browsing.ui.graph.impl.SessionContextInputSource;
+import org.simantics.db.Session;
+import org.simantics.db.common.request.Queries;
+import org.simantics.db.exception.DatabaseException;
+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.IProject;
+import org.simantics.project.ProjectKeys;
+import org.simantics.ui.SimanticsUI;
+import org.simantics.ui.dnd.BasicDragSource;
+import org.simantics.ui.dnd.SessionContainer;
+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.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.LayoutUtils;
+
+/**
+ * An abstract base Eclipse workbench ViewPart for use in situations where a
+ * tree-based GraphExplorer graph model browser is needed.
+ * 
+ * <p>
+ * Override to customize behavior:
+ * <ul>
+ * <li>{@link #createControls(Composite)}</li>
+ * <li>{@link #createExplorerControl(Composite)}</li>
+ * <li>{@link #createDragSource(GraphExplorer)}</li>
+ * <li>{@link #getContextMenuId()}</li>
+ * <li>{@link #getContextMenuInitializer()}</li>
+ * <li>{@link #addListeners(GraphExplorer, IMenuManager)}</li>
+ * </ul>
+ * </p>
+ * 
+ * <p>
+ * You can invoke the following methods from within
+ * {@link #createControls(Composite)} to customize how the view keeps track of
+ * the active ISessionContext and how the view resolves the input object of the
+ * GraphExplorer control.
+ * <ul>
+ * <li>{@link #setSessionContextTracker(IHintTracker)}</li>
+ * <li>{@link #setInputSource(SessionContextInputSource)}</li>
+ * </ul>
+ * </p>
+ * 
+ * @author Tuukka Lehtonen
+ * @deprecated in favor of org.simantics.views.swt.ModelledView 
+ */
+public abstract class GraphExplorerViewBase extends ViewPart {
+
+    /**
+     * The default hint tracker that will be active if
+     * {@link GraphExplorerViewBase#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);
+        }
+    }
+
+    /**
+     * The default implementation of a {@link SessionContextInputSource} that
+     * will be active if
+     * {@link GraphExplorerViewBase#setInputSource(SessionContextInputSource)}
+     * is not called.
+     */
+    public class SessionContextProjectSource implements SessionContextInputSource {
+        /**
+         * Returns the input object used by this GraphExplorer view. This object
+         * will be the starting point for all content shown in this explorer tree.
+         * 
+         * @param sessionContext a valid database session context
+         * @return the root object of the graph explorer tree or <code>null</code>
+         *         to indicate that there is no input and nothing should be shown.
+         */
+        @Override
+        public Object get(ISessionContext ctx) {
+            if (ctx == null)
+                return GraphExplorer.EMPTY_INPUT;
+
+            String inputId = getViewArguments().get(IViewArguments.INPUT);
+            if (inputId != null) {
+                try {
+                    return ctx.getSession().syncRequest(Queries.resource(inputId));
+                } catch (DatabaseException e) {
+                    // Ok, the view argument was invalid. Just continue to the next
+                    // method.
+                }
+            }
+
+            Object input = GraphExplorer.EMPTY_INPUT;
+            IProject project2 = ctx.getHint(ProjectKeys.KEY_PROJECT);
+            if (project2 != null)
+                input = project2.get();
+            return input;
+        }
+        
+        @Override
+        public IWorkbenchPart getProvider() {
+               return null;
+        }
+        
+    }
+
+    protected LocalResourceManager           resourceManager;
+
+    protected ISelectionListener             workbenchSelectionListener;
+
+    protected Composite                      parent;
+
+    protected GraphExplorer                 explorer;
+
+    protected IMenuManager                   menuManager;
+
+    private Map<String, String>              args;
+
+    private ISessionContextProvider          contextProvider;
+
+    private ISessionContext                  sessionContext;
+
+    private Object                           dragSource;
+
+    protected IMemento                       memento;
+
+    private IHintTracker                     sessionContextTracker = new SessionContextProjectTracker();
+
+    private SessionContextInputSource        inputSource           = new SessionContextProjectSource();
+
+    private DisposeState                     disposeState          = DisposeState.Alive;
+
+    protected ISessionContextChangedListener contextChangeListener = new ISessionContextChangedListener() {
+        @Override
+        public void sessionContextChanged(SessionContextChangedEvent event) {
+            sessionContext = event.getNewValue();
+            sessionContextTracker.track(sessionContext);
+        }
+    };
+
+    protected void setSessionContextTracker(IHintTracker tracker) {
+        this.sessionContextTracker = tracker;
+    }
+
+    protected void setInputSource(SessionContextInputSource source) {
+        this.inputSource = source;
+    }
+
+    protected SessionContextInputSource getInputSource() {
+        return inputSource;
+    }
+
+    protected Map<String, String> 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());
+        createControls(parent);
+        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() {
+        disposeState = DisposeState.Disposing;
+        try {
+            //System.out.println(this + ".GraphExplorerViewBase.dispose()");
+            if (contextProvider != null) {
+                contextProvider.removeContextChangedListener(contextChangeListener);
+                contextProvider = null;
+            }
+            sessionContextTracker.untrack();
+            resourceManager.dispose();
+            resourceManager = null;
+            args = null;
+            explorer = null;
+            sessionContext = null;
+            dragSource = null;
+            parent = null;
+            super.dispose();
+        } finally {
+            disposeState = DisposeState.Disposed;
+        }
+    }
+
+    @Override
+    public void setFocus() {
+        if (explorer != null && !explorer.isDisposed())
+            explorer.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:
+
+//    /**
+//     * Returns an ID that is used for persisting a GraphExplorer instance.
+//     *
+//     * Used for </code>restoreState(IMemento)</code> and
+//     * <code>restoreState(IMemento)</code> 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";
+//    }
+
+    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));
+
+        // Initialize explorer control.
+        explorer = createExplorerControl(parent);
+
+        ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
+        Control control = explorer.getControl();
+
+        Column[] columns = getColumns();
+        if(columns != null)
+            explorer.setColumns(columns);
+
+        GridDataFactory.fillDefaults().grab(true, true).applyTo(control);
+
+        // Initialize context menu if an initializer is provided.
+        IContextMenuInitializer cmi = getContextMenuInitializer();
+        if (cmi != null) {
+            menuManager = cmi.createContextMenu(control, selectionProvider, getSite());
+        }
+
+        // Initialize DND.
+        dragSource = createDragSource(explorer);
+
+        // Listeners are only added once per listener, not every time the
+        // session context changes.
+        addListeners(explorer, menuManager);
+    }
+
+    /**
+     * 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;
+        }
+    }
+
+    /**
+     * @return the ID of the context menu to initialize for this this graph
+     *         explorer view or <code>null</code> to not initialize a context
+     *         menu
+     */
+    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 drag source initialization. This default
+     * implementation creates a {@link BasicDragSource}. The drag source is
+     * initialized when the active database session is set.
+     * 
+     * @param explorer
+     * @return the object representing the drag source. If the object implements
+     *         {@link SessionContainer}, its
+     *         {@link SessionContainer#setSession(Session)} will be invoked
+     *         every time the active database session changes.
+     */
+    protected Object createDragSource(GraphExplorer explorer) {
+        ISelectionProvider selectionProvider = (ISelectionProvider)explorer.getAdapter(ISelectionProvider.class);
+        Control control = explorer.getControl();
+        return new BasicDragSource(selectionProvider, control, null);
+    }
+
+    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<String[]>() {
+            @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;
+    }
+
+    /**
+     * Override to customize the initialization of the content provision and
+     * presentation of a GraphExplorer. This is called every time the input
+     * database session changes.
+     * 
+     * @param explorer
+     * @param context may be <code>null</code> if there is no session
+     */
+    protected void initializeExplorer(final GraphExplorer explorer, ISessionContext context) {
+        setupDragSource((context != null) ? context.getSession() : null);
+    }
+
+    // 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 + ": applySessionContext(" + context + "), explorer="  + explorer);
+        if (disposeState != DisposeState.Alive)
+            return false;
+
+        this.sessionContext = context;
+        Object input = inputSource.get(context);
+        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;
+
+        // 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("rawtypes")
+    @Override
+    public Object getAdapter(Class adapter) {
+
+        if (GraphExplorer.class == adapter)
+            return explorer;
+        else if(ISessionContextProvider.class == adapter)
+            return getSessionContextProvider();
+        else if(IPropertyPage.class == adapter)
+            return getPropertyPage();
+
+        return super.getAdapter(adapter);
+
+    }
+
+    protected IPropertyPage getPropertyPage() {
+        return null;
+    }
+
+
+
+}