]> gerrit.simantics Code Review - simantics/3d.git/blob - dev/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/dialogs/ConfigureAnimationDialog.java
Release
[simantics/3d.git] / dev / org.simantics.proconf.processeditor / src / fi / vtt / simantics / processeditor / dialogs / ConfigureAnimationDialog.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  *\r
8  * Contributors:\r
9  *     VTT Technical Research Centre of Finland - initial API and implementation\r
10  *******************************************************************************/\r
11 package fi.vtt.simantics.processeditor.dialogs;\r
12 \r
13 import java.util.ArrayList;\r
14 import java.util.Collection;\r
15 import java.util.HashMap;\r
16 import java.util.HashSet;\r
17 import java.util.Map;\r
18 import java.util.Set;\r
19 import java.util.TreeMap;\r
20 import java.util.Map.Entry;\r
21 \r
22 import org.eclipse.jface.dialogs.Dialog;\r
23 import org.eclipse.jface.dialogs.IDialogConstants;\r
24 import org.eclipse.swt.SWT;\r
25 import org.eclipse.swt.events.SelectionAdapter;\r
26 import org.eclipse.swt.events.SelectionEvent;\r
27 import org.eclipse.swt.events.SelectionListener;\r
28 import org.eclipse.swt.layout.FillLayout;\r
29 import org.eclipse.swt.layout.GridData;\r
30 import org.eclipse.swt.layout.GridLayout;\r
31 import org.eclipse.swt.widgets.Button;\r
32 import org.eclipse.swt.widgets.Composite;\r
33 import org.eclipse.swt.widgets.Control;\r
34 import org.eclipse.swt.widgets.Label;\r
35 import org.eclipse.swt.widgets.List;\r
36 import org.eclipse.swt.widgets.Shell;\r
37 import org.eclipse.swt.widgets.Text;\r
38 import org.simantics.db.Graph;\r
39 import org.simantics.db.GraphRequestAdapter;\r
40 import org.simantics.db.GraphRequestStatus;\r
41 import org.simantics.db.Resource;\r
42 import org.simantics.db.Session;\r
43 import org.simantics.g2d.stubs.anim.Animation;\r
44 import org.simantics.layer0.utils.EntityFactory;\r
45 import org.simantics.layer0.utils.IEntity;\r
46 import org.simantics.layer0.utils.viewpoints.TraversalPath;\r
47 import org.simantics.proconf.browsing.GraphExplorer;\r
48 import org.simantics.proconf.g3d.animation.Animatable;\r
49 import org.simantics.proconf.g3d.animation.AnimationSystem;\r
50 import org.simantics.proconf.g3d.animation.ResourceAnimationController;\r
51 import org.simantics.proconf.g3d.animation.ScaledResourceAnimationController;\r
52 import org.simantics.proconf.g3d.base.ScenegraphAdapter;\r
53 import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
54 import org.simantics.proconf.g3d.stubs.G3DModel;\r
55 import org.simantics.proconf.g3d.tools.OEPathSelectionListener;\r
56 import org.simantics.utils.ErrorLogger;\r
57 \r
58 import fi.vtt.simantics.processeditor.ProcessResource;\r
59 import fi.vtt.simantics.processeditor.common.PathUtils;\r
60 \r
61 public class ConfigureAnimationDialog extends Dialog {\r
62         Session session;\r
63         List typeList;\r
64         List animationList;\r
65         java.util.List<Resource> nodes;\r
66         Set<Resource> models;\r
67         \r
68         private Composite oeLabelComposite;\r
69         //private Control viewpointControl;\r
70         private Composite oeComposite;\r
71         private GraphExplorer oe;\r
72         private Map<Resource,Resource> instanceModelMap = new HashMap<Resource, Resource>();\r
73         private ScenegraphAdapter adapter;\r
74         \r
75         private Button applyAnimationButton;\r
76         \r
77         Resource selectedType;\r
78         Resource sampleInstance;\r
79         Resource sampleSource;\r
80         java.util.List<Resource> samplePath;\r
81         AnimationSystem animationSystem;\r
82         \r
83         Button scaleButton;\r
84         Text minText;\r
85         Text maxText;\r
86         \r
87         public ConfigureAnimationDialog(Shell parentShell, Session session, java.util.List<Resource> nodes, ScenegraphAdapter adapter, AnimationSystem animationSystem) {\r
88                 super(parentShell);\r
89                 this.session = session;\r
90                 this.nodes = nodes;\r
91                 models = new HashSet<Resource>();\r
92                 session.syncRead(new GraphRequestAdapter() {\r
93                         @Override\r
94                         public GraphRequestStatus perform(Graph g) throws Exception {\r
95                                 for (Resource n : ConfigureAnimationDialog.this.nodes) {\r
96                                         IEntity t = EntityFactory.create(g,n);\r
97                                         Collection<IEntity> r = t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics);\r
98                                         if (r.size() == 1) {\r
99                                                 IEntity model = r.iterator().next();\r
100                                                 if (model.isInstanceOf(ProcessResource.g3dResource.G3DModel)) {\r
101                                                         models.add(model.getResource());\r
102                                                         instanceModelMap.put(n, model.getResource());\r
103                                                 } else {\r
104                                                         throw new RuntimeException("Expected G3DModel, got something else " + model);\r
105                                                 }\r
106                                         } else {\r
107                                                 ErrorLogger.getDefault().logWarning("Got node without a model", null);\r
108                                         }\r
109                                 }\r
110                                 return GraphRequestStatus.transactionComplete();\r
111                         }\r
112                 });\r
113                 \r
114                 this.adapter = adapter;\r
115                 this.animationSystem = animationSystem;\r
116                 int shellStyle = getShellStyle();\r
117                 setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);\r
118         }\r
119         \r
120         @Override\r
121     protected void configureShell(Shell newShell) {  \r
122         super.configureShell(newShell);\r
123         newShell.setText("Configure animations");\r
124         \r
125     }\r
126         \r
127         protected Control createDialogArea(Composite parent) {\r
128         Composite composite = (Composite) super.createDialogArea(parent);\r
129         GridLayout layout = new GridLayout(4,true);\r
130                 layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);\r
131                 layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);\r
132                 layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);\r
133                 layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);\r
134                 composite.setLayout(layout);\r
135                 \r
136                 Label label = new Label(composite, SWT.WRAP);\r
137         label.setText("Types");\r
138 //        GridData data = new GridData(GridData.GRAB_HORIZONTAL\r
139 //                | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL\r
140 //                | GridData.VERTICAL_ALIGN_BEGINNING);\r
141         GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1);\r
142         data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
143         label.setLayoutData(data);\r
144         label.setFont(parent.getFont());\r
145         \r
146         label = new Label(composite, SWT.WRAP);\r
147         label.setText("Models");\r
148         label.setLayoutData(data);\r
149         label.setFont(parent.getFont());\r
150         \r
151         label = new Label(composite, SWT.WRAP);\r
152         label.setText("Animations");\r
153         label.setLayoutData(data);\r
154         label.setFont(parent.getFont());\r
155         \r
156         oeLabelComposite = new Composite(composite,SWT.NONE);\r
157         data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1);\r
158         data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);\r
159         \r
160         oeLabelComposite.setLayoutData(data);\r
161         oeLabelComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
162         //label = new Label(composite, SWT.WRAP);\r
163         label = new Label(oeLabelComposite, SWT.WRAP);\r
164         label.setText("Animation source");\r
165 //        label.setLayoutData(data);\r
166         label.setFont(parent.getFont());\r
167         \r
168         typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL);\r
169         typeList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
170 //        modelList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL);\r
171 //        modelList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
172         animationList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL);\r
173         animationList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
174         oeComposite = new Composite(composite,SWT.BORDER);\r
175         oeComposite.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
176         layout = new GridLayout();\r
177         layout.marginWidth = 0;\r
178         layout.marginHeight = 0;\r
179         oeComposite.setLayout(layout);\r
180         \r
181         session.asyncRead(new GraphRequestAdapter() {\r
182                 TreeMap<String, Resource> sorter;\r
183                 @Override\r
184                 public GraphRequestStatus perform(Graph g) throws Exception {\r
185                         Collection<Resource> types = getTypes(g,nodes);\r
186                         \r
187                          sorter = new TreeMap<String, Resource>();\r
188                         for (Resource type : types) {\r
189                                 IEntity t = EntityFactory.create(g,type);\r
190                                 if (t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() > 0) {\r
191                                         String key = t.getName();\r
192                                 if (key.equals("")) key = "ERROR (" + type.getResourceId() + ")";\r
193                                 sorter.put(key, type);\r
194                                 }\r
195                         }\r
196                         \r
197                         \r
198                         \r
199                         return GraphRequestStatus.transactionComplete();\r
200                 }\r
201                 \r
202                 @Override\r
203                 public void requestCompleted(GraphRequestStatus status) {\r
204                         getShell().getDisplay().asyncExec(new Runnable(){\r
205                                 @Override\r
206                                 public void run() {\r
207                                         for (Entry<String, Resource> e : sorter.entrySet()) {\r
208                             typeList.add(e.getKey());\r
209                             typeList.setData(e.getKey(), e.getValue());\r
210                         }\r
211                                 }\r
212                         });\r
213                 }\r
214         });\r
215        \r
216         typeList.addSelectionListener(new SelectionListener() {\r
217             public void widgetSelected(SelectionEvent e) {\r
218                 session.asyncRead(new GraphRequestAdapter(){\r
219                         @Override\r
220                         public GraphRequestStatus perform(Graph g) throws Exception {\r
221                                 String key = typeList.getItem(typeList.getSelectionIndex());\r
222                         selectType(EntityFactory.create(g,(Resource) typeList.getData(key)));\r
223                                 return GraphRequestStatus.transactionComplete();\r
224                         }\r
225                 });\r
226                 \r
227             }\r
228             public void widgetDefaultSelected(SelectionEvent e) {\r
229             }\r
230         });\r
231         \r
232 //        modelList.addSelectionListener(new SelectionListener() {\r
233 //            public void widgetSelected(SelectionEvent e) {\r
234 //              if (modelList.getSelectionIndex() < 0 || modelList.getSelectionIndex() >= modelList.getItemCount())\r
235 //                      return;\r
236 //                String key = modelList.getItem(modelList.getSelectionIndex());\r
237 //                selectModel((GraphicsModel) modelList.getData(key));\r
238 //            }\r
239 //            public void widgetDefaultSelected(SelectionEvent e) {\r
240 //            }\r
241 //        });\r
242         \r
243         Composite buttonComposite = new Composite(composite,SWT.NONE);\r
244         buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,4,1));\r
245         buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
246         scaleButton = new Button(buttonComposite,SWT.CHECK);\r
247         scaleButton.setText("Scaling");\r
248         scaleButton.addSelectionListener(new SelectionAdapter() {\r
249                 @Override\r
250                 public void widgetSelected(SelectionEvent e) {\r
251                         if (scaleButton.getSelection()) {\r
252                                 minText.setEnabled(true);\r
253                                 maxText.setEnabled(true);\r
254                         } else {\r
255                                 minText.setEnabled(false);\r
256                                 maxText.setEnabled(false);\r
257                         }\r
258                 }\r
259         });\r
260         minText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);\r
261         minText.setText("0.0");\r
262         \r
263         maxText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);\r
264         maxText.setText("1.0");\r
265         \r
266         minText.setEnabled(false);\r
267                 maxText.setEnabled(false);\r
268         \r
269         applyAnimationButton = new Button(buttonComposite,SWT.PUSH);\r
270         applyAnimationButton.setText("Apply animation");\r
271         applyAnimationButton.addSelectionListener(new SelectionAdapter() {\r
272                 @Override\r
273                 public void widgetSelected(SelectionEvent e) {\r
274                         session.asyncRead(new GraphRequestAdapter() {\r
275                                 @Override\r
276                                 public GraphRequestStatus perform(Graph g) throws Exception {\r
277                                         applyAnimation(g);\r
278                                         return GraphRequestStatus.transactionComplete();\r
279                                 }\r
280                         });\r
281                         \r
282                 }\r
283         });\r
284         return composite;\r
285         }\r
286         \r
287         /**\r
288          * Updates type selection:\r
289          * Finds all GraphicsModels that are connected to instances of selected type with HasGraphics-relation\r
290          * and lists them in modelList.\r
291          *\r
292          * @param resource\r
293          */\r
294         private void selectType(IEntity resource) {\r
295                 Graph g = resource.getGraph();\r
296                 selectedType = resource.getResource();\r
297                 //modelList.removeAll();\r
298                 animationList.removeAll();\r
299                 \r
300                 Collection<IEntity> model = resource.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics);\r
301                 if (model.size() != 1)\r
302                         throw new RuntimeException("Type " + resource + " does not have a model");\r
303         \r
304         if (oe != null) {\r
305                 oe.dispose();   \r
306         }\r
307         sampleInstance = null;\r
308         sampleSource = null;\r
309         for (Resource n : nodes) {\r
310                 IEntity t = EntityFactory.create(g,n);\r
311                 if (t.isInstanceOf(resource.getResource())) {\r
312                         sampleInstance = n;\r
313                         break;\r
314                 }\r
315         }\r
316         if (sampleInstance != null) {\r
317 //              oe = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId()));\r
318 //              if(viewpointControl != null && !viewpointControl.isDisposed()) {\r
319 //                      viewpointControl.dispose();\r
320 //              }\r
321 //              viewpointControl = oe.getControl(oeLabelComposite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE);\r
322 //              Control c = oe.getControl(oeComposite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE);\r
323 //              c.setLayoutData(new GridData(GridData.FILL_BOTH));\r
324 //              oe.init(null, ViewpointUtils.getModelledHandler(oe.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false);\r
325 //              //oeComposite.layout(true, true);\r
326 //              oe.setSelectionScheme(new SourceSelectionScheme(oe));\r
327 //              //oeLabelComposite.layout(true, true);\r
328 //              oeComposite.getParent().getParent().layout(true,true);\r
329         \r
330                 oe = new GraphExplorer(oeComposite,SWT.SINGLE);\r
331                 oe.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));\r
332                 oe.getViewer().addPostSelectionChangedListener(new OEPathSelectionListener(){\r
333                         @Override\r
334                         protected void pathSelectionUpdated(java.util.List<TraversalPath> paths) {\r
335                                 if (paths.size() == 0) {\r
336                         //selectSource(null);\r
337                     } else {\r
338                         final TraversalPath path = paths.iterator().next();\r
339                         session.asyncRead(new GraphRequestAdapter() {\r
340                                 @Override\r
341                                 public GraphRequestStatus perform(Graph g) throws Exception {\r
342                                         selectSource(g,path);\r
343                                         return GraphRequestStatus.transactionComplete();\r
344                                 }\r
345                         });\r
346                         \r
347                     }   \r
348                         }\r
349                 });\r
350         }\r
351                 \r
352 //        modelList.redraw();\r
353 //        animationList.redraw();\r
354         selectModel(new G3DModel(model.iterator().next()));\r
355         }\r
356         \r
357         /**\r
358          * Selects model and shows model's animations in animationList\r
359          * @param model\r
360          */\r
361         private void selectModel(G3DModel model) {\r
362                 animationList.removeAll();\r
363                 \r
364                 TreeMap<String, Animation> sorter = new TreeMap<String, Animation>();\r
365         \r
366                 Collection<Animation> animations = model.getAnimation();\r
367                 for (Animation a : animations) {\r
368                         String key = a.getName();\r
369                 if (key.equals("")) key = "ERROR (" + a.getResource().getResourceId() + ")";\r
370                 sorter.put(key, a);\r
371                 }\r
372                 \r
373                 final TreeMap<String, Animation> fa = sorter;\r
374                 \r
375                 getShell().getDisplay().asyncExec(new Runnable() {\r
376                         @Override\r
377                         public void run() {\r
378                                 for (Entry<String, Animation> e : fa.entrySet()) {\r
379                             animationList.add(e.getKey());\r
380                             animationList.setData(e.getKey(), e.getValue());\r
381                         }\r
382                                 animationList.redraw();\r
383                                 \r
384                         }\r
385                 });\r
386                 \r
387         }\r
388         \r
389         private void selectSource(Graph graph,TraversalPath path) {\r
390                 //System.out.println(sampleInstance + " " + resource);\r
391                 \r
392                 if (path == null) {\r
393                         sampleSource = null;\r
394                         return;\r
395                 } \r
396                 IEntity t = EntityFactory.create(graph,path.getResource());\r
397                 if (!t.isInstanceOf(ProcessResource.builtins.Double)) {\r
398                         sampleSource = null;\r
399                 } else {\r
400                         sampleSource = path.getResource();\r
401                         samplePath = new ArrayList<Resource>();\r
402                         PathUtils.createPath(samplePath, path ,sampleInstance,sampleSource,oe);\r
403                 }\r
404         }\r
405         \r
406         \r
407         \r
408         private void applyAnimation(Graph graph) {\r
409                 int animationIndex = animationList.getSelectionIndex();\r
410                 if (sampleInstance == null || sampleSource == null || samplePath == null || animationIndex == -1) {\r
411                         throw new RuntimeException("Missing required selections");\r
412                         //return;\r
413                 }\r
414                 \r
415                 java.util.List<Resource> instances = new ArrayList<Resource>();\r
416                 java.util.List<Resource> sources = new ArrayList<Resource>();\r
417                 browseOthers(graph,instances, sources);\r
418                 instances.add(sampleInstance);\r
419                 sources.add(sampleSource);\r
420                 \r
421                 for (int i = 0; i < instances.size(); i++) {\r
422                         IGraphicsNode n = adapter.getNode(instances.get(i));\r
423                         if (!(n instanceof Animatable)) {\r
424                                 //throw new RuntimeException("Node is not animatable");\r
425                                 continue;\r
426                         }\r
427 \r
428                         Animatable animatable = (Animatable) n;\r
429                         Animation a = (Animation) animationList.getData(animationList.getItem(animationIndex));\r
430                         if (!animatable.setAnimation(graph,a.getResource())) {\r
431                                 //throw new RuntimeException("Cannot set animation");\r
432                                 continue;\r
433                         }\r
434                         ResourceAnimationController c;\r
435                         if (scaleButton.getSelection()) {\r
436                                 c = new ScaledResourceAnimationController(sources.get(i),Double.parseDouble(minText.getText()),Double.parseDouble(maxText.getText()));\r
437                         } else {\r
438                                 c = new ResourceAnimationController(sources.get(i));\r
439                         }\r
440                         c.addAnimatable(animatable);\r
441                         animationSystem.add(c);\r
442                 }\r
443                 \r
444         }\r
445         \r
446         private void browseOthers(Graph g, java.util.List<Resource> instances,java.util.List<Resource> sources) {\r
447                 java.util.List<Resource> possibleInstances = new ArrayList<Resource>();\r
448                 for (Resource n : nodes) {\r
449                         IEntity t = EntityFactory.create(g,n);\r
450                         if (t.isInstanceOf(selectedType) && !n.equals(sampleInstance)) {\r
451                                 possibleInstances.add(n.getResource());\r
452                         }\r
453                 }\r
454                 \r
455                 for (Resource instance : possibleInstances) {\r
456                         IEntity source = PathUtils.findSimilar(samplePath,EntityFactory.create(g,instance));\r
457                         if (source != null) {\r
458                                 instances.add(instance);\r
459                                 sources.add(source.getResource());\r
460                         } else {\r
461                                 ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null);\r
462                         }\r
463                 }\r
464         }\r
465         \r
466         \r
467         private Collection<Resource> getTypes(Graph g, java.util.List<Resource> instances) {\r
468                 Set<Resource> types = new HashSet<Resource>();\r
469                 for (Resource r : instances) {\r
470                         IEntity t = EntityFactory.create(g,r);\r
471                         Collection<IEntity> tTypes = t.getTypes();\r
472                         for (IEntity type : tTypes)\r
473                                 types.add(type.getResource());\r
474                 }\r
475                 return types;\r
476         }\r
477 \r
478 }\r