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.actions;
\r
13 import java.awt.event.KeyEvent;
\r
14 import java.awt.event.MouseEvent;
\r
15 import java.util.ArrayList;
\r
16 import java.util.List;
\r
18 import javax.vecmath.Point3d;
\r
20 import org.eclipse.swt.widgets.Display;
\r
21 import org.simantics.db.Graph;
\r
22 import org.simantics.db.GraphRequestAdapter;
\r
23 import org.simantics.db.GraphRequestStatus;
\r
24 import org.simantics.db.GraphRequestWithResult;
\r
25 import org.simantics.db.Resource;
\r
26 import org.simantics.layer0.utils.EntityFactory;
\r
27 import org.simantics.layer0.utils.IEntity;
\r
28 import org.simantics.proconf.g3d.actions.InteractiveAction;
\r
29 import org.simantics.proconf.g3d.base.G3DAPI;
\r
30 import org.simantics.proconf.g3d.base.G3DTools;
\r
31 import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;
\r
32 import org.simantics.proconf.g3d.common.StructuredResourceSelection;
\r
33 import org.simantics.proconf.g3d.dnd.DropListener;
\r
34 import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;
\r
35 import org.simantics.utils.datastructures.Pair;
\r
37 import fi.vtt.simantics.processeditor.Activator;
\r
38 import fi.vtt.simantics.processeditor.ProcessResource;
\r
39 import fi.vtt.simantics.processeditor.common.ControlPointTools;
\r
40 import fi.vtt.simantics.processeditor.common.PipingTools2;
\r
41 import fi.vtt.simantics.processeditor.common.PipingTools2.Direction;
\r
42 import fi.vtt.simantics.processeditor.dialogs.PipelineComponentDialog;
\r
43 import fi.vtt.simantics.processeditor.gizmo.PositionSelectionGizmo;
\r
44 import fi.vtt.simantics.processeditor.stubs.PipeControlPoint;
\r
45 import fi.vtt.simantics.processeditor.stubs.PipelineComponent;
\r
50 * Action that inserts new components into pipe run.
\r
51 * - VariableLengthInlineComponents cannot be inserted with this action
\r
52 * - Assumes that SizeChangeComponent is dual connected
\r
55 * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>
\r
58 public class InsertComponentAction extends InteractiveAction implements DropListener, SplitPointListener {
\r
60 Resource typeResource; // type of inserted component
\r
61 Resource targetResource; // component where we are inserting new one
\r
62 Resource selectedPosition; // selected control point for insertion
\r
63 PositionType selectedType; // selected position type
\r
64 List<Pair<Resource, PositionType>> insertPositions;
\r
65 List<Pair<Point3d, PositionType>> insertPoints;
\r
66 PositionSelectionGizmo gizmo = null;
\r
68 boolean activated = false;
\r
70 private SelectSplitPointAction splitPointAction;
\r
72 public InsertComponentAction(ThreeDimensionalEditorBase parent) {
\r
74 splitPointAction = new SelectSplitPointAction(parent,this);
\r
78 public void init() {
\r
79 this.setText("Insert Component");
\r
80 this.setToolTipText("Inserts a Component into Pipeline");
\r
81 this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/Component.png"));
\r
85 public boolean usable(Graph graph, List<Resource> resources) {
\r
86 if (!(resources.size() == 1)) {
\r
89 IEntity target = EntityFactory.create(graph,resources.get(0));
\r
91 if (!target.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {
\r
94 PipelineComponent ic = new PipelineComponent(target);
\r
95 PipeControlPoint pcp = ic.getControlPoint();
\r
96 // one possibility: adding new component to unconnected position
\r
97 // TODO : how about inserting new components between existing ones.
\r
98 // TODO : can there be fixed length components that can be split (for example fixed length pipe)
\r
99 if (pcp.getNext() == null && pcp.getPrevious() == null)
\r
101 if (ic.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent) && (pcp.getNext() == null || pcp.getPrevious() == null))
\r
103 for (PipeControlPoint p : pcp.getSubPoint())
\r
104 // SubPoint's other connection is always null
\r
105 // Exception: size change components offset point (that is subpoint)
\r
106 // does have one or both ends connected, but it won't matter
\r
107 // here because previous test fould return true, if insertion
\r
109 // TODO : here we assume that Size Change Component is dual connected
\r
110 if (p.getNext() == null && p.getPrevious() == null)
\r
113 if (target.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {
\r
114 // last option to insert component is split variable length component.
\r
115 // If user chooses to split the component, inserted component must be
\r
116 // inline component, but not size change component
\r
123 public void activate() {
\r
124 insertPositions = null;
\r
125 if (targetResource == null) {
\r
126 List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();
\r
127 if (mos.size() != 1) {
\r
131 IGraphicsNode startNode = mos.get(0);
\r
132 targetResource = startNode.getResource();
\r
134 if (selectedPosition == null) {
\r
135 updateInsertPositions();
\r
137 if (typeResource == null) {
\r
139 List<Resource> filter = new ArrayList<Resource>();
\r
140 filter.add(ProcessResource.plant3Dresource.VariableLengthInlineComponent);
\r
142 boolean containsEnd = false;
\r
143 for (Pair<Point3d, PositionType> p : insertPoints) {
\r
144 if (p.second == PositionType.NEXT || p.second == PositionType.PREVIOUS) {
\r
145 containsEnd = true;
\r
151 filter.add(ProcessResource.plant3Dresource.EndComponent);
\r
153 PipelineComponentDialog dialog = new PipelineComponentDialog(Display.getCurrent().getActiveShell(),null, filter , parent.getSession());
\r
154 if (dialog.open() == PipelineComponentDialog.CANCEL) {
\r
158 typeResource = dialog.getComboValue();
\r
159 updateInsertPositions();
\r
165 private void updateInsertPositions() {
\r
166 parent.getSession().syncRead(new GraphRequestAdapter() {
\r
169 public GraphRequestStatus perform(Graph g) throws Exception {
\r
170 insertPositions = getInsertPositions(g,targetResource,typeResource);
\r
171 insertPoints = new ArrayList<Pair<Point3d,PositionType>>();
\r
172 for (Pair<Resource, PositionType> p : insertPositions) {
\r
173 IEntity entity = EntityFactory.create(g,p.first);
\r
174 Point3d pos = ControlPointTools.getRealPosition(entity, p.second);
\r
175 insertPoints.add(new Pair<Point3d, PositionType>(pos,p.second));
\r
177 return GraphRequestStatus.transactionComplete();
\r
183 * Finds possible locations of inserted component
\r
185 * TODO (s): currently allows only inline, non size change components to split variable length component
\r
186 * assumes that size change component is DualConnected component
\r
190 * @param acceptSplit
\r
193 private List<Pair<Resource, PositionType>> getInsertPositions(Graph g, Resource target, Resource typeResource) {
\r
195 boolean acceptSplit = true;
\r
196 boolean checkSubPoints = !g.isInstanceOf(target, ProcessResource.plant3Dresource.DualInlineControlPoint);
\r
197 if (typeResource != null)
\r
198 acceptSplit = g.isInstanceOf(typeResource, ProcessResource.plant3Dresource.InlineComponent) &&
\r
199 !g.isInstanceOf(typeResource, ProcessResource.plant3Dresource.SizeChangeComponent);
\r
202 List<Pair<Resource, PositionType>> insertPositions = new ArrayList<Pair<Resource,PositionType>>();
\r
203 PipelineComponent ic = new PipelineComponent(g,target);
\r
204 PipeControlPoint pcp = ic.getControlPoint();
\r
205 if (pcp.getNext() == null) {
\r
206 insertPositions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.NEXT));
\r
208 if (pcp.getPrevious() == null) {
\r
209 insertPositions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));
\r
211 if (checkSubPoints) {
\r
212 for (PipeControlPoint p : pcp.getSubPoint()) {
\r
213 if (p.getNext() == null && p.getPrevious() == null) {
\r
214 insertPositions.add(new Pair<Resource, PositionType>(p.getResource(),PositionType.PORT));
\r
218 if (acceptSplit && ic.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {
\r
219 insertPositions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.SPLIT));
\r
221 return insertPositions;
\r
225 public void update() {
\r
226 if (splitPointAction.active()) {
\r
227 splitPointAction.update();
\r
233 if (insertPositions == null)
\r
235 if (insertPositions.size() == 0) {
\r
239 if (insertPositions.size() == 1) {
\r
241 insertComponent(insertPositions.get(0));
\r
245 if (gizmo == null) {
\r
246 gizmo = new PositionSelectionGizmo(parent,insertPoints);
\r
247 parent.setGizmo(gizmo);
\r
248 parent.getRenderingComponent().getNoShadowRoot().attachChild(gizmo.getNode());
\r
251 if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) {
\r
253 insertComponent(insertPositions.get(gizmo.getSelected()));
\r
255 if (input.keyPressed(KeyEvent.VK_ESCAPE)) {
\r
260 private void insertComponent(Pair<Resource, PositionType> position) {
\r
261 selectedPosition = position.first;
\r
262 selectedType = position.second;
\r
263 switch (selectedType) {
\r
267 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
269 public GraphRequestStatus perform(Graph g) throws Exception {
\r
270 IEntity pcp = EntityFactory.create(g,selectedPosition);
\r
271 Point3d point = ControlPointTools.getRealPosition(pcp, selectedType);
\r
272 IEntity component = instantiateComponent(g,point);
\r
273 PipingTools2.insertComponent(component, EntityFactory.create(g, targetResource), pcp , Direction.NEXT);
\r
275 return GraphRequestStatus.transactionComplete();
\r
282 parent.getSession().asyncRead(new GraphRequestAdapter() {
\r
284 public GraphRequestStatus perform(Graph g) throws Exception {
\r
285 PipeControlPoint pcp = new PipeControlPoint(g,selectedPosition);
\r
286 Point3d p1 = new Point3d();
\r
287 Point3d p2 = new Point3d();
\r
288 ControlPointTools.getInlineControlPointEnds(pcp, p1, p2);
\r
289 splitPointAction.setSplit(p1, p2);
\r
290 splitPointAction.activate();
\r
291 return GraphRequestStatus.transactionComplete();
\r
298 private void endThreaded() {
\r
299 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
301 public void run() {
\r
308 public void setSplitPoint(final Point3d point) {
\r
309 splitPointAction.deactivate();
\r
310 if (point == null) {
\r
314 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
316 public GraphRequestStatus perform(Graph g) throws Exception {
\r
317 IEntity component = instantiateComponent(g,point);
\r
318 PipingTools2.splitVariableLengthComponent(component, EntityFactory.create(g,targetResource));
\r
320 return GraphRequestStatus.transactionComplete();
\r
324 public void requestCompleted(GraphRequestStatus status) {
\r
325 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){
\r
327 public void run() {
\r
337 * instantiates selected component
\r
338 * @param worldPosition position of the new component
\r
340 private PipelineComponent instantiateComponent(Graph g,Point3d worldPosition) {
\r
341 PipelineComponent target = new PipelineComponent(g,targetResource);
\r
342 IEntity piperun = target.getParent();
\r
343 PipelineComponent instance = PipingTools2.instantiatePipelineComponent(g,piperun.getResource(), typeResource);
\r
344 G3DTools.resetTransformation(instance);
\r
345 //G3DAPI.addNodeWorld(piperun, instance);
\r
346 G3DAPI.setWorldPosition(instance, worldPosition);
\r
351 public void deactivate() {
\r
352 typeResource = null;
\r
353 targetResource = null;
\r
354 selectedPosition = null;
\r
355 selectedType = null;
\r
356 insertPoints = null;
\r
357 insertPositions = null;
\r
358 if (gizmo != null) {
\r
359 parent.setGizmo(null);
\r
364 public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) {
\r
369 if (ids.length != 1)
\r
372 final Resource type = ids[0];
\r
373 final Resource target = s.getSelectionList().get(0);
\r
374 GraphRequestWithResult<Boolean> query = new GraphRequestWithResult<Boolean>() {
\r
376 public Boolean performWithResult(Graph g) throws Exception {
\r
377 IEntity entity = EntityFactory.create(g, type);
\r
378 // dropped type must be pipeline component
\r
379 if (!entity.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent))
\r
381 // but not variable length inline component
\r
382 if (entity.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent))
\r
384 if (entity.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() != 1)
\r
387 List<Pair<Resource, PositionType>> insertPositions = getInsertPositions(g,target,type);
\r
388 return insertPositions.size() > 0;
\r
392 parent.getSession().syncRead(query);
\r
394 return query.getResult();
\r
397 public void doDrop(StructuredResourceSelection s, Resource[] ids) {
\r
398 typeResource = ids[0];
\r
399 targetResource = s.getSelectionList().get(0);
\r
400 parent.setCurrentAction(this);
\r