-/*******************************************************************************\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.eclipse.ui.services.IDisposable;
+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);
+ if (workbenchSelectionListener instanceof IDisposable)
+ ((IDisposable) workbenchSelectionListener).dispose();
+ 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("unchecked")
+ @Override
+ public <T> T getAdapter(Class<T> adapter) {
+
+ if (GraphExplorer.class == adapter)
+ return (T) explorer;
+ else if(ISessionContextProvider.class == adapter)
+ return (T) getSessionContextProvider();
+ else if(IPropertyPage.class == adapter)
+ return (T) getPropertyPage();
+
+ return super.getAdapter(adapter);
+
+ }
+
+ protected IPropertyPage getPropertyPage() {
+ return null;
+ }
+
+
+
+}