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
9 * VTT Technical Research Centre of Finland - initial API and implementation
\r
10 *******************************************************************************/
\r
11 package fi.vtt.simantics.processeditor.dialogs;
\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
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
58 import fi.vtt.simantics.processeditor.ProcessResource;
\r
59 import fi.vtt.simantics.processeditor.common.PathUtils;
\r
61 public class ConfigureAnimationDialog extends Dialog {
\r
65 java.util.List<Resource> nodes;
\r
66 Set<Resource> models;
\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
75 private Button applyAnimationButton;
\r
77 Resource selectedType;
\r
78 Resource sampleInstance;
\r
79 Resource sampleSource;
\r
80 java.util.List<Resource> samplePath;
\r
81 AnimationSystem animationSystem;
\r
87 public ConfigureAnimationDialog(Shell parentShell, Session session, java.util.List<Resource> nodes, ScenegraphAdapter adapter, AnimationSystem animationSystem) {
\r
89 this.session = session;
\r
91 models = new HashSet<Resource>();
\r
92 session.syncRead(new GraphRequestAdapter() {
\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
104 throw new RuntimeException("Expected G3DModel, got something else " + model);
\r
107 ErrorLogger.getDefault().logWarning("Got node without a model", null);
\r
110 return GraphRequestStatus.transactionComplete();
\r
114 this.adapter = adapter;
\r
115 this.animationSystem = animationSystem;
\r
116 int shellStyle = getShellStyle();
\r
117 setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE);
\r
121 protected void configureShell(Shell newShell) {
\r
122 super.configureShell(newShell);
\r
123 newShell.setText("Configure animations");
\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
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
146 label = new Label(composite, SWT.WRAP);
\r
147 label.setText("Models");
\r
148 label.setLayoutData(data);
\r
149 label.setFont(parent.getFont());
\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
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
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
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
181 session.asyncRead(new GraphRequestAdapter() {
\r
182 TreeMap<String, Resource> sorter;
\r
184 public GraphRequestStatus perform(Graph g) throws Exception {
\r
185 Collection<Resource> types = getTypes(g,nodes);
\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
199 return GraphRequestStatus.transactionComplete();
\r
203 public void requestCompleted(GraphRequestStatus status) {
\r
204 getShell().getDisplay().asyncExec(new Runnable(){
\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
216 typeList.addSelectionListener(new SelectionListener() {
\r
217 public void widgetSelected(SelectionEvent e) {
\r
218 session.asyncRead(new GraphRequestAdapter(){
\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
228 public void widgetDefaultSelected(SelectionEvent e) {
\r
232 // modelList.addSelectionListener(new SelectionListener() {
\r
233 // public void widgetSelected(SelectionEvent e) {
\r
234 // if (modelList.getSelectionIndex() < 0 || modelList.getSelectionIndex() >= modelList.getItemCount())
\r
236 // String key = modelList.getItem(modelList.getSelectionIndex());
\r
237 // selectModel((GraphicsModel) modelList.getData(key));
\r
239 // public void widgetDefaultSelected(SelectionEvent e) {
\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
250 public void widgetSelected(SelectionEvent e) {
\r
251 if (scaleButton.getSelection()) {
\r
252 minText.setEnabled(true);
\r
253 maxText.setEnabled(true);
\r
255 minText.setEnabled(false);
\r
256 maxText.setEnabled(false);
\r
260 minText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);
\r
261 minText.setText("0.0");
\r
263 maxText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER);
\r
264 maxText.setText("1.0");
\r
266 minText.setEnabled(false);
\r
267 maxText.setEnabled(false);
\r
269 applyAnimationButton = new Button(buttonComposite,SWT.PUSH);
\r
270 applyAnimationButton.setText("Apply animation");
\r
271 applyAnimationButton.addSelectionListener(new SelectionAdapter() {
\r
273 public void widgetSelected(SelectionEvent e) {
\r
274 session.asyncRead(new GraphRequestAdapter() {
\r
276 public GraphRequestStatus perform(Graph g) throws Exception {
\r
278 return GraphRequestStatus.transactionComplete();
\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
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
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
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
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
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
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
334 protected void pathSelectionUpdated(java.util.List<TraversalPath> paths) {
\r
335 if (paths.size() == 0) {
\r
336 //selectSource(null);
\r
338 final TraversalPath path = paths.iterator().next();
\r
339 session.asyncRead(new GraphRequestAdapter() {
\r
341 public GraphRequestStatus perform(Graph g) throws Exception {
\r
342 selectSource(g,path);
\r
343 return GraphRequestStatus.transactionComplete();
\r
352 // modelList.redraw();
\r
353 // animationList.redraw();
\r
354 selectModel(new G3DModel(model.iterator().next()));
\r
358 * Selects model and shows model's animations in animationList
\r
361 private void selectModel(G3DModel model) {
\r
362 animationList.removeAll();
\r
364 TreeMap<String, Animation> sorter = new TreeMap<String, Animation>();
\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
373 final TreeMap<String, Animation> fa = sorter;
\r
375 getShell().getDisplay().asyncExec(new Runnable() {
\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
382 animationList.redraw();
\r
389 private void selectSource(Graph graph,TraversalPath path) {
\r
390 //System.out.println(sampleInstance + " " + resource);
\r
392 if (path == null) {
\r
393 sampleSource = null;
\r
396 IEntity t = EntityFactory.create(graph,path.getResource());
\r
397 if (!t.isInstanceOf(ProcessResource.builtins.Double)) {
\r
398 sampleSource = null;
\r
400 sampleSource = path.getResource();
\r
401 samplePath = new ArrayList<Resource>();
\r
402 PathUtils.createPath(samplePath, path ,sampleInstance,sampleSource,oe);
\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
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
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
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
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
438 c = new ResourceAnimationController(sources.get(i));
\r
440 c.addAnimatable(animatable);
\r
441 animationSystem.add(c);
\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
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
461 ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null);
\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