]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.views.swt/src/org/simantics/views/swt/ModelledView.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.views.swt / src / org / simantics / views / swt / ModelledView.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.views.swt;\r
13 \r
14 import org.eclipse.core.runtime.IConfigurationElement;\r
15 import org.eclipse.jface.layout.GridDataFactory;\r
16 import org.eclipse.jface.layout.GridLayoutFactory;\r
17 import org.eclipse.jface.viewers.ISelection;\r
18 import org.eclipse.swt.SWT;\r
19 import org.eclipse.swt.graphics.Point;\r
20 import org.eclipse.swt.widgets.Composite;\r
21 import org.eclipse.swt.widgets.Display;\r
22 import org.eclipse.swt.widgets.Event;\r
23 import org.eclipse.swt.widgets.Listener;\r
24 import org.eclipse.ui.IPartListener2;\r
25 import org.eclipse.ui.IWorkbenchPage;\r
26 import org.eclipse.ui.IWorkbenchPart;\r
27 import org.eclipse.ui.IWorkbenchPartReference;\r
28 import org.eclipse.ui.IWorkbenchSite;\r
29 import org.simantics.Simantics;\r
30 import org.simantics.browsing.ui.common.ErrorLogger;\r
31 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;\r
32 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupportImpl;\r
33 import org.simantics.db.ReadGraph;\r
34 import org.simantics.db.Resource;\r
35 import org.simantics.db.VirtualGraph;\r
36 import org.simantics.db.WriteGraph;\r
37 import org.simantics.db.common.request.WriteRequest;\r
38 import org.simantics.db.common.request.WriteResultRequest;\r
39 import org.simantics.db.common.utils.Logger;\r
40 import org.simantics.db.exception.DatabaseException;\r
41 import org.simantics.db.exception.ServiceNotFoundException;\r
42 import org.simantics.db.layer0.util.RemoverUtil;\r
43 import org.simantics.db.layer0.variable.Variable;\r
44 import org.simantics.db.management.ISessionContext;\r
45 import org.simantics.db.request.Read;\r
46 import org.simantics.layer0.Layer0;\r
47 import org.simantics.scenegraph.ontology.ScenegraphResources;\r
48 import org.simantics.scl.runtime.function.Function1;\r
49 import org.simantics.ui.workbench.IPropertyPage;\r
50 import org.simantics.utils.ui.jface.ActiveSelectionProvider;\r
51 import org.simantics.views.swt.client.base.SWTRoot;\r
52 \r
53 /**\r
54  * To use this class, first model your view contents in .pgraph files according\r
55  * to the Browsing.pgraph ontology. After that there are two ways to put your\r
56  * configuration to use by defining a new view extension:\r
57  * <ol>\r
58  * <li>Set view extension class to\r
59  * <code>org.simantics.browsing.ui.swt.ModelledView:configurationURI=ConfigURI</code>\r
60  * , where ConfigURI is the URI of your view configuration.</li>\r
61  * <li>Extend this class and override at least {@link #configurationURI()} to\r
62  * define the URI from which the configuration for the view is found. Set view\r
63  * extension class to the created class.</li>\r
64  * </ol>\r
65  * \r
66  * @author Antti Villberg\r
67  */\r
68 public class ModelledView extends SimanticsView implements IPartListener2 {\r
69 \r
70     public static final int TIME_BEFORE_DISPOSE_WHEN_HIDDEN = 30000; // ms\r
71     \r
72     private static final boolean           DEBUG             = false;\r
73 \r
74     protected Resource                     runtime;\r
75     protected String                       configurationURI;\r
76 \r
77     protected SWTRoot                      root;\r
78 \r
79     protected Variable                     viewVariable;\r
80 \r
81     protected Function1<Variable, Boolean> onInputChanged    = null;\r
82 \r
83     protected SWTViewLoaderProcess         loader;\r
84 \r
85     protected Composite                    body;\r
86 \r
87     protected Composite                    container;\r
88 \r
89     protected ModelledSupport              support;\r
90 \r
91     ActiveSelectionProvider                selectionProvider = new ActiveSelectionProvider() {\r
92         @Override\r
93         public void setSelection(ISelection selection) {\r
94             super.setSelection(selection);\r
95         }\r
96     };\r
97 \r
98     protected String configurationURI() {\r
99         return configurationURI;\r
100     }\r
101 \r
102     @Override\r
103     protected WidgetSupportImpl createSupport() {\r
104 \r
105         try {\r
106             runtime = Simantics.getSession().sync(\r
107                     new WriteResultRequest<Resource>(Simantics.getSession().getService(VirtualGraph.class)) {\r
108                         @Override\r
109                         public Resource perform(WriteGraph graph) throws DatabaseException {\r
110                             Layer0 L0 = Layer0.getInstance(graph);\r
111                             ScenegraphResources SG = ScenegraphResources.getInstance(graph);\r
112                             Resource runtime = graph.newResource();\r
113                             graph.claim(runtime, L0.InstanceOf, null, SG.Runtime);\r
114                             return runtime;\r
115                         }\r
116                     });\r
117         } catch (ServiceNotFoundException e) {\r
118             Logger.defaultLogError(e);\r
119         } catch (DatabaseException e) {\r
120             Logger.defaultLogError(e);\r
121         }\r
122 \r
123         support = new ModelledSupport(this);\r
124 \r
125         return support;\r
126 \r
127     }\r
128 \r
129     public void fireInput() {\r
130         if (onInputChanged != null)\r
131             onInputChanged.apply(viewVariable);\r
132     }\r
133 \r
134     @Override\r
135     public void setInitializationData(IConfigurationElement cfig, String propertyName, Object data) {\r
136         super.setInitializationData(cfig, propertyName, data);\r
137         if (data instanceof String) {\r
138             String[] parameters = ((String) data).split(";");\r
139 \r
140             for (String parameter : parameters) {\r
141                 String[] keyValue = parameter.split("=");\r
142                 if (keyValue.length > 2) {\r
143                     ErrorLogger.defaultLogWarning("Invalid parameter '" + parameter + ". Complete view argument: "\r
144                             + data, null);\r
145                     continue;\r
146                 }\r
147                 String key = keyValue[0];\r
148                 String value = keyValue.length > 1 ? keyValue[1] : "";\r
149 \r
150                 if ("configurationURI".equals(key)) {\r
151                     configurationURI = value;\r
152                 }\r
153             }\r
154         }\r
155     }\r
156 \r
157     protected void doCreateControls(boolean load) {\r
158         if (DEBUG)\r
159             System.out.println(this + " doCreateControls(" + load + ")");\r
160 \r
161         if (container == null) {\r
162             GridLayoutFactory.fillDefaults().applyTo(body);\r
163             container = new Composite(body, SWT.NONE);\r
164             GridDataFactory.fillDefaults().grab(true, true).applyTo(container);\r
165             GridLayoutFactory.fillDefaults().applyTo(container);\r
166         }\r
167 \r
168         if (load) {\r
169 \r
170             try {\r
171 \r
172                 loader = new SWTViewLoaderProcess(this, getSite(), getClass().getSimpleName());\r
173 \r
174                 viewVariable = loader.getVariable(Simantics.getSession(), configurationURI(), runtime);\r
175 \r
176                 onInputChanged = Simantics.getSession().syncRequest(new Read<Function1<Variable, Boolean>>() {\r
177 \r
178                     @Override\r
179                     public Function1<Variable, Boolean> perform(ReadGraph graph) throws DatabaseException {\r
180                         return viewVariable.getPossiblePropertyValue(graph, "onInputChanged");\r
181                     }\r
182 \r
183                 });\r
184 \r
185                 root = loader.load(Simantics.getSession(), viewVariable);\r
186                 root.createControls(container);\r
187                 root.getControl().addListener(SWT.Dispose, new Listener() {\r
188 \r
189                     final SWTViewLoaderProcess oldLoader = ModelledView.this.loader;\r
190 \r
191                     @Override\r
192                     public void handleEvent(Event event) {\r
193 \r
194                         if (oldLoader != null && !oldLoader.isDisposed())\r
195                             oldLoader.dispose();\r
196 \r
197                     }\r
198 \r
199                 });\r
200 \r
201                 body.layout(true);\r
202 \r
203                 getSite().setSelectionProvider(selectionProvider);\r
204 \r
205             } catch (DatabaseException e) {\r
206 \r
207                 e.printStackTrace();\r
208                 Logger.defaultLogError(e);\r
209 \r
210             }\r
211 \r
212         }\r
213 \r
214     }\r
215 \r
216     @Override\r
217     protected void createControls(Composite body, IWorkbenchSite site, ISessionContext context, WidgetSupport support) {\r
218         this.body = body;\r
219 \r
220         // Only create controls if the part is TRULY visible.\r
221         // Fast view parts seem to cause calls to createPartControl even\r
222         // when the part is hidden in reality\r
223         boolean visible = site.getPage().isPartVisible(this);\r
224         if (DEBUG)\r
225             System.out.println(this + ": createControls( visible=" + site.getPage().isPartVisible(this) + " )");\r
226         doCreateControls(true);\r
227 \r
228         getSite().setSelectionProvider(selectionProvider);\r
229         getSite().getPage().addPartListener(this);\r
230 \r
231     }\r
232 \r
233     protected void inputChanged(IWorkbenchPart provider, Object input) {\r
234         // Do not accept selections from self\r
235         if (provider == this)\r
236             return;\r
237         applySessionContext(getSessionContext());\r
238     }\r
239 \r
240     @Override\r
241     public void setFocus() {\r
242         if (root != null && !root.isNodeDisposed())\r
243             root.setFocus();\r
244     }\r
245 \r
246     public void setVisible(boolean value) {\r
247         if (root != null && !root.isNodeDisposed())\r
248             root.setVisible(value);\r
249     }\r
250 \r
251     @Override\r
252     public void dispose() {\r
253 \r
254         disposeRuntime(runtime);\r
255 \r
256         IWorkbenchSite site = getSite();\r
257         if (site != null) {\r
258             IWorkbenchPage page = site.getPage();\r
259             if (page != null) {\r
260                 page.removePartListener(this);\r
261             }\r
262         }\r
263 \r
264         if (root != null) {\r
265             root.cleanup();\r
266             root = null;\r
267         }\r
268         if (loader != null) {\r
269             loader.dispose();\r
270             loader = null;\r
271         }\r
272         if (support != null) {\r
273             support.dispose();\r
274             support = null;\r
275         }\r
276 \r
277         super.dispose();\r
278         \r
279     }\r
280 \r
281     protected void disposeRuntime(Resource runtime) {\r
282         final Resource rt = this.runtime;\r
283         this.runtime = null;\r
284         if (rt == null)\r
285             return;\r
286 \r
287         try {\r
288             Simantics.getSession().sync(new WriteRequest(Simantics.getSession().getService(VirtualGraph.class)) {\r
289                 @Override\r
290                 public void perform(WriteGraph graph) throws DatabaseException {\r
291                     RemoverUtil.remove(graph, rt);\r
292                 }\r
293             });\r
294         } catch (ServiceNotFoundException e) {\r
295             Logger.defaultLogError(e);\r
296         } catch (DatabaseException e) {\r
297             Logger.defaultLogError(e);\r
298         }\r
299     }\r
300 \r
301     @Override\r
302     public void partActivated(IWorkbenchPartReference partRef) {\r
303         if (DEBUG) {\r
304             IWorkbenchPart part = partRef.getPart(false);\r
305             if (this.equals(part)) {\r
306                 System.out.println(this + ": ACTIVATED ( loader=" + loader + ", visible="\r
307                         + getSite().getPage().isPartVisible(part) + " )");\r
308             }\r
309         }\r
310     }\r
311 \r
312     @Override\r
313     public void partBroughtToTop(IWorkbenchPartReference partRef) {\r
314         if (DEBUG) {\r
315             IWorkbenchPart part = partRef.getPart(false);\r
316             if (this.equals(part)) {\r
317                 System.out.println(this + ": BROUGHT TO TOP ( loader=" + loader + ", visible="\r
318                         + getSite().getPage().isPartVisible(part) + " )");\r
319             }\r
320         }\r
321     }\r
322 \r
323     @Override\r
324     public void partClosed(IWorkbenchPartReference partRef) {\r
325         if (DEBUG) {\r
326             IWorkbenchPart part = partRef.getPart(false);\r
327             if (this.equals(part)) {\r
328                 System.out.println(this + ": CLOSED ( loader=" + loader + ", visible="\r
329                         + getSite().getPage().isPartVisible(part) + " )");\r
330             }\r
331         }\r
332     }\r
333 \r
334     @Override\r
335     public void partDeactivated(IWorkbenchPartReference partRef) {\r
336         IWorkbenchPart part = partRef.getPart(false);\r
337         if (this.equals(part)) {\r
338             if (DEBUG)\r
339                 System.out.println(this + ": DEACTIVATED ( loader=" + loader + ", visible="\r
340                         + getSite().getPage().isPartVisible(part) + " )");\r
341             // clearExisting();\r
342         }\r
343     }\r
344 \r
345     @Override\r
346     public void partOpened(IWorkbenchPartReference partRef) {\r
347         if (DEBUG) {\r
348             IWorkbenchPart part = partRef.getPart(false);\r
349             if (this.equals(part)) {\r
350                 System.out.println(this + ": OPENED ( loader=" + loader + ", visible="\r
351                         + getSite().getPage().isPartVisible(part) + " )");\r
352             }\r
353         }\r
354     }\r
355 \r
356     @Override\r
357     public void partInputChanged(IWorkbenchPartReference partRef) {\r
358     }\r
359 \r
360     @Override\r
361     public void partHidden(IWorkbenchPartReference partRef) {\r
362         IWorkbenchPart part = partRef.getPart(false);\r
363         if (this.equals(part)) {\r
364             if (DEBUG)\r
365                 System.out.println(this + ": HID ( loader=" + loader + ", visible="\r
366                         + getSite().getPage().isPartVisible(part) + " )");\r
367             clearExisting();\r
368         }\r
369     }\r
370 \r
371     @Override\r
372     public void partVisible(IWorkbenchPartReference partRef) {\r
373         IWorkbenchPart part = partRef.getPart(false);\r
374         if (this.equals(part)) {\r
375             if (DEBUG)\r
376                 System.out.println(this + ": MADE VISIBLE ( loader=" + loader + ", visible="\r
377                         + getSite().getPage().isPartVisible(part) + " )");\r
378             createControlsIfNecessary(false);\r
379         }\r
380     }\r
381 \r
382     private void createControlsIfNecessary(boolean forceContainerRepaint) {\r
383         // Cancel potential dispose before creating controls\r
384         reallyClearExisting = false;\r
385         if (loader == null) {\r
386             doCreateControls(true);\r
387             body.layout(true);\r
388 \r
389             if (forceContainerRepaint) {\r
390                 container.layout(true);\r
391                 Point size = container.getSize();\r
392                 container.redraw(0, 0, size.x, size.y, true);\r
393                 container.update();\r
394             }\r
395         }\r
396     }\r
397     \r
398     // Can be used to cancel already scheduled dispose\r
399     volatile boolean reallyClearExisting = false;\r
400     \r
401     Runnable clearExisting = new Runnable() {\r
402 \r
403         @Override\r
404         public void run() {\r
405             if(!reallyClearExisting)\r
406                 return;\r
407             viewVariable = null;\r
408             onInputChanged = null;\r
409 \r
410             if (loader != null) {\r
411                 loader.dispose();\r
412                 loader = null;\r
413             }\r
414             if (container != null) {\r
415 \r
416                 final Composite oldContainer = container;\r
417                 Display.getCurrent().asyncExec(new Runnable() {\r
418                     @Override\r
419                     public void run() {\r
420                         if (!oldContainer.isDisposed())\r
421                             oldContainer.dispose();\r
422                     }\r
423                 });\r
424 \r
425                 if (!container.isDisposed())\r
426                     GridDataFactory.fillDefaults().exclude(true).applyTo(container);\r
427                 container = null;\r
428 \r
429             }\r
430 \r
431             root = null;\r
432         }\r
433         \r
434     };\r
435 \r
436     private void clearExisting() {\r
437         Display.getCurrent().timerExec(TIME_BEFORE_DISPOSE_WHEN_HIDDEN, clearExisting);\r
438         \r
439         // Do this after scheduling the runnable, because otherwise already scheduled runnable could \r
440         // get the flag.\r
441         reallyClearExisting = true;\r
442     }\r
443 \r
444     @Override\r
445     protected IPropertyPage getPropertyPage() {\r
446         return null;\r
447     }\r
448     \r
449 }\r