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 org.simantics.processeditor.views;
\r
13 import java.util.ArrayList;
\r
14 import java.util.Collection;
\r
15 import java.util.HashMap;
\r
16 import java.util.List;
\r
17 import java.util.Map;
\r
19 import org.eclipse.jface.action.Action;
\r
20 import org.eclipse.jface.dialogs.Dialog;
\r
21 import org.eclipse.jface.dialogs.IDialogConstants;
\r
22 import org.eclipse.jface.viewers.ISelection;
\r
23 import org.eclipse.jface.viewers.ISelectionChangedListener;
\r
24 import org.eclipse.jface.viewers.SelectionChangedEvent;
\r
25 import org.eclipse.swt.SWT;
\r
26 import org.eclipse.swt.events.KeyEvent;
\r
27 import org.eclipse.swt.events.KeyListener;
\r
28 import org.eclipse.swt.events.SelectionEvent;
\r
29 import org.eclipse.swt.events.SelectionListener;
\r
30 import org.eclipse.swt.layout.GridData;
\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.Shell;
\r
36 import org.eclipse.swt.widgets.Text;
\r
37 import org.eclipse.ui.IWorkbenchPart;
\r
38 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
\r
39 import org.simantics.db.Graph;
\r
40 import org.simantics.db.Resource;
\r
41 import org.simantics.db.Session;
\r
42 import org.simantics.db.management.ISessionContext;
\r
43 import org.simantics.layer0.utils.EntityFactory;
\r
44 import org.simantics.layer0.utils.IEntity;
\r
45 import org.simantics.layer0.utils.Property;
\r
46 import org.simantics.processeditor.Activator;
\r
47 import org.simantics.processeditor.ProcessResource;
\r
48 import org.simantics.processeditor.actions.InsertComponentAction;
\r
49 import org.simantics.processeditor.actions.InsertEquipmentAction;
\r
50 import org.simantics.processeditor.actions.InsertNozzleAction;
\r
51 import org.simantics.processeditor.actions.RoutePipeAction;
\r
52 import org.simantics.processeditor.common.ControlPointTools;
\r
53 import org.simantics.processeditor.common.PipingRules;
\r
54 import org.simantics.processeditor.scenegraph.NonVisibleNode;
\r
55 import org.simantics.processeditor.scenegraph.PipeComponentNode;
\r
56 import org.simantics.processeditor.scenegraph.PipeRunNode;
\r
57 import org.simantics.processeditor.scenegraph.PipelineComponentNode;
\r
58 import org.simantics.processeditor.stubs.PipeControlPoint;
\r
59 import org.simantics.processeditor.stubs.PipeRun;
\r
60 import org.simantics.processeditor.stubs.Plant;
\r
61 import org.simantics.processeditor.stubs.Plant3DResource;
\r
62 import org.simantics.processeditor.tools.PlantEditContribution;
\r
63 import org.simantics.processeditor.tools.PlantVisualizationContribution;
\r
64 import org.simantics.proconf.g3d.base.JmeRenderingComponent;
\r
65 import org.simantics.proconf.g3d.base.ScenegraphAdapter;
\r
66 import org.simantics.proconf.g3d.base.ScenegraphAdapterImpl;
\r
67 import org.simantics.proconf.g3d.base.SelectionAdapter;
\r
68 import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;
\r
69 import org.simantics.proconf.g3d.common.StructuredResourceSelection;
\r
70 import org.simantics.proconf.g3d.scenegraph.IGeometryNode;
\r
71 import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;
\r
72 import org.simantics.proconf.g3d.scenegraph.ISelectableNode;
\r
73 import org.simantics.proconf.g3d.scenegraph.ParameterizedModelNode;
\r
74 import org.simantics.proconf.g3d.shapes.FloorShape;
\r
75 import org.simantics.proconf.g3d.stubs.G3DNode;
\r
76 import org.simantics.utils.ui.ErrorLogger;
\r
77 import org.simantics.utils.ui.jface.MenuTools;
\r
79 import com.jme.math.Vector3f;
\r
80 import com.jme.scene.Geometry;
\r
83 public class ProcessEditor extends ThreeDimensionalEditorBase {
\r
85 private Resource plantResource = null;
\r
87 //private List<AnimationController> animationControllers = new ArrayList<AnimationController>();
\r
89 private Action configureFloorAction = null;
\r
91 private Geometry floorShape = null;
\r
93 public ProcessEditor(ISessionContext session) {
\r
95 addEditorContribution(new PlantEditContribution(this));
\r
96 addEditorContribution(new PlantVisualizationContribution(this));
\r
99 public ProcessEditor(ISessionContext session,JmeRenderingComponent component) {
\r
100 super(session,component);
\r
101 addEditorContribution(new PlantEditContribution(this));
\r
102 addEditorContribution(new PlantVisualizationContribution(this));
\r
106 protected ScenegraphAdapter createScenegraphAdapter() {
\r
107 return new ProcessEditorAdapter(session,getRenderingComponent());
\r
111 public void createControl(Graph graph,Composite parent) {
\r
112 super.createControl(graph,parent);
\r
114 floorShape = FloorShape.getShape(getRenderingComponent().getDisplaySystem().getRenderer(), 100.f,0.2f);
\r
115 getRenderingComponent().getNoCastRoot().attachChild(floorShape);
\r
116 floorShape.setLocalTranslation(new Vector3f(0.f,-0.01f,0.f));
\r
120 protected void makeActions(Graph graph) {
\r
121 super.makeActions(graph);
\r
123 //actions.add(new ShowTrendsAction(this));
\r
125 configureFloorAction = new Action() {
\r
126 public void run() {
\r
127 FloorConfigureDialog dialog = new FloorConfigureDialog(ProcessEditor.this.parent.getShell());
\r
128 if (dialog.open() == FloorConfigureDialog.CANCEL)
\r
130 if (dialog.isFloorEnabled()) {
\r
131 if (floorShape.getParent() == null)
\r
132 getRenderingComponent().getNoCastRoot().attachChild(floorShape);
\r
134 floorShape.removeFromParent();
\r
136 floorShape.setLocalTranslation(new Vector3f(0.f,(float)dialog.getFloorHeight(),0.f));
\r
140 configureFloorAction.setText("Configure floor");
\r
141 configureFloorAction.setImageDescriptor(Activator.imageDescriptorFromPlugin("fi.vtt.proconf.ode", "icons/silk/shape_align_bottom.png"));
\r
143 // ContextActionFactory extended[] = ContextActionRegistry.getActions("fi.vtt.proconf.shapeeditor.processeditorview");
\r
144 // for (ContextActionFactory c : extended) {
\r
145 // actions.add(c.createAction(this));
\r
149 // protected void stopAnimations() {
\r
150 // animationSystem.stop();
\r
153 protected void fillLocalPullDown() {
\r
154 super.fillLocalPullDown();
\r
155 MenuTools.getOrCreate(getMenuID(),"Advanced", menuManager).add(configureFloorAction);
\r
158 protected class ProcessEditorAdapter extends ScenegraphAdapterImpl {
\r
160 public ProcessEditorAdapter(Session session, JmeRenderingComponent component) {
\r
161 super(session, component);
\r
164 private class NormalScenegraphQuery extends ScenegraphQuery {
\r
166 public NormalScenegraphQuery(Resource node) {
\r
172 public void shapeAdded(Graph graph, IGraphicsNode node) {
\r
173 // FIXME : this won't work like in previous ProConf
\r
177 private Map<Resource,PipeRunControlPointQuery> pipeRunQueries = new HashMap<Resource, PipeRunControlPointQuery>();
\r
179 protected ScenegraphQuery newSubnodeListener(G3DNode node) {
\r
180 if (node.isInstanceOf(ProcessResource.plant3Dresource.PipeRun)) {
\r
181 PipeRunControlPointQuery query = new PipeRunControlPointQuery(node.getResource());
\r
182 pipeRunQueries.put(node.getResource(), query);
\r
183 node.getGraph().performQuery(query);
\r
184 // return new SubnodeListener(node) {
\r
186 // public void shapeAdded(IGraphicsNode node) {
\r
187 // if (node instanceof IGeometryNode) {
\r
188 // updateGeometry((IGeometryNode)node);
\r
191 // node.setVisible(true);
\r
195 return new NormalScenegraphQuery(node.getResource());
\r
200 protected NodePropertyQuery newRootPropertyListener(G3DNode root) {
\r
201 // currently Plant does not have any properties.
\r
205 private class TransformationQuery extends NodeTransformationQuery {
\r
207 public TransformationQuery(Resource res) {
\r
212 public void shapeUpdated(Graph graph, IGraphicsNode shape) {
\r
213 //if (shape instanceof IGeometryNode) {
\r
214 // updateGeometry((IGeometryNode)shape);
\r
216 shape.updateTransform(graph);
\r
222 protected NodeTransformationQuery newTransformationListener(G3DNode root) {
\r
223 return new TransformationQuery(root.getResource());
\r
226 private class NormalNodePropertyQuery extends org.simantics.proconf.g3d.base.ScenegraphAdapterImpl.NodePropertyQuery {
\r
228 public NormalNodePropertyQuery(Resource resource) {
\r
233 public void shapeUpdated(Graph graph,IGraphicsNode shape) {
\r
234 if (shape instanceof IGeometryNode) {
\r
235 updateGeometry((IGeometryNode)shape);
\r
237 shape.updateTransform(graph);
\r
242 protected NodePropertyQuery newPropertyListener(G3DNode node) {
\r
243 return new NormalNodePropertyQuery(node.getResource());
\r
247 protected IGraphicsNode instantiateNode(IGraphicsNode parent,
\r
249 Plant3DResource p3r = ProcessResource.plant3Dresource;
\r
250 IGraphicsNode newNode = null;
\r
252 if (node.isInstanceOf(p3r.Equipment)) {
\r
253 newNode = new ParameterizedModelNode(
\r
254 ProcessEditor.this, parent, node.getGraph(),
\r
255 node.getResource(), p3r.HasGraphics);
\r
256 } else if (node.isInstanceOf(p3r.PipeRun)) {
\r
257 newNode = new PipeRunNode(parent, node.getGraph(), node.getResource());
\r
258 } else if (node.isInstanceOf(p3r.Nozzle)) {
\r
259 newNode = new ParameterizedModelNode(
\r
260 ProcessEditor.this, parent, node.getGraph(),
\r
261 node.getResource(), p3r.HasGraphics);
\r
262 // CodedComponent must be handled first since it uses
\r
263 // hard-coded geometries
\r
264 // TODO : is this really necessary, or could we unify
\r
265 // PipeComponentNode, InlineComponentNode,...
\r
266 } else if (node.isInstanceOf(p3r.CodedComponent)) {
\r
267 newNode = new PipeComponentNode(ProcessEditor.this,
\r
268 parent, node.getGraph(), node.getResource());
\r
269 } else if (node.isInstanceOf(p3r.NonVisibleComponent)) {
\r
270 newNode = new NonVisibleNode(parent, node.getGraph(), node.getResource());
\r
271 } else if (node.isInstanceOf(p3r.PipelineComponent)) {
\r
272 newNode = new PipelineComponentNode(ProcessEditor.this,
\r
273 parent, node.getGraph(), node.getResource());
\r
276 // } else if (node instanceof Shape) // Markers (ar/mobile)
\r
278 // newNode = new ShapeNode(TestProcessEditor.this,parent,node);
\r
279 if (newNode != null) {
\r
280 if (newNode instanceof ISelectableNode)
\r
281 ((ISelectableNode) newNode).setVisible(true);
\r
282 if (newNode instanceof IGeometryNode) {
\r
283 updateGeometry((IGeometryNode) newNode);
\r
287 } catch (Exception e) {
\r
288 ErrorLogger.defaultLogError("Cannot handle node " + node.getResource(), e);
\r
291 ErrorLogger.defaultLogError("Cannot handle node " + node.getResource(), null);
\r
297 * This is used to create elbows and straight pipes to pipeline TODO :
\r
298 * this should be done with rule-engine!
\r
301 * @author Marko Luukkainen
\r
304 protected class PipeRunControlPointQuery extends NodeQuery {
\r
305 private List<Resource> removed = new ArrayList<Resource>();
\r
306 private List<Resource> added = new ArrayList<Resource>();
\r
308 public PipeRunControlPointQuery(Resource r) {
\r
310 if (DEBUG) System.out.println("Created PipeRunControlPointQuery for " + r);
\r
315 protected Object compute2(Graph graph) {
\r
316 PipeRun run = new PipeRun(graph, nodeResource);
\r
317 Collection<IEntity> cps = run
\r
318 .getRelatedObjects(ProcessResource.plant3Dresource.HasControlPoints);
\r
319 List<Resource> res = new ArrayList<Resource>();
\r
320 for (IEntity t : cps)
\r
321 res.add(t.getResource());
\r
326 public boolean updated(Graph graph, Object oldResult,
\r
327 Object newResult) {
\r
332 List<Resource> oldCps = (List<Resource>) oldResult;
\r
333 List<Resource> newCps = (List<Resource>) newResult;
\r
334 if (oldCps == null)
\r
335 oldCps = new ArrayList<Resource>();
\r
337 for (Resource r : oldCps) {
\r
338 if (!newCps.contains(r))
\r
342 for (Resource r : newCps) {
\r
343 if (!oldCps.contains(r))
\r
346 for (Resource r : removed)
\r
347 removeControlPoint(graph, r);
\r
348 for (Resource r : added) {
\r
349 addControlPoint(graph, r);
\r
350 // ControlPointTools.addControlPoint(new
\r
351 // PipeRun(graph,pipeRun), new PipeControlPoint(graph, r));
\r
354 return (added.size() > 0 || removed.size() > 0);
\r
358 public void dispose() {
\r
360 for (ControlPointPropertyQuery q : controlPointPropertyQueries.values())
\r
362 controlPointPropertyQueries.clear();
\r
365 private Map<Resource,ControlPointPropertyQuery> controlPointPropertyQueries = new HashMap<Resource, ControlPointPropertyQuery>();
\r
367 private void addControlPoint(Graph graph, Resource resource) {
\r
368 ControlPointPropertyQuery query = new ControlPointPropertyQuery(resource);
\r
369 graph.performQuery(query);
\r
370 controlPointPropertyQueries.put(resource,query);
\r
373 private void removeControlPoint(Graph graph, Resource resource) {
\r
374 ControlPointPropertyQuery query = controlPointPropertyQueries.remove(resource);
\r
376 ControlPointTools.removeControlPoint(new PipeControlPoint(
\r
382 protected class ControlPointPropertyQuery extends NodeQuery {
\r
383 boolean initialized = false;
\r
385 public ControlPointPropertyQuery(Resource r) {
\r
387 if (DEBUG) System.out.println("Created ControlPointPropertyQuery for " + r);
\r
391 public List<Object> compute2(Graph g) {
\r
392 IEntity t = EntityFactory.create(g,nodeResource);
\r
394 Collection<Property> properties = t.getRelatedProperties(ProcessResource.builtins.HasProperty);
\r
395 List<Object> propertyValues = new ArrayList<Object>();
\r
396 p(properties,propertyValues);
\r
398 return propertyValues;
\r
401 private void p(Collection<Property> properties, List<Object> propertyValues) {
\r
402 for (Property p : properties) {
\r
403 Collection<Property> subProperties = p.getRelatedProperties(p.getGraph().getBuiltins().HasProperty);
\r
404 if (subProperties.size() != 0) {
\r
405 p(subProperties,propertyValues);
\r
408 propertyValues.add(p.getValue());
\r
414 public boolean updated(Graph graph, Object oldResult, Object newResult) {
\r
415 PipingRules.pipeControlPointPositionUpdate(graph, this.nodeResource);
\r
417 //PipingRules.pipeControlPointPositionUpdate(graph, this.nodeResource);
\r
419 initialized = true;
\r
426 protected void removeNode(Resource parent, Resource r) {
\r
427 super.removeNode(parent, r);
\r
428 PipeRunControlPointQuery q = pipeRunQueries.get(r);
\r
434 public void dispose() {
\r
440 protected void pageSelectionChanged(IWorkbenchPart part, ISelection selection) {
\r
441 if (!(selection instanceof StructuredResourceSelection)) {
\r
445 StructuredResourceSelection s = (StructuredResourceSelection) selection;
\r
446 selectionAdapter.setCurrentSelection(s);
\r
447 viewChanged = true;
\r
449 //if (s.getRootSelection() == null) {
\r
450 if (!(part instanceof ProcessEditor)) {
\r
451 //System.out.println("ShapeEditorView.pageSelectionChanged() no root selection");
\r
452 ((ProcessEditorSelectionAdapter)selectionAdapter).setEditorSelection(true);
\r
455 //if (!s.getRootSelection().getResource().getId().equals(plant.getResource().getId())) {
\r
456 ProcessEditor sender = (ProcessEditor)part;
\r
457 if (!sender.getPlantResource().equals(plantResource)) {
\r
458 // System.out.println("ShapeEditorView.pageSelectionChanged() not right group "
\r
459 // + s.getRootSelection().getResource().getId() + " != " + model.getResource().getId());
\r
460 selectionAdapter.setCurrentSelection(new StructuredResourceSelection());
\r
461 ((ProcessEditorSelectionAdapter)selectionAdapter).setEditorSelection(false);
\r
464 selectionAdapter.setEditorSelection();
\r
469 protected void reloadFrom(IEntity thing) {
\r
470 if (plantResource != null) {
\r
471 throw new UnsupportedOperationException("Reloading instantiated viewer not supported");
\r
473 if (thing.isInstanceOf(ProcessResource.plant3Dresource.Plant)) {
\r
474 plantResource = thing.getResource();
\r
475 G3DNode plant = new G3DNode(thing);
\r
476 adapter.setRootNode(plant);
\r
477 //adapter.addOutbound(plant);
\r
478 ControlPointTools.reloadCache(thing.getGraph(),plant.getResource());
\r
480 throw new IllegalArgumentException("Resource is not a plant");
\r
484 public Resource getPlantResource() {
\r
485 return plantResource;
\r
488 public Plant getPlant(Graph g) {
\r
489 return new Plant(g, plantResource);
\r
493 protected SelectionAdapter createSelectionAdapter() {
\r
494 return new ProcessEditorSelectionAdapter(adapter);
\r
497 protected class ProcessEditorSelectionAdapter extends SelectionAdapter {
\r
500 public ProcessEditorSelectionAdapter(ScenegraphAdapter adapter) {
\r
502 // TODO Auto-generated constructor stub
\r
506 public void setEditorSelection() {
\r
507 List<IGraphicsNode> sel = getSelectedObjects();
\r
508 for (IGraphicsNode o : adapter.getNodes())
\r
509 if (o instanceof ISelectableNode) {
\r
510 if (sel.contains(o)) {
\r
511 ((ISelectableNode)o).setSelected(true);
\r
513 ((ISelectableNode)o).setSelected(false);
\r
516 List<Resource> selected = getSelectedResources();
\r
517 // TODO : don't know why this code is here, but it seems unnecessary
\r
518 // for (Resource r : selected) {
\r
519 // if (!adapter.hasNode(r)) {
\r
520 // // instantiating a new resource : usin this editor's tc
\r
521 // Resource resource = graph.getResource(r.getId());
\r
522 // adapter.addInbound(resource).setSelected(true);
\r
529 public void setEditorSelection(boolean addShapes) {
\r
531 List<IGraphicsNode> sel = getSelectedObjects();
\r
532 for (IGraphicsNode o : adapter.getNodes())
\r
533 if (o instanceof ISelectableNode) {
\r
534 if (sel.contains(o)) {
\r
535 ((ISelectableNode)o).setSelected(true);
\r
537 ((ISelectableNode)o).setSelected(false);
\r
541 // TODO : don't know why this code is here, but it seems unnecessary
\r
542 // List<Resource> selected = getSelectedResources();
\r
543 // for (Resource r : selected) {
\r
544 // if (!adapter.hasNode(r)) {
\r
545 // if (r.isInstanceOf(GlobalIdMap.get(PSK3DModelingOntologyMapping.EQUIPMENT))) {
\r
546 // Resource group = GraphicsNodeTools.getModelFromResource(r);
\r
547 // if (group != null && group.getId() == plant.getResource().getId()) {
\r
548 //// instantiating a new resource : usin this editor's tc
\r
549 // Resource resource = graph.getResource(r.getId());
\r
550 // adapter.addInbound(resource).setSelected(true);
\r
560 protected void setEditorHighlightSelection() {
\r
561 List<IGraphicsNode> sel = getInteractiveSelectedObjects();
\r
562 for (IGraphicsNode o : adapter.getNodes())
\r
563 if (o instanceof ISelectableNode) {
\r
564 if (sel.contains(o)) {
\r
565 ((ISelectableNode)o).setHighlighted(true);
\r
567 ((ISelectableNode)o).setHighlighted(false);
\r
573 private class FloorConfigureDialog extends Dialog implements KeyListener,SelectionListener {
\r
575 private boolean floorEnabled = true;
\r
576 private double floorHeight = 0.0;
\r
578 private Text floorHeightText = null;
\r
579 private Button floorEnabledButton = null;
\r
581 public FloorConfigureDialog(Shell shell) {
\r
586 protected Control createDialogArea(Composite parent) {
\r
587 Composite composite = (Composite) super.createDialogArea(parent);
\r
588 Label label = new Label(composite, SWT.WRAP);
\r
589 label.setText("Configure floor");
\r
590 GridData data = new GridData(GridData.GRAB_HORIZONTAL
\r
591 | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL
\r
592 | GridData.VERTICAL_ALIGN_CENTER);
\r
594 data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
\r
595 label.setLayoutData(data);
\r
596 label.setFont(parent.getFont());
\r
597 floorEnabledButton = new Button(composite,SWT.CHECK);
\r
598 floorEnabledButton.setText("Enabled");
\r
599 label = new Label(composite, SWT.WRAP);
\r
600 label.setText("Height");
\r
601 label.setLayoutData(data);
\r
602 label.setFont(parent.getFont());
\r
603 floorHeightText = new Text(composite,SWT.NONE);
\r
606 floorHeightText.addKeyListener(this);
\r
607 floorEnabledButton.addSelectionListener(this);
\r
608 floorEnabledButton.setSelection(floorEnabled);
\r
609 floorHeightText.setText(Double.toString(floorHeight));
\r
615 protected void configureShell(Shell newShell) {
\r
616 super.configureShell(newShell);
\r
617 newShell.setText("Configure floor");
\r
620 public void keyPressed(KeyEvent e) {
\r
624 public void keyReleased(KeyEvent e) {
\r
627 floorHeight = Double.parseDouble(floorHeightText.getText());
\r
628 } catch (NumberFormatException err) {
\r
632 this.getButton(IDialogConstants.OK_ID).setEnabled(true);
\r
634 this.getButton(IDialogConstants.OK_ID).setEnabled(false);
\r
638 public void widgetDefaultSelected(SelectionEvent e) {
\r
642 public void widgetSelected(SelectionEvent e) {
\r
643 floorEnabled = floorEnabledButton.getSelection();
\r
646 public boolean isFloorEnabled() {
\r
647 return floorEnabled;
\r
650 public double getFloorHeight() {
\r
651 return floorHeight;
\r
657 protected void hookDragAndDrop() {
\r
658 super.hookDragAndDrop();
\r
659 dropTarget.addDropListener(new InsertEquipmentAction(this));
\r
660 dropTarget.addDropListener(new InsertNozzleAction(this));
\r
661 dropTarget.addDropListener(new InsertComponentAction(this));
\r
662 dropTarget.addDropListener(new RoutePipeAction(this));
\r
666 public Object getAdapter(Class adapter) {
\r
667 if (adapter == IContentOutlinePage.class) {
\r
668 if (getPlantResource() == null)
\r
670 final PlantStructureOutlinePage page = new PlantStructureOutlinePage(sessionContext,getPlantResource());
\r
672 getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() {
\r
674 public void selectionChanged(SelectionChangedEvent event) {
\r
675 page.setSelection(event.getSelection());
\r
679 parent.getDisplay().asyncExec(new Runnable() {
\r
681 public void run() {
\r
682 page.addSelectionChangedListener(new ISelectionChangedListener() {
\r
684 public void selectionChanged(SelectionChangedEvent event) {
\r
685 selectionAdapter.setSelection(SelectionAdapter.transformSelection(event.getSelection()));
\r