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