/******************************************************************************* * Copyright (c) 2007 VTT Technical Research Centre of Finland and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package fi.vtt.simantics.processeditor.dialogs; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.Map.Entry; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.simantics.db.Graph; import org.simantics.db.GraphRequestAdapter; import org.simantics.db.GraphRequestStatus; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.g2d.stubs.anim.Animation; import org.simantics.layer0.utils.EntityFactory; import org.simantics.layer0.utils.IEntity; import org.simantics.layer0.utils.viewpoints.TraversalPath; import org.simantics.proconf.browsing.GraphExplorer; import org.simantics.proconf.g3d.animation.Animatable; import org.simantics.proconf.g3d.animation.AnimationSystem; import org.simantics.proconf.g3d.animation.ResourceAnimationController; import org.simantics.proconf.g3d.animation.ScaledResourceAnimationController; import org.simantics.proconf.g3d.base.ScenegraphAdapter; import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; import org.simantics.proconf.g3d.stubs.G3DModel; import org.simantics.proconf.g3d.tools.OEPathSelectionListener; import org.simantics.utils.ErrorLogger; import fi.vtt.simantics.processeditor.ProcessResource; import fi.vtt.simantics.processeditor.common.PathUtils; public class ConfigureAnimationDialog extends Dialog { Session session; List typeList; List animationList; java.util.List nodes; Set models; private Composite oeLabelComposite; //private Control viewpointControl; private Composite oeComposite; private GraphExplorer oe; private Map instanceModelMap = new HashMap(); private ScenegraphAdapter adapter; private Button applyAnimationButton; Resource selectedType; Resource sampleInstance; Resource sampleSource; java.util.List samplePath; AnimationSystem animationSystem; Button scaleButton; Text minText; Text maxText; public ConfigureAnimationDialog(Shell parentShell, Session session, java.util.List nodes, ScenegraphAdapter adapter, AnimationSystem animationSystem) { super(parentShell); this.session = session; this.nodes = nodes; models = new HashSet(); session.syncRead(new GraphRequestAdapter() { @Override public GraphRequestStatus perform(Graph g) throws Exception { for (Resource n : ConfigureAnimationDialog.this.nodes) { IEntity t = EntityFactory.create(g,n); Collection r = t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); if (r.size() == 1) { IEntity model = r.iterator().next(); if (model.isInstanceOf(ProcessResource.g3dResource.G3DModel)) { models.add(model.getResource()); instanceModelMap.put(n, model.getResource()); } else { throw new RuntimeException("Expected G3DModel, got something else " + model); } } else { ErrorLogger.getDefault().logWarning("Got node without a model", null); } } return GraphRequestStatus.transactionComplete(); } }); this.adapter = adapter; this.animationSystem = animationSystem; int shellStyle = getShellStyle(); setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); } @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText("Configure animations"); } protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); GridLayout layout = new GridLayout(4,true); layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); composite.setLayout(layout); Label label = new Label(composite, SWT.WRAP); label.setText("Types"); // GridData data = new GridData(GridData.GRAB_HORIZONTAL // | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL // | GridData.VERTICAL_ALIGN_BEGINNING); GridData data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); label.setLayoutData(data); label.setFont(parent.getFont()); label = new Label(composite, SWT.WRAP); label.setText("Models"); label.setLayoutData(data); label.setFont(parent.getFont()); label = new Label(composite, SWT.WRAP); label.setText("Animations"); label.setLayoutData(data); label.setFont(parent.getFont()); oeLabelComposite = new Composite(composite,SWT.NONE); data = new GridData(GridData.CENTER,GridData.FILL,true,false,1,1); data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); oeLabelComposite.setLayoutData(data); oeLabelComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); //label = new Label(composite, SWT.WRAP); label = new Label(oeLabelComposite, SWT.WRAP); label.setText("Animation source"); // label.setLayoutData(data); label.setFont(parent.getFont()); typeList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); typeList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); // modelList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); // modelList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); animationList = new List(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY | SWT.V_SCROLL); animationList.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); oeComposite = new Composite(composite,SWT.BORDER); oeComposite.setLayoutData(new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); layout = new GridLayout(); layout.marginWidth = 0; layout.marginHeight = 0; oeComposite.setLayout(layout); session.asyncRead(new GraphRequestAdapter() { TreeMap sorter; @Override public GraphRequestStatus perform(Graph g) throws Exception { Collection types = getTypes(g,nodes); sorter = new TreeMap(); for (Resource type : types) { IEntity t = EntityFactory.create(g,type); if (t.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() > 0) { String key = t.getName(); if (key.equals("")) key = "ERROR (" + type.getResourceId() + ")"; sorter.put(key, type); } } return GraphRequestStatus.transactionComplete(); } @Override public void requestCompleted(GraphRequestStatus status) { getShell().getDisplay().asyncExec(new Runnable(){ @Override public void run() { for (Entry e : sorter.entrySet()) { typeList.add(e.getKey()); typeList.setData(e.getKey(), e.getValue()); } } }); } }); typeList.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { session.asyncRead(new GraphRequestAdapter(){ @Override public GraphRequestStatus perform(Graph g) throws Exception { String key = typeList.getItem(typeList.getSelectionIndex()); selectType(EntityFactory.create(g,(Resource) typeList.getData(key))); return GraphRequestStatus.transactionComplete(); } }); } public void widgetDefaultSelected(SelectionEvent e) { } }); // modelList.addSelectionListener(new SelectionListener() { // public void widgetSelected(SelectionEvent e) { // if (modelList.getSelectionIndex() < 0 || modelList.getSelectionIndex() >= modelList.getItemCount()) // return; // String key = modelList.getItem(modelList.getSelectionIndex()); // selectModel((GraphicsModel) modelList.getData(key)); // } // public void widgetDefaultSelected(SelectionEvent e) { // } // }); Composite buttonComposite = new Composite(composite,SWT.NONE); buttonComposite.setLayoutData(new GridData(GridData.END,GridData.FILL,true,false,4,1)); buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL)); scaleButton = new Button(buttonComposite,SWT.CHECK); scaleButton.setText("Scaling"); scaleButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (scaleButton.getSelection()) { minText.setEnabled(true); maxText.setEnabled(true); } else { minText.setEnabled(false); maxText.setEnabled(false); } } }); minText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); minText.setText("0.0"); maxText = new Text(buttonComposite,SWT.SINGLE|SWT.BORDER); maxText.setText("1.0"); minText.setEnabled(false); maxText.setEnabled(false); applyAnimationButton = new Button(buttonComposite,SWT.PUSH); applyAnimationButton.setText("Apply animation"); applyAnimationButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { session.asyncRead(new GraphRequestAdapter() { @Override public GraphRequestStatus perform(Graph g) throws Exception { applyAnimation(g); return GraphRequestStatus.transactionComplete(); } }); } }); return composite; } /** * Updates type selection: * Finds all GraphicsModels that are connected to instances of selected type with HasGraphics-relation * and lists them in modelList. * * @param resource */ private void selectType(IEntity resource) { Graph g = resource.getGraph(); selectedType = resource.getResource(); //modelList.removeAll(); animationList.removeAll(); Collection model = resource.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics); if (model.size() != 1) throw new RuntimeException("Type " + resource + " does not have a model"); if (oe != null) { oe.dispose(); } sampleInstance = null; sampleSource = null; for (Resource n : nodes) { IEntity t = EntityFactory.create(g,n); if (t.isInstanceOf(resource.getResource())) { sampleInstance = n; break; } } if (sampleInstance != null) { // oe = new OntologyExplorer("Animation Source",this.getShell(), new OntologyEditorInput(sampleInstance.getId())); // if(viewpointControl != null && !viewpointControl.isDisposed()) { // viewpointControl.dispose(); // } // viewpointControl = oe.getControl(oeLabelComposite, 1, OntologyExplorer.ViewpointSelector, SWT.NONE); // Control c = oe.getControl(oeComposite, 1, OntologyExplorer.OntologyTree, SWT.SINGLE); // c.setLayoutData(new GridData(GridData.FILL_BOTH)); // oe.init(null, ViewpointUtils.getModelledHandler(oe.getGraph(), Builtins.DefaultViewpointId), null, ViewLabelProviderDecorationSettings.DEFAULT, new MenuAboutToShowAction(), new NullAdditionAction(), false); // //oeComposite.layout(true, true); // oe.setSelectionScheme(new SourceSelectionScheme(oe)); // //oeLabelComposite.layout(true, true); // oeComposite.getParent().getParent().layout(true,true); oe = new GraphExplorer(oeComposite,SWT.SINGLE); oe.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); oe.getViewer().addPostSelectionChangedListener(new OEPathSelectionListener(){ @Override protected void pathSelectionUpdated(java.util.List paths) { if (paths.size() == 0) { //selectSource(null); } else { final TraversalPath path = paths.iterator().next(); session.asyncRead(new GraphRequestAdapter() { @Override public GraphRequestStatus perform(Graph g) throws Exception { selectSource(g,path); return GraphRequestStatus.transactionComplete(); } }); } } }); } // modelList.redraw(); // animationList.redraw(); selectModel(new G3DModel(model.iterator().next())); } /** * Selects model and shows model's animations in animationList * @param model */ private void selectModel(G3DModel model) { animationList.removeAll(); TreeMap sorter = new TreeMap(); Collection animations = model.getAnimation(); for (Animation a : animations) { String key = a.getName(); if (key.equals("")) key = "ERROR (" + a.getResource().getResourceId() + ")"; sorter.put(key, a); } final TreeMap fa = sorter; getShell().getDisplay().asyncExec(new Runnable() { @Override public void run() { for (Entry e : fa.entrySet()) { animationList.add(e.getKey()); animationList.setData(e.getKey(), e.getValue()); } animationList.redraw(); } }); } private void selectSource(Graph graph,TraversalPath path) { //System.out.println(sampleInstance + " " + resource); if (path == null) { sampleSource = null; return; } IEntity t = EntityFactory.create(graph,path.getResource()); if (!t.isInstanceOf(ProcessResource.builtins.Double)) { sampleSource = null; } else { sampleSource = path.getResource(); samplePath = new ArrayList(); PathUtils.createPath(samplePath, path ,sampleInstance,sampleSource,oe); } } private void applyAnimation(Graph graph) { int animationIndex = animationList.getSelectionIndex(); if (sampleInstance == null || sampleSource == null || samplePath == null || animationIndex == -1) { throw new RuntimeException("Missing required selections"); //return; } java.util.List instances = new ArrayList(); java.util.List sources = new ArrayList(); browseOthers(graph,instances, sources); instances.add(sampleInstance); sources.add(sampleSource); for (int i = 0; i < instances.size(); i++) { IGraphicsNode n = adapter.getNode(instances.get(i)); if (!(n instanceof Animatable)) { //throw new RuntimeException("Node is not animatable"); continue; } Animatable animatable = (Animatable) n; Animation a = (Animation) animationList.getData(animationList.getItem(animationIndex)); if (!animatable.setAnimation(graph,a.getResource())) { //throw new RuntimeException("Cannot set animation"); continue; } ResourceAnimationController c; if (scaleButton.getSelection()) { c = new ScaledResourceAnimationController(sources.get(i),Double.parseDouble(minText.getText()),Double.parseDouble(maxText.getText())); } else { c = new ResourceAnimationController(sources.get(i)); } c.addAnimatable(animatable); animationSystem.add(c); } } private void browseOthers(Graph g, java.util.List instances,java.util.List sources) { java.util.List possibleInstances = new ArrayList(); for (Resource n : nodes) { IEntity t = EntityFactory.create(g,n); if (t.isInstanceOf(selectedType) && !n.equals(sampleInstance)) { possibleInstances.add(n.getResource()); } } for (Resource instance : possibleInstances) { IEntity source = PathUtils.findSimilar(samplePath,EntityFactory.create(g,instance)); if (source != null) { instances.add(instance); sources.add(source.getResource()); } else { ErrorLogger.getDefault().logWarning("Cannot find animation source for " + instance, null); } } } private Collection getTypes(Graph g, java.util.List instances) { Set types = new HashSet(); for (Resource r : instances) { IEntity t = EntityFactory.create(g,r); Collection tTypes = t.getTypes(); for (IEntity type : tTypes) types.add(type.getResource()); } return types; } }