]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/PopulateElementDropParticipant.java
Configurable connection crossing styles
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / PopulateElementDropParticipant.java
index bbac2a08a025ce3cc65a8e6b37330fbcba299fa0..49adcb65b48155ebe6f2082975551f030c1fba1c 100644 (file)
-/*******************************************************************************\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;\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.jface.viewers.IStructuredSelection;\r
-import org.eclipse.ui.IWorkbenchPartSite;\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.ResourceRead2;\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.layer0.variable.Variable;\r
-import org.simantics.db.layer0.variable.Variables;\r
-import org.simantics.db.service.SerialisationSupport;\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.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.utils.logging.TimeLogger;\r
-import org.simantics.utils.ui.workbench.WorkbenchUtils;\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 IWorkbenchPartSite partSite;\r
-\r
-    public PopulateElementDropParticipant(GraphToDiagramSynchronizer synchronizer) {\r
-        this(synchronizer, null);\r
-    }\r
-\r
-    public PopulateElementDropParticipant(GraphToDiagramSynchronizer synchronizer, IWorkbenchPartSite partSite) {\r
-        this.synchronizer = synchronizer;\r
-        this.partSite = partSite;\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
-                    Session db = Simantics.getSession();\r
-                    DiagramResource DIA = DiagramResource.getInstance(db);\r
-                    Variable function = db.syncRequest(new PossibleVariableProperty(element, DIA.symbolDropHandler));\r
-                    if (function != null) {\r
-                        db.syncRequest(new WriteRequest() {\r
-                            @Override\r
-                            public void perform(WriteGraph graph) throws DatabaseException {\r
-                                Simantics.invokeSCLWrite(graph, function, wses);\r
-                            }\r
-                        });\r
-                        return;\r
-                    }\r
-                } catch (DatabaseException e) {\r
-                    Activator.getDefault().getLog()\r
-                            .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID,\r
-                                    "Invocation to custom symbolDropHandler for element "\r
-                                            + element + " failed.",\r
-                                    e));\r
-                    return;\r
-                }\r
-\r
-               }\r
-\r
-\r
-        }\r
-        \r
-        Runnable creator = new Runnable() {\r
-            public void run() {\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
-\r
-        selectNewDiagramContentAfter(d, partSite, creator);\r
-\r
-        getContext().getContentContext().setDirty();\r
-    }\r
-\r
-    private static class PossibleVariableProperty extends ResourceRead2<Variable> {\r
-\r
-        public PossibleVariableProperty(Resource entity, Resource property) {\r
-            super(entity, property);\r
-        }\r
-\r
-        @Override\r
-        public Variable perform(ReadGraph graph) throws DatabaseException {\r
-            return Variables.tryGetProperty(graph, resource, resource2);\r
-        }\r
-\r
-    }\r
-\r
-    protected void selectNewDiagramContentAfter(IDiagram d, IWorkbenchPartSite activateSite, 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 (activateSite != null)\r
-                        WorkbenchUtils.activatePart(activateSite);\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
+/*******************************************************************************
+ * Copyright (c) 2007, 2018 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - gitlab #215
+ *******************************************************************************/
+package org.simantics.modeling.ui.diagramEditor;
+
+import java.awt.Point;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.RequestProcessor;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.common.request.PossibleIndexRoot;
+import org.simantics.db.common.request.ResourceRead2;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.request.IsLinkedTo;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.db.request.Read;
+import org.simantics.db.request.Write;
+import org.simantics.db.service.SerialisationSupport;
+import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
+import org.simantics.diagram.content.Change;
+import org.simantics.diagram.content.DiagramContentChanges;
+import org.simantics.diagram.content.DiagramContentTracker;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.diagram.synchronization.runtime.DiagramSelectionUpdater;
+import org.simantics.diagram.ui.DiagramModelHints;
+import org.simantics.diagram.ui.ElementClassTransferable;
+import org.simantics.diagram.ui.ElementClassTransferable.ResourceElementClassTransferData;
+import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
+import org.simantics.g2d.diagram.DiagramHints;
+import org.simantics.g2d.diagram.DiagramUtils;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.PickContext;
+import org.simantics.g2d.diagram.handler.PickRequest;
+import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;
+import org.simantics.g2d.dnd.DnDHints;
+import org.simantics.g2d.dnd.ElementClassDragItem;
+import org.simantics.g2d.dnd.IDnDContext;
+import org.simantics.g2d.dnd.IDragItem;
+import org.simantics.g2d.dnd.IDropTargetParticipant;
+import org.simantics.g2d.element.ElementClass;
+import org.simantics.g2d.element.ElementHints;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.participant.TransformUtil;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.modeling.ui.Activator;
+import org.simantics.modeling.ui.diagramEditor.dnd.DropSuggestion;
+import org.simantics.modeling.ui.diagramEditor.dnd.DropSuggestions;
+import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.ui.dnd.LocalObjectTransfer;
+import org.simantics.ui.dnd.LocalObjectTransferable;
+import org.simantics.ui.selection.WorkbenchSelectionElement;
+import org.simantics.utils.datastructures.hints.IHintContext;
+import org.simantics.utils.datastructures.hints.IHintContext.Key;
+import org.simantics.utils.logging.TimeLogger;
+import org.simantics.utils.strings.EString;
+import org.simantics.utils.ui.SWTUtils;
+import org.simantics.utils.ui.dialogs.ShowError;
+import org.simantics.utils.ui.workbench.WorkbenchUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This participant populates Elements from ElementClass-resources drops
+ */
+public class PopulateElementDropParticipant extends AbstractDiagramParticipant implements IDropTargetParticipant {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(PopulateElementDropParticipant.class);
+
+    /**
+     * List of {@link DropSuggestion} instances that need to be applied to be model
+     * before the drop can commence. Used with the hint context from
+     * {@link IDnDContext#getHints()}.
+     */
+    private static final Key KEY_SUGGESTIONS = new IHintContext.KeyOf(List.class);
+
+    @Dependency PickContext pickContext;
+    @Dependency TransformUtil transformUtil;
+
+    protected GraphToDiagramSynchronizer synchronizer;
+    protected IWorkbenchPartSite partSite;
+
+    public PopulateElementDropParticipant(GraphToDiagramSynchronizer synchronizer) {
+        this(synchronizer, null);
+    }
+
+    public PopulateElementDropParticipant(GraphToDiagramSynchronizer synchronizer, IWorkbenchPartSite partSite) {
+        this.synchronizer = synchronizer;
+        this.partSite = partSite;
+    }
+
+    @Override
+    public void dragEnter(DropTargetDragEvent dtde, IDnDContext dp) {
+        if (diagram == null)
+            return;
+
+        Transferable tr = dtde.getTransferable();
+        if (tr.isDataFlavorSupported(LocalObjectTransferable.FLAVOR)) {
+            Object obj = null;
+
+            // This must be done to have SWT transfer set the source data
+            try {
+                obj = tr.getTransferData(LocalObjectTransferable.FLAVOR);
+                // System.out.println("GOT FROM AWT: " + obj);
+            } catch (UnsupportedFlavorException | IOException e) {
+                LOGGER.error("Could not get AWT transferable data", e); //$NON-NLS-1$
+            }
+
+            // Check SWT
+            if (!(obj instanceof IStructuredSelection)) {
+                obj = LocalObjectTransfer.getTransfer().getObject();
+                // System.out.println("GOT FROM SWT: " + obj);
+            }
+
+            if (obj instanceof IStructuredSelection) {
+                IStructuredSelection sel = (IStructuredSelection) obj;
+                if (!sel.isEmpty()) {
+                    for (Object elm : sel.toList()) {
+                        if (elm instanceof IAdaptable) {
+                            ElementClass ec = (ElementClass) ((IAdaptable) elm).getAdapter(ElementClass.class);
+                            if (ec != null) {
+                                dp.add(new ElementClassDragItem(ec));
+                            } else {
+                                Resource r = (Resource) ((IAdaptable) elm).getAdapter(Resource.class);
+                                if (r != null) {
+                                    try {
+                                        Object errorOrSymbolResource = validateDrag(synchronizer.getSession(), r,
+                                                diagram.<Resource> getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE),
+                                                dp.getHints());
+                                        if (errorOrSymbolResource instanceof Resource) {
+                                            Resource symbol = (Resource) errorOrSymbolResource;
+                                            ElementClassDragItem item = new ElementClassDragItem(synchronizer.getNodeClass(symbol));
+                                            item.getHintContext().setHint(ElementHints.KEY_TRANSFORM, AffineTransform.getScaleInstance(1, 1));
+                                            item.getHintContext().setHint(ElementHints.KEY_OBJECT, symbol);
+                                            dp.add(item);
+                                        }
+                                    } catch (DatabaseException e) {
+                                        // Ignore node-class retrieval failures, so only log as debug
+                                        LOGGER.debug("Could not retrieve node class for dropped symbol", e); //$NON-NLS-1$
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    // Let the default logic handle out how many columns to use.
+                    dp.getHints().removeHint(DnDHints.KEY_DND_GRID_COLUMNS);
+                }
+            }
+
+            return;
+        }
+
+        if (tr.isDataFlavorSupported(ElementClassTransferable.FLAVOR)) {
+            ResourceElementClassTransferData dada;
+            try {
+                dada = (ResourceElementClassTransferData) tr.getTransferData(ElementClassTransferable.FLAVOR);
+            } catch (UnsupportedFlavorException e) {
+                throw new Error(e);
+            } catch (IOException e) {
+                throw new Error(e);
+            }
+            Session s = synchronizer.getSession();
+            try {
+                for (String rid : dada.elementClassResourceRandomAccessReference) {
+                    SerialisationSupport support = s.getService(SerialisationSupport.class);
+                    Resource r = support.getResource(Long.parseLong(rid));
+                    dp.add(new ElementClassDragItem(synchronizer.getNodeClass(r)));
+                }
+            } catch (DatabaseException e) {
+                throw new RuntimeException(e);
+            }
+
+            return;
+        }
+    }
+
+    private Object validateDrag(RequestProcessor processor, final Resource draggedResource, final Resource dropTarget, IHintContext dndHints) throws DatabaseException {
+        return processor.syncRequest((Read<Object>) graph -> {
+            List<DropSuggestion> suggestions = dndHints.getHint(KEY_SUGGESTIONS);
+            if (suggestions == null) {
+                suggestions = new ArrayList<>();
+                dndHints.setHint(KEY_SUGGESTIONS, suggestions);
+            }
+
+            //System.out.println("dragged resource: " + draggedResource);
+            //System.out.println("drop target resource: " + dropTarget);
+            Resource sourceRoot = graph.syncRequest(new PossibleIndexRoot(draggedResource));
+            Resource targetRoot = graph.syncRequest(new PossibleIndexRoot(dropTarget));
+            //System.out.println("source model: " + sourceRoot);
+            //System.out.println("target model: " + targetRoot);
+
+            // Prevent dragging data from one source model to another.
+            // If source is not part of any model, everything is okay.
+            if (sourceRoot != null && !graph.syncRequest(new IsLinkedTo(targetRoot, sourceRoot))) {
+                // Prevent instantiation from source roots that are already dependent on the target root.
+                // This would form a dependency cycle.
+                if (graph.syncRequest(new IsLinkedTo(sourceRoot, targetRoot))) {
+                    return NLS.bind("Cannot instantiate {0} into namespace {1}. The source namespace ({2}) is already linked to the target namespace. Linking the target to the source would form a dependency cycle.", //$NON-NLS-1$
+                            new Object[] {
+                                    NameUtils.getSafeName(graph, draggedResource),
+                                    NameUtils.getURIOrSafeNameInternal(graph, targetRoot),
+                                    NameUtils.getURIOrSafeNameInternal(graph, sourceRoot)
+                    });
+                }
+
+                // It is OK to continue for now, even though the target root is not linked to the source root.
+                // The question of whether to link the target root to the source root will asked at drop time.
+                suggestions.add(DropSuggestions.linkToLibrary(graph, targetRoot, sourceRoot));
+            }
+
+            ModelingResources MOD = ModelingResources.getInstance(graph);
+            StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+            Resource configurationComposite = graph.getPossibleObject(dropTarget, MOD.DiagramToComposite);
+            Resource componentTypeFromDiagram = configurationComposite != null ? graph.getPossibleObject(configurationComposite, STR.Defines) : null;
+
+            // Prevent dragging to published components
+            if (componentTypeFromDiagram != null && Layer0Utils.isPublished(graph, componentTypeFromDiagram))
+                return "Cannot create elements into a diagram that belongs to a published user component."; //$NON-NLS-1$
+
+            // Check if dragged object is symbol or component type and determine other
+            Resource componentType;
+            Resource symbol = graph.getPossibleObject(draggedResource, MOD.ComponentTypeToSymbol);
+            if (symbol != null)
+                componentType = draggedResource;
+            else {
+                componentType = graph.getPossibleObject(draggedResource, MOD.SymbolToComponentType);
+                symbol = draggedResource;
+            }
+
+            // Prevent dragging a symbol of component type into its own configuration.
+            if (componentType != null
+                    && configurationComposite != null
+                    && componentTypeFromDiagram != null
+                    && componentType.equals(componentTypeFromDiagram)) {
+                return "Cannot instantiate user component within its own configuration."; //$NON-NLS-1$
+            }
+
+            return symbol;
+        });
+    }
+
+    @Override
+    public void dragExit(DropTargetEvent dte, IDnDContext dp) {
+        // System.out.println("exit");
+    }
+
+    @Override
+    public void dragOver(DropTargetDragEvent dtde, IDnDContext dp) {
+        // System.out.println("over");
+    }
+
+    private IElement tryPick(Point p) {
+        Point2D canvas = transformUtil.controlToCanvas(p, null);
+
+        assertDependencies();
+
+        PickRequest    req                     = new PickRequest(canvas);
+        req.pickPolicy = PickRequest.PickPolicy.PICK_INTERSECTING_OBJECTS;
+        List<IElement>         picks                   = new ArrayList<>();
+        pickContext.pick(diagram, req, picks);
+
+        if(picks.size() == 1) return picks.iterator().next();
+
+        return null;
+    }
+
+    @Override
+    public void drop(DropTargetDropEvent dtde, final IDnDContext dp) {
+        TimeLogger.resetTimeAndLog(getClass(), "drop"); //$NON-NLS-1$
+
+        final Point loc = dtde.getLocation();
+        final IDiagram d = diagram;
+        if (d == null)
+            return;
+
+        try {
+            validateDrop(d, dp, () -> performDrop(d, loc, dp));
+        } catch (DatabaseException e) {
+            LOGGER.error("Element drop validation failed", e); //$NON-NLS-1$
+        } 
+    }
+
+    private void validateDrop(IDiagram diagram, IDnDContext dp, Runnable dropFunction)
+            throws DatabaseException {
+        List<DropSuggestion> reqs = dp.getHints().getHint(KEY_SUGGESTIONS);
+        if (reqs != null && !reqs.isEmpty()) {
+            // Ask user if suggestions should be ran before dropping.
+            // If not, cancel.
+            Shell parentShell = partSite.getWorkbenchWindow().getShell();
+            SWTUtils.asyncExec(parentShell, () -> {
+                if (parentShell.isDisposed())
+                    return;
+                if (!DropSuggestions.askSuggestions(parentShell, reqs))
+                    return;
+
+                try {
+                    Simantics.getSession().syncRequest(DropSuggestions.performSuggestionsRequest(reqs));
+
+                    getThread().asyncExec(() -> {
+                        if (isRemoved())
+                            return;
+                        dropFunction.run();
+                    });
+                } catch (DatabaseException e) {
+                    String format = Messages.PopulateElementDropParticipant_PreDropFixesFailed;
+                    String formattedSuggestions = EString.implode(reqs);
+                    LOGGER.error(format, formattedSuggestions, e);
+                    ShowError.showError(Messages.PopulateElementDropParticipant_PreDropFixesFailed_Title, NLS.bind(format, formattedSuggestions), e);
+                }
+            });
+        } else {
+            dropFunction.run();
+        }
+    }
+
+    private void performDrop(IDiagram d, Point loc, IDnDContext dp) {
+        IElement pick = tryPick(loc);
+        if (pick != null) {
+            List<WorkbenchSelectionElement> wses = Arrays.stream(dp.toArray())
+                    .filter(WSEDragItem.class::isInstance)
+                    .map(di -> ((WSEDragItem) di).getObject())
+                    .collect(Collectors.toList());
+
+            final Resource element = (Resource) ElementUtils.getData(d, pick);
+            if (element != null && !wses.isEmpty()) {
+                try {
+                    Session db = Simantics.getSession();
+                    DiagramResource DIA = DiagramResource.getInstance(db);
+                    Variable function = db.syncRequest(new PossibleVariableProperty(element, DIA.symbolDropHandler));
+                    if (function != null) {
+                        db.syncRequest((Write) graph -> Simantics.invokeSCLWrite(graph, function, wses));
+                        return;
+                    }
+                } catch (DatabaseException e) {
+                    Activator.getDefault().getLog()
+                            .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+                                    "Invocation to custom symbolDropHandler for element " //$NON-NLS-1$
+                                            + element + " failed.", //$NON-NLS-1$
+                                    e));
+                    return;
+                }
+            }
+        }
+
+        Runnable creator = () -> {
+            DiagramUtils.mutateDiagram(d, m -> {
+                IDragItem items[] = dp.toArray();
+
+                for (IDragItem i : items) {
+                    if (!(i instanceof ElementClassDragItem))
+                        continue;
+
+                    ElementClassDragItem res = (ElementClassDragItem) i;
+                    ElementClass ec = res.getElementClass();
+
+                    Point2D pos = dp.getItemPosition(i);
+                    // System.out.println(pos);
+                    assert (pos != null);
+
+                    IElement element = m.newElement(ec);
+                    element.setHints(res.getHintContext().getHints());
+
+                    setupDroppedElement(element, pos);
+
+                    // Remove only the drag items we've processed.
+                    dp.remove(i);
+                }
+            });
+        };
+
+        selectNewDiagramContentAfter(d, partSite, creator);
+
+        getContext().getContentContext().setDirty();
+    }
+
+    private static class PossibleVariableProperty extends ResourceRead2<Variable> {
+
+        public PossibleVariableProperty(Resource entity, Resource property) {
+            super(entity, property);
+        }
+
+        @Override
+        public Variable perform(ReadGraph graph) throws DatabaseException {
+            return Variables.tryGetProperty(graph, resource, resource2);
+        }
+
+    }
+
+    protected void selectNewDiagramContentAfter(IDiagram d, IWorkbenchPartSite activateSite, Runnable diagramModifier) {
+        try {
+            Resource diagramResource = d.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
+            final DiagramContentTracker tracker = diagramResource == null ? null
+                    : DiagramContentTracker.start(getContext(), Simantics.getSession(), diagramResource);
+
+            diagramModifier.run();
+
+            if (tracker != null) {
+                // Get difference of diagram contents to find out what was added.
+                DiagramContentChanges changes = tracker.update();
+                Set<Resource> addedElements = changes.pick(changes.elements, Change.ADDED);
+                if (!addedElements.isEmpty()) {
+                    new DiagramSelectionUpdater(getContext())
+                    .setNewSelection(0, addedElements)
+                    .setOneshot(true)
+                    .track();
+                    if (activateSite != null)
+                        WorkbenchUtils.activatePart(activateSite);
+                }
+            }
+        } catch (DatabaseException e) {
+            Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Diagram content change tracking failed.", e)); //$NON-NLS-1$
+        }
+    }
+
+    protected void setupDroppedElement(IElement element, Point2D dropPos) {
+        // This works only for elements without parents.
+        ISnapAdvisor snapAdvisor = getContext().getHintStack().getHint(DiagramHints.SNAP_ADVISOR);
+        if(snapAdvisor != null)
+            snapAdvisor.snap(dropPos);
+
+        IElement parent = element.getHint(ElementHints.KEY_PARENT_ELEMENT);
+        if (parent != null) {
+            Point2D parentPos = ElementUtils.getPos(parent);
+            Point2D pos = new Point2D.Double(dropPos.getX() - parentPos.getX(), dropPos.getY() - parentPos.getY());
+            ElementUtils.setPos(element, pos);
+        } else {
+            ElementUtils.setPos(element, dropPos);
+        }
+    }
+
+    @Override
+    public void dropActionChanged(DropTargetDragEvent dtde, IDnDContext dp) {
+        dtde.acceptDrag(DnDConstants.ACTION_COPY);
+    }
+
+    @Override
+    public int getAllowedOps() {
+        return DnDConstants.ACTION_COPY;
+    }
+
+    @Override
+    public double getPriority() {
+       return 10.0;
+    }
+
 }
\ No newline at end of file