/***************************************************************************** * Copyright (c) 2009 CEA LIST. * * * 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: * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.clazz.custom.policies; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.eclipse.emf.ecore.EObject; import org.eclipse.gef.EditPart; import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.UnexecutableCommand; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gmf.runtime.common.core.command.CompositeCommand; import org.eclipse.gmf.runtime.diagram.core.commands.DeleteCommand; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IPrimaryEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart; import org.eclipse.gmf.runtime.diagram.ui.requests.DropObjectsRequest; import org.eclipse.gmf.runtime.emf.type.core.IElementType; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.uml.diagram.clazz.custom.helper.AssociationClassHelper; import org.eclipse.papyrus.uml.diagram.clazz.custom.helper.ClassLinkMappingHelper; import org.eclipse.papyrus.uml.diagram.clazz.custom.helper.ContainmentHelper; import org.eclipse.papyrus.uml.diagram.clazz.custom.helper.InstanceSpecificationLinkHelper; import org.eclipse.papyrus.uml.diagram.clazz.custom.helper.MultiAssociationHelper; import org.eclipse.papyrus.uml.diagram.clazz.custom.helper.MultiDependencyHelper; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.AssociationClassEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.AssociationEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.AssociationNodeEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ClassEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ClassEditPartCN; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.DependencyNodeEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.EnumerationLiteralEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.InstanceSpecificationEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.InstanceSpecificationEditPartCN; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.InstanceSpecificationLinkEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.InterfaceRealizationEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ModelEditPartCN; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.ModelEditPartTN; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.NestedClassForClassEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.PackageEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.PackageEditPartCN; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.RedefinableTemplateSignatureEditPart; import org.eclipse.papyrus.uml.diagram.clazz.edit.parts.SubstitutionEditPart; import org.eclipse.papyrus.uml.diagram.clazz.part.UMLVisualIDRegistry; import org.eclipse.papyrus.uml.diagram.clazz.providers.UMLElementTypes; import org.eclipse.papyrus.uml.diagram.common.editpolicies.OldCommonDiagramDragDropEditPolicy; import org.eclipse.uml2.uml.Association; import org.eclipse.uml2.uml.AssociationClass; import org.eclipse.uml2.uml.Dependency; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.InstanceSpecification; import org.eclipse.uml2.uml.PackageableElement; /** * The Class ClassDiagramDragDropEditPolicy. */ public class ClassDiagramDragDropEditPolicy extends OldCommonDiagramDragDropEditPolicy { public static final String CONTAINED_CLASS_DROP_TO_COMPARTMENT = "ContainedClassDropToCompartment"; /** * Instantiates a new class diagram drag drop edit policy. */ public ClassDiagramDragDropEditPolicy() { super(ClassLinkMappingHelper.getInstance()); } /** * {@inheritDoc} */ @Override protected Set<Integer> getDroppableElementVisualId() { Set<Integer> droppableElementsVisualID = new HashSet<Integer>(); droppableElementsVisualID.add(DependencyNodeEditPart.VISUAL_ID); droppableElementsVisualID.add(AssociationEditPart.VISUAL_ID); droppableElementsVisualID.add(AssociationClassEditPart.VISUAL_ID); droppableElementsVisualID.add(AssociationNodeEditPart.VISUAL_ID); droppableElementsVisualID.add(NestedClassForClassEditPart.VISUAL_ID); droppableElementsVisualID.add(ClassEditPartCN.VISUAL_ID); droppableElementsVisualID.add(PackageEditPartCN.VISUAL_ID); droppableElementsVisualID.add(ModelEditPartCN.VISUAL_ID); droppableElementsVisualID.add(ModelEditPartTN.VISUAL_ID); droppableElementsVisualID.add(ClassEditPart.VISUAL_ID); droppableElementsVisualID.add(PackageEditPart.VISUAL_ID); droppableElementsVisualID.add(InstanceSpecificationEditPart.VISUAL_ID); droppableElementsVisualID.add(InstanceSpecificationLinkEditPart.VISUAL_ID); return droppableElementsVisualID; } /** * {@inheritedDoc} */ protected Command getSpecificDropCommand(DropObjectsRequest dropRequest, Element semanticLink, int nodeVISUALID, int linkVISUALID) { //respecify for enumeration because this is also an instancespecification if(nodeVISUALID == EnumerationLiteralEditPart.VISUAL_ID) { return new ICommandProxy(getDefaultDropNodeCommand(nodeVISUALID, dropRequest.getLocation(), semanticLink)); } if(nodeVISUALID == InstanceSpecificationEditPart.VISUAL_ID || linkVISUALID == InstanceSpecificationLinkEditPart.VISUAL_ID) { return dropInstanceSpecification(dropRequest, semanticLink, linkVISUALID); } if(linkVISUALID == SubstitutionEditPart.VISUAL_ID) { return dropAsNormalBinaryLink(dropRequest, semanticLink, linkVISUALID); } if(linkVISUALID == InterfaceRealizationEditPart.VISUAL_ID) { return dropAsNormalBinaryLink(dropRequest, semanticLink, linkVISUALID); } if(linkVISUALID == AssociationEditPart.VISUAL_ID) { return dropAssociation(dropRequest, semanticLink, linkVISUALID); } switch(nodeVISUALID) { case DependencyNodeEditPart.VISUAL_ID: return dropDependency(dropRequest, semanticLink, nodeVISUALID); case AssociationClassEditPart.VISUAL_ID: return dropAssociationClass(dropRequest, semanticLink, nodeVISUALID); case AssociationNodeEditPart.VISUAL_ID: return dropAssociation(dropRequest, semanticLink, nodeVISUALID); case NestedClassForClassEditPart.VISUAL_ID: case ClassEditPartCN.VISUAL_ID: case PackageEditPartCN.VISUAL_ID: case ModelEditPartCN.VISUAL_ID: return dropChildNodeWithContainmentLink(dropRequest, semanticLink, nodeVISUALID); case ModelEditPartTN.VISUAL_ID: case ClassEditPart.VISUAL_ID: case PackageEditPart.VISUAL_ID: return dropTopLevelNodeWithContainmentLink(dropRequest, semanticLink, nodeVISUALID); default: return UnexecutableCommand.INSTANCE; } } /** * drop a instance specification as a link or as a node * * @param dropRequest * the drop request * @param semanticLink * the element * @param linkVISUALID * the visualID * @return the command in charge of the drop */ protected Command dropInstanceSpecification(DropObjectsRequest dropRequest, Element semanticLink, int linkVISUALID) { if(semanticLink instanceof InstanceSpecification) { if(((InstanceSpecification)semanticLink).getClassifiers().size() > 0) { if(((InstanceSpecification)semanticLink).getClassifiers().get(0) instanceof Association) { //DROP AS LINK ArrayList<InstanceSpecification> endTypes = InstanceSpecificationLinkHelper.getEnds(((InstanceSpecification)semanticLink)); if(endTypes.size() > 0) { Element source = endTypes.get(0); Element target = endTypes.get(1); return new ICommandProxy(dropBinaryLink(new CompositeCommand("drop Instance"), source, target, InstanceSpecificationLinkEditPart.VISUAL_ID, dropRequest.getLocation(), semanticLink)); } } } //DROP AS A NODE EObject graphicalParent = ((GraphicalEditPart)getHost()).resolveSemanticElement(); // Restrict the default node creation to the following cases: // . Take the containment relationship into consideration // . Release the constraint when GraphicalParent is a diagram //drop into diagram if(getHost().getModel() instanceof Diagram) { return new ICommandProxy(getDefaultDropNodeCommand(InstanceSpecificationEditPart.VISUAL_ID, dropRequest.getLocation(), semanticLink)); //drop into another editpart } else if((graphicalParent instanceof Element) && ((Element)graphicalParent).getOwnedElements().contains(semanticLink)) { return new ICommandProxy(getDefaultDropNodeCommand(InstanceSpecificationEditPartCN.VISUAL_ID, dropRequest.getLocation(), semanticLink)); } } return UnexecutableCommand.INSTANCE; } /** * {@inheritDoc} */ @Override public int getLinkWithClassVisualID(EObject domainElement) { return UMLVisualIDRegistry.getLinkWithClassVisualID(domainElement); } /** * {@inheritDoc} */ @Override public int getNodeVisualID(View containerView, EObject domainElement) { return UMLVisualIDRegistry.getNodeVisualID(containerView, domainElement); } /** * {@inheritDoc} */ @Override public IElementType getUMLElementType(int elementID) { return UMLElementTypes.getElementType(elementID); } /** * this method has in charge to create command for create an association if the number of * endtype is superior of 2 a multi association is dropped. if the number of endtype this is * binary association that is dropped. * * @param dropRequest * the drop request * @param semanticLink * the semantic link * @param nodeVISUALID * the node visualid * * @return the command */ protected Command dropAssociation(DropObjectsRequest dropRequest, Element semanticLink, int nodeVISUALID) { Collection endtypes = ClassLinkMappingHelper.getInstance().getSource(semanticLink); if(endtypes.size() == 1) { Element source = (Element)endtypes.toArray()[0]; Element target = (Element)endtypes.toArray()[0]; return new ICommandProxy(dropBinaryLink(new CompositeCommand("drop Association"), source, target, 4001, dropRequest.getLocation(), semanticLink)); } if(endtypes.size() == 2) { Element source = (Element)endtypes.toArray()[0]; Element target = (Element)endtypes.toArray()[1]; return new ICommandProxy(dropBinaryLink(new CompositeCommand("drop Association"), source, target, 4001, dropRequest.getLocation(), semanticLink)); } if(endtypes.size() > 2) { MultiAssociationHelper associationHelper = new MultiAssociationHelper(getEditingDomain()); return associationHelper.dropMutliAssociation((Association)semanticLink, getViewer(), getDiagramPreferencesHint(), dropRequest.getLocation(), ((GraphicalEditPart)getHost()).getNotationView()); } return UnexecutableCommand.INSTANCE; } /** * this method send a Command that create views for associationClass * * @param dropRequest * the drop request * @param semanticLink * the semantic link * @param nodeVISUALID * the node visualid * * @return the command */ protected Command dropAssociationClass(DropObjectsRequest dropRequest, Element semanticLink, int nodeVISUALID) { AssociationClassHelper associationClassHelper = new AssociationClassHelper(getEditingDomain()); return associationClassHelper.dropAssociationClass((AssociationClass)semanticLink, getViewer(), getDiagramPreferencesHint(), dropRequest.getLocation(), ((GraphicalEditPart)getHost()).getNotationView()); } /** * this method send a command to create views to display * * @param dropRequest * the drop request * @param semanticLink * the semantic link * @param nodeVISUALID * the node visualid * * @return the command */ protected Command dropDependency(DropObjectsRequest dropRequest, Element semanticLink, int nodeVISUALID) { Collection sources = ClassLinkMappingHelper.getInstance().getSource(semanticLink); Collection targets = ClassLinkMappingHelper.getInstance().getTarget(semanticLink); if(sources.size() == 1 && targets.size() == 1) { Element source = (Element)sources.toArray()[0]; Element target = (Element)targets.toArray()[0]; return new ICommandProxy(dropBinaryLink(new CompositeCommand("drop Association"), source, target, 4008, dropRequest.getLocation(), semanticLink)); } if(sources.size() > 1 || targets.size() > 1) { MultiDependencyHelper dependencyHelper = new MultiDependencyHelper(getEditingDomain()); return dependencyHelper.dropMutliDependency((Dependency)semanticLink, getViewer(), getDiagramPreferencesHint(), dropRequest.getLocation(), ((GraphicalEditPart)getHost()).getNotationView()); } return UnexecutableCommand.INSTANCE; } /** * Use to drop a class from the outline to the diagram * * @param dropRequest * is the request for the drop, never be null * @param semanticObject * is the class dropped * @param nodeVISUALID * is the visual ID of the class * @return a command to execute */ protected Command dropTopLevelNodeWithContainmentLink(DropObjectsRequest dropRequest, Element semanticObject, int nodeVISUALID) { ContainmentHelper containmentHelper = new ContainmentHelper(getEditingDomain()); Element owner = (Element)semanticObject.getOwner(); if( owner==null){ return new ICommandProxy(getDefaultDropNodeCommand(nodeVISUALID, dropRequest.getLocation(), semanticObject)); } EditPart ownerEditPart = containmentHelper.findEditPartFor(getViewer().getEditPartRegistry(), owner); if(ownerEditPart != null) { return containmentHelper.outlineDropContainedClass((PackageableElement)semanticObject, getViewer(), getDiagramPreferencesHint(), dropRequest.getLocation(), ((GraphicalEditPart)getHost()).getNotationView()); } else { return new ICommandProxy(getDefaultDropNodeCommand(nodeVISUALID, dropRequest.getLocation(), semanticObject)); } } /** * Use to drop a class from the diagram to the nestedClassifierCompartment * * @param dropRequest * is the request for the drop, never be null * @param droppedElement * is the class dropped * @param nodeVISUALID * is the visual ID of the class * @return a command to execute */ protected Command dropChildNodeWithContainmentLink(DropObjectsRequest dropRequest, Element droppedElement, int nodeVISUALID) { ContainmentHelper containmentHelper = new ContainmentHelper(getEditingDomain()); CompositeCommand cc = new CompositeCommand(CONTAINED_CLASS_DROP_TO_COMPARTMENT); cc.add(getDefaultDropNodeCommand(nodeVISUALID, dropRequest.getLocation(), droppedElement)); EObject graphicalParent = ((GraphicalEditPart)getHost()).resolveSemanticElement(); if(!((droppedElement instanceof Element) && ((Element)graphicalParent).getOwnedElements().contains(droppedElement))) { return UnexecutableCommand.INSTANCE; } if(containmentHelper.findEditPartFor(getViewer().getEditPartRegistry(), droppedElement) != null) { EditPart editpart=containmentHelper.findEditPartFor(getViewer().getEditPartRegistry(), droppedElement); View droppedView = (View)(editpart.getModel()); containmentHelper.deleteIncomingContainmentLinksFor(cc, droppedView); // Delete the dropped element existing outside the compartment cc.add(new DeleteCommand(getEditingDomain(), droppedView)); } return new ICommandProxy(cc); } /** * call the mechanism to drop a binary link without specific type * * @param dropRequest * the drop request * @param semanticLink * the element that is the interfaceRealization * @param linkVISUALID * the visualID of the interfaceRealization * @return the command containing the creation of the view ffor a link */ protected Command dropAsNormalBinaryLink(DropObjectsRequest dropRequest, Element semanticLink, int linkVISUALID) { Collection<?> sources = linkmappingHelper.getSource(semanticLink); Collection<?> targets = linkmappingHelper.getTarget(semanticLink); if(sources.size() == 0 || targets.size() == 0) { return UnexecutableCommand.INSTANCE; } Element source = (Element)sources.toArray()[0]; Element target = (Element)targets.toArray()[0]; CompositeCommand cc = new CompositeCommand(""); dropBinaryLink(cc, source, target, linkVISUALID, dropRequest.getLocation(), semanticLink); return new ICommandProxy(cc); } /** * * @see org.eclipse.gmf.runtime.diagram.ui.editpolicies.DiagramDragDropEditPolicy#getDropCommand(org.eclipse.gef.requests.ChangeBoundsRequest) * */ protected Command getDropCommand(ChangeBoundsRequest request) { //this is a drop done by user internal to the diagram //prevent from the drop intra diagram of a template signature into the diagram Iterator editPartsIter = request.getEditParts().iterator(); while(editPartsIter.hasNext()) { if(editPartsIter.next() instanceof RedefinableTemplateSignatureEditPart) { return UnexecutableCommand.INSTANCE; } } // in the case of labelEditPart the command add can launch null pointer exception editPartsIter = request.getEditParts().iterator(); boolean containsLabelEditpart=false; while(editPartsIter.hasNext()&& !containsLabelEditpart) { EditPart currentEditPart=(EditPart) editPartsIter.next(); if(currentEditPart instanceof ITextAwareEditPart&& currentEditPart instanceof IPrimaryEditPart) { containsLabelEditpart=true; } } //the addCommand of a label edit part into the diagram raises an null pointer exception. //it is due to the label has not constraint, used during the AddCommand if(containsLabelEditpart&& getHost() instanceof DiagramEditPart){ return UnexecutableCommand.INSTANCE; } else{ //normal case ChangeBoundsRequest req = new ChangeBoundsRequest(REQ_ADD); req.setEditParts(request.getEditParts()); req.setMoveDelta(request.getMoveDelta()); req.setSizeDelta(request.getSizeDelta()); req.setLocation(request.getLocation()); req.setResizeDirection(request.getResizeDirection()); Command cmd = getHost().getCommand(req); if(cmd == null || !cmd.canExecute()) { return getDropObjectsCommand(castToDropObjectsRequest(request)); } return cmd; } } }