/***************************************************************************** * Copyright (c) 2009 CEA * * * 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: * Soyatec - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.diagram.sequence.util; import java.util.ArrayList; import java.util.List; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.edit.command.RemoveCommand; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.Request; import org.eclipse.gef.commands.Command; import org.eclipse.gef.requests.DropRequest; import org.eclipse.gef.requests.GroupRequest; import org.eclipse.gef.requests.ReconnectRequest; import org.eclipse.gmf.runtime.common.core.command.ICommand; 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.editpolicies.ComponentEditPolicy; import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; import org.eclipse.gmf.runtime.notation.Bounds; import org.eclipse.gmf.runtime.notation.Shape; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.gmf.runtime.notation.impl.ShapeImpl; import org.eclipse.papyrus.commands.wrappers.EMFtoGEFCommandWrapper; import org.eclipse.papyrus.uml.diagram.common.draw2d.anchors.LifelineAnchor; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.Message4EditPart; import org.eclipse.uml2.uml.InteractionFragment; import org.eclipse.uml2.uml.Lifeline; import org.eclipse.uml2.uml.UMLPackage; public class LifelineMessageCreateHelper { public static class ComponentEditPolicyEx extends ComponentEditPolicy { @Override protected Command createDeleteViewCommand(GroupRequest deleteRequest) { Command command = super.createDeleteViewCommand(deleteRequest); if(command != null && getHost() instanceof LifelineEditPart) command = restoreLifelineOnDelete(command, (LifelineEditPart)getHost()); /* apex added start */ // Jiho - Lifeline 삭제시 coveredBys(InteractionFragment)의 covereds에서 해당 Lifeline삭제 if (command != null && getHost() instanceof LifelineEditPart) { LifelineEditPart lifelineEP = (LifelineEditPart)getHost(); Lifeline lifeline = (Lifeline) lifelineEP.resolveSemanticElement(); List<InteractionFragment> coveredBysToRemove = new ArrayList<InteractionFragment>(lifeline.getCoveredBys()); Command removeCmd = new EMFtoGEFCommandWrapper(RemoveCommand.create(lifelineEP.getEditingDomain(), lifeline, UMLPackage.eINSTANCE.getLifeline_CoveredBy(), coveredBysToRemove)); command = command.chain(removeCmd); } /* apex added end */ return command; } } public static ConnectionAnchor getCreateMessageAnchor(LifelineEditPart part, Request request, Point location) { IFigure fig = part.getPrimaryShape().getFigureLifelineNameContainerFigure(); fig.translateToRelative(location); if(fig.containsPoint(location)) {// move to header return new LifelineAnchor(part.getPrimaryShape().getFigureLifelineNameContainerFigure()); } // move to dash line return getTargetConnectionAnchor(part, request); } static ConnectionAnchor getTargetConnectionAnchor(LifelineEditPart part, Request request) { if (request instanceof ReconnectRequest) { if (((DropRequest) request).getLocation() == null) { return part.getNodeFigure().getTargetConnectionAnchorAt(null); } Point pt = ((DropRequest) request).getLocation().getCopy(); return part.getNodeFigure().getTargetConnectionAnchorAt(pt); } else if (request instanceof DropRequest){ return part.getNodeFigure().getTargetConnectionAnchorAt( ((DropRequest) request).getLocation()); } return part.getNodeFigure().getTargetConnectionAnchorAt(null); } //when a create message is deleted, move its target lifelines up public static Command restoreLifelineOnMessageDelete(Command commands, EditPart editPart){ if(editPart instanceof Message4EditPart) { Message4EditPart part = (Message4EditPart)editPart; if(part.getTarget() instanceof LifelineEditPart && LifelineMessageCreateHelper.getIncomingMessageCreate(part.getTarget()).size() == 1){ LifelineEditPart target = (LifelineEditPart)part.getTarget(); if(target.getModel() instanceof Shape){ Shape view = (ShapeImpl) target.getModel(); if(view.getLayoutConstraint() instanceof Bounds){ Bounds bounds = (Bounds) view.getLayoutConstraint(); ICommand boundsCommand = new SetBoundsCommand( target.getEditingDomain(), DiagramUIMessages.SetLocationCommand_Label_Resize, new EObjectAdapter(view), new Point(bounds.getX(),SequenceUtil.LIFELINE_VERTICAL_OFFSET)); commands = commands.chain(new ICommandProxy(boundsCommand)); int dy = SequenceUtil.LIFELINE_VERTICAL_OFFSET - bounds.getY(); commands = moveCascadeLifeline(target, commands, dy); } } } } return commands; } // when a lifleine is deleted, move its created lifelines up public static Command restoreLifelineOnDelete(Command command, LifelineEditPart part) { List list = part.getSourceConnections(); if(list != null && list.size() > 0) { for(Object l : list) if(l instanceof Message4EditPart) { EditPart target = ((Message4EditPart)l).getTarget(); if(target instanceof LifelineEditPart && getIncomingMessageCreate(target).size() == 1) { LifelineEditPart lp = (LifelineEditPart)target; Rectangle bounds = lp.getPrimaryShape().getBounds(); Point location = new Point(bounds.x, SequenceUtil.LIFELINE_VERTICAL_OFFSET); int dy = location.y - bounds.y; ICommand boundsCommand = new SetBoundsCommand(lp.getEditingDomain(), DiagramUIMessages.SetLocationCommand_Label_Resize, new EObjectAdapter(lp.getNotationView()), location); command = command.chain(new ICommandProxy(boundsCommand)); command = moveCascadeLifeline(lp, command, dy); } } } return command; } public static boolean hasMessageCreate(GraphicalEditPart sourceEditPart, EditPart targetEditPart) { List list = sourceEditPart.getSourceConnections(); for(Object o : list) if(o instanceof Message4EditPart && targetEditPart.equals(((Message4EditPart)o).getTarget())){ return true; } return false; } public static boolean hasIncomingMessageCreate(EditPart target) { return getIncomingMessageCreate(target).size() > 0; } public static List getIncomingMessageCreate(EditPart target) { List create = new ArrayList(); if(target instanceof LifelineEditPart) { List list = ((LifelineEditPart)target).getTargetConnections(); if(list != null && list.size() > 0) { for(Object l : list) if(l instanceof Message4EditPart) { create.add(l); } } } return create; } public static boolean canReconnectMessageCreate(ReconnectRequest request){ Message4EditPart connPart = (Message4EditPart)request.getConnectionEditPart(); if(request.isMovingStartAnchor()){ // reconnect source if( hasMessageCreate( (GraphicalEditPart)request.getTarget(), (GraphicalEditPart)connPart.getTarget())) return false; }else{ // reconnect target if( hasMessageCreate((GraphicalEditPart)connPart.getSource(), request.getTarget())) return false; } return true; } public static Command reconnectMessageCreateTarget(ReconnectRequest request, Command command) { LifelineEditPart oldTarget = (LifelineEditPart)request.getConnectionEditPart().getTarget(); LifelineEditPart source = (LifelineEditPart)request.getConnectionEditPart().getSource(); LifelineEditPart newTarget = (LifelineEditPart)request.getTarget(); // move up the original connection target lifeline, it has only one create message, which will be removed if(getIncomingMessageCreate(oldTarget).size() == 1) { Rectangle bounds = oldTarget.getPrimaryShape().getBounds(); Point location = new Point(bounds.x, SequenceUtil.LIFELINE_VERTICAL_OFFSET); int dy = location.y - bounds.y; ICommand boundsCommand = new SetBoundsCommand(oldTarget.getEditingDomain(), DiagramUIMessages.SetLocationCommand_Label_Resize, new EObjectAdapter(oldTarget.getNotationView()), location); command = command.chain(new ICommandProxy(boundsCommand)); command = moveCascadeLifeline(oldTarget, command, dy); } //move down the new connection target lifeline command = moveLifelineDown(command, newTarget, request.getLocation().getCopy()); return command; } public static Command moveLifelineDown(Command command, LifelineEditPart part, Point sourcePointCopy) { IFigure fig = part.getFigure(); Rectangle bounds = fig.getBounds().getCopy(); fig.translateToAbsolute(bounds); int height = part.getPrimaryShape().getFigureLifelineNameContainerFigure().getBounds().height; Point location = new Point(bounds.x, Math.max(bounds.y, sourcePointCopy.y() - height / 2)); View targetView = part.getNotationView(); if(location.y != bounds.y) { int dy = location.y - bounds.y; fig.translateToRelative(location); fig.translateToParent(location); ICommand boundsCommand = new SetBoundsCommand(part.getEditingDomain(), DiagramUIMessages.SetLocationCommand_Label_Resize, new EObjectAdapter(targetView), location); command = command.chain(new ICommandProxy(boundsCommand)); command = moveCascadeLifeline(part, command, dy); } return command; } // move all lifelines which has incoming create link from part public static Command moveCascadeLifeline(LifelineEditPart part, Command command, int dy) { List list = part.getSourceConnections(); if(list != null && list.size() > 0) { for(Object l : list) if(l instanceof Message4EditPart) { EditPart target = ((Message4EditPart)l).getTarget(); if(target instanceof LifelineEditPart) { LifelineEditPart lp = (LifelineEditPart)target; Rectangle bounds = lp.getFigure().getBounds().getCopy(); View targetView = lp.getNotationView(); Point location = bounds.getLocation().getCopy().translate(0, dy); Command boundsCommand = new ICommandProxy(new SetBoundsCommand(part.getEditingDomain(), DiagramUIMessages.SetLocationCommand_Label_Resize, new EObjectAdapter(targetView), location)); // Take care of the order of commands, to make sure target is always bellow the source. if(dy < 0){ // move up command = command == null? boundsCommand: command.chain(boundsCommand); command = moveCascadeLifeline(lp, command, dy); }else{ // move down command = moveCascadeLifeline(lp, command, dy); command = command == null? boundsCommand: command.chain(boundsCommand); } } } } return command; } public static boolean canMoveLifelineVertical(LifelineEditPart child, Rectangle newBounds) { int halfHeight = child.getPrimaryShape().getFigureLifelineNameContainerFigure().getBounds().height / 2; // check outgoing links List list = child.getSourceConnections(); if(list != null && list.size() > 0) { for(Object l : list) if(l instanceof Message4EditPart && ((Message4EditPart)l).getTarget() instanceof LifelineEditPart) { LifelineEditPart lowPart = (LifelineEditPart)((Message4EditPart)l).getTarget(); Rectangle outBounds = lowPart.getFigure().getBounds(); if(outBounds.y - newBounds.y < halfHeight) return false; } } // check incoming links list = child.getTargetConnections(); if(list != null && list.size() > 0) { for(Object l : list) if(l instanceof Message4EditPart && ((Message4EditPart)l).getSource() instanceof LifelineEditPart) { LifelineEditPart highPart = (LifelineEditPart)((Message4EditPart)l).getSource(); Rectangle inBounds = highPart.getFigure().getBounds(); if(newBounds.y - inBounds.y < halfHeight) return false; if(newBounds.y > inBounds.getBottom().y - halfHeight) return false; } } return true; } }