X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.modeling.ui%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fui%2FdiagramEditor%2FPopulateElementDropParticipant.java;h=49adcb65b48155ebe6f2082975551f030c1fba1c;hp=bbac2a08a025ce3cc65a8e6b37330fbcba299fa0;hb=8ded56d0a440f78cbf649b1e59b8a464e8650fdc;hpb=969bd23cab98a79ca9101af33334000879fb60c5 diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/PopulateElementDropParticipant.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/PopulateElementDropParticipant.java index bbac2a08a..49adcb65b 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/PopulateElementDropParticipant.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/PopulateElementDropParticipant.java @@ -1,436 +1,484 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 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 - *******************************************************************************/ -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.List; -import java.util.Set; - -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.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.WriteGraph; -import org.simantics.db.common.request.PossibleIndexRoot; -import org.simantics.db.common.request.ResourceRead2; -import org.simantics.db.common.request.UniqueRead; -import org.simantics.db.common.request.WriteRequest; -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.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.symbollibrary.ISymbolItem; -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.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.logging.TimeLogger; -import org.simantics.utils.ui.workbench.WorkbenchUtils; - -/** - * This participant populates Elements from ElementClass-resources drops - */ -public class PopulateElementDropParticipant extends AbstractDiagramParticipant implements IDropTargetParticipant { - - @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)) { - // System.out.println("joo"); - 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 e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - // 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) { - if (elm instanceof ISymbolItem) { - /* FIXME fix this check - ISymbolItem symbol = (ISymbolItem) elm; - Resource dia = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE); - try { - if (!DiagramTypeUtils.symbolAllowedOnDiagram(synchronizer.getSession(), symbol, dia)) { - // Deny dragging of this symbol - continue; - } - } catch (DatabaseException e) { - e.printStackTrace(); - continue; - }*/ - } - - try { - String valid = validateDrop(synchronizer.getSession(), r, - diagram. getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE)); - if (valid == null) { - ElementClassDragItem item = new ElementClassDragItem(synchronizer.getNodeClass(r)); - item.getHintContext().setHint(ElementHints.KEY_TRANSFORM, AffineTransform.getScaleInstance(1, 1)); - dp.add(item); - } - } catch (DatabaseException e) { - // Ignore node-class retrieval failures. - //System.out.println("error: " + e.getMessage()); - } - } - } - } - } - - // 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 String validateDrop(RequestProcessor processor, final Resource draggedResource, final Resource dropTarget) throws DatabaseException { - return processor.syncRequest(new UniqueRead() { - @Override - public String perform(ReadGraph graph) throws DatabaseException { -// System.out.println("dragged resource: " + draggedResource); -// System.out.println("drop target resource: " + dropTarget); - Resource sourceModel = graph.syncRequest(new PossibleIndexRoot(draggedResource)); - Resource targetModel = graph.syncRequest(new PossibleIndexRoot(dropTarget)); -// System.out.println("source model: " + sourceModel); -// System.out.println("target model: " + targetModel); - - // Prevent dragging data from one source model to another. - // If source is not part of any model, everything is okay. - if (sourceModel != null && !graph.syncRequest(new IsLinkedTo(targetModel, sourceModel))) { - // Prevent a symbol instantiating within its own configuration. - // NOTE: this doesn't handle transitive cycles. - return "Cannot instantiate " + NameUtils.getSafeName(graph, draggedResource) + " into model " - + NameUtils.getURIOrSafeNameInternal(graph, targetModel) + ". The source namespace (" - + NameUtils.getURIOrSafeNameInternal(graph, sourceModel) + ") is not linked to the target model."; - } - - // Prevent dragging to published components - ModelingResources MOD = ModelingResources.getInstance(graph); - StructuralResource2 STR = StructuralResource2.getInstance(graph); - Resource configuration = graph.getPossibleObject(dropTarget, MOD.DiagramToComposite); - if (configuration != null) { - Resource componentTypeFromDiagram = graph.getPossibleObject(configuration, STR.Defines); - if(componentTypeFromDiagram != null) { - if(Layer0Utils.isPublished(graph, componentTypeFromDiagram)) - return "Cannot create elements into a diagram that belongs to a published user component."; - } - } - - // Prevent dragging a symbol of component type into its own configuration. - Resource componentTypeFromSymbol = graph.getPossibleObject(draggedResource, MOD.SymbolToComponentType); - if (componentTypeFromSymbol != null) { - if (configuration != null) { - Resource componentTypeFromDiagram = graph.getPossibleObject(configuration, STR.Defines); - if (componentTypeFromDiagram != null && componentTypeFromSymbol.equals(componentTypeFromDiagram)) { - return "Cannot instantiate user component within its own configuration."; - } - } - } - - return null; - } - }); - } - - @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 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"); - - final IDiagram d = getHint(DiagramHints.KEY_DIAGRAM); - if (d == null) - return; - - IElement pick = tryPick(dtde.getLocation()); - if(pick != null) { - - final List wses = new ArrayList(); - - for(IDragItem i : dp.toArray()) - if(i instanceof WSEDragItem) - wses.add(((WSEDragItem)i).getObject()); - - 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(new WriteRequest() { - @Override - public void perform(WriteGraph graph) throws DatabaseException { - 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 " - + element + " failed.", - e)); - return; - } - - } - - - } - - Runnable creator = new Runnable() { - public void run() { - 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 { - - 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 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)); - } - } - - 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; - } - +/******************************************************************************* + * 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. 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) graph -> { + List 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 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 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 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 { + + 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 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