]> gerrit.simantics Code Review - simantics/3d.git/blob - dev/org.simantics.proconf.processeditor/src/fi/vtt/simantics/processeditor/actions/InsertComponentAction.java
50f8fed4e6f1592e24b4551d6ac475dcc69a6b5f
[simantics/3d.git] / dev / org.simantics.proconf.processeditor / src / fi / vtt / simantics / processeditor / actions / InsertComponentAction.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.actions;\r
12 \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
17 \r
18 import javax.vecmath.Point3d;\r
19 \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
36 \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
46 \r
47 \r
48 \r
49 /**\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
53  * \r
54  * \r
55  * @author Marko Luukkainen <Marko.Luukkainen@vtt.fi>\r
56  *\r
57  */\r
58 public class InsertComponentAction extends InteractiveAction implements DropListener, SplitPointListener {\r
59 \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
67         \r
68     boolean activated = false;\r
69     \r
70     private SelectSplitPointAction splitPointAction;\r
71     \r
72     public InsertComponentAction(ThreeDimensionalEditorBase parent) {\r
73         super(parent);\r
74         splitPointAction = new SelectSplitPointAction(parent,this);\r
75     }\r
76     \r
77     @Override\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
82     }\r
83     \r
84     @Override\r
85     public boolean usable(Graph graph, List<Resource> resources) {\r
86         if (!(resources.size() == 1)) {\r
87                 return false;\r
88         }\r
89         IEntity target = EntityFactory.create(graph,resources.get(0));\r
90         \r
91         if (!target.isInstanceOf(ProcessResource.plant3Dresource.PipelineComponent)) {\r
92                 return false;\r
93         }\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
100                 return true;\r
101         if (ic.isInstanceOf(ProcessResource.plant3Dresource.InlineComponent) && (pcp.getNext() == null || pcp.getPrevious() == null))\r
102                         return true;\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
108                 //            is possible:\r
109                 // TODO : here we assume that Size Change Component is dual connected\r
110                 if (p.getNext() == null && p.getPrevious() == null) \r
111                         return true;\r
112         \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
117                 return true;\r
118         } \r
119         return false;\r
120     }\r
121     \r
122     @Override\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
128                                 end();\r
129                                 return;\r
130                         }\r
131                 IGraphicsNode startNode = mos.get(0);\r
132                 targetResource = startNode.getResource();\r
133         }\r
134         if (selectedPosition == null) {\r
135                 updateInsertPositions();\r
136         }\r
137         if (typeResource == null) {\r
138                         \r
139                         List<Resource> filter = new ArrayList<Resource>();\r
140                         filter.add(ProcessResource.plant3Dresource.VariableLengthInlineComponent);\r
141                         \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
146                                         break;\r
147                                 }\r
148                                         \r
149                         }\r
150                         if(!containsEnd)\r
151                                 filter.add(ProcessResource.plant3Dresource.EndComponent);\r
152                         \r
153                         PipelineComponentDialog dialog = new PipelineComponentDialog(Display.getCurrent().getActiveShell(),null, filter , parent.getSession());\r
154                         if (dialog.open() == PipelineComponentDialog.CANCEL) {\r
155                                 end();\r
156                                 return;\r
157                         }\r
158                         typeResource = dialog.getComboValue();\r
159                         updateInsertPositions();\r
160         }\r
161         \r
162         activated = true;\r
163     }\r
164     \r
165     private void updateInsertPositions() {\r
166         parent.getSession().syncRead(new GraphRequestAdapter() {\r
167                         \r
168                         @Override\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
176                                 }\r
177                                 return GraphRequestStatus.transactionComplete();\r
178                         }\r
179                 });\r
180     }\r
181     \r
182     /**\r
183      * Finds possible locations of inserted component\r
184      * \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
187      * \r
188      * @param g\r
189      * @param target \r
190      * @param acceptSplit\r
191      * @return\r
192      */\r
193     private List<Pair<Resource, PositionType>> getInsertPositions(Graph g, Resource target, Resource typeResource) {\r
194         \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
200 \r
201         \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
207             }\r
208             if (pcp.getPrevious() == null) {\r
209                 insertPositions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.PREVIOUS));\r
210             }\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
215                         }\r
216                 }\r
217             }\r
218             if (acceptSplit && ic.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent)) {\r
219                 insertPositions.add(new Pair<Resource, PositionType>(pcp.getResource(),PositionType.SPLIT));\r
220             }\r
221             return insertPositions;\r
222     }\r
223     \r
224     @Override\r
225     public void update() {\r
226         if (splitPointAction.active()) {\r
227                 splitPointAction.update();\r
228                 return;\r
229         }\r
230         if (!activated) {\r
231             return;\r
232         }\r
233         if (insertPositions == null)\r
234                 return;\r
235         if (insertPositions.size() == 0) {\r
236                 end();\r
237                 return;\r
238         }\r
239         if (insertPositions.size() == 1) {\r
240                 activated = false;\r
241                 insertComponent(insertPositions.get(0));\r
242                 return;\r
243         }\r
244         \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
249         }\r
250         gizmo.update();\r
251         if (gizmo.getSelected() >= 0 && input.mouseClicked() && input.clickButton() == MouseEvent.BUTTON1) {\r
252                 activated = false;\r
253                 insertComponent(insertPositions.get(gizmo.getSelected()));\r
254         }\r
255         if (input.keyPressed(KeyEvent.VK_ESCAPE)) {\r
256                 end();\r
257         }\r
258     }\r
259     \r
260     private void insertComponent(Pair<Resource, PositionType> position) {\r
261         selectedPosition = position.first;\r
262         selectedType = position.second;\r
263         switch (selectedType) {\r
264         case NEXT:\r
265         case PREVIOUS:\r
266         case PORT:\r
267                 parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
268                         @Override\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
274                                 endThreaded();\r
275                                 return GraphRequestStatus.transactionComplete();\r
276                         }\r
277                         \r
278                         \r
279                 });\r
280                 break;\r
281         case SPLIT:\r
282                 parent.getSession().asyncRead(new GraphRequestAdapter() {\r
283                         @Override\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
292                         }\r
293                 });             \r
294                 break;\r
295         }\r
296     }\r
297     \r
298     private void endThreaded() {\r
299         parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
300                         @Override\r
301                         public void run() {\r
302                                 end();\r
303                         }\r
304                 });\r
305     }\r
306     \r
307     @Override\r
308     public void setSplitPoint(final Point3d point) {\r
309         splitPointAction.deactivate();\r
310         if (point == null) {\r
311                 end();\r
312                 return;\r
313         }\r
314         parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
315                         @Override\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
319                                 \r
320                                 return GraphRequestStatus.transactionComplete();\r
321                         }\r
322                         \r
323                         @Override\r
324                         public void requestCompleted(GraphRequestStatus status) {\r
325                                 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable(){\r
326                                         @Override\r
327                                         public void run() {\r
328                                                 end();\r
329                                                 \r
330                                         }\r
331                                 });\r
332                         }\r
333                 });\r
334     }\r
335     \r
336     /**\r
337      * instantiates selected component\r
338      * @param worldPosition position of the new component\r
339      */\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
347         return instance;\r
348     }\r
349     \r
350     @Override\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
360                 gizmo = null;\r
361         }\r
362     }\r
363 \r
364     public boolean acceptDrop(StructuredResourceSelection s, Resource[] ids) {\r
365                 if(s.size() != 1)\r
366                         return false;\r
367                 if (ids == null)\r
368                         return false;\r
369                 if (ids.length != 1)\r
370                         return false;\r
371                 \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
375                         @Override\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
380                                         return false;\r
381                                 // but not variable length inline component\r
382                                 if (entity.isInstanceOf(ProcessResource.plant3Dresource.VariableLengthInlineComponent))\r
383                                         return false;\r
384                                 if (entity.getRelatedObjects(ProcessResource.plant3Dresource.HasGraphics).size() != 1)\r
385                                         return false;\r
386                         \r
387                                 List<Pair<Resource, PositionType>> insertPositions = getInsertPositions(g,target,type);\r
388                                 return insertPositions.size() > 0;      \r
389                         }\r
390                 };\r
391                 \r
392                 parent.getSession().syncRead(query);\r
393                 \r
394                 return query.getResult();\r
395         }    \r
396     \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
401         }\r
402 \r
403 }\r