--- /dev/null
+/*******************************************************************************\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.ui.workbench;\r
+\r
+import org.eclipse.jface.action.IStatusLineManager;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.ui.IActionBars;\r
+import org.eclipse.ui.IMemento;\r
+import org.eclipse.ui.IViewSite;\r
+import org.eclipse.ui.PartInitException;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.event.ChangeEvent;\r
+import org.simantics.db.event.ChangeListener;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.management.ISessionContext;\r
+import org.simantics.db.service.GraphChangeListenerSupport;\r
+import org.simantics.ui.SimanticsUI;\r
+\r
+/**\r
+ * This class acts as a base class for ViewParts that to access the semantic\r
+ * graph from ProCore via {@link Session} and {@link Graph}.\r
+ * \r
+ * <p>\r
+ * This class contains the vitals for setting up a the editor for ProCore\r
+ * access. It also contains some support for dynamically allocating persistent\r
+ * (via the viewpart memento) ResourceInput instances for the viewpart's\r
+ * use, i.e. with OntologyExplorer controls.\r
+ * </p>\r
+ * \r
+ * <p>\r
+ * To use this class all you need to do is call super.createPartControl in your\r
+ * own createPartControl implementation. This will make sure a {@link Graph}\r
+ * will be available directly after that for initializing the UI and its\r
+ * contents.\r
+ * </p>\r
+ * \r
+ * <pre>\r
+ * class MyViewPart extends GraphAccessViewPart\r
+ * public void createPartControl(Composite parent) {\r
+ * super.createPartControl(parent);\r
+ * \r
+ * // Initialize UI controls.\r
+ * // Initialize "controllers" based on the "model" (graph structure).\r
+ * // Initialize "view" structures from the "controllers"\r
+ * // Reflect "model" state into "view"\r
+ * reload();\r
+ * }\r
+ * \r
+ * public void reload(Graph g) {\r
+ * // Reflect the current graph model state in the UI...\r
+ * }\r
+ * }\r
+ * </pre>\r
+ * \r
+ * <p>\r
+ * To open a GraphAccessViewPart use\r
+ * <code>WorkbenchUtils.activateView(view id)</code>.\r
+ * </p>\r
+ * \r
+ * TODO: support changing active database session ?\r
+ * \r
+ * @author Tuukka Lehtonen\r
+ */\r
+public abstract class GraphAccessViewPart extends ViewPart {\r
+\r
+ private IMemento memento;\r
+\r
+ private ChangeListener graphChangeListener;\r
+\r
+ protected ISessionContext sessionContext;\r
+\r
+ protected Session session;\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @Override\r
+ public <A> A getAdapter(Class<A> adapter) {\r
+ // NOTE: the Session is instantiated at createPartControl time!\r
+ if (adapter == Session.class)\r
+ return (A) getSession();\r
+ return super.getAdapter(adapter);\r
+ }\r
+\r
+ // ----------------------------------------------------------------------\r
+ // Getters\r
+\r
+ public IStatusLineManager getStatusLineManager() {\r
+ IViewSite site = getViewSite();\r
+ IActionBars bars = site.getActionBars();\r
+ IStatusLineManager mgr = bars.getStatusLineManager();\r
+ // if (mgr instanceof SubStatusLineManager)\r
+ // ((SubStatusLineManager)mgr).setVisible(true);\r
+ return mgr;\r
+ }\r
+\r
+ /**\r
+ * @param message <code>null</code> to remove message\r
+ */\r
+ public void setStatusMessage(String message) {\r
+ getStatusLineManager().setMessage(message);\r
+ }\r
+\r
+ /**\r
+ * @param message <code>null</code> to remove message\r
+ */\r
+ public void setStatusErrorMessage(String message) {\r
+ getStatusLineManager().setErrorMessage(message);\r
+ }\r
+\r
+ public IMemento getLastMemento() {\r
+ return memento;\r
+ }\r
+\r
+ public IMemento consumeLastMemento() {\r
+ IMemento m = memento;\r
+ memento = null;\r
+ return m;\r
+ }\r
+\r
+ // ----------------------------------------------------------------------\r
+ // Event handlers & initialisation\r
+\r
+ /**\r
+ * Default implementation of createPartControl. Merely calls\r
+ * {@link #initialize()} to initialize the graph access. To make your\r
+ * ViewPart do anything meaningful, you must override this method. But\r
+ * remember to call super before trying to use the graph.\r
+ * \r
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ public void createPartControl(Composite parent) {\r
+ initialize();\r
+ }\r
+\r
+ @Override\r
+ public void dispose() {\r
+ cleanup();\r
+ super.dispose();\r
+ }\r
+\r
+ @Override\r
+ public void init(IViewSite site) throws PartInitException {\r
+ super.init(site);\r
+ }\r
+\r
+ @Override\r
+ public void init(IViewSite site, IMemento memento) throws PartInitException {\r
+ super.init(site, memento);\r
+ this.memento = memento;\r
+ }\r
+\r
+ protected ISessionContext getSessionContext() {\r
+ return sessionContext;\r
+ }\r
+\r
+ protected Session getSession() {\r
+ return session;\r
+ }\r
+\r
+ protected void initializeSession() {\r
+ sessionContext = SimanticsUI.getSessionContext();\r
+ if (sessionContext == null)\r
+ throw new IllegalStateException("no active session context");\r
+ session = sessionContext.getSession();\r
+ }\r
+\r
+ /**\r
+ * Initializes graph data access and view resource ID input structures.\r
+ * \r
+ * <p>\r
+ * This method is automatically called by\r
+ * {@link #createPartControl(Composite)}. Override to perform own\r
+ * graph-related initializations but be absolutely sure to call super the\r
+ * first thing. Clients must not directly call this method.\r
+ * </p>\r
+ */\r
+ protected void initialize() {\r
+ initializeSession();\r
+\r
+ graphChangeListener = getGraphChangeListener();\r
+ if (graphChangeListener != null) {\r
+ GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class);\r
+ support.addListener(graphChangeListener);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Override this and return <code>null</code> to prevent a\r
+ * {@link GraphChangeListener} from being added automatically.\r
+ * \r
+ * @return\r
+ */\r
+ protected ChangeListener getGraphChangeListener() {\r
+ return new ChangeListenerImpl();\r
+ }\r
+\r
+ /**\r
+ */\r
+ protected void cleanup() {\r
+ if (session != null) {\r
+ Session s = session;\r
+ session = null;\r
+\r
+ if (graphChangeListener != null) {\r
+ GraphChangeListenerSupport support = s.getService(GraphChangeListenerSupport.class);\r
+ support.removeListener(graphChangeListener);\r
+ graphChangeListener = null;\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * The ProCore update notification listener for all GraphAccessViewPart\r
+ * instances. Calls\r
+ * {@link ResourceInputViewPart#update(GraphChangeEvent)} default\r
+ * implementation of which merely invokes\r
+ * {@link ResourceInputViewPart#reload()} for which overriding is\r
+ * allowed.\r
+ */\r
+ class ChangeListenerImpl implements ChangeListener {\r
+ public void graphChanged(ChangeEvent e) throws DatabaseException {\r
+ // System.out.println(GraphAccessViewPart.this.getClass().getName()\r
+ // + " receives update.");\r
+ update(e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * This method is called when an update event is received from the Graph of\r
+ * this {@link ResourceInputViewPart}.\r
+ * \r
+ * This base implementation stupidly calls {@link #reload()} on every\r
+ * committed transaction or undo point change.\r
+ * \r
+ * @param event\r
+ * the received change event\r
+ */\r
+ protected void update(ChangeEvent event) throws DatabaseException {\r
+ getSession().asyncRequest(new ReadRequest() {\r
+ @Override\r
+ public void run(ReadGraph g) {\r
+ reload(g);\r
+ }\r
+ });\r
+ }\r
+\r
+ // ----------------------------------------------------------------------\r
+ // Event utilities\r
+\r
+ public void updateTitle() {\r
+ // setPartName must not be called with a null name!\r
+ String partName = getTitleText();\r
+ if (partName != null) {\r
+ setPartName(partName);\r
+ }\r
+ // Tooltip may be null, which clears the tooltip.\r
+ setTitleToolTip(getTitleTooltip());\r
+ }\r
+\r
+ // ----------------------------------------------------------------------\r
+ // (Re-)Implement these if necessary:\r
+\r
+ /**\r
+ * Returns null by default which makes {@link #updateTitle()} not set the\r
+ * part name programmatically, i.e. the plugin-defined view name will stay.\r
+ * \r
+ * @return\r
+ */\r
+ protected String getTitleText() {\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Return null by default which makes {@link #updateTitle()} clear the\r
+ * tooltip.\r
+ * \r
+ * @return\r
+ */\r
+ protected String getTitleTooltip() {\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Reload the UI because there are changes in the data model that have not\r
+ * been reflected to the UI.\r
+ */\r
+ public abstract void reload(ReadGraph g);\r
+\r
+}\r