/******************************************************************************* * 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.ui.workbench; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.ViewPart; import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Session; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.event.ChangeEvent; import org.simantics.db.event.ChangeListener; import org.simantics.db.exception.DatabaseException; import org.simantics.db.management.ISessionContext; import org.simantics.db.service.GraphChangeListenerSupport; /** * This class acts as a base class for ViewParts that to access the semantic * graph from ProCore via {@link Session} and {@link Graph}. * *

* This class contains the vitals for setting up a the editor for ProCore * access. It also contains some support for dynamically allocating persistent * (via the viewpart memento) ResourceInput instances for the viewpart's * use, i.e. with OntologyExplorer controls. *

* *

* To use this class all you need to do is call super.createPartControl in your * own createPartControl implementation. This will make sure a {@link Graph} * will be available directly after that for initializing the UI and its * contents. *

* *
 *       class MyViewPart extends GraphAccessViewPart
 *           public void createPartControl(Composite parent) {
 *               super.createPartControl(parent);
 * 
 *               // Initialize UI controls.
 *               // Initialize "controllers" based on the "model" (graph structure).
 *               // Initialize "view" structures from the "controllers"
 *               // Reflect "model" state into "view"
 *               reload();
 *           }
 * 
 *           public void reload(Graph g) {
 *               // Reflect the current graph model state in the UI...
 *           }
 *       }
 * 
* *

* To open a GraphAccessViewPart use * WorkbenchUtils.activateView(view id). *

* * TODO: support changing active database session ? * * @author Tuukka Lehtonen */ public abstract class GraphAccessViewPart extends ViewPart { private IMemento memento; private ChangeListener graphChangeListener; protected ISessionContext sessionContext; protected Session session; @SuppressWarnings("unchecked") @Override public A getAdapter(Class adapter) { // NOTE: the Session is instantiated at createPartControl time! if (adapter == Session.class) return (A) getSession(); return super.getAdapter(adapter); } // ---------------------------------------------------------------------- // Getters public IStatusLineManager getStatusLineManager() { IViewSite site = getViewSite(); IActionBars bars = site.getActionBars(); IStatusLineManager mgr = bars.getStatusLineManager(); // if (mgr instanceof SubStatusLineManager) // ((SubStatusLineManager)mgr).setVisible(true); return mgr; } /** * @param message null to remove message */ public void setStatusMessage(String message) { getStatusLineManager().setMessage(message); } /** * @param message null to remove message */ public void setStatusErrorMessage(String message) { getStatusLineManager().setErrorMessage(message); } public IMemento getLastMemento() { return memento; } public IMemento consumeLastMemento() { IMemento m = memento; memento = null; return m; } // ---------------------------------------------------------------------- // Event handlers & initialisation /** * Default implementation of createPartControl. Merely calls * {@link #initialize()} to initialize the graph access. To make your * ViewPart do anything meaningful, you must override this method. But * remember to call super before trying to use the graph. * * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) */ @Override public void createPartControl(Composite parent) { initialize(); } @Override public void dispose() { cleanup(); super.dispose(); } @Override public void init(IViewSite site) throws PartInitException { super.init(site); } @Override public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); this.memento = memento; } protected ISessionContext getSessionContext() { return sessionContext; } protected Session getSession() { return session; } protected void initializeSession() { sessionContext = Simantics.getSessionContext(); if (sessionContext == null) throw new IllegalStateException("no active session context"); session = sessionContext.getSession(); } /** * Initializes graph data access and view resource ID input structures. * *

* This method is automatically called by * {@link #createPartControl(Composite)}. Override to perform own * graph-related initializations but be absolutely sure to call super the * first thing. Clients must not directly call this method. *

*/ protected void initialize() { initializeSession(); graphChangeListener = getGraphChangeListener(); if (graphChangeListener != null) { GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class); support.addListener(graphChangeListener); } } /** * Override this and return null to prevent a * {@link GraphChangeListener} from being added automatically. * * @return */ protected ChangeListener getGraphChangeListener() { return new ChangeListenerImpl(); } /** */ protected void cleanup() { if (session != null) { Session s = session; session = null; if (graphChangeListener != null) { GraphChangeListenerSupport support = s.getService(GraphChangeListenerSupport.class); support.removeListener(graphChangeListener); graphChangeListener = null; } } } /** * The ProCore update notification listener for all GraphAccessViewPart * instances. Calls * {@link ResourceInputViewPart#update(GraphChangeEvent)} default * implementation of which merely invokes * {@link ResourceInputViewPart#reload()} for which overriding is * allowed. */ class ChangeListenerImpl implements ChangeListener { public void graphChanged(ChangeEvent e) throws DatabaseException { // System.out.println(GraphAccessViewPart.this.getClass().getName() // + " receives update."); update(e); } } /** * This method is called when an update event is received from the Graph of * this {@link ResourceInputViewPart}. * * This base implementation stupidly calls {@link #reload()} on every * committed transaction or undo point change. * * @param event * the received change event */ protected void update(ChangeEvent event) throws DatabaseException { getSession().asyncRequest(new ReadRequest() { @Override public void run(ReadGraph g) { reload(g); } }); } // ---------------------------------------------------------------------- // Event utilities public void updateTitle() { // setPartName must not be called with a null name! String partName = getTitleText(); if (partName != null) { setPartName(partName); } // Tooltip may be null, which clears the tooltip. setTitleToolTip(getTitleTooltip()); } // ---------------------------------------------------------------------- // (Re-)Implement these if necessary: /** * Returns null by default which makes {@link #updateTitle()} not set the * part name programmatically, i.e. the plugin-defined view name will stay. * * @return */ protected String getTitleText() { return null; } /** * Return null by default which makes {@link #updateTitle()} clear the * tooltip. * * @return */ protected String getTitleTooltip() { return null; } /** * Reload the UI because there are changes in the data model that have not * been reflected to the UI. */ public abstract void reload(ReadGraph g); }