/***************************************************************************** * Copyright (c) 2009 Atos Origin. * * * 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: * Atos Origin - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.activity.edit.policies; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.gef.EditPart; import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.CompoundCommand; 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.common.core.command.ICommand; import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; import org.eclipse.gmf.runtime.diagram.ui.commands.CreateCommand; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.LabelEditPart; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor; import org.eclipse.gmf.runtime.diagram.ui.requests.DropObjectsRequest; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; import org.eclipse.gmf.runtime.emf.type.core.IElementType; import org.eclipse.gmf.runtime.emf.type.core.IHintedType; import org.eclipse.gmf.runtime.notation.Edge; import org.eclipse.gmf.runtime.notation.Node; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ActionLocalPostconditionEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ActionLocalPreconditionEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.CallBehaviorActionEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.CallOperationActionEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ConstraintAsLocalPostcondEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ConstraintAsLocalPrecondEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ControlFlowEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.DurationConstraintAsLocalPostcondEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.DurationConstraintAsLocalPrecondEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.IntervalConstraintAsLocalPostcondEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.IntervalConstraintAsLocalPrecondEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ObjectFlowEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.OpaqueActionEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ReadSelfActionEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.TimeConstraintAsLocalPostcondEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.TimeConstraintAsLocalPrecondEditPart; import org.eclipse.papyrus.uml.diagram.activity.edit.parts.ValueSpecificationActionEditPart; import org.eclipse.papyrus.uml.diagram.activity.helper.ActivityLinkMappingHelper; import org.eclipse.papyrus.uml.diagram.activity.part.UMLVisualIDRegistry; import org.eclipse.papyrus.uml.diagram.activity.providers.UMLElementTypes; import org.eclipse.papyrus.uml.diagram.common.commands.CommonDeferredCreateConnectionViewCommand; import org.eclipse.papyrus.uml.diagram.common.commands.SemanticAdapter; import org.eclipse.papyrus.uml.diagram.common.editpolicies.CommonDiagramDragDropEditPolicy; import org.eclipse.papyrus.uml.diagram.common.util.DiagramEditPartsUtil; import org.eclipse.uml2.uml.Action; import org.eclipse.uml2.uml.Activity; import org.eclipse.uml2.uml.ActivityEdge; import org.eclipse.uml2.uml.ActivityNode; import org.eclipse.uml2.uml.Behavior; import org.eclipse.uml2.uml.Constraint; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.ObjectFlow; import org.eclipse.uml2.uml.StructuredActivityNode; /** * This class is used to execute the drag and drop from the outline. It can * manage the drop of nodes and binary links. To manage specific drop the method * CommonDiagramDragDropEditPolicy.getSpecificDropCommand has to be implemented */ public class CustomDiagramDragDropEditPolicy extends CommonDiagramDragDropEditPolicy { /** DropActionLocalConditionsAfterActionCommand label */ private static final String LABEL = "DropLocalConditions"; /** Point to translate successive local conditions to avoid overlapping */ private static final Point LOCAL_CONDITIONS_TRANSLATION_POINT = new Point(160, 0); /** * Instantiates a new custom diagram drag drop edit policy with the right * link mapping helper */ public CustomDiagramDragDropEditPolicy() { super(ActivityLinkMappingHelper.getInstance()); } /** * {@inheritDoc} */ @Override protected Set<Integer> getDroppableElementVisualId() { Set<Integer> droppableElementsVisualID = new HashSet<Integer>(); droppableElementsVisualID.add(OpaqueActionEditPart.VISUAL_ID); droppableElementsVisualID.add(CallBehaviorActionEditPart.VISUAL_ID); droppableElementsVisualID.add(CallOperationActionEditPart.VISUAL_ID); droppableElementsVisualID.add(TimeConstraintAsLocalPrecondEditPart.VISUAL_ID); droppableElementsVisualID.add(TimeConstraintAsLocalPostcondEditPart.VISUAL_ID); droppableElementsVisualID.add(DurationConstraintAsLocalPrecondEditPart.VISUAL_ID); droppableElementsVisualID.add(DurationConstraintAsLocalPostcondEditPart.VISUAL_ID); droppableElementsVisualID.add(IntervalConstraintAsLocalPrecondEditPart.VISUAL_ID); droppableElementsVisualID.add(IntervalConstraintAsLocalPostcondEditPart.VISUAL_ID); droppableElementsVisualID.add(ConstraintAsLocalPrecondEditPart.VISUAL_ID); droppableElementsVisualID.add(ConstraintAsLocalPostcondEditPart.VISUAL_ID); droppableElementsVisualID.add(ObjectFlowEditPart.VISUAL_ID); droppableElementsVisualID.add(ControlFlowEditPart.VISUAL_ID); droppableElementsVisualID.add(ValueSpecificationActionEditPart.VISUAL_ID); droppableElementsVisualID.add(ReadSelfActionEditPart.VISUAL_ID); return droppableElementsVisualID; } /** * {@inheritDoc} */ @Override public IElementType getUMLElementType(int elementID) { return UMLElementTypes.getElementType(elementID); } /** * {@inheritDoc} */ @Override public int getNodeVisualID(View containerView, EObject domainElement) { return UMLVisualIDRegistry.getNodeVisualID(containerView, domainElement); } /** * {@inheritDoc} */ @Override public int getLinkWithClassVisualID(EObject domainElement) { return UMLVisualIDRegistry.getLinkWithClassVisualID(domainElement); } /** * {@inheritDoc} */ @Override protected Command getSpecificDropCommand(DropObjectsRequest dropRequest, Element semanticElement, int nodeVISUALID, int linkVISUALID) { switch(nodeVISUALID) { case OpaqueActionEditPart.VISUAL_ID: case CallBehaviorActionEditPart.VISUAL_ID: case CallOperationActionEditPart.VISUAL_ID: case ValueSpecificationActionEditPart.VISUAL_ID: case ReadSelfActionEditPart.VISUAL_ID: return dropAction(dropRequest, semanticElement, nodeVISUALID); case TimeConstraintAsLocalPrecondEditPart.VISUAL_ID: case TimeConstraintAsLocalPostcondEditPart.VISUAL_ID: case DurationConstraintAsLocalPrecondEditPart.VISUAL_ID: case DurationConstraintAsLocalPostcondEditPart.VISUAL_ID: case IntervalConstraintAsLocalPrecondEditPart.VISUAL_ID: case IntervalConstraintAsLocalPostcondEditPart.VISUAL_ID: case ConstraintAsLocalPrecondEditPart.VISUAL_ID: case ConstraintAsLocalPostcondEditPart.VISUAL_ID: return dropActionLocalCondition(dropRequest, semanticElement, nodeVISUALID); } switch(linkVISUALID) { case ObjectFlowEditPart.VISUAL_ID: case ControlFlowEditPart.VISUAL_ID: return dropActivityEdge(dropRequest, semanticElement, linkVISUALID); } return super.getSpecificDropCommand(dropRequest, semanticElement, nodeVISUALID, linkVISUALID); } /** * Specific drop action for an action (with its local conditions) * * @param dropRequest * the drop request * @param semanticElement * the semantic link * @param nodeVISUALID * the node visual id * * @return the command for action */ protected Command dropAction(final DropObjectsRequest dropRequest, final Element semanticElement, int nodeVISUALID) { // The element to drop is a node /* * Check if the element is contained in this new container. * A special case as to be handle for structured element as contained node are not contained by the reference OwnedElement */ // Retrieve it's expected graphical parent EObject graphicalParent = ((GraphicalEditPart)getHost()).resolveSemanticElement(); if(graphicalParent instanceof StructuredActivityNode) { if(!((StructuredActivityNode)graphicalParent).getNodes().contains(semanticElement)) { return UnexecutableCommand.INSTANCE; } } else if(graphicalParent instanceof Element) { if(!((Element)graphicalParent).getOwnedElements().contains(semanticElement)) { return UnexecutableCommand.INSTANCE; } } CompoundCommand globalCmd = new CompoundCommand(); if(globalCmd.isEmpty()) { ICommand cmd = getDefaultDropNodeCommand(nodeVISUALID, dropRequest.getLocation(), semanticElement); globalCmd.add(new ICommandProxy(cmd)); } // also drop local conditions DropActionLocalConditionsAfterActionCommand cmd = new DropActionLocalConditionsAfterActionCommand(dropRequest, semanticElement); globalCmd.add(cmd); return globalCmd; } /** * Specific drop action for an action's local condition * * @param dropRequest * the drop request * @param semanticElement * the semantic link * @param nodeVISUALID * the node visual id * * @return the command for local condition */ protected Command dropActionLocalCondition(DropObjectsRequest dropRequest, Element semanticElement, int nodeVISUALID) { if(getHost() instanceof GraphicalEditPart) { // Adapt the location Point location = dropRequest.getLocation().getCopy(); ((GraphicalEditPart)getHost()).getContentPane().translateToRelative(location); ((GraphicalEditPart)getHost()).getContentPane().translateFromParent(location); location.translate(((GraphicalEditPart)getHost()).getContentPane().getClientArea().getLocation().getNegated()); location.y += 100; // Retrieve expected graphical parent EObject graphicalParent = ((GraphicalEditPart)getHost()).resolveSemanticElement(); // verification of container differs from usually, condition is // graphically contained by the activity if(graphicalParent instanceof Activity) { // drop the constraint and its link to the action Element linkSource = semanticElement.getOwner(); Element linkTarget = semanticElement; // check for existing link part for(Object targetView : DiagramEditPartsUtil.getEObjectViews(linkTarget)) { if(targetView instanceof View) { EditPart targetEditpart = DiagramEditPartsUtil.getEditPartFromView((View)targetView, getHost()); if(targetEditpart instanceof ActionLocalPreconditionEditPart || targetEditpart instanceof ActionLocalPostconditionEditPart) { // condition link is already drawn. return UnexecutableCommand.INSTANCE; } } } if(TimeConstraintAsLocalPrecondEditPart.VISUAL_ID == nodeVISUALID || DurationConstraintAsLocalPrecondEditPart.VISUAL_ID == nodeVISUALID || IntervalConstraintAsLocalPrecondEditPart.VISUAL_ID == nodeVISUALID || ConstraintAsLocalPrecondEditPart.VISUAL_ID == nodeVISUALID) { return new ICommandProxy(dropBinaryLink(new CompositeCommand("drop Local Precondition link"), linkSource, linkTarget, ActionLocalPreconditionEditPart.VISUAL_ID, location, semanticElement)); } else if(TimeConstraintAsLocalPostcondEditPart.VISUAL_ID == nodeVISUALID || DurationConstraintAsLocalPostcondEditPart.VISUAL_ID == nodeVISUALID || IntervalConstraintAsLocalPostcondEditPart.VISUAL_ID == nodeVISUALID || ConstraintAsLocalPostcondEditPart.VISUAL_ID == nodeVISUALID) { return new ICommandProxy(dropBinaryLink(new CompositeCommand("drop Local Postcondition link"), linkSource, linkTarget, ActionLocalPostconditionEditPart.VISUAL_ID, location, semanticElement)); } } } return UnexecutableCommand.INSTANCE; } /** * the method provides command to create the binary link into the diagram. * If the source and the target views do not exist, these views will be * created. * * @param cc * the composite command that will contain the set of command to * create the binary link * @param source * the source the element source of the link * @param target * the target the element target of the link * @param linkVISUALID * the link VISUALID used to create the view * @param location * the location the location where the view will be be created * @param semanticLink * the semantic link that will be attached to the view * * @return the composite command */ public CompositeCommand dropObjectFlowSpecification(CompositeCommand cc, ObjectFlow source, Behavior target, int linkVISUALID, int specificationVISUALID, Point location, Element semanticLink) { // look for editpart ObjectFlowEditPart sourceEditPart = lookForEdgePart(source); // look for editpart linked with the object flow GraphicalEditPart targetEditPart = null; if(sourceEditPart != null) { // TODO check that there is not already a representation linked to // the source object flow } // descriptor of the link CreateConnectionViewRequest.ConnectionViewDescriptor linkdescriptor = new CreateConnectionViewRequest.ConnectionViewDescriptor(getUMLElementType(linkVISUALID), ((IHintedType)getUMLElementType(linkVISUALID)).getSemanticHint(), getDiagramPreferencesHint()); IAdaptable sourceAdapter = null; IAdaptable targetAdapter = null; if(sourceEditPart == null) { // creation of the node ViewDescriptor descriptor = new ViewDescriptor(new EObjectAdapter(source), Edge.class, null, ViewUtil.APPEND, false, ((IGraphicalEditPart)getHost()).getDiagramPreferencesHint()); // get the command and execute it. CreateCommand nodeCreationCommand = new CreateCommand(((IGraphicalEditPart)getHost()).getEditingDomain(), descriptor, ((View)getHost().getModel())); cc.compose(nodeCreationCommand); SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(), new Point(location.x, location.y + 100)); cc.compose(setBoundsCommand); sourceAdapter = (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(); } else { sourceAdapter = new SemanticAdapter(null, sourceEditPart.getModel()); } if(targetEditPart == null) { // creation of the node String nodeSemanticHint = ((IHintedType)getUMLElementType(specificationVISUALID)).getSemanticHint(); ViewDescriptor descriptor = new ViewDescriptor(new EObjectAdapter(target), Node.class, nodeSemanticHint, ViewUtil.APPEND, false, ((IGraphicalEditPart)getHost()).getDiagramPreferencesHint()); // get the command and execute it. CreateCommand nodeCreationCommand = new CreateCommand(((IGraphicalEditPart)getHost()).getEditingDomain(), descriptor, ((View)getHost().getModel())); cc.compose(nodeCreationCommand); SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(), new Point(location.x, location.y - 100)); cc.compose(setBoundsCommand); targetAdapter = (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(); } else { targetAdapter = new SemanticAdapter(null, targetEditPart.getModel()); } CommonDeferredCreateConnectionViewCommand aLinkCommand = new CommonDeferredCreateConnectionViewCommand(getEditingDomain(), ((IHintedType)getUMLElementType(linkVISUALID)).getSemanticHint(), sourceAdapter, targetAdapter, getViewer(), getDiagramPreferencesHint(), linkdescriptor, null); aLinkCommand.setElement(semanticLink); cc.compose(aLinkCommand); return cc; } /** * Look for editPart from its semantic. * * @param semantic * the semantic * * @return the edits the part or null if not found */ private ObjectFlowEditPart lookForEdgePart(EObject semantic) { Collection<EditPart> editPartSet = getHost().getViewer().getEditPartRegistry().values(); Iterator<EditPart> editPartIterator = editPartSet.iterator(); ObjectFlowEditPart existedEditPart = null; while(editPartIterator.hasNext() && existedEditPart == null) { EditPart currentEditPart = editPartIterator.next(); if(currentEditPart instanceof ObjectFlowEditPart && semantic.equals(((ObjectFlowEditPart)currentEditPart).resolveSemanticElement())) { existedEditPart = (ObjectFlowEditPart)currentEditPart; } } return existedEditPart; } /** * Specific drop action for an activity edge * * @param dropRequest * the drop request * @param semanticLink * the semantic link * @param linkVISUALID * the link visual id * * @return the command for association */ protected Command dropActivityEdge(DropObjectsRequest dropRequest, Element semanticLink, int linkVISUALID) { Collection<?> sources = ActivityLinkMappingHelper.getInstance().getSource(semanticLink); Collection<?> targets = ActivityLinkMappingHelper.getInstance().getTarget(semanticLink); if(sources.size() == 1 && targets.size() == 1) { ActivityNode source = (ActivityNode)sources.toArray()[0]; ActivityNode target = (ActivityNode)targets.toArray()[0]; CompositeCommand dropBinaryLink = dropBinaryLink(new CompositeCommand("drop Activity Edge"), source, target, linkVISUALID, dropRequest.getLocation(), semanticLink); // If the activity edge is interruptible edge we forbib to drag it outside the interuptible edge if(dropBinaryLink != null && semanticLink instanceof ActivityEdge && ((ActivityEdge)semanticLink).getInterrupts() != null) { if(!((ActivityEdge)semanticLink).getInterrupts().equals(((IGraphicalEditPart)getHost()).resolveSemanticElement())) { return UnexecutableCommand.INSTANCE; } else { return new ICommandProxy(getInterruptbleEdgeCommand(new CompositeCommand("drop Interruptible Activity Edge"), source, target, linkVISUALID, dropRequest.getLocation(), semanticLink));////$NON-NLS-0$ } } return new ICommandProxy(dropBinaryLink); } else { return UnexecutableCommand.INSTANCE; } } /** * Get the command to drag and drop an interruptible Edge * Set the source inside the Interruptible Edge and set the target outside the interruptible edge * * @param dropBinaryLink * {@link CompositeCommand} to compose the newly created command * @param semanticLink * @param point * @param linkVISUALID * @param target * @param source */ protected CompositeCommand getInterruptbleEdgeCommand(CompositeCommand cc, Element source, Element target, int linkVISUALID, Point location, Element semanticLink) { // look for editpart GraphicalEditPart sourceEditPart = (GraphicalEditPart)lookForEditPart(source); GraphicalEditPart targetEditPart = (GraphicalEditPart)lookForEditPart(target); // descriptor of the link CreateConnectionViewRequest.ConnectionViewDescriptor linkdescriptor = new CreateConnectionViewRequest.ConnectionViewDescriptor(getUMLElementType(linkVISUALID), ((IHintedType)getUMLElementType(linkVISUALID)).getSemanticHint(), getDiagramPreferencesHint()); IAdaptable sourceAdapter = null; IAdaptable targetAdapter = null; if(sourceEditPart == null) { // creation of the node ViewDescriptor descriptor = new ViewDescriptor(new EObjectAdapter(source), Node.class, null, ViewUtil.APPEND, false, ((IGraphicalEditPart)getHost()).getDiagramPreferencesHint()); // get the command and execute it. CreateCommand nodeCreationCommand = new CreateCommand(((IGraphicalEditPart)getHost()).getEditingDomain(), descriptor, ((View)getHost().getModel())); cc.compose(nodeCreationCommand); SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(), new Point(location.x, location.y)); //$NON-NLS-1$ cc.compose(setBoundsCommand); sourceAdapter = (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(); } else { sourceAdapter = new SemanticAdapter(null, sourceEditPart.getModel()); } if(targetEditPart == null) { // creation of the node ViewDescriptor descriptor = new ViewDescriptor(new EObjectAdapter(target), Node.class, null, ViewUtil.APPEND, false, ((IGraphicalEditPart)getHost()).getDiagramPreferencesHint()); // get the command and execute it. CreateCommand nodeCreationCommand = new CreateCommand(((IGraphicalEditPart)getHost()).getEditingDomain(), descriptor, ((View)((View)((IGraphicalEditPart)getHost()).getTopGraphicEditPart().getModel()).eContainer())); cc.compose(nodeCreationCommand); IFigure interruptibleActivityRegionFigure = ((IGraphicalEditPart)getHost()).getFigure(); interruptibleActivityRegionFigure.getBounds(); Point targetPoint = location.getCopy(); targetPoint.setX(targetPoint.x() + 50); interruptibleActivityRegionFigure.translateToAbsolute(targetPoint); while(interruptibleActivityRegionFigure.containsPoint(targetPoint)) { targetPoint.setX(targetPoint.x() + 50); } SetBoundsCommand setBoundsCommand = new SetBoundsCommand(getEditingDomain(), "move", (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(), targetPoint); //$NON-NLS-1$ cc.compose(setBoundsCommand); targetAdapter = (IAdaptable)nodeCreationCommand.getCommandResult().getReturnValue(); } else { targetAdapter = new SemanticAdapter(null, targetEditPart.getModel()); } CommonDeferredCreateConnectionViewCommand aLinkCommand = new CommonDeferredCreateConnectionViewCommand(getEditingDomain(), ((IHintedType)getUMLElementType(linkVISUALID)).getSemanticHint(), sourceAdapter, targetAdapter, getViewer(), getDiagramPreferencesHint(), linkdescriptor, null); aLinkCommand.setElement(semanticLink); cc.compose(aLinkCommand); return cc; } /** * Avoid selection of label edit parts * * @see org.eclipse.papyrus.uml.diagram.common.editpolicies.OldCommonDiagramDragDropEditPolicy#isEditPartTypeSuitableForEClass(java.lang.Class, * org.eclipse.emf.ecore.EClass) */ @Override protected boolean isEditPartTypeSuitableForEClass(Class<? extends GraphicalEditPart> editPartClass, EClass eClass) { // avoid selecting a label instead of the activity node return !LabelEditPart.class.isAssignableFrom(editPartClass); } /** * This action enables to drop an action's local conditions when an action * is dropped. Check of the existing action view is run at execution time to * avoid duplication of the action's view. This action is an intern class * since it is narrowly linked with this edit policy properties and * operations */ private class DropActionLocalConditionsAfterActionCommand extends Command { /** The drop request */ private DropObjectsRequest request; /** The dropped action */ private Element droppedAction; /** The command which have been executed (known at execution time) */ private List<Command> executedCommands = new LinkedList<Command>(); /** * Constructor. * * @param dropRequest * the initial request to drop elements * @param action * the dropped action (whose local conditions must follow) */ public DropActionLocalConditionsAfterActionCommand(DropObjectsRequest dropRequest, Element action) { super(LABEL); request = dropRequest; droppedAction = action; } /** * This command can always execute, though it may have no effect * * @see org.eclipse.gef.commands.Command#canExecute() * @return true */ @Override public boolean canExecute() { return true; } /** * Execute the command and drop each local condition view * * @see org.eclipse.gef.commands.Command#execute() */ @Override public void execute() { // update request to unset the position, so that position is // automatically recomputed each time (to avoid superposition). Object hostView = getHost().getModel(); if(hostView instanceof View) { if(droppedAction instanceof Action) { Point initialLocation = request.getLocation().getCopy(); for(Constraint pre : ((Action)droppedAction).getLocalPreconditions()) { int visual = UMLVisualIDRegistry.getNodeVisualID((View)hostView, pre); Command localCmd = dropActionLocalCondition(request, pre, visual); if(localCmd != null && localCmd.canExecute()) { localCmd.execute(); executedCommands.add(localCmd); // update the request's position to avoid conditions // superposition request.getLocation().translate(LOCAL_CONDITIONS_TRANSLATION_POINT); } } for(Constraint post : ((Action)droppedAction).getLocalPostconditions()) { int visual = UMLVisualIDRegistry.getNodeVisualID((View)hostView, post); Command localCmd = dropActionLocalCondition(request, post, visual); if(localCmd != null && localCmd.canExecute()) { localCmd.execute(); executedCommands.add(localCmd); // update the request's position to avoid conditions // superposition request.getLocation().translate(LOCAL_CONDITIONS_TRANSLATION_POINT); } } // restore initial location request.getLocation().setLocation(initialLocation); } } } /** * Undo executed commands * * @see org.eclipse.gef.commands.Command#undo() */ @Override public void undo() { // undo commands in the inverse order for(int i = executedCommands.size() - 1; i >= 0; i--) { Command cmd = executedCommands.get(i); cmd.undo(); } executedCommands.clear(); } } @Override protected Command getDropCommand(ChangeBoundsRequest request) { return super.getDropCommand(request); } }