]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.selectionview/src/org/simantics/selectionview/ModelledTabContributor.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.selectionview / src / org / simantics / selectionview / ModelledTabContributor.java
1 package org.simantics.selectionview;
2
3 import java.util.function.Consumer;
4
5 import org.eclipse.jface.layout.GridDataFactory;
6 import org.eclipse.jface.layout.GridLayoutFactory;
7 import org.eclipse.jface.viewers.ISelection;
8 import org.eclipse.jface.viewers.ISelectionProvider;
9 import org.eclipse.jface.viewers.StructuredSelection;
10 import org.eclipse.swt.SWT;
11 import org.eclipse.swt.widgets.Composite;
12 import org.eclipse.swt.widgets.Control;
13 import org.eclipse.swt.widgets.Event;
14 import org.eclipse.swt.widgets.Listener;
15 import org.eclipse.ui.IWorkbenchSite;
16 import org.simantics.Simantics;
17 import org.simantics.browsing.ui.common.ErrorLogger;
18 import org.simantics.browsing.ui.common.views.IFilterArea;
19 import org.simantics.browsing.ui.common.views.IFilterAreaProvider;
20 import org.simantics.browsing.ui.swt.PartNameListener;
21 import org.simantics.databoard.Bindings;
22 import org.simantics.db.AsyncReadGraph;
23 import org.simantics.db.ReadGraph;
24 import org.simantics.db.Resource;
25 import org.simantics.db.VirtualGraph;
26 import org.simantics.db.WriteGraph;
27 import org.simantics.db.common.procedure.adapter.DisposableAsyncListener;
28 import org.simantics.db.common.procedure.adapter.ListenerSupport;
29 import org.simantics.db.common.request.UniqueRead;
30 import org.simantics.db.common.request.WriteRequest;
31 import org.simantics.db.common.request.WriteResultRequest;
32 import org.simantics.db.common.utils.Logger;
33 import org.simantics.db.common.utils.NameUtils;
34 import org.simantics.db.exception.DatabaseException;
35 import org.simantics.db.exception.ServiceNotFoundException;
36 import org.simantics.db.layer0.variable.Variable;
37 import org.simantics.db.management.ISessionContext;
38 import org.simantics.db.request.Read;
39 import org.simantics.layer0.Layer0;
40 import org.simantics.scenegraph.ontology.ScenegraphResources;
41 import org.simantics.utils.datastructures.Pair;
42 import org.simantics.utils.ui.ISelectionUtils;
43 import org.simantics.utils.ui.jface.ActiveSelectionProvider;
44
45 abstract public class ModelledTabContributor implements PropertyTabContributor, ListenerSupport {
46
47         static class InputRead extends UniqueRead<Pair<Variable, Resource>> {
48                 
49                 private Object input;
50                 
51                 InputRead(Object input) {
52                         this.input = input;
53                 }
54
55                 @Override
56                 public Pair<Variable, Resource> perform(ReadGraph graph) throws DatabaseException {
57
58                         Variable resultVariable = null;
59                         Resource resultResource = null;
60
61                         if(input instanceof ISelection) {
62                                 Variable var = ISelectionUtils.filterSingleSelection((ISelection)input, Variable.class);
63                                 if(var != null) resultVariable = var;
64                                 Resource res = ISelectionUtils.filterSingleSelection((ISelection)input, Resource.class);
65                                 if(res != null) resultResource = res;
66                         } else if (input instanceof Resource) {
67                                 resultResource = (Resource)input;
68                         }
69
70                         return Pair.make(resultVariable, resultResource);
71
72                 }
73
74         };
75         
76         static class InputListener extends DisposableAsyncListener<Pair<Variable, Resource>> {
77         
78         final Resource runtime;
79         
80         public InputListener(Resource runtime) {
81                 this.runtime = runtime;
82         }
83
84                 @Override
85                 public void execute(AsyncReadGraph graph, final Pair<Variable, Resource> result) {
86                         
87                         Simantics.getSession().async(new WriteRequest(Simantics.getSession().getService(VirtualGraph.class)) {
88
89                                 @Override
90                                 public void perform(WriteGraph graph) throws DatabaseException {
91
92                                         ScenegraphResources SG = ScenegraphResources.getInstance(graph);
93                                         
94                                         if(result.first != null) {
95                                                 String uri = result.first.getURI(graph);
96                                                 graph.claimLiteral(runtime, SG.Runtime_HasVariable, uri, Bindings.STRING);
97                                         }
98
99                                         if(result.second != null) {
100                         graph.deny(runtime, SG.Runtime_HasResource);
101                         graph.claim(runtime, SG.Runtime_HasResource, result.second);
102                     }
103                                         
104                                 }
105                                 
106                         });                             
107                         
108                 }
109
110                 @Override
111                 public void exception(AsyncReadGraph graph, Throwable throwable) {
112                         Logger.defaultLogError(throwable);
113                 }
114                 
115     }
116         
117     protected Resource runtime;
118         
119     // For ListenerSupport (supporting DB request listeners)
120     protected boolean    disposed = false;
121     protected ISelection input    = StructuredSelection.EMPTY;
122     
123     protected ISelectionProvider selectionProvider = new ActiveSelectionProvider();
124
125     abstract public void createControls(Composite body, IWorkbenchSite site);
126
127     public IFilterArea getFilterArea() {
128         return null;
129     }
130
131     public void requestFocus() {
132     }
133
134     public ISelectionProvider getSelectionProvider() {
135         return selectionProvider; 
136     }
137
138     public Read<String> getPartNameReadRequest(final ISelection forSelection) {
139         return new UniqueRead<String>() {
140
141                 private String forResource(ReadGraph graph, Resource resource) throws DatabaseException {
142                         Layer0 L0 = Layer0.getInstance(graph);
143                         String name = NameUtils.getSafeName(graph, resource);
144                         Resource type = graph.getPossibleType(resource, L0.Entity);
145                         if(type != null) {
146                                 name += " : " + NameUtils.getSafeName(graph, type);
147                         }
148                         return name;
149                 }
150                  
151                         @Override
152                         public String perform(ReadGraph graph) throws DatabaseException {
153                                 Resource resource = ISelectionUtils.filterSingleSelection(forSelection, Resource.class);
154                                 if(resource != null) return forResource(graph, resource);
155                                 Variable variable = ISelectionUtils.filterSingleSelection(forSelection, Variable.class);
156                                 if(variable != null) {
157                                         Resource represents = variable.getPossibleRepresents(graph);
158                                         if(represents != null) return forResource(graph, represents);
159                                 }
160                                 return "Selection";
161                         }
162                 
163         };
164     }
165
166     public void updatePartName(ISelection forSelection, Consumer<String> updateCallback) {
167         Read<String> read = getPartNameReadRequest(forSelection);
168         if (read == null) {
169             updateCallback.accept("Selection");
170         } else {
171             Simantics.getSession().asyncRequest(read, new PartNameListener(updateCallback, this));
172         }
173     }
174
175     public void updatePartName(Consumer<String> updateCallback) {
176         updatePartName(input, updateCallback);
177     }
178
179     protected void dispose() {
180         this.disposed = true;
181     }
182
183     @Override
184     public void exception(Throwable t) {
185         ErrorLogger.defaultLogError("PropertyTabContributorImpl received unexpected exception.", t);
186     }
187
188     @Override
189     public boolean isDisposed() {
190         return disposed;
191     }
192
193     public Control createControl(Composite parent, final IWorkbenchSite site) {
194
195         class TabComposite extends Composite {
196             public TabComposite(Composite parent) {
197                 super(parent, 0);
198
199                 GridLayoutFactory.fillDefaults().applyTo(parent);
200                 GridDataFactory.fillDefaults().span(1, 1).grab(true, true).applyTo(this);
201
202                 Composite body = this;
203                 GridLayoutFactory.fillDefaults().spacing(0, 0).equalWidth(false).numColumns(1).applyTo(body);
204
205                 try {
206                         ModelledTabContributor.this.createControls(body, site);
207                 } catch (Throwable t) {
208                     ErrorLogger.defaultLogError(t);
209                 }
210             }
211         }
212
213         final TabComposite tc = new TabComposite(parent);
214         tc.addListener(SWT.Dispose, new Listener() {
215             public void handleEvent(Event e) {
216                 ModelledTabContributor.this.dispose();
217             }
218         });
219         
220         return tc;
221         
222     }
223
224     @Override
225     public IPropertyTab create(Composite parent, IWorkbenchSite site, ISessionContext context, Object input) {
226         IPropertyTab tab = new Tab(site, parent);
227         tab.createControl((Composite) tab.getControl(), context);
228         return tab;
229     }
230
231     class Tab extends Composite implements IPropertyTab2, IFilterAreaProvider {
232
233         final IWorkbenchSite    site;
234
235         private InputListener listener;
236         
237         public Tab(IWorkbenchSite site, Composite parent) {
238                 
239             super(parent, SWT.NONE);
240             this.site = site;
241             
242                 try {
243                         runtime = Simantics.getSession().sync(new WriteResultRequest<Resource>(Simantics.getSession().getService(VirtualGraph.class)) {
244                             @Override
245                             public Resource perform(WriteGraph graph) throws DatabaseException {
246                                 Layer0 L0 = Layer0.getInstance(graph);
247                                 ScenegraphResources SG = ScenegraphResources.getInstance(graph);
248                                 Resource runtime = graph.newResource();
249                                                 graph.claim(runtime, L0.InstanceOf, null, SG.Runtime);
250                                                 return runtime;
251                             }
252                         });
253                 } catch (ServiceNotFoundException e) {
254                         Logger.defaultLogError(e);
255                 } catch (DatabaseException e) {
256                         Logger.defaultLogError(e);
257                 }
258             
259         }
260
261         @Override
262         public void createControl(Composite parent, ISessionContext context) {
263                 Control c = ModelledTabContributor.this.createControl(parent, site);
264             c.addListener(SWT.Dispose, new Listener() {
265                 public void handleEvent(Event e) {
266                         if(listener != null) {
267                                 listener.dispose();
268                                 listener = null;
269                         }
270                 }
271             });
272         }
273
274         @Override
275         public Control getControl() {
276             return this;
277         }
278
279         @Override
280         public boolean isDisposed() {
281             return super.isDisposed();
282         }
283
284         @Override
285         public void requestFocus() {
286                 ModelledTabContributor.this.requestFocus();
287         }
288
289         @Override
290         public void setInput(ISessionContext context, ISelection selection, boolean force) {
291                 
292                 ModelledTabContributor.this.input = selection;
293
294                         if(listener != null) listener.dispose();
295                         
296                         listener = new InputListener(runtime);
297                         
298                         try {
299                                 Simantics.getSession().syncRequest(new InputRead(ModelledTabContributor.this.input), listener);
300                         } catch (DatabaseException e) {
301                                 Logger.defaultLogError(e);
302                         }
303             
304         }
305
306         @Override
307         public ISelectionProvider getSelectionProvider() {
308             return ModelledTabContributor.this.getSelectionProvider();
309         }
310
311         @Override
312         public IFilterArea getFilterArea() {
313             return ModelledTabContributor.this.getFilterArea();
314         }
315
316         @Override
317         public void updatePartName(Consumer<String> updateCallback) {
318                 ModelledTabContributor.this.updatePartName(input, updateCallback);
319         }
320
321     }
322         
323 }