]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.ui/src/org/simantics/ui/workbench/GraphAccessViewPart.java
739796aae3554eca1575ff307bc16912da504e11
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / workbench / GraphAccessViewPart.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.ui.workbench;
13
14 import org.eclipse.jface.action.IStatusLineManager;
15 import org.eclipse.swt.widgets.Composite;
16 import org.eclipse.ui.IActionBars;
17 import org.eclipse.ui.IMemento;
18 import org.eclipse.ui.IViewSite;
19 import org.eclipse.ui.PartInitException;
20 import org.eclipse.ui.part.ViewPart;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.Session;
23 import org.simantics.db.common.request.ReadRequest;
24 import org.simantics.db.event.ChangeEvent;
25 import org.simantics.db.event.ChangeListener;
26 import org.simantics.db.exception.DatabaseException;
27 import org.simantics.db.management.ISessionContext;
28 import org.simantics.db.service.GraphChangeListenerSupport;
29 import org.simantics.ui.SimanticsUI;
30
31 /**
32  * This class acts as a base class for ViewParts that to access the semantic
33  * graph from ProCore via {@link Session} and {@link Graph}.
34  * 
35  * <p>
36  * This class contains the vitals for setting up a the editor for ProCore
37  * access. It also contains some support for dynamically allocating persistent
38  * (via the viewpart memento) ResourceInput instances for the viewpart's
39  * use, i.e. with OntologyExplorer controls.
40  * </p>
41  * 
42  * <p>
43  * To use this class all you need to do is call super.createPartControl in your
44  * own createPartControl implementation. This will make sure a {@link Graph}
45  * will be available directly after that for initializing the UI and its
46  * contents.
47  * </p>
48  * 
49  * <pre>
50  *       class MyViewPart extends GraphAccessViewPart
51  *           public void createPartControl(Composite parent) {
52  *               super.createPartControl(parent);
53  * 
54  *               // Initialize UI controls.
55  *               // Initialize &quot;controllers&quot; based on the &quot;model&quot; (graph structure).
56  *               // Initialize &quot;view&quot; structures from the &quot;controllers&quot;
57  *               // Reflect &quot;model&quot; state into &quot;view&quot;
58  *               reload();
59  *           }
60  * 
61  *           public void reload(Graph g) {
62  *               // Reflect the current graph model state in the UI...
63  *           }
64  *       }
65  * </pre>
66  * 
67  * <p>
68  * To open a GraphAccessViewPart use
69  * <code>WorkbenchUtils.activateView(view id)</code>.
70  * </p>
71  * 
72  * TODO: support changing active database session ?
73  * 
74  * @author Tuukka Lehtonen
75  */
76 public abstract class GraphAccessViewPart extends ViewPart {
77
78     private IMemento          memento;
79
80     private ChangeListener    graphChangeListener;
81
82     protected ISessionContext sessionContext;
83
84     protected Session         session;
85
86     @SuppressWarnings("unchecked")
87         @Override
88     public <A> A getAdapter(Class<A> adapter) {
89         // NOTE: the Session is instantiated at createPartControl time!
90         if (adapter == Session.class)
91             return (A) getSession();
92         return super.getAdapter(adapter);
93     }
94
95     // ----------------------------------------------------------------------
96     // Getters
97
98     public IStatusLineManager getStatusLineManager() {
99         IViewSite site = getViewSite();
100         IActionBars bars = site.getActionBars();
101         IStatusLineManager mgr = bars.getStatusLineManager();
102         // if (mgr instanceof SubStatusLineManager)
103         // ((SubStatusLineManager)mgr).setVisible(true);
104         return mgr;
105     }
106
107     /**
108      * @param message <code>null</code> to remove message
109      */
110     public void setStatusMessage(String message) {
111         getStatusLineManager().setMessage(message);
112     }
113
114     /**
115      * @param message <code>null</code> to remove message
116      */
117     public void setStatusErrorMessage(String message) {
118         getStatusLineManager().setErrorMessage(message);
119     }
120
121     public IMemento getLastMemento() {
122         return memento;
123     }
124
125     public IMemento consumeLastMemento() {
126         IMemento m = memento;
127         memento = null;
128         return m;
129     }
130
131     // ----------------------------------------------------------------------
132     // Event handlers & initialisation
133
134     /**
135      * Default implementation of createPartControl. Merely calls
136      * {@link #initialize()} to initialize the graph access. To make your
137      * ViewPart do anything meaningful, you must override this method. But
138      * remember to call super before trying to use the graph.
139      * 
140      * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
141      */
142     @Override
143     public void createPartControl(Composite parent) {
144         initialize();
145     }
146
147     @Override
148     public void dispose() {
149         cleanup();
150         super.dispose();
151     }
152
153     @Override
154     public void init(IViewSite site) throws PartInitException {
155         super.init(site);
156     }
157
158     @Override
159     public void init(IViewSite site, IMemento memento) throws PartInitException {
160         super.init(site, memento);
161         this.memento = memento;
162     }
163
164     protected ISessionContext getSessionContext() {
165         return sessionContext;
166     }
167
168     protected Session getSession() {
169         return session;
170     }
171
172     protected void initializeSession() {
173         sessionContext = SimanticsUI.getSessionContext();
174         if (sessionContext == null)
175             throw new IllegalStateException("no active session context");
176         session = sessionContext.getSession();
177     }
178
179     /**
180      * Initializes graph data access and view resource ID input structures.
181      * 
182      * <p>
183      * This method is automatically called by
184      * {@link #createPartControl(Composite)}. Override to perform own
185      * graph-related initializations but be absolutely sure to call super the
186      * first thing. Clients must not directly call this method.
187      * </p>
188      */
189     protected void initialize() {
190         initializeSession();
191
192         graphChangeListener = getGraphChangeListener();
193         if (graphChangeListener != null) {
194             GraphChangeListenerSupport support = session.getService(GraphChangeListenerSupport.class);
195             support.addListener(graphChangeListener);
196         }
197     }
198
199     /**
200      * Override this and return <code>null</code> to prevent a
201      * {@link GraphChangeListener} from being added automatically.
202      * 
203      * @return
204      */
205     protected ChangeListener getGraphChangeListener() {
206         return new ChangeListenerImpl();
207     }
208
209     /**
210      */
211     protected void cleanup() {
212         if (session != null) {
213             Session s = session;
214             session = null;
215
216             if (graphChangeListener != null) {
217                 GraphChangeListenerSupport support = s.getService(GraphChangeListenerSupport.class);
218                 support.removeListener(graphChangeListener);
219                 graphChangeListener = null;
220             }
221         }
222     }
223
224     /**
225      * The ProCore update notification listener for all GraphAccessViewPart
226      * instances. Calls
227      * {@link ResourceInputViewPart#update(GraphChangeEvent)} default
228      * implementation of which merely invokes
229      * {@link ResourceInputViewPart#reload()} for which overriding is
230      * allowed.
231      */
232     class ChangeListenerImpl implements ChangeListener {
233         public void graphChanged(ChangeEvent e) throws DatabaseException {
234             // System.out.println(GraphAccessViewPart.this.getClass().getName()
235             // + " receives update.");
236             update(e);
237         }
238     }
239
240     /**
241      * This method is called when an update event is received from the Graph of
242      * this {@link ResourceInputViewPart}.
243      * 
244      * This base implementation stupidly calls {@link #reload()} on every
245      * committed transaction or undo point change.
246      * 
247      * @param event
248      *            the received change event
249      */
250     protected void update(ChangeEvent event) throws DatabaseException {
251         getSession().asyncRequest(new ReadRequest() {
252             @Override
253             public void run(ReadGraph g) {
254                 reload(g);
255             }
256         });
257     }
258
259     // ----------------------------------------------------------------------
260     // Event utilities
261
262     public void updateTitle() {
263         // setPartName must not be called with a null name!
264         String partName = getTitleText();
265         if (partName != null) {
266             setPartName(partName);
267         }
268         // Tooltip may be null, which clears the tooltip.
269         setTitleToolTip(getTitleTooltip());
270     }
271
272     // ----------------------------------------------------------------------
273     // (Re-)Implement these if necessary:
274
275     /**
276      * Returns null by default which makes {@link #updateTitle()} not set the
277      * part name programmatically, i.e. the plugin-defined view name will stay.
278      * 
279      * @return
280      */
281     protected String getTitleText() {
282         return null;
283     }
284
285     /**
286      * Return null by default which makes {@link #updateTitle()} clear the
287      * tooltip.
288      * 
289      * @return
290      */
291     protected String getTitleTooltip() {
292         return null;
293     }
294
295     /**
296      * Reload the UI because there are changes in the data model that have not
297      * been reflected to the UI.
298      */
299     public abstract void reload(ReadGraph g);
300
301 }