Sync git svn branch with SVN repository r33406.
[simantics/platform.git] / bundles / org.simantics.charts / src / org / simantics / charts / editor / SubscriptionDropParticipant.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2016 Association for Decentralized Information Management in\r
3  * 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  *     Semantum Oy - JSON plain text input support\r
12  *******************************************************************************/\r
13 package org.simantics.charts.editor;\r
14 \r
15 import java.awt.datatransfer.DataFlavor;\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.dnd.DropTargetDropEvent;\r
21 import java.awt.dnd.DropTargetEvent;\r
22 import java.io.IOException;\r
23 import java.io.InputStream;\r
24 import java.nio.charset.Charset;\r
25 import java.util.ArrayList;\r
26 import java.util.Collection;\r
27 import java.util.Collections;\r
28 import java.util.List;\r
29 import java.util.Optional;\r
30 import java.util.stream.Collectors;\r
31 \r
32 import org.eclipse.jface.viewers.ISelection;\r
33 import org.simantics.Simantics;\r
34 import org.simantics.charts.internal.JsonUtils;\r
35 import org.simantics.charts.query.AddChartItem;\r
36 import org.simantics.charts.query.ChartItemDescriptor;\r
37 import org.simantics.charts.ui.AddVariableToChartAction;\r
38 import org.simantics.charts.ui.ChartDropActionFactory;\r
39 import org.simantics.charts.ui.ChartVariable;\r
40 import org.simantics.databoard.util.ObjectUtils;\r
41 import org.simantics.db.ReadGraph;\r
42 import org.simantics.db.Resource;\r
43 import org.simantics.db.Session;\r
44 import org.simantics.db.common.request.UnaryRead;\r
45 import org.simantics.db.common.request.UniqueRead;\r
46 import org.simantics.db.exception.DatabaseException;\r
47 import org.simantics.db.layer0.SelectionHints;\r
48 import org.simantics.db.layer0.request.PossibleModel;\r
49 import org.simantics.db.layer0.variable.RVI;\r
50 import org.simantics.db.layer0.variable.Variable;\r
51 import org.simantics.db.layer0.variable.VariableReference;\r
52 import org.simantics.db.layer0.variable.Variables;\r
53 import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;\r
54 import org.simantics.g2d.dnd.DragItem;\r
55 import org.simantics.g2d.dnd.IDnDContext;\r
56 import org.simantics.g2d.dnd.IDragItem;\r
57 import org.simantics.g2d.dnd.IDropTargetParticipant;\r
58 import org.simantics.modeling.ModelingResources;\r
59 import org.simantics.modeling.PropertyVariables;\r
60 import org.simantics.modeling.PropertyVariablesImpl;\r
61 import org.simantics.modeling.utils.VariableReferences;\r
62 import org.simantics.ui.dnd.LocalObjectTransfer;\r
63 import org.simantics.ui.dnd.LocalObjectTransferable;\r
64 import org.simantics.ui.selection.WorkbenchSelectionElement;\r
65 import org.simantics.utils.FileUtils;\r
66 import org.simantics.utils.ui.ErrorLogger;\r
67 import org.simantics.utils.ui.ISelectionUtils;\r
68 import org.simantics.utils.ui.dialogs.ShowMessage;\r
69 \r
70 /**\r
71  * @author Tuukka Lehtonen\r
72  */\r
73 public class SubscriptionDropParticipant extends AbstractDiagramParticipant implements IDropTargetParticipant { \r
74 \r
75     private static class SubscriptionItemDragItem extends DragItem<ChartItemDescriptor> {\r
76         public SubscriptionItemDragItem(ChartItemDescriptor obj) {\r
77             super(obj);\r
78         }\r
79     }\r
80 \r
81     private static class VariableReferenceDragItem extends DragItem<VariableReference> {\r
82         public VariableReferenceDragItem(VariableReference obj) {\r
83             super(obj);\r
84         }\r
85     }\r
86     \r
87     Resource container;\r
88     Resource model;\r
89 \r
90     public SubscriptionDropParticipant(Resource container) {\r
91         this.container = container;\r
92         try {\r
93                         model = Simantics.getSession().sync( new PossibleModel( container ) );\r
94                 } catch (DatabaseException e) {\r
95                 }\r
96     }\r
97 \r
98     @Override\r
99     public void dragEnter(DropTargetDragEvent dtde, IDnDContext dp) {\r
100         // The source cannot link, too bad\r
101         if ((dtde.getSourceActions() & DnDConstants.ACTION_LINK) == 0) {\r
102             dtde.rejectDrag();\r
103             return;\r
104         }\r
105 \r
106         // Ensure the content is usable\r
107         if (dtde.isDataFlavorSupported(LocalObjectTransferable.FLAVOR)) {\r
108             dragEnterLocalObject(dtde, dp);\r
109         } else if (dtde.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor())) {\r
110             dragEnterPlainText(dtde, dp);\r
111         } else {\r
112             dtde.rejectDrag();\r
113         }\r
114     }\r
115 \r
116     private void dragEnterLocalObject(DropTargetDragEvent dtde, IDnDContext dp) {\r
117         try {\r
118             Object data = dtde.getTransferable().getTransferData(LocalObjectTransferable.FLAVOR);\r
119             data = LocalObjectTransfer.getTransfer().getObject();\r
120 \r
121             List<IDragItem> items = new ArrayList<>();\r
122             Session session = Simantics.getSession();\r
123 \r
124             final List<Resource> resources = ISelectionUtils.getPossibleKeys(data, SelectionHints.KEY_MAIN, Resource.class);\r
125             if (!resources.isEmpty()) {\r
126                 // Support SubscriptionItem drags\r
127                 items.addAll( session.syncRequest(new UniqueRead<List<IDragItem>>() {\r
128                     @Override\r
129                     public List<IDragItem> perform(ReadGraph graph) throws DatabaseException {\r
130                         List<IDragItem> result = new ArrayList<>();\r
131                         ModelingResources MOD = ModelingResources.getInstance(graph);\r
132                         Resource targetModel = graph.syncRequest(new PossibleModel(container));\r
133                         if (targetModel != null) {\r
134                             for (Resource r : resources) {\r
135                                 if (graph.isInstanceOf(r, MOD.Subscription_Item)) {\r
136                                     Resource model = graph.syncRequest(new PossibleModel(r));\r
137                                     if (ObjectUtils.objectEquals(targetModel, model))\r
138                                         result.add( new SubscriptionItemDragItem( AddChartItem.createDescriptor(graph, r) ) );\r
139                                 }\r
140                             }\r
141                         }\r
142                         return result;\r
143                     }\r
144                 }) );\r
145             }\r
146 \r
147             if(data instanceof RVI) {\r
148 \r
149                 VariableReferenceDragItem vrdi = new VariableReferenceDragItem(session.sync(new UnaryRead<RVI, VariableReference>((RVI)data) {\r
150                     @Override\r
151                     public VariableReference perform(ReadGraph graph) throws DatabaseException {\r
152                         return new VariableReference(parameter, Variables.getDatatype(graph, model, parameter), null);\r
153                     }\r
154                 }));\r
155                 items.add( vrdi );\r
156 \r
157             } else {\r
158                 // Variable/PropertyVariable are mutually exclusive\r
159                 List<IDragItem> varItems = null;\r
160 \r
161                 // 1st try Variable\r
162                 final List<Variable> vars2 = ISelectionUtils.getPossibleKeys(data, SelectionHints.KEY_MAIN, Variable.class);\r
163                 if (!vars2.isEmpty()) {\r
164                     varItems = session.syncRequest( new UniqueRead<List<IDragItem>>() {\r
165                         @Override\r
166                         public List<IDragItem> perform(ReadGraph graph) throws DatabaseException {\r
167                             return toDragItems( graph.syncRequest(VariableReferences.variablesToReferences(model, vars2)) );\r
168                         }\r
169                     } );\r
170                 }\r
171                 if (varItems == null || varItems.isEmpty()) {\r
172                     // Try legacy PropertyVariables\r
173                     final List<PropertyVariables> vars = ISelectionUtils.getPossibleKeys(data, SelectionHints.KEY_MAIN, PropertyVariables.class);\r
174                     if (!vars.isEmpty()) {\r
175                         varItems = session.syncRequest( new UniqueRead<List<IDragItem>>() {\r
176                             @Override\r
177                             public List<IDragItem> perform(ReadGraph graph) throws DatabaseException {\r
178                                 List<PropertyVariables> vars2 = PropertyVariablesImpl.resolve(graph, vars);\r
179                                 return toDragItems( graph.syncRequest(VariableReferences.toReferences(model, vars2)) );\r
180                             }\r
181                         } );\r
182                     }\r
183                 }\r
184                 if (varItems != null)\r
185                     items.addAll(varItems);\r
186 \r
187                 // Try WorkbenchSelectionElement\r
188                 if (data instanceof ISelection) {\r
189                     final List<WorkbenchSelectionElement> wses = ISelectionUtils.filterSelection((ISelection)data, WorkbenchSelectionElement.class);\r
190                     if (!wses.isEmpty()) {\r
191                         items.addAll( session.syncRequest( new UniqueRead<List<IDragItem>>() {\r
192                             @Override\r
193                             public List<IDragItem> perform(ReadGraph graph) throws DatabaseException {\r
194                                 List<Variable> wsevars = new ArrayList<>();\r
195                                 ChartVariable av = new ChartVariable(graph);\r
196                                 for(WorkbenchSelectionElement wse : wses) {\r
197                                     Variable v = wse.getContent(av);\r
198                                     if(v != null) {\r
199                                         wsevars.add(v);\r
200                                     }\r
201                                 }\r
202                                 return toDragItems( graph.syncRequest(VariableReferences.variablesToReferences(model, wsevars)) );\r
203                             }\r
204                         } ) );\r
205                     }\r
206                 }\r
207             }\r
208 \r
209             if (items.isEmpty()) {\r
210                 dtde.rejectDrag();\r
211             } else {\r
212                 // Accept, make sure it is Link\r
213                 for (IDragItem i : items)\r
214                     dp.add(i);\r
215                 dtde.acceptDrag( DnDConstants.ACTION_LINK );\r
216             }\r
217         } catch (UnsupportedFlavorException e) {\r
218             throw new RuntimeException(e);\r
219         } catch (IOException e) {\r
220             ErrorLogger.defaultLogError(e);\r
221             dtde.rejectDrag();\r
222         } catch (DatabaseException e) {\r
223             ErrorLogger.defaultLogError(e);\r
224             dtde.rejectDrag();\r
225         }\r
226     }\r
227 \r
228     private void dragEnterPlainText(DropTargetDragEvent dtde, IDnDContext dp) {\r
229         try {\r
230             DataFlavor flavor = DataFlavor.getTextPlainUnicodeFlavor();\r
231             String flavorCharset = flavor.getParameter("charset");\r
232             Transferable t = dtde.getTransferable();\r
233             InputStream in = (InputStream) t.getTransferData(flavor);\r
234             String data = FileUtils.getContents(in, Charset.forName(flavorCharset));\r
235 \r
236             List<IDragItem> items = new ArrayList<>();\r
237             Session session = Simantics.getSession();\r
238             Optional<Variable> v = JsonUtils.tryParseJsonPropertyVariable(session, data);\r
239             if (v.isPresent()) {\r
240                 items.addAll( toDragItems( session.syncRequest(VariableReferences.variablesToReferences(model, Collections.singletonList(v.get()))) ) );\r
241             }\r
242 \r
243             if (items.isEmpty()) {\r
244                 dtde.rejectDrag();\r
245             } else {\r
246                 // Accept, make sure it is Link\r
247                 for (IDragItem i : items)\r
248                     dp.add(i);\r
249                 dtde.acceptDrag( DnDConstants.ACTION_LINK );\r
250             }\r
251         } catch (UnsupportedFlavorException e) {\r
252             throw new RuntimeException(e);\r
253         } catch (IOException e) {\r
254             ErrorLogger.defaultLogError(e);\r
255             dtde.rejectDrag();\r
256         } catch (DatabaseException e) {\r
257             ErrorLogger.defaultLogError(e);\r
258             dtde.rejectDrag();\r
259         }\r
260     }\r
261 \r
262     @Override\r
263     public void dragExit(DropTargetEvent dte, IDnDContext dp) {\r
264         for (IDragItem i : dp.getItemsByClass(SubscriptionItemDragItem.class))\r
265             dp.remove(i);\r
266         for (IDragItem i : dp.getItemsByClass(VariableReferenceDragItem.class))\r
267             dp.remove(i);\r
268     }\r
269 \r
270     @Override\r
271     public void dragOver(DropTargetDragEvent dtde, IDnDContext dp) {\r
272     }\r
273 \r
274     @Override\r
275     public void drop(DropTargetDropEvent dtde, IDnDContext dp) {\r
276         // Subscription Item\r
277         Collection<SubscriptionItemDragItem> subs = dp.getItemsByClass(SubscriptionItemDragItem.class);\r
278         if (!subs.isEmpty()) {\r
279             ChartDropActionFactory.addPlots(container,\r
280                     subs.stream().map(DragItem::getObject).collect(Collectors.toList()),\r
281                     Collections.<Resource>emptySet()).run();\r
282             dtde.dropComplete(true);\r
283             return;\r
284         }\r
285 \r
286         // Variable Reference\r
287         Collection<VariableReferenceDragItem> vrdis = dp.getItemsByClass(VariableReferenceDragItem.class);\r
288         if (!vrdis.isEmpty()) {\r
289             try {\r
290                 new AddVariableToChartAction( container, null,\r
291                         vrdis.stream().map(DragItem::getObject).collect(Collectors.toList()) )\r
292                 .init().run();\r
293                     dtde.dropComplete(true);\r
294                         } catch (DatabaseException e) {\r
295                                 ShowMessage.showError(e.getClass().getName(), e.getMessage());\r
296                     dtde.dropComplete(true);\r
297                         }\r
298             return;\r
299         }\r
300 \r
301         dtde.rejectDrop();\r
302     }\r
303 \r
304     @Override\r
305     public void dropActionChanged(DropTargetDragEvent dtde, IDnDContext dp) {\r
306         dtde.acceptDrag( DnDConstants.ACTION_LINK );\r
307     }\r
308 \r
309     @Override\r
310     public int getAllowedOps() {\r
311         return DnDConstants.ACTION_LINK;\r
312     }\r
313 \r
314     private static List<IDragItem> toDragItems(Collection<VariableReference> references) {\r
315         return references.stream().map(VariableReferenceDragItem::new).collect(Collectors.toList());\r
316     }\r
317 \r
318     @Override\r
319     public double getPriority() {\r
320         return 10.0;\r
321     }\r
322 \r
323 }