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