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