]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/PopulateElementMonitorDropParticipant.java
0deeb1be1a7f02c49fa2e82084320c83e749832e
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / PopulateElementMonitorDropParticipant.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.modeling.ui.diagramEditor;\r
13 \r
14 import gnu.trove.set.hash.THashSet;\r
15 \r
16 import java.awt.datatransfer.Transferable;\r
17 import java.awt.datatransfer.UnsupportedFlavorException;\r
18 import java.awt.dnd.DnDConstants;\r
19 import java.awt.dnd.DropTargetDragEvent;\r
20 import java.awt.geom.AffineTransform;\r
21 import java.io.IOException;\r
22 import java.util.ArrayList;\r
23 import java.util.Collections;\r
24 import java.util.HashMap;\r
25 import java.util.List;\r
26 \r
27 import org.eclipse.jface.viewers.IStructuredSelection;\r
28 import org.simantics.Logger;\r
29 import org.simantics.db.ReadGraph;\r
30 import org.simantics.db.RequestProcessor;\r
31 import org.simantics.db.Resource;\r
32 import org.simantics.db.Session;\r
33 import org.simantics.db.common.request.UnaryRead;\r
34 import org.simantics.db.common.request.UniqueRead;\r
35 import org.simantics.db.common.utils.NameUtils;\r
36 import org.simantics.db.common.utils.OrderedSetUtils;\r
37 import org.simantics.db.exception.DatabaseException;\r
38 import org.simantics.db.layer0.SelectionHints;\r
39 import org.simantics.db.layer0.variable.Variable;\r
40 import org.simantics.db.layer0.variable.Variables;\r
41 import org.simantics.db.layer0.variable.Variables.Role;\r
42 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;\r
43 import org.simantics.diagram.content.ConnectionUtil;\r
44 import org.simantics.diagram.stubs.DiagramResource;\r
45 import org.simantics.diagram.ui.DiagramModelHints;\r
46 import org.simantics.g2d.diagram.handler.DataElementMap;\r
47 import org.simantics.g2d.dnd.DnDHints;\r
48 import org.simantics.g2d.dnd.ElementClassDragItem;\r
49 import org.simantics.g2d.dnd.IDnDContext;\r
50 import org.simantics.g2d.dnd.IDropTargetParticipant;\r
51 import org.simantics.g2d.element.ElementHints;\r
52 import org.simantics.g2d.element.IElement;\r
53 import org.simantics.g2d.utils.Alignment;\r
54 import org.simantics.layer0.Layer0;\r
55 import org.simantics.modeling.ModelingResources;\r
56 import org.simantics.modeling.PropertyVariables;\r
57 import org.simantics.modeling.PropertyVariablesImpl;\r
58 import org.simantics.modeling.ui.diagram.monitor.MonitorClassFactory2;\r
59 import org.simantics.structural.stubs.StructuralResource2;\r
60 import org.simantics.ui.dnd.LocalObjectTransfer;\r
61 import org.simantics.ui.dnd.LocalObjectTransferable;\r
62 import org.simantics.ui.selection.WorkbenchSelectionElement;\r
63 import org.simantics.ui.selection.WorkbenchSelectionUtils;\r
64 import org.simantics.utils.datastructures.Triple;\r
65 import org.simantics.utils.datastructures.hints.IHintContext;\r
66 import org.simantics.utils.ui.ISelectionUtils;\r
67 \r
68 public class PopulateElementMonitorDropParticipant extends PopulateElementDropParticipant implements IDropTargetParticipant {\r
69 \r
70     private static final boolean DEBUG = false;\r
71 \r
72     // Scale for the monitors\r
73     double scaleX, scaleY;\r
74     // Monitor type\r
75     String typeURI;\r
76 \r
77     public PopulateElementMonitorDropParticipant(GraphToDiagramSynchronizer synchronizer, double scaleX, double scaleY) {\r
78         super(synchronizer);\r
79         this.scaleX = scaleX;\r
80         this.scaleY = scaleY;\r
81         this.typeURI = DiagramResource.URIs.Monitor;\r
82     }\r
83 \r
84     public PopulateElementMonitorDropParticipant(GraphToDiagramSynchronizer synchronizer, String typeURI, double scaleX, double scaleY) {\r
85         super(synchronizer);\r
86         this.scaleX = scaleX;\r
87         this.scaleY = scaleY;\r
88         this.typeURI = typeURI;\r
89     }\r
90 \r
91     @Override\r
92     public void dragEnter(DropTargetDragEvent dtde, final IDnDContext dp) {\r
93 \r
94         Transferable tr = dtde.getTransferable();\r
95 \r
96         if (tr.isDataFlavorSupported(LocalObjectTransferable.FLAVOR)) {\r
97 \r
98             // This must be done to have SWT transfer set the source data\r
99             try {\r
100                 Object obj = tr.getTransferData(LocalObjectTransferable.FLAVOR);\r
101                 if (DEBUG)\r
102                     System.out.println("GOT FROM AWT: " + obj);\r
103 \r
104                 // Check SWT\r
105                 if (!(obj instanceof IStructuredSelection)) {\r
106                     obj = LocalObjectTransfer.getTransfer().getObject();\r
107                     if (DEBUG)\r
108                         System.out.println("GOT FROM SWT: " + obj);\r
109                 }\r
110 \r
111                 if (obj instanceof IStructuredSelection) {\r
112                         \r
113                     IStructuredSelection sel = (IStructuredSelection) obj;\r
114                     \r
115                         for(WorkbenchSelectionElement wse : WorkbenchSelectionUtils.getWorkbenchSelectionElements(sel)) {\r
116                                 dp.add(new WSEDragItem(wse));\r
117                         }\r
118 \r
119                     Session session = synchronizer.getSession();\r
120 \r
121                     List<Variable> properties = resolveVariables(session, (IStructuredSelection) obj);\r
122                     if (properties.isEmpty())\r
123                         return;\r
124 \r
125                     List<ElementClassDragItem> items = session.syncRequest(new ResolveItems(properties));\r
126                     for (ElementClassDragItem item : items)\r
127                         dp.add(item);\r
128 \r
129                     dp.getHints().setHint(DnDHints.KEY_DND_GRID_COLUMNS, Integer.valueOf(1));\r
130                 }\r
131 \r
132             } catch (UnsupportedFlavorException e) {\r
133                 Logger.defaultLogError(e);\r
134             } catch (IOException e) {\r
135                 Logger.defaultLogError(e);\r
136             } catch (DatabaseException e) {\r
137                 Logger.defaultLogError(e);\r
138             }\r
139 \r
140         }\r
141 \r
142         dtde.acceptDrag(DnDConstants.ACTION_COPY);\r
143 \r
144     }\r
145 \r
146     public void setHints(IHintContext context) {\r
147     }\r
148 \r
149     protected List<Variable> resolveVariables(RequestProcessor processor, IStructuredSelection sel) throws DatabaseException {\r
150         if (sel.isEmpty())\r
151             return Collections.emptyList();\r
152 \r
153         Variable property = WorkbenchSelectionUtils.getPossibleVariable(sel);\r
154         if(property != null)\r
155             return Collections.singletonList(property);\r
156 \r
157         property = ISelectionUtils.getSinglePossibleKey(sel, SelectionHints.KEY_SELECTION_PROPERTY, Variable.class);\r
158         if (property != null)\r
159             return Collections.singletonList(property);\r
160 \r
161         final List<PropertyVariables> vars = ISelectionUtils.getPossibleKeys(sel, SelectionHints.KEY_MAIN, PropertyVariables.class);\r
162         if (!vars.isEmpty()) {\r
163             return processor.syncRequest(new UniqueRead<List<Variable>>() {\r
164                 @Override\r
165                 public List<Variable> perform(ReadGraph graph) throws DatabaseException {\r
166                     // FIXME: this is a hack for indexed value support\r
167                     List<PropertyVariables> vs = PropertyVariablesImpl.resolve(graph, vars);\r
168                     List<Variable> result = new ArrayList<Variable>(vs.size());\r
169                     for (PropertyVariables v : vs)\r
170                         result.add(v.getVisualVariable());\r
171                     return result;\r
172                 }\r
173             });\r
174         }\r
175 \r
176         return Collections.emptyList();\r
177     }\r
178 \r
179     protected class ResolveItems extends UnaryRead<List<Variable>, List<ElementClassDragItem>> {\r
180 \r
181         public ResolveItems(List<Variable> parameter) {\r
182             super(parameter);\r
183         }\r
184 \r
185         @Override\r
186         public List<ElementClassDragItem> perform(ReadGraph graph) throws DatabaseException {\r
187             List<ElementClassDragItem> result = new ArrayList<ElementClassDragItem>(parameter.size());\r
188             for (Variable property : parameter)\r
189                 result.addAll( resolve(graph, property) );\r
190             return result;\r
191         }\r
192 \r
193         public List<ElementClassDragItem> resolve(ReadGraph graph, Variable parameter) throws DatabaseException {\r
194 \r
195             if (DEBUG) {\r
196                 System.out.println("PARAM: " + parameter.getURI(graph));\r
197                 Variable parent = parameter.browsePossible(graph, "..");\r
198                 System.out.println("PARENT: " + parent.getURI(graph));\r
199                 Resource parentComposite = parent.getPossibleRepresents(graph);\r
200                 System.out.println("PARENT REPRESENTS: " + NameUtils.getSafeLabel(graph, parentComposite));\r
201                 String prvi = Variables.getRVI(graph, parent);\r
202                 System.out.println("PARENT RVI: " + prvi);\r
203                 String parvi = Variables.getRVI(graph, parameter);\r
204                 System.out.println("PARAM RVI: " + parvi);\r
205             }\r
206 \r
207             Triple<Variable, Resource, IElement> match = findElementInDiagram(graph, parameter, false);\r
208             if (match == null)\r
209                 return Collections.emptyList();\r
210             \r
211             if(match.third == null) {\r
212                 // We are in a different diagram, prevent creation of monitors\r
213                 // from UCs to different UCs or model configuration\r
214                 Resource diagram = synchronizer.getDiagram().getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);\r
215                 Resource commonParent = findCommonParent(graph, diagram, match.second);\r
216                 StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
217                 if(!graph.isInstanceOf(commonParent, STR.Composite))\r
218                     return Collections.emptyList();\r
219             }\r
220 \r
221             if (DEBUG) {\r
222                 System.out.println("p=" + parameter.getURI(graph));\r
223                 System.out.println("c=" + match.first.getURI(graph));\r
224             }\r
225 \r
226             String rvi = Variables.getRVI(graph, match.first, parameter);\r
227             if (DEBUG)\r
228                 System.out.println("r=" + rvi);\r
229 \r
230             Resource type = graph.getResource(typeURI);\r
231 \r
232             ElementClassDragItem item = new ElementClassDragItem(MonitorClassFactory2.createMonitorClass(type, match.third, new HashMap<String, String>(), match.second, rvi, scaleX, scaleY));\r
233             item.getHintContext().setHint(ElementHints.KEY_HORIZONTAL_ALIGN, Alignment.LEADING);\r
234 \r
235             if (match.third != null)\r
236                 item.getHintContext().setHint(ElementHints.KEY_PARENT_ELEMENT, match.third);\r
237 \r
238             AffineTransform initialTr = AffineTransform.getScaleInstance(scaleX, scaleY);\r
239             item.getHintContext().setHint(ElementHints.KEY_TRANSFORM, initialTr);\r
240 \r
241             setHints(item.getHintContext());\r
242 \r
243             return Collections.singletonList(item);\r
244 \r
245         }\r
246 \r
247         private Triple<Variable, Resource, IElement> findElementInDiagram(ReadGraph graph, Variable property, boolean propertyRoleFound) throws DatabaseException {\r
248             if (property == null)\r
249                 return null;\r
250 \r
251             if (DEBUG)\r
252                 System.out.println("findElementInDiagram " + property.getURI(graph) + " " + property);\r
253 \r
254             DiagramResource DIA = DiagramResource.getInstance(graph);\r
255             ModelingResources MOD = ModelingResources.getInstance(graph);\r
256             final Resource diagram = synchronizer.getDiagram().getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);\r
257 \r
258             if (!propertyRoleFound) {\r
259                 Role role = property.getPossibleRole(graph);\r
260                 propertyRoleFound = role == Role.PROPERTY;\r
261             }\r
262 \r
263             Resource represents = property.getPossibleRepresents(graph);\r
264             if (represents != null) {\r
265                 if (DEBUG)\r
266                     System.out.println("represents " + NameUtils.getSafeName(graph, represents, true));\r
267                 Resource elementResource = graph.getPossibleObject(represents, MOD.ComponentToElement);\r
268                 // There must have be at least one\r
269                 // PROPERTY role variable in the\r
270                 // browsed path before finding this\r
271                 // element.\r
272                 if(elementResource != null && propertyRoleFound) {\r
273                     Resource elementDiagram = OrderedSetUtils.getSingleOwnerList(graph, elementResource, DIA.Diagram);\r
274                     if(diagram.equals(elementDiagram)) {\r
275                         final DataElementMap map = synchronizer.getDiagram().getDiagramClass().getSingleItem(DataElementMap.class);\r
276                         IElement parentElement = map.getElement(synchronizer.getDiagram(), elementResource);\r
277 \r
278                         if (graph.isInstanceOf(elementResource, DIA.Connection)) {\r
279                             Resource tailNode = ConnectionUtil.getConnectionTailNode(graph, elementResource);\r
280                             if (tailNode != null) {\r
281                                 IElement tailNodeElement = map.getElement(synchronizer.getDiagram(), tailNode);\r
282                                 if (tailNodeElement != null)\r
283                                     parentElement = tailNodeElement;\r
284                             }\r
285                         }\r
286 \r
287                         return Triple.make(property, represents, parentElement);\r
288                     } else {\r
289                         // The monitored target module is on another diagram/composite.\r
290                         // No parent for the monitor then.\r
291                         return Triple.make(property, represents, null);\r
292                     }\r
293                 }\r
294             }\r
295 \r
296             return findElementInDiagram(graph, property.browsePossible(graph, "."), propertyRoleFound);\r
297         }\r
298 \r
299     }\r
300 \r
301     private static Resource findCommonParent(ReadGraph graph, Resource a, Resource b) throws DatabaseException {\r
302         Layer0 L0 = Layer0.getInstance(graph);\r
303         THashSet<Resource> set = new THashSet<>();\r
304         while(true) {\r
305             if(a != null) {\r
306                 if(!set.add(a))\r
307                     return a;\r
308                 a = graph.getPossibleObject(a, L0.PartOf);\r
309             }\r
310             else if(b == null)\r
311                 return graph.getRootLibrary();\r
312             if(b != null) {\r
313                 if(!set.add(b))\r
314                     return b;\r
315                 b = graph.getPossibleObject(a, L0.PartOf);\r
316             }\r
317         }\r
318     }\r
319 \r
320     @Override\r
321     public double getPriority() {\r
322         return 9.0;\r
323     }\r
324     \r
325 }