package org.eclipse.papyrus.uml.diagram.sequence.apex.edit.policies; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.EditPart; import org.eclipse.gef.RequestConstants; import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.CompoundCommand; import org.eclipse.gef.requests.ChangeBoundsRequest; 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.ConnectionNodeEditPart; 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.ShapeNodeEditPart; import org.eclipse.papyrus.uml.diagram.sequence.apex.interfaces.IApexLifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.apex.util.ApexSequenceDiagramConstants; import org.eclipse.papyrus.uml.diagram.sequence.apex.util.ApexSequenceUtil; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionOperandEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart; import org.eclipse.papyrus.uml.diagram.sequence.edit.policies.InteractionCompartmentXYLayoutEditPolicy; import org.eclipse.papyrus.uml.diagram.sequence.util.OccurrenceSpecificationMoveHelper; import org.eclipse.papyrus.uml.diagram.sequence.util.OperandBoundsComputeHelper; import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceRequestConstant; import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceUtil; import org.eclipse.swt.SWT; import org.eclipse.uml2.uml.ExecutionSpecification; import org.eclipse.uml2.uml.Message; import org.eclipse.uml2.uml.MessageEnd; import org.eclipse.uml2.uml.MessageOccurrenceSpecification; import org.eclipse.uml2.uml.OccurrenceSpecification; public class ApexMessageConnectionLineSegmentEditPolicy { /** * 이동하려는 상단에 ExecutionSpecification이 있는 경우 */ private static boolean flexiblePrev = false; private static final int MARGIN = ApexSequenceDiagramConstants.VERTICAL_MARGIN; private static final int PADDING = ApexSequenceDiagramConstants.EXECUTION_PADDING; /** * * @param request * @param connectionPart * @param moveAlone * @return */ public static Command apexGetMoveConnectionCommand(ChangeBoundsRequest request, ConnectionNodeEditPart connectionPart, boolean moveAlone) { EObject message = connectionPart.resolveSemanticElement(); if(message instanceof Message) { MessageEnd send = ((Message)message).getSendEvent(); MessageEnd rcv = ((Message)message).getReceiveEvent(); EditPart srcPart = connectionPart.getSource(); LifelineEditPart srcLifelinePart = SequenceUtil.getParentLifelinePart(srcPart); EditPart tgtPart = connectionPart.getTarget(); LifelineEditPart tgtLifelinePart = SequenceUtil.getParentLifelinePart(tgtPart); CompoundCommand compoundCmd = new CompoundCommand("Move Message"); if(send instanceof OccurrenceSpecification && rcv instanceof OccurrenceSpecification && srcLifelinePart != null && tgtLifelinePart != null) { Point moveDelta = request.getMoveDelta().getCopy(); int moveDeltaY = moveDelta.y(); Point oldLocation = ApexSequenceUtil.apexGetAbsoluteRectangle(connectionPart).getLocation(); if (oldLocation == null) return null; int y = oldLocation.y() + moveDeltaY; List<EditPart> empty = Collections.emptyList(); int minY = Integer.MIN_VALUE, maxY = Integer.MAX_VALUE; int realMinY = Integer.MIN_VALUE; IGraphicalEditPart realPrevPart = null; // ExecutionSpecificationEditPart 포함하여 가장 하위 List<IGraphicalEditPart> prevParts = ApexSequenceUtil.apexGetPrevSiblingEditParts(connectionPart); List<IGraphicalEditPart> frontLinkedParts = ApexSequenceUtil.apexGetLinkedEditPartList(connectionPart, true, false, true); for (IGraphicalEditPart part : prevParts) { minY = Math.max(minY, ApexSequenceUtil.apexGetAbsolutePosition(part, SWT.BOTTOM) + MARGIN); if (realMinY < minY) { realMinY = minY; } if (part instanceof ConnectionNodeEditPart && !frontLinkedParts.contains(part)) { // activation중 가장 하위 검색. realMinY는 activation 포함 가장 하위 y값 ConnectionNodeEditPart prevConnPart = (ConnectionNodeEditPart)part; EditPart prevSourcePart = prevConnPart.getSource(); EditPart prevTargetPart = prevConnPart.getTarget(); if (prevSourcePart instanceof IGraphicalEditPart ) { EObject eObj = ((IGraphicalEditPart) prevSourcePart).resolveSemanticElement(); if (eObj instanceof ExecutionSpecification && prevSourcePart instanceof ShapeNodeEditPart) { int tMinY = ApexSequenceUtil.apexGetAbsolutePosition((IGraphicalEditPart)prevTargetPart, SWT.BOTTOM) + MARGIN; if (realMinY < tMinY) { realMinY = tMinY; realPrevPart = (IGraphicalEditPart)prevTargetPart; } } } if (prevTargetPart instanceof IGraphicalEditPart ) { EObject eObj = ((IGraphicalEditPart) prevSourcePart).resolveSemanticElement(); if (eObj instanceof ExecutionSpecification && prevTargetPart instanceof ShapeNodeEditPart) { int ty = ApexSequenceUtil.apexGetAbsolutePosition((IGraphicalEditPart)prevTargetPart, SWT.BOTTOM) + MARGIN; if (realMinY < ty) { realMinY = ty; realPrevPart = (IGraphicalEditPart)prevTargetPart; } } } } } if (prevParts.size() == 0) { IFigure dotLine = ((IApexLifelineEditPart)srcLifelinePart).getPrimaryShape().getFigureLifelineDotLineFigure(); Rectangle dotLineBounds = dotLine.getBounds().getCopy(); dotLine.translateToAbsolute(dotLineBounds); minY = dotLineBounds.y() + MARGIN; realMinY = minY; } EObject eObj = realPrevPart.resolveSemanticElement(); if (flexiblePrev && eObj instanceof ExecutionSpecification && realPrevPart instanceof ShapeNodeEditPart) { Dimension minimumSize = realPrevPart.getFigure().getMinimumSize(); int minimumBottom = ApexSequenceUtil.apexGetAbsolutePosition(realPrevPart, SWT.TOP) + minimumSize.height(); minY = Math.max(minY, minimumBottom); } else { minY = realMinY; } List<IGraphicalEditPart> nextParts = ApexSequenceUtil.apexGetNextSiblingEditParts(connectionPart); for (IGraphicalEditPart part : nextParts) { int ty = ApexSequenceUtil.apexGetAbsolutePosition(part, SWT.TOP) - MARGIN; if (maxY > ty) { maxY = ty; } } if (moveAlone) { // Target인 Activation의 Minimumsize 이하로 줄어들 수 없음 if ( tgtPart instanceof IGraphicalEditPart ) { EObject eTgtObj = ((IGraphicalEditPart) tgtPart).resolveSemanticElement(); if (eTgtObj instanceof ExecutionSpecification && tgtPart instanceof ShapeNodeEditPart) { List sourceConnections = ((IGraphicalEditPart)tgtPart).getSourceConnections(); if (sourceConnections == null || sourceConnections.size() == 0) { int minimumHeight = ((IGraphicalEditPart)tgtPart).getFigure().getMinimumSize().height(); int bottom = ApexSequenceUtil.apexGetAbsolutePosition((IGraphicalEditPart)tgtPart, SWT.BOTTOM); maxY = bottom - minimumHeight; } } y = Math.min(maxY, Math.max(minY, y)); moveDeltaY = y - oldLocation.y(); } // source : AbstractExecutionSpecificationEditPart if ( srcPart instanceof IGraphicalEditPart ) { EObject eSrcObj = ((IGraphicalEditPart) srcPart).resolveSemanticElement(); if (eSrcObj instanceof ExecutionSpecification && srcPart instanceof ShapeNodeEditPart) { IGraphicalEditPart srcExecSpecEP = (IGraphicalEditPart)srcPart; Rectangle oldBounds = ApexSequenceUtil.apexGetAbsoluteRectangle(srcExecSpecEP); Rectangle newBounds = oldBounds.getCopy(); if (newBounds.bottom() < y + PADDING) { newBounds.height = y + PADDING - newBounds.y; } compoundCmd.add( apexCreateChangeBoundsCommand(srcExecSpecEP, oldBounds, newBounds, true) ); compoundCmd.add( OccurrenceSpecificationMoveHelper.getMoveMessageOccurrenceSpecificationsCommand( (OccurrenceSpecification)send, y, newBounds, srcPart, srcLifelinePart, empty) ); } else if (srcPart.equals(srcLifelinePart)) { // source : LifelineEditPart IFigure figure = ((IApexLifelineEditPart)srcLifelinePart).getPrimaryShape().getFigureLifelineDotLineFigure(); Rectangle oldBounds = figure.getBounds().getCopy(); figure.translateToAbsolute(oldBounds); Rectangle newBounds = oldBounds.getCopy(); if (newBounds.bottom() < y + MARGIN) { newBounds.height = y + MARGIN - oldBounds.y; } compoundCmd.add( apexCreateChangeBoundsCommand(srcLifelinePart, oldBounds, newBounds, true) ); compoundCmd.add( OccurrenceSpecificationMoveHelper.getMoveMessageOccurrenceSpecificationsCommand( (OccurrenceSpecification)send, y, newBounds, srcPart, srcLifelinePart, empty) ); } } // target : AbstractExecutionSpecificationEditPart if ( tgtPart instanceof IGraphicalEditPart ) { EObject eTgtObj = ((IGraphicalEditPart) tgtPart).resolveSemanticElement(); if (eTgtObj instanceof ExecutionSpecification && tgtPart instanceof ShapeNodeEditPart) { IGraphicalEditPart tgtExecSpecEP = (IGraphicalEditPart)tgtPart; Rectangle oldBounds = ApexSequenceUtil.apexGetAbsoluteRectangle(tgtExecSpecEP); Rectangle newBounds = oldBounds.getCopy(); newBounds.y = y; newBounds.height -= moveDeltaY; compoundCmd.add( apexCreateChangeBoundsCommand(tgtExecSpecEP, oldBounds, newBounds, true) ); } } } else { if (moveDeltaY < 0) { y = Math.min(maxY, Math.max(minY, y)); moveDeltaY = y - oldLocation.y(); } // flexiblePrev인 경우, 상당 ExecutionSpecification의 크기 줄임 EObject eRealPrevObj = realPrevPart.resolveSemanticElement(); if (flexiblePrev && (eRealPrevObj instanceof ExecutionSpecification && realPrevPart instanceof ShapeNodeEditPart) && realMinY > y) { Rectangle oldBounds = ApexSequenceUtil.apexGetAbsoluteRectangle(realPrevPart); Rectangle newBounds = oldBounds.getCopy(); newBounds.height += (y - realMinY); compoundCmd.add( apexCreateChangeBoundsCommand(realPrevPart, oldBounds, newBounds, true) ); } Command sendMessageMoveCmd = null; if ( srcPart instanceof IGraphicalEditPart ) { EObject eSrcPart = ((IGraphicalEditPart) srcPart).resolveSemanticElement(); if (eSrcPart instanceof ExecutionSpecification && srcPart instanceof ShapeNodeEditPart) { IGraphicalEditPart srcExecSpecEP = (IGraphicalEditPart)srcPart; ConnectionNodeEditPart lastConnPart = null; int lastY = Integer.MIN_VALUE; List srcConnParts = srcExecSpecEP.getSourceConnections(); Iterator iter = srcConnParts.iterator(); while (iter.hasNext()) { ConnectionNodeEditPart srcConnPart = (ConnectionNodeEditPart)iter.next(); EObject semanticElement = srcConnPart.resolveSemanticElement(); if (semanticElement instanceof Message) { MessageEnd sendEvent = ((Message)semanticElement).getSendEvent(); Point location = SequenceUtil.findLocationOfMessageOccurrence((GraphicalEditPart) srcExecSpecEP, (MessageOccurrenceSpecification) sendEvent); // Point location = ApexSequenceUtil.apexGetAbsoluteRectangle(srcConnPart).getLocation(); if (lastY < location.y) { lastY = location.y; lastConnPart = srcConnPart; } } } Rectangle oldBounds = ApexSequenceUtil.apexGetAbsoluteRectangle(srcExecSpecEP); Rectangle newBounds = oldBounds.getCopy(); if (connectionPart.equals(lastConnPart)) { newBounds.height = oldBounds.height + moveDeltaY; compoundCmd.add( apexCreateChangeBoundsCommand(srcExecSpecEP, oldBounds, newBounds, true) ); } if (moveDeltaY > 0) { newBounds.height = oldBounds.height + moveDeltaY; } sendMessageMoveCmd = OccurrenceSpecificationMoveHelper.getMoveMessageOccurrenceSpecificationsCommand( (OccurrenceSpecification)send, y, newBounds, srcPart, srcLifelinePart, empty); } } else if (srcPart.equals(srcLifelinePart)) { // source : LifelineEditPart IFigure figure = ((IApexLifelineEditPart)srcLifelinePart).getPrimaryShape().getFigureLifelineDotLineFigure(); Rectangle oldBounds = figure.getBounds().getCopy(); figure.translateToAbsolute(oldBounds); Rectangle newBounds = oldBounds.getCopy(); if (newBounds.bottom() < y + MARGIN) { newBounds.height = y + MARGIN - oldBounds.y; } compoundCmd.add( apexCreateChangeBoundsCommand(srcLifelinePart, oldBounds, newBounds, true) ); compoundCmd.add( OccurrenceSpecificationMoveHelper.getMoveMessageOccurrenceSpecificationsCommand( (OccurrenceSpecification)send, y, newBounds, srcPart, srcLifelinePart, empty) ); } List<IGraphicalEditPart> linkedParts = ApexSequenceUtil.apexGetLinkedEditPartList(connectionPart, false, true, false); for (IGraphicalEditPart linkedPart : linkedParts) { Rectangle oldBounds = ApexSequenceUtil.apexGetAbsoluteRectangle(linkedPart); Rectangle newBounds = oldBounds.getCopy(); newBounds.y += moveDeltaY; compoundCmd.add( apexCreateChangeBoundsCommand(linkedPart, oldBounds, newBounds, false) ); } if (moveDeltaY > 0) { linkedParts = ApexSequenceUtil.apexGetLinkedEditPartList(connectionPart, true, true, false); // containing Operand Resize 처리 - omw ShapeNodeEditPart ioep = ApexSequenceUtil.apexGetEnclosingInteractionOperandEditpart(connectionPart); if ( ioep != null ) { ChangeBoundsRequest cbRequest = new ChangeBoundsRequest(); cbRequest.setSizeDelta(new Dimension(0, moveDeltaY)); cbRequest.setResizeDirection(PositionConstants.SOUTH); compoundCmd.add(OperandBoundsComputeHelper.createIOEPResizeCommand(cbRequest, (InteractionOperandEditPart)ioep)); } nextParts.removeAll(linkedParts); if (nextParts.size() > 0) { IGraphicalEditPart nextSiblingEditPart = nextParts.get(0); if (nextSiblingEditPart instanceof ConnectionNodeEditPart) { Command nextCmd = apexGetMoveConnectionCommand(request, (ConnectionNodeEditPart) nextSiblingEditPart, moveAlone); compoundCmd.add(nextCmd); } else { Command nextCmd = nextSiblingEditPart.getCommand(request); compoundCmd.add(nextCmd); // apexGetResizeOrMoveBelowItemsCommand(request, nextSiblingEditPart); } } } compoundCmd.add(sendMessageMoveCmd); } return compoundCmd.size() > 0 ? compoundCmd : null; } } return null; } /** * Message보다 하위의 item들을 delta만큼 이동 * @param request * @param abstractGraphicalEditPart * @return */ private static Command apexGetResizeOrMoveBelowItemsCommand(ChangeBoundsRequest request, IGraphicalEditPart gep) { CompoundCommand command = new CompoundCommand(); gep.getCommand(request); command.add(InteractionCompartmentXYLayoutEditPolicy.getCombinedFragmentResizeChildrenCommand(request, (GraphicalEditPart)gep)); return command; } /** * bounds를 변경하는 Command를 생성 * @param gep * @param oldRect * @param newRect * @param isPreserveAnchorsPosition true이면 gep만 단독으로 변경하는 Command 생성, false이면 Request에 의해 변경하는 Command 그룹 생성 * @return */ private static Command apexCreateChangeBoundsCommand(IGraphicalEditPart gep, Rectangle oldRect, Rectangle newRect, boolean isPreserveAnchorsPosition) { Command command = null; /* apex improved start */ if (oldRect.getLocation().equals(newRect.getLocation()) && oldRect.height == newRect.height) { return null; } /* apex improved start */ /* apex replaced if (oldRect.x == newRect.x && oldRect.y == newRect.y && oldRect.width == newRect.width && oldRect.height == newRect.height) { return null; } */ if (!isPreserveAnchorsPosition) { TransactionalEditingDomain editingDomain = gep.getEditingDomain(); Rectangle parentRect = gep.getFigure().getParent().getBounds().getCopy(); // newBounds를 parent(Lifeline)을 기준으로 한 상대좌표로 변경 gep.getFigure().translateToRelative(newRect); newRect.translate(-parentRect.x, -parentRect.y); // end command = new ICommandProxy( new SetBoundsCommand(editingDomain, "Apex in ApexMessageLineSegmentEditPolicy", gep, newRect) ); } else { ChangeBoundsRequest request = apexCreateChangeBoundsRequest(oldRect, newRect); command = gep.getCommand(request); } return command; } /** * bounds를 변경하는 ChangeBoundsRequest 생성 * @param oldRect * @param newRect * @return */ private static ChangeBoundsRequest apexCreateChangeBoundsRequest(Rectangle oldRect, Rectangle newRect) { ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE); request.setMoveDelta(new Point(newRect.x - oldRect.x, newRect.y - oldRect.y)); request.setSizeDelta(new Dimension(newRect.width - oldRect.width, newRect.height - oldRect.height)); // execution 이동에 의해 editpart들이 겹치는 현상 방지 request.getExtendedData().put(SequenceRequestConstant.DO_NOT_MOVE_EDIT_PARTS, true); if (oldRect.y == newRect.y) request.setResizeDirection(PositionConstants.SOUTH); else if (oldRect.bottom() == newRect.bottom()) request.setResizeDirection(PositionConstants.NORTH); else request.setResizeDirection(PositionConstants.NORTH_SOUTH); return request; } }