]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/e4/PopulateElementDropParticipant.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / e4 / PopulateElementDropParticipant.java
diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/e4/PopulateElementDropParticipant.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/e4/PopulateElementDropParticipant.java
new file mode 100644 (file)
index 0000000..73a2cd0
--- /dev/null
@@ -0,0 +1,419 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.modeling.ui.diagramEditor.e4;\r
+\r
+import java.awt.Point;\r
+import java.awt.datatransfer.Transferable;\r
+import java.awt.datatransfer.UnsupportedFlavorException;\r
+import java.awt.dnd.DnDConstants;\r
+import java.awt.dnd.DropTargetDragEvent;\r
+import java.awt.dnd.DropTargetDropEvent;\r
+import java.awt.dnd.DropTargetEvent;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Point2D;\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.eclipse.core.runtime.IAdaptable;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.simantics.Simantics;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.RequestProcessor;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.PossibleIndexRoot;\r
+import org.simantics.db.common.request.UniqueRead;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.request.IsLinkedTo;\r
+import org.simantics.db.layer0.util.Layer0Utils;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.diagram.Logger;\r
+import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;\r
+import org.simantics.diagram.content.Change;\r
+import org.simantics.diagram.content.DiagramContentChanges;\r
+import org.simantics.diagram.content.DiagramContentTracker;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.diagram.symbollibrary.ISymbolItem;\r
+import org.simantics.diagram.synchronization.runtime.DiagramSelectionUpdater;\r
+import org.simantics.diagram.ui.DiagramModelHints;\r
+import org.simantics.diagram.ui.ElementClassTransferable;\r
+import org.simantics.diagram.ui.ElementClassTransferable.ResourceElementClassTransferData;\r
+import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;\r
+import org.simantics.g2d.diagram.DiagramHints;\r
+import org.simantics.g2d.diagram.DiagramUtils;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.handler.PickContext;\r
+import org.simantics.g2d.diagram.handler.PickRequest;\r
+import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;\r
+import org.simantics.g2d.dnd.DnDHints;\r
+import org.simantics.g2d.dnd.ElementClassDragItem;\r
+import org.simantics.g2d.dnd.IDnDContext;\r
+import org.simantics.g2d.dnd.IDragItem;\r
+import org.simantics.g2d.dnd.IDropTargetParticipant;\r
+import org.simantics.g2d.element.ElementClass;\r
+import org.simantics.g2d.element.ElementHints;\r
+import org.simantics.g2d.element.ElementUtils;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.g2d.participant.TransformUtil;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.modeling.ui.Activator;\r
+import org.simantics.modeling.ui.diagramEditor.WSEDragItem;\r
+import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.ui.dnd.LocalObjectTransfer;\r
+import org.simantics.ui.dnd.LocalObjectTransferable;\r
+import org.simantics.ui.selection.WorkbenchSelectionElement;\r
+import org.simantics.ui.workbench.e4.E4WorkbenchUtils;\r
+import org.simantics.utils.logging.TimeLogger;\r
+\r
+/**\r
+ * This participant populates Elements from ElementClass-resources drops\r
+ */\r
+public class PopulateElementDropParticipant extends AbstractDiagramParticipant implements IDropTargetParticipant {\r
+\r
+    @Dependency PickContext pickContext;\r
+    @Dependency TransformUtil transformUtil;\r
+       \r
+    protected GraphToDiagramSynchronizer synchronizer;\r
+    protected MPart part;\r
+\r
+    public PopulateElementDropParticipant(GraphToDiagramSynchronizer synchronizer) {\r
+        this(synchronizer, null);\r
+    }\r
+\r
+    public PopulateElementDropParticipant(GraphToDiagramSynchronizer synchronizer, MPart part) {\r
+        this.synchronizer = synchronizer;\r
+        this.part = part;\r
+    }\r
+\r
+    @Override\r
+    public void dragEnter(DropTargetDragEvent dtde, IDnDContext dp) {\r
+        if (diagram == null)\r
+            return;\r
+\r
+        Transferable tr = dtde.getTransferable();\r
+        if (tr.isDataFlavorSupported(LocalObjectTransferable.FLAVOR)) {\r
+            // System.out.println("joo");\r
+            Object obj = null;\r
+\r
+            // This must be done to have SWT transfer set the source data\r
+            try {\r
+                obj = tr.getTransferData(LocalObjectTransferable.FLAVOR);\r
+                // System.out.println("GOT FROM AWT: " + obj);\r
+            } catch (UnsupportedFlavorException e) {\r
+                // TODO Auto-generated catch block\r
+                e.printStackTrace();\r
+            } catch (IOException e) {\r
+                // TODO Auto-generated catch block\r
+                e.printStackTrace();\r
+            }\r
+\r
+            // Check SWT\r
+            if (!(obj instanceof IStructuredSelection)) {\r
+                obj = LocalObjectTransfer.getTransfer().getObject();\r
+                // System.out.println("GOT FROM SWT: " + obj);\r
+            }\r
+\r
+            if (obj instanceof IStructuredSelection) {\r
+                IStructuredSelection sel = (IStructuredSelection) obj;\r
+                if (!sel.isEmpty()) {\r
+                    for (Object elm : sel.toList()) {\r
+                        if (elm instanceof IAdaptable) {\r
+                            ElementClass ec = (ElementClass) ((IAdaptable) elm).getAdapter(ElementClass.class);\r
+                            if (ec != null) {\r
+                                dp.add(new ElementClassDragItem(ec));\r
+                            } else {\r
+                                Resource r = (Resource) ((IAdaptable) elm).getAdapter(Resource.class);\r
+                                if (r != null) {\r
+                                    if (elm instanceof ISymbolItem) {\r
+                                        /* FIXME fix this check \r
+                                        ISymbolItem symbol = (ISymbolItem) elm;\r
+                                        Resource dia = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);\r
+                                        try {\r
+                                            if (!DiagramTypeUtils.symbolAllowedOnDiagram(synchronizer.getSession(), symbol, dia)) {\r
+                                                // Deny dragging of this symbol\r
+                                                continue;\r
+                                            }\r
+                                        } catch (DatabaseException e) {\r
+                                            e.printStackTrace();\r
+                                            continue;\r
+                                        }*/\r
+                                    }\r
+\r
+                                    try {\r
+                                        String valid = validateDrop(synchronizer.getSession(), r,\r
+                                                diagram.<Resource> getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE));\r
+                                        if (valid == null) {\r
+                                            ElementClassDragItem item = new ElementClassDragItem(synchronizer.getNodeClass(r));\r
+                                            item.getHintContext().setHint(ElementHints.KEY_TRANSFORM, AffineTransform.getScaleInstance(1, 1));\r
+                                            dp.add(item);\r
+                                        }\r
+                                    } catch (DatabaseException e) {\r
+                                        // Ignore node-class retrieval failures.\r
+                                        //System.out.println("error: " + e.getMessage());\r
+                                    }\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
+\r
+                    // Let the default logic handle out how many columns to use.\r
+                    dp.getHints().removeHint(DnDHints.KEY_DND_GRID_COLUMNS);\r
+                }\r
+            }\r
+\r
+            return;\r
+        }\r
+\r
+        if (tr.isDataFlavorSupported(ElementClassTransferable.FLAVOR)) {\r
+            ResourceElementClassTransferData dada;\r
+            try {\r
+                dada = (ResourceElementClassTransferData) tr.getTransferData(ElementClassTransferable.FLAVOR);\r
+            } catch (UnsupportedFlavorException e) {\r
+                throw new Error(e);\r
+            } catch (IOException e) {\r
+                throw new Error(e);\r
+            }\r
+            Session s = synchronizer.getSession();\r
+            try {\r
+                for (String rid : dada.elementClassResourceRandomAccessReference) {\r
+                    SerialisationSupport support = s.getService(SerialisationSupport.class);\r
+                    Resource r = support.getResource(Long.parseLong(rid));\r
+                    dp.add(new ElementClassDragItem(synchronizer.getNodeClass(r)));\r
+                }\r
+            } catch (DatabaseException e) {\r
+                throw new RuntimeException(e);\r
+            }\r
+\r
+            return;\r
+        }\r
+    }\r
+\r
+    private String validateDrop(RequestProcessor processor, final Resource draggedResource, final Resource dropTarget) throws DatabaseException {\r
+        return processor.syncRequest(new UniqueRead<String>() {\r
+            @Override\r
+            public String perform(ReadGraph graph) throws DatabaseException {\r
+//                System.out.println("dragged resource: " + draggedResource);\r
+//                System.out.println("drop target resource: " + dropTarget);\r
+                Resource sourceModel = graph.syncRequest(new PossibleIndexRoot(draggedResource));\r
+                Resource targetModel = graph.syncRequest(new PossibleIndexRoot(dropTarget));\r
+//                System.out.println("source model: " + sourceModel);\r
+//                System.out.println("target model: " + targetModel);\r
+\r
+                // Prevent dragging data from one source model to another.\r
+                // If source is not part of any model, everything is okay.\r
+                if (sourceModel != null && !graph.syncRequest(new IsLinkedTo(targetModel, sourceModel))) {\r
+                    // Prevent a symbol instantiating within its own configuration.\r
+                    // NOTE: this doesn't handle transitive cycles.\r
+                    return "Cannot instantiate " + NameUtils.getSafeName(graph, draggedResource) + " into model "\r
+                            + NameUtils.getURIOrSafeNameInternal(graph, targetModel) + ". The source namespace ("\r
+                            + NameUtils.getURIOrSafeNameInternal(graph, sourceModel) + ") is not linked to the target model.";\r
+                }\r
+                \r
+                // Prevent dragging to published components\r
+                ModelingResources MOD = ModelingResources.getInstance(graph);\r
+                StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+                Resource configuration = graph.getPossibleObject(dropTarget, MOD.DiagramToComposite);\r
+                if (configuration != null) {\r
+                    Resource componentTypeFromDiagram = graph.getPossibleObject(configuration, STR.Defines);\r
+                    if(componentTypeFromDiagram != null) {\r
+                           if(Layer0Utils.isPublished(graph, componentTypeFromDiagram))\r
+                               return "Cannot create elements into a diagram that belongs to a published user component.";\r
+                    }\r
+                }\r
+\r
+                // Prevent dragging a symbol of component type into its own configuration.\r
+                Resource componentTypeFromSymbol = graph.getPossibleObject(draggedResource, MOD.SymbolToComponentType);\r
+                if (componentTypeFromSymbol != null) {\r
+                    if (configuration != null) {\r
+                        Resource componentTypeFromDiagram = graph.getPossibleObject(configuration, STR.Defines);\r
+                        if (componentTypeFromDiagram != null && componentTypeFromSymbol.equals(componentTypeFromDiagram)) {\r
+                            return "Cannot instantiate user component within its own configuration.";\r
+                        }\r
+                    }\r
+                }\r
+\r
+                return null;\r
+            }\r
+        });\r
+    }\r
+\r
+    @Override\r
+    public void dragExit(DropTargetEvent dte, IDnDContext dp) {\r
+        // System.out.println("exit");\r
+    }\r
+\r
+    @Override\r
+    public void dragOver(DropTargetDragEvent dtde, IDnDContext dp) {\r
+        // System.out.println("over");\r
+    }\r
+\r
+    private IElement tryPick(Point p) {\r
+\r
+       Point2D canvas = transformUtil.controlToCanvas(p, null);\r
+       \r
+        assertDependencies();\r
+\r
+        PickRequest    req                     = new PickRequest(canvas);\r
+        req.pickPolicy = PickRequest.PickPolicy.PICK_INTERSECTING_OBJECTS;\r
+        List<IElement>         picks                   = new ArrayList<IElement>();\r
+        pickContext.pick(diagram, req, picks);\r
+\r
+        if(picks.size() == 1) return picks.iterator().next();\r
+        \r
+        return null;\r
+       \r
+    }\r
+\r
+    @Override\r
+    public void drop(DropTargetDropEvent dtde, final IDnDContext dp) {\r
+        TimeLogger.resetTimeAndLog(getClass(), "drop");\r
+\r
+        final IDiagram d = getHint(DiagramHints.KEY_DIAGRAM);\r
+        if (d == null)\r
+            return;\r
+\r
+        IElement pick = tryPick(dtde.getLocation()); \r
+        if(pick != null) {\r
+               \r
+                       final List<WorkbenchSelectionElement> wses = new ArrayList<WorkbenchSelectionElement>();\r
+                       \r
+                       for(IDragItem i : dp.toArray())\r
+                               if(i instanceof WSEDragItem)\r
+                                       wses.add(((WSEDragItem)i).getObject());\r
+\r
+               final Resource element = (Resource)ElementUtils.getData(d, pick);\r
+               if(element != null && !wses.isEmpty()) {\r
+               \r
+               try {\r
+                       \r
+                                       Simantics.getSession().syncRequest(new WriteRequest() {\r
+\r
+                                               @Override\r
+                                               public void perform(WriteGraph graph) throws DatabaseException {\r
+                                                       \r
+                                                       DiagramResource DIA = DiagramResource.getInstance(graph);\r
+                                                       \r
+                                               Simantics.invokeSCLWrite(graph, element, DIA.symbolDropHandler, wses);\r
+                                               \r
+                                               }\r
+                                               \r
+                                       });\r
+                                       \r
+                               } catch (DatabaseException e) {\r
+                                       Logger.defaultLogError(e);\r
+                               }\r
+               \r
+               return;\r
+               \r
+               }\r
+               \r
+\r
+        }\r
+        \r
+        Runnable creator = () -> {\r
+            DiagramUtils.mutateDiagram(d, m -> {\r
+                IDragItem items[] = dp.toArray();\r
+\r
+                for (IDragItem i : items) {\r
+                    if (!(i instanceof ElementClassDragItem))\r
+                        continue;\r
+\r
+                    ElementClassDragItem res = (ElementClassDragItem) i;\r
+                    ElementClass ec = res.getElementClass();\r
+\r
+                    Point2D pos = dp.getItemPosition(i);\r
+                    // System.out.println(pos);\r
+                    assert (pos != null);\r
+\r
+                    IElement element = m.newElement(ec);\r
+                    element.setHints(res.getHintContext().getHints());\r
+\r
+                    setupDroppedElement(element, pos);\r
+\r
+                    // Remove only the drag items we've processed.\r
+                    dp.remove(i);\r
+                }\r
+            });\r
+        };\r
+\r
+        selectNewDiagramContentAfter(d, part, creator);\r
+\r
+        getContext().getContentContext().setDirty();\r
+    }\r
+\r
+    protected void selectNewDiagramContentAfter(IDiagram d, MPart activatePart, Runnable diagramModifier) {\r
+        try {\r
+            Resource diagramResource = d.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);\r
+            final DiagramContentTracker tracker = diagramResource == null ? null\r
+                    : DiagramContentTracker.start(getContext(), Simantics.getSession(), diagramResource);\r
+\r
+            diagramModifier.run();\r
+\r
+            if (tracker != null) {\r
+                // Get difference of diagram contents to find out what was added.\r
+                DiagramContentChanges changes = tracker.update();\r
+                Set<Resource> addedElements = changes.pick(changes.elements, Change.ADDED);\r
+                if (!addedElements.isEmpty()) {\r
+                    new DiagramSelectionUpdater(getContext())\r
+                    .setNewSelection(0, addedElements)\r
+                    .setOneshot(true)\r
+                    .track();\r
+                    if (activatePart != null)\r
+                        E4WorkbenchUtils.activatePart(activatePart);\r
+                }\r
+            }\r
+        } catch (DatabaseException e) {\r
+            Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Diagram content change tracking failed.", e));\r
+        }\r
+    }\r
+\r
+    protected void setupDroppedElement(IElement element, Point2D dropPos) {\r
+        // This works only for elements without parents.\r
+        ISnapAdvisor snapAdvisor = getContext().getHintStack().getHint(DiagramHints.SNAP_ADVISOR);\r
+        if(snapAdvisor != null)\r
+            snapAdvisor.snap(dropPos);\r
+\r
+        IElement parent = element.getHint(ElementHints.KEY_PARENT_ELEMENT);\r
+        if (parent != null) {\r
+            Point2D parentPos = ElementUtils.getPos(parent);\r
+            Point2D pos = new Point2D.Double(dropPos.getX() - parentPos.getX(), dropPos.getY() - parentPos.getY());\r
+            ElementUtils.setPos(element, pos);\r
+        } else {\r
+            ElementUtils.setPos(element, dropPos);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void dropActionChanged(DropTargetDragEvent dtde, IDnDContext dp) {\r
+        dtde.acceptDrag(DnDConstants.ACTION_COPY);\r
+    }\r
+\r
+    @Override\r
+    public int getAllowedOps() {\r
+        return DnDConstants.ACTION_COPY;\r
+    }\r
+    \r
+    @Override\r
+    public double getPriority() {\r
+       return 10.0;\r
+    }\r
+\r
+}
\ No newline at end of file