/*****************************************************************************
* 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.sequence.edit.policies;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.ConnectionAnchor;
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.PrecisionPoint;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.commands.UnexecutableCommand;
import org.eclipse.gef.requests.AlignmentRequest;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.requests.CreateRequest;
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.editparts.ConnectionEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.figures.IBorderItemLocator;
import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.type.core.IHintedType;
import org.eclipse.gmf.runtime.emf.type.core.commands.SetValueCommand;
import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.IdentityAnchor;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.uml.diagram.common.commands.PreserveAnchorsPositionCommand;
import org.eclipse.papyrus.uml.diagram.common.service.AspectUnspecifiedTypeCreationTool.CreateAspectUnspecifiedTypeRequest;
import org.eclipse.papyrus.uml.diagram.sequence.apex.util.ApexSequenceRequestConstants;
import org.eclipse.papyrus.uml.diagram.sequence.apex.util.ApexSequenceUtil;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.ActionExecutionSpecificationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.BehaviorExecutionSpecificationEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CombinedFragmentCombinedFragmentCompartmentEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.CombinedFragmentEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.DurationConstraintEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionInteractionCompartmentEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionOperandEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.InteractionUseEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.LifelineEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.edit.parts.MessageEditPart;
import org.eclipse.papyrus.uml.diagram.sequence.providers.UMLElementTypes;
import org.eclipse.papyrus.uml.diagram.sequence.util.HighlightUtil;
import org.eclipse.papyrus.uml.diagram.sequence.util.LifelineResizeHelper;
import org.eclipse.papyrus.uml.diagram.sequence.util.OperandBoundsComputeHelper;
import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceUtil;
import org.eclipse.swt.SWT;
import org.eclipse.uml2.uml.CombinedFragment;
import org.eclipse.uml2.uml.ExecutionSpecification;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.InteractionOperand;
import org.eclipse.uml2.uml.Lifeline;
/**
* The customn XYLayoutEditPolicy for InteractionCompartmentEditPart.
*/
public class InteractionCompartmentXYLayoutEditPolicy extends XYLayoutEditPolicy {
protected Command getCreateCommand(CreateRequest request) {
CreateViewRequest req = (CreateViewRequest) request;
Command cmd = super.getCreateCommand(request);
if(cmd != null && req.getSize() != null){ // create lifeline with specific size
TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain();
Iterator iter = req.getViewDescriptors().iterator();
while (iter.hasNext()) {
CreateViewRequest.ViewDescriptor viewDescriptor = (CreateViewRequest.ViewDescriptor)iter.next();
if (((IHintedType) UMLElementTypes.Lifeline_3001).getSemanticHint().equals(viewDescriptor.getSemanticHint())) {
cmd = (new ICommandProxy(LifelineResizeHelper.createManualLabelSizeCommand(editingDomain, viewDescriptor))).chain(cmd);
}
}
}
return cmd;
}
/**
* apex updated
*
*
*
* Handle lifeline and combined fragment resize
*/
@Override
protected Command getResizeChildrenCommand(ChangeBoundsRequest request) {
CompoundCommand compoundCmd = new CompoundCommand();
compoundCmd.setLabel(ApexSequenceRequestConstants.APEX_COMMAND_LABLE_MOVE_OR_RESIZE);
IFigure figure = getHostFigure();
Rectangle hostBounds = figure.getBounds();
for(Object o : request.getEditParts()) {
org.eclipse.gef.GraphicalEditPart child = (org.eclipse.gef.GraphicalEditPart)o;
Object constraintFor = getConstraintFor(request, child);
if (constraintFor instanceof Rectangle) {
Rectangle childBounds = (Rectangle) constraintFor;
// System.out
// .println("InteractionCompartmentXYLayoutEditPolicy.getResizeChildrenCommand(), line : "
// + Thread.currentThread().getStackTrace()[1]
// .getLineNumber());
// System.out.println("constraintFor : " + childBounds);
if (childBounds.x < 0 || childBounds.y < 0) {
// return UnexecutableCommand.INSTANCE;
}
if(child instanceof LifelineEditPart) {
if (isHorizontalMove(request)) {
addLifelineResizeChildrenCommand(compoundCmd, request, (LifelineEditPart)child, 1);
/* apex improved start */
LifelineEditPart lep = (LifelineEditPart)child;
ICommand boundsCommand = new SetBoundsCommand(lep.getEditingDomain(),
ApexSequenceRequestConstants.APEX_COMMAND_LABLE_LIFELINE_MOVE_OR_RESIZE,
lep,
(Rectangle)translateToModelConstraint(constraintFor));
compoundCmd.add(new ICommandProxy(boundsCommand));
/* apex improved end */
/* apex replaced
addLifelineResizeChildrenCommand(compoundCmd, request, (LifelineEditPart)child, 1);
*/
}
} else if(child instanceof CombinedFragmentEditPart) {
// Add restrictions to change the size
if(!OperandBoundsComputeHelper.checkRedistrictOnCFResize(request,child)){
return null;
}
Command resizeChildrenCommand = getCombinedFragmentResizeChildrenCommand(request, (CombinedFragmentEditPart)child);
if(resizeChildrenCommand != null && resizeChildrenCommand.canExecute()) {
compoundCmd.add(resizeChildrenCommand);
}
/* apex improved start */
else if(resizeChildrenCommand != null) {
return UnexecutableCommand.INSTANCE;
}
/* apex improved end */
/* apex replaced
// else if(resizeChildrenCommand != null) {
// return UnexecutableCommand.INSTANCE;
// }
*/
}
/* apex improved start */
// Lifeline이나 CF의 move는 위에서 처리
else if ( isHorizontalMove(request)) {
Command changeConstraintCommand = createChangeConstraintCommand(request, child, translateToModelConstraint(constraintFor));
compoundCmd.add(changeConstraintCommand);
}
/* apex improved end */
/* apex replaced
if(!(child instanceof LifelineEditPart) || isVerticalMove(request)) {
Command changeConstraintCommand = createChangeConstraintCommand(request, child, translateToModelConstraint(constraintFor));
compoundCmd.add(changeConstraintCommand);
}
*/
/* apex replaced
// CF, IO 관련은 InteractionCompartmentXYLayoutPolicy나 OperationBoundsComputeHelper에서 자체 처리
if(child instanceof CombinedFragmentEditPart) {
OperandBoundsComputeHelper.createUpdateIOBoundsForCFResizeCommand(compoundCmd,request,(CombinedFragmentEditPart)child);
}
*/
/* apex added start */
if(child instanceof InteractionUseEditPart) {
InteractionCompartmentXYLayoutEditPolicy.apexMoveBelowItems(request, (InteractionUseEditPart)child, compoundCmd);
}
/* apex added end */
int right = childBounds.right();
int bottom = childBounds.bottom();
int deltaX = 0;
int deltaY = 0;
if (right > hostBounds.width) {
deltaX = right - hostBounds.width;
}
if (bottom > hostBounds.height) {
deltaY = bottom - hostBounds.height;
}
if (deltaX != 0 || deltaY != 0) {
ChangeBoundsRequest boundsRequest = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
boundsRequest.setSizeDelta(new Dimension(deltaX, deltaY));
EditPart hostParent = getHost().getParent();
boundsRequest.setEditParts(hostParent);
Command cmd = hostParent.getCommand(boundsRequest);
if (cmd != null && cmd.canExecute()) {
compoundCmd.add(cmd);
}
}
}
}
return compoundCmd.unwrap();
}
/* apex replaced
protected Command getResizeChildrenCommand(ChangeBoundsRequest request) {
CompoundCommand compoundCmd = new CompoundCommand();
compoundCmd.setLabel("Move or Resize");
IFigure figure = getHostFigure();
Rectangle hostBounds = figure.getBounds();
for(Object o : request.getEditParts()) {
GraphicalEditPart child = (GraphicalEditPart)o;
Object constraintFor = getConstraintFor(request, child);
if (constraintFor instanceof Rectangle) {
Rectangle childBounds = (Rectangle) constraintFor;
if (childBounds.x < 0 || childBounds.y < 0) {
return UnexecutableCommand.INSTANCE;
}
if(child instanceof LifelineEditPart) {
if (isVerticalMove(request)) {
addLifelineResizeChildrenCommand(compoundCmd, request, (LifelineEditPart)child, 1);
}
} else if(child instanceof CombinedFragmentEditPart) {
// Add restrictions to change the size
if(!OperandBoundsComputeHelper.checkRedistrictOnCFResize(request,child)){
return null;
}
Command resizeChildrenCommand = getCombinedFragmentResizeChildrenCommand(request, (CombinedFragmentEditPart)child);
if(resizeChildrenCommand != null && resizeChildrenCommand.canExecute()) {
compoundCmd.add(resizeChildrenCommand);
}
// else if(resizeChildrenCommand != null) {
// return UnexecutableCommand.INSTANCE;
// }
}
boolean hasCreateLink = LifelineMessageCreateHelper.hasIncomingMessageCreate(child);
if(hasCreateLink && !LifelineMessageCreateHelper.canMoveLifelineVertical((LifelineEditPart) child, (Rectangle) translateToModelConstraint(constraintFor)) ){
return UnexecutableCommand.INSTANCE;
}
if(!(child instanceof LifelineEditPart) || isVerticalMove(request) || hasCreateLink) {
Command changeConstraintCommand = createChangeConstraintCommand(request, child, translateToModelConstraint(constraintFor));
// When we change the width by mouse, it passe to manual mode. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=383723
if(child instanceof LifelineEditPart && changeConstraintCommand != null && request.getSizeDelta().width != 0){
compoundCmd.add(new ICommandProxy(LifelineResizeHelper.createManualLabelSizeCommand((LifelineEditPart)child)));
}
compoundCmd.add(changeConstraintCommand);
}
if(child instanceof CombinedFragmentEditPart) {
OperandBoundsComputeHelper.createUpdateIOBoundsForCFResizeCommand(compoundCmd,request,(CombinedFragmentEditPart)child);
}
int right = childBounds.right();
int bottom = childBounds.bottom();
int deltaX = 0;
int deltaY = 0;
if (right > hostBounds.width) {
deltaX = right - hostBounds.width;
}
if (bottom > hostBounds.height) {
deltaY = bottom - hostBounds.height;
}
if (deltaX != 0 || deltaY != 0) {
ChangeBoundsRequest boundsRequest = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
boundsRequest.setSizeDelta(new Dimension(deltaX, deltaY));
EditPart hostParent = getHost().getParent();
boundsRequest.setEditParts(hostParent);
Command cmd = hostParent.getCommand(boundsRequest);
if (cmd != null && cmd.canExecute()) {
compoundCmd.add(cmd);
}
}
}
}
return compoundCmd.unwrap();
}
*/
/**
* apex updated
*
* 원래 method 명이 isVerticalMove 이나
* 실제 구동내역에 따라 isHorizontalMove로 변경
*
* @param request
* @return
*/
protected boolean isHorizontalMove(ChangeBoundsRequest request) {
if (request instanceof AlignmentRequest) {
AlignmentRequest alignmentRequest = (AlignmentRequest) request;
switch(alignmentRequest.getAlignment()) {
case PositionConstants.BOTTOM:
case PositionConstants.TOP:
case PositionConstants.MIDDLE:
case PositionConstants.VERTICAL:
case PositionConstants.NORTH_EAST:
case PositionConstants.NORTH_WEST:
case PositionConstants.SOUTH_EAST:
case PositionConstants.SOUTH_WEST:
return false;
}
}
Point point = request.getMoveDelta();
return point.y == 0;
}
/**
* Resize children of LifelineEditPart (Execution specification and lifeline)
*
* @param compoundCmd
* The command
* @param request
* The request
* @param lifelineEditPart
* The lifelineEditPart to resize
* @param number
* The number of brother of the LifelineEditPart
*/
private static void addLifelineResizeChildrenCommand(CompoundCommand compoundCmd, ChangeBoundsRequest request, LifelineEditPart lifelineEditPart, int number) {
// If the width increases or decreases, ExecutionSpecification elements need to
// be moved
int widthDelta;
for(ShapeNodeEditPart executionSpecificationEP : lifelineEditPart.getChildShapeNodeEditPart()) {
if(executionSpecificationEP.resolveSemanticElement() instanceof ExecutionSpecification) {
// Lifeline's figure where the child is drawn
Rectangle rDotLine = lifelineEditPart.getContentPane().getBounds();
// The new bounds will be calculated from the current bounds
Rectangle newBounds = executionSpecificationEP.getFigure().getBounds().getCopy();
widthDelta = request.getSizeDelta().width;
if(widthDelta != 0) {
if(rDotLine.getSize().width + widthDelta < newBounds.width * 2) {
compoundCmd.add(UnexecutableCommand.INSTANCE);
}
// Apply SizeDelta to the children
widthDelta = Math.round(widthDelta / ((float)2 * number));
newBounds.x += widthDelta;
// Convert to relative
newBounds.x -= rDotLine.x;
newBounds.y -= rDotLine.y;
SetBoundsCommand setBoundsCmd = new SetBoundsCommand(executionSpecificationEP.getEditingDomain(), "Re-location of a ExecutionSpecification due to a Lifeline movement", executionSpecificationEP, newBounds);
compoundCmd.add(new ICommandProxy(setBoundsCmd));
}
// update the enclosing interaction of a moved execution specification
compoundCmd.add(SequenceUtil.createUpdateEnclosingInteractionCommand(executionSpecificationEP, request.getMoveDelta(), new Dimension(widthDelta, 0)));
}
}
List<LifelineEditPart> innerConnectableElementList = lifelineEditPart.getInnerConnectableElementList();
for(LifelineEditPart lifelineEP : innerConnectableElementList) {
addLifelineResizeChildrenCommand(compoundCmd, request, lifelineEP, number * innerConnectableElementList.size());
}
// fixed bug (id=364711) when lifeline bounds changed update coveredBys'
// bounds.
addUpdateInteractionFragmentsLocationCommand(compoundCmd, request,
lifelineEditPart);
}
/**
* apex update
*
* Lifeline 좌우 이동 시 CF의 Resize 처리
*
* Resize InteractionFragments if the Lifeline has CoveredBys, while
* Lifeline moving.
*
* @param compoundCmd
* @param request
* @param lifelineEditPart
*/
private static void addUpdateInteractionFragmentsLocationCommand(
CompoundCommand compoundCmd, ChangeBoundsRequest request,
LifelineEditPart lifelineEditPart) {
View shape = (View) lifelineEditPart.getModel();
Lifeline element = (Lifeline) shape.getElement();
EList<InteractionFragment> covereds = element.getCoveredBys();
EditPart parent = lifelineEditPart.getParent();
List<?> children = parent.getChildren();
for (Object obj : children) {
EditPart et = (EditPart) obj;
View sp = (View) et.getModel();
/* apex improved start */
EObject eObj = sp.getElement();
if (covereds.contains(eObj)) {
ChangeBoundsRequest req = null;
if ( eObj instanceof CombinedFragment ) { // Lifeline을 커버하고 있는 CF의 이동은 아래에서 별도 처리
continue;
} else {
req = new ChangeBoundsRequest(REQ_MOVE);
req.setEditParts(et);
req.setMoveDelta(request.getMoveDelta());
}
Command command = et.getCommand(req);
if (command != null && command.canExecute()) {
compoundCmd.add(command);
}
}
/* apex improved end */
/* apex replaced
if (!covereds.contains(sp.getElement())) {
continue;
}
ChangeBoundsRequest req = new ChangeBoundsRequest(REQ_MOVE);
req.setEditParts(et);
req.setMoveDelta(request.getMoveDelta());
Command command = et.getCommand(req);
if (command != null && command.canExecute()) {
compoundCmd.add(command);
}
*/
}
/* apex added start */
resizeCombinedFragmentByMovingLifelineCommand(compoundCmd, request, lifelineEditPart);
/* apex added end */
}
/**
* apex update
*
* Lifeline 좌우 이동 시 CF의 Resize 처리
*
* Resize InteractionFragments if the Lifeline has CoveredBys, while
* Lifeline moving.
*
* @param compoundCmd
* @param request
* @param lifelineEditPart
*/
public static void resizeCombinedFragmentByMovingLifelineCommand(
CompoundCommand compoundCmd, ChangeBoundsRequest request,
LifelineEditPart lifelineEditPart) {
/* apex added start */
// Lifeline을 커버하고 있는 CF의 이동 처리
int deltaX = request.getMoveDelta().x;
ChangeBoundsRequest req = null;
List<CombinedFragmentEditPart> coveringCFEPs = ApexSequenceUtil.apexGetCoveringCombinedFragmentEditParts(lifelineEditPart);
for ( CombinedFragmentEditPart cfep : coveringCFEPs ) {
List<LifelineEditPart> coveredLifelineEditParts = ApexSequenceUtil.apexGetCoveredLifelineEditParts(cfep, true);
List sortedCoveredLifelineEditParts = ApexSequenceUtil.apexGetSortedGraphicalEditPartList(coveredLifelineEditParts, SWT.LEFT);
Map apexMoveInfo = new HashMap();
if ( sortedCoveredLifelineEditParts.size() > 0 ) {
ShapeNodeEditPart leftestLifelineEditPart = (ShapeNodeEditPart)sortedCoveredLifelineEditParts.get(0);
ShapeNodeEditPart rightestLifelineEditPart = (ShapeNodeEditPart)sortedCoveredLifelineEditParts.get(sortedCoveredLifelineEditParts.size()-1);
boolean isLeftestLifelineEditPart = lifelineEditPart.equals(leftestLifelineEditPart);
boolean isRightestLifelineEditPart = lifelineEditPart.equals(rightestLifelineEditPart);
if ( isLeftestLifelineEditPart && deltaX < 0 ) { // 맨왼쪽 Lifeline을 좌측으로 이동하는 경우
req = new ChangeBoundsRequest(REQ_RESIZE);
req.setEditParts(cfep);
req.setMoveDelta(new Point(deltaX, 0)); // WEST의 경우 resize 시에도 moveDelta 필요
req.setSizeDelta(new Dimension(Math.abs(deltaX), 0));
req.setResizeDirection(PositionConstants.WEST);
} else if ( isLeftestLifelineEditPart && deltaX > 0 ) { // 맨왼쪽 Lifeline을 우측으로 이동하는 경우
if ( isRightestLifelineEditPart ) { // 유일한 Lifeline인 경우
req = new ChangeBoundsRequest(REQ_RESIZE);
req.setEditParts(cfep);
req.setMoveDelta(new Point(deltaX, 0)); // WEST의 경우 resize 시에도 moveDelta 필요
req.setSizeDelta(new Dimension(-deltaX, 0));
req.setResizeDirection(PositionConstants.WEST);
} else { // 우측에 Lifeline이 있는 경우 아래의 apexGetPushNextLifeline()을 통해 이동시킴
continue;
}
} else if ( isRightestLifelineEditPart && deltaX < 0 ) { // 맨우측 Lifeline을 좌측으로 이동하는 경우
req = new ChangeBoundsRequest(REQ_RESIZE);
req.setEditParts(cfep);
req.setSizeDelta(new Dimension(deltaX, 0));
req.setResizeDirection(PositionConstants.EAST);
} else if ( isRightestLifelineEditPart && deltaX > 0 ) { // 맨우측 Lifeline을 우측으로 이동하는 경우에만 CF Resize(안그러면 Resize가 누적됨)
req = new ChangeBoundsRequest(REQ_RESIZE);
req.setEditParts(cfep);
req.setSizeDelta(new Dimension(deltaX, 0));
req.setResizeDirection(PositionConstants.EAST);
} else { // 그 외 중간 Lifeline을 좌측으로 이동 시 CF에는 아무런 변화 없음
continue;
}
}
// cfep가 중첩된 CF인 경우
// lifeline이 parent CF의 최좌측 covered Lifeline 인지 여부 확인(Resize 시 parent의 resize를 유발하냐 마냐에 필요)
EditPart pEditPart = cfep.getParent();
if ( pEditPart instanceof IGraphicalEditPart ) {
EObject eObj = ((IGraphicalEditPart) pEditPart).resolveSemanticElement();
if ( eObj instanceof InteractionOperand ) {
List<LifelineEditPart> parentCFCoveredLifelineEditParts = ApexSequenceUtil.apexGetCoveredLifelineEditParts((ShapeNodeEditPart)cfep.getParent().getParent().getParent(), true);
List parentCFSortedCoveredLifelineEditParts = ApexSequenceUtil.apexGetSortedGraphicalEditPartList(parentCFCoveredLifelineEditParts, SWT.LEFT);
boolean isLeftestLifelineOfParent = lifelineEditPart.equals((ShapeNodeEditPart)parentCFSortedCoveredLifelineEditParts.get(0));
apexMoveInfo.put(ApexSequenceRequestConstants.APEX_KEY_IS_LEFTESTLIFELINE_OF_PARENT_COMBINEDFRAGMENT,
new Boolean(isLeftestLifelineOfParent));
}
}
apexMoveInfo.put(ApexSequenceRequestConstants.APEX_KEY_MOVING_LIFELINEEDITPART, lifelineEditPart);
req.setExtendedData(apexMoveInfo);
Command command = cfep.getCommand(req);
if (command != null && command.canExecute()) {
compoundCmd.add(command);
}
}
if ( request.getMoveDelta().x > 0 ) {
apexGetPushNextLifeline(compoundCmd, request, lifelineEditPart);
}
/* apex added end */
}
/**
* apex updated
*
* 중첩CF처리 재귀호출을 위한 메서드
* 기존 getCombinedFragmentResizeChildrenCommand(ChangeBoundsRequest, CombinedFragmentEditPart)를 호출하고
* 그 결과 CompoundCommand를 분해하여
* 파라미터로 받은 ccmd에 add
*
* @param request
* @param combinedFragmentEditPart
* @param compoundCmd
* @return
*/
public static void apexCombinedFragmentResizeChildren(ChangeBoundsRequest request,
GraphicalEditPart combinedFragmentEditPart,
GraphicalEditPart childEditPart,
CompoundCommand compoundCmd) {
// cpCmd를 분해하여 넘겨받은 원래의 ccmd 에 add
ApexSequenceUtil.apexCompoundCommandToCompoundCommand(getCombinedFragmentResizeChildrenCommand(request, combinedFragmentEditPart, childEditPart), compoundCmd);
}
/**
* Lifeline 이동 시 우측의 Lifeline을 함께 이동
*
* @param compoundCmd
* @param request
* @param lifelineEditPart
*/
public static void apexGetPushNextLifeline(CompoundCommand compoundCmd, ChangeBoundsRequest request, LifelineEditPart lifelineEditPart) {
List nextLifelineEditParts = ApexSequenceUtil.apexGetNextLifelineEditParts(lifelineEditPart);
if ( nextLifelineEditParts.size() > 0 ) {
LifelineEditPart nextLifelineEditPart = (LifelineEditPart)ApexSequenceUtil.apexGetNextLifelineEditParts(lifelineEditPart).get(0);
// Type을 REQ_MOVE로 바꿔주지 않으면 REQ_MOVE_CHILDREN인 상태로 다른 로직을 타게 됨
request.setType(RequestConstants.REQ_MOVE);
Command cmd = nextLifelineEditPart.getCommand(request);
compoundCmd.add(cmd);
}
}
/**
* CF bound의 resize 처리
* Child CF의 right, bottom 보다 작게 Resize 방지
*
* @param combinedFragmentEditPart
* @param byMove Child CF의 Move에 의한 Resize인지 구별
* @return
*/
public static CompoundCommand apexGetResizeCombinedFragmentBoundsCommand(ChangeBoundsRequest request,
GraphicalEditPart combinedFragmentEditPart,
GraphicalEditPart childEditPart,
boolean byMove) {
CompoundCommand compoundCmd = new CompoundCommand(ApexSequenceRequestConstants.APEX_COMMAND_LABEL_RESIZE_THE_CF_BOUNDS);
// request 에서 size 뽑아서 처리
IFigure cfFigure = combinedFragmentEditPart.getFigure();
Rectangle origCFBounds = cfFigure.getBounds().getCopy();
cfFigure.translateToAbsolute(origCFBounds);
Point moveDelta = request.getMoveDelta();
Dimension sizeDelta = request.getSizeDelta();
int direction = request.getResizeDirection();
origCFBounds.translate(moveDelta);
origCFBounds.resize(sizeDelta);
// 상향 move 시 침범 방지
if ( moveDelta.y < 0 ) {
int yAfterMove = ApexSequenceUtil.apexGetAbsolutePosition(combinedFragmentEditPart, SWT.TOP)+moveDelta.y;
// 상향 move 시 Interaction 또는 InteractionOperand 침범 방지
EditPart ep = combinedFragmentEditPart.getParent();
IGraphicalEditPart parentCompartmentEditPart = null;
if ( ep instanceof InteractionOperandEditPart || ep instanceof InteractionInteractionCompartmentEditPart ) {
parentCompartmentEditPart = (IGraphicalEditPart)ep;
} else {
compoundCmd.add(UnexecutableCommand.INSTANCE);
return compoundCmd;
}
int topOfParentCompartment = ApexSequenceUtil.apexGetAbsolutePosition(parentCompartmentEditPart, SWT.TOP);
if ( yAfterMove <= topOfParentCompartment ) {
compoundCmd.add(UnexecutableCommand.INSTANCE);
return compoundCmd;
}
// 상향 move 시 aboveEditPart 침범 방지
List higherEditPartList = ApexSequenceUtil.apexGetHigherEditPartList(combinedFragmentEditPart);
if ( higherEditPartList.size() > 0 ) {
IGraphicalEditPart aboveEditPart = ApexSequenceUtil.apexGetAboveEditPart(combinedFragmentEditPart, higherEditPartList);
int yAbove = ApexSequenceUtil.apexGetAbsolutePosition(aboveEditPart, SWT.BOTTOM);
if ( yAfterMove <= yAbove ) {
compoundCmd.add(UnexecutableCommand.INSTANCE);
return compoundCmd;
}
}
}
// resize 없는 순수 move 시 좌우 move 금지 (ApexCombinedFragmentResizableShapeEditPolicy에서 처리)
/*
if(sizeDelta.equals(0, 0)) {
if ( moveDelta.x != 0 ) {
// ccmd.add(UnexecutableCommand.INSTANCE);
}
}
*/
// 상향 확대 resize 시 AboveEditPart 침범 방지
if ( sizeDelta.height > 0 && (request.getResizeDirection() & PositionConstants.NORTH) != 0) {
List higherEditParts = ApexSequenceUtil.apexGetHigherEditPartList(combinedFragmentEditPart);
if ( higherEditParts.size() > 0 ) {
IGraphicalEditPart igep = ApexSequenceUtil.apexGetAboveEditPart(combinedFragmentEditPart, higherEditParts);
int bottomAboveEP = ApexSequenceUtil.apexGetAbsolutePosition(igep, SWT.BOTTOM);
int topIgep = ApexSequenceUtil.apexGetAbsolutePosition(combinedFragmentEditPart, SWT.TOP)-sizeDelta.height;
if ( topIgep <= bottomAboveEP ) {
compoundCmd.add(UnexecutableCommand.INSTANCE);
return compoundCmd;
}
}
}
// childCombinedFragment가 있고, child의 right 보다 작게 resize 안되게
List children = ApexSequenceUtil.apexGetChildEditPartList(combinedFragmentEditPart);
Iterator it1 = children.iterator();
while ( it1.hasNext()) {
EditPart childEp = (EditPart)it1.next();
if ( childEp instanceof CombinedFragmentEditPart ) {
CombinedFragmentEditPart cfep = (CombinedFragmentEditPart)childEp;
Rectangle childRect = cfep.getFigure().getBounds().getCopy();
cfep.getFigure().translateToAbsolute(childRect);
// child.right보다 작으면 X
if ( origCFBounds.right() <= childRect.right() ) {
compoundCmd.add(UnexecutableCommand.INSTANCE);
return compoundCmd;
}
// child.left보다 크면 X
if ( origCFBounds.x >= childRect.x ) {
compoundCmd.add(UnexecutableCommand.INSTANCE);
return compoundCmd;
}
// child.bottom보다 작으면 X
if ( origCFBounds.bottom() <= childRect.bottom() ) {
// request 가 resize인 경우에만 unexecutable
// request 가 move인 경우 child의 bottom 보다 위로 올려도 문제 없음
if ( request.getType().equals(REQ_RESIZE)
|| request.getType().equals(REQ_RESIZE_CHILDREN) ) {
compoundCmd.add(UnexecutableCommand.INSTANCE);
return compoundCmd;
}
}
}
}
// CF 경계 변경 실제 처리 부분 - 중첩된 CF의 move/resize에 의한 포함하는 CF의 경계 resize/move 처리
cfFigure.translateToRelative(origCFBounds);
// System.out.println(byMove ? "byMove" : "byResize");
// parent 보다 좌측으로 resize하는 경우 자동으로 move되므로 위에서 translate해준 값 원상복구
TransactionalEditingDomain editingDomain = combinedFragmentEditPart.getEditingDomain();
ICommand resizeOrMoveCFCommand = null;
if ( byMove ) {
resizeOrMoveCFCommand = new SetBoundsCommand(editingDomain,
ApexSequenceRequestConstants.APEX_COMMAND_LABEL_MOVE_THE_CF_BOUNDS,
combinedFragmentEditPart,
origCFBounds);
} else {
// parent CF보다 좌측으로 resize 되는 경우 parent의 이동에 따라 한번더 이동되지 않도록 sizeDelta 만큼 보정
if ( origCFBounds.x < 0 ) {
origCFBounds.x += sizeDelta.width;
// Lifeline에 의한 좌측 이동 시 중첩된 CF의 경우 parent resize 유발 안하더라도 Lifeline의 이동에 의해 parent가 좌측으로 이동되므로 moveDelta 만큼 보정
} else {
boolean isMoveRequestFromLifelineMove = false;
boolean isLeftestLifelineOfParent = false;
LifelineEditPart lep = null;
Map extData = request.getExtendedData();
Set<Entry<Object, Object>> entrySet = extData.entrySet();
for (Entry<Object, Object> aExtendedDataEntry : entrySet ) {
Object value = aExtendedDataEntry.getValue();
if ( value instanceof LifelineEditPart ) {
isMoveRequestFromLifelineMove = true;
lep = (LifelineEditPart)value;
} else if ( value instanceof Boolean ) {
isLeftestLifelineOfParent = ((Boolean)value).booleanValue();
}
}
if ( isMoveRequestFromLifelineMove
&& moveDelta.x < 0
// 이 lifeline 이 parentCF의 최좌측 lifeline인 경우
&& isLeftestLifelineOfParent
&& combinedFragmentEditPart.getParent() instanceof InteractionOperandEditPart ) {
origCFBounds.x += Math.abs(moveDelta.x);
}
}
resizeOrMoveCFCommand = new SetBoundsCommand(editingDomain,
ApexSequenceRequestConstants.APEX_COMMAND_LABEL_RESIZE_THE_CF_BOUNDS,
//new EObjectAdapter((View) combinedFragmentEditPart.getModel()),
combinedFragmentEditPart,
//new Dimension(origCFBounds.width, origCFBounds.height));
origCFBounds);
}
// ICommand resizeOrMoveCFCommand = byMove ? new SetBoundsCommand(editingDomain,
// "Apex_CF_Move",
// new EObjectAdapter((View) combinedFragmentEditPart.getModel()),
// origCFBounds)
// : new SetBoundsCommand(editingDomain,
// "Apex_CF_Resize",
// new EObjectAdapter((View) combinedFragmentEditPart.getModel()),
// //new Dimension(origCFBounds.width, origCFBounds.height));
// origCFBounds);
compoundCmd.add(new ICommandProxy(resizeOrMoveCFCommand));
// 좌변에서 resize 시 child가 현위치에 머무르드록 처리
if ( (direction & PositionConstants.WEST) != 0 ) {
// child가 좌측으로 따라 이동되지 않도록 우측으로 미리 이동시켜둠
List cfChildren = combinedFragmentEditPart.getChildren();
for ( Object aCfChild : cfChildren ) {
if ( aCfChild instanceof CombinedFragmentCombinedFragmentCompartmentEditPart ) {
CombinedFragmentCombinedFragmentCompartmentEditPart cfcfcep = (CombinedFragmentCombinedFragmentCompartmentEditPart)aCfChild;
List cfcfcChildren = cfcfcep.getChildren();
for ( Object aCfcfcChild : cfcfcChildren ) {
if ( aCfcfcChild instanceof InteractionOperandEditPart ) {
InteractionOperandEditPart ioep1 = (InteractionOperandEditPart)aCfcfcChild;
List childCFs = ioep1.getChildren();
for ( Object aOpChild : childCFs ) {
if ( aOpChild instanceof CombinedFragmentEditPart ) {
CombinedFragmentEditPart childCfep = (CombinedFragmentEditPart)aOpChild;
IFigure childCfFigure = childCfep.getFigure();
Rectangle childCfRect = childCfFigure.getBounds().getCopy();
// resizeParent에 의해 호출된 경우 childEditPart가 아닌 것은 따라 이동되지 않도록 x 값 보정
if ( childEditPart != null && !childCfep.equals(childEditPart) ) {
childCfRect.x += sizeDelta.width;
ICommand childAdjustment = new SetBoundsCommand(childCfep.getEditingDomain(),
ApexSequenceRequestConstants.APEX_COMMAND_LABEL_CHILD_MOVE_ADJUSTMENT,
childCfep,
childCfRect);
compoundCmd.add(new ICommandProxy(childAdjustment));
}
// resizeParent에 의해 호출되지 않은 경우
if ( childEditPart == null ) {
// child들이 parent에 따라 이동되지 않도록 x 값 보정
childCfRect.x += sizeDelta.width;
ICommand childAdjustment = new SetBoundsCommand(childCfep.getEditingDomain(),
ApexSequenceRequestConstants.APEX_COMMAND_LABEL_CHILD_MOVE_ADJUSTMENT,
childCfep,
childCfRect);
compoundCmd.add(new ICommandProxy(childAdjustment));
}
}
}
}
}
}
}
}
// CF 자체의 resize 또는 Lifeline의 move에 의한 IO 변경 실제 처리 부분
boolean isResizeByLifelineMove = false;
boolean isResizeByInteractionOperandResize = false;
Map reqExtMap = request.getExtendedData();
Set<Entry<Object, Object>> entrySet = reqExtMap.entrySet();
for (Entry<Object, Object> aExtendedDataEntry : entrySet ) {
Object value = aExtendedDataEntry.getValue();
if ( value instanceof LifelineEditPart ) {
isResizeByLifelineMove = true;
//lep = (LifelineEditPart)value;
} else if ( value instanceof InteractionOperandEditPart ) {
isResizeByInteractionOperandResize = true;
}
}
if ( !byMove && (isResizeByLifelineMove || !isResizeByInteractionOperandResize) ) {
apexUpdateChildrenIOBoundsByLifelineOrCombinedFragment(request, combinedFragmentEditPart, childEditPart, compoundCmd);
}
return compoundCmd;
}
/**
* abstractGraphicalEditPart보다 아래에 있는 item들 모두의 좌표를 request내의 delta만 이동
*
* @param abstractGraphicalEditPart
* @param request
* @return
*/
public static void apexMoveBelowItems(ChangeBoundsRequest request, GraphicalEditPart abstractGraphicalEditPart, CompoundCommand compoundCmd) {
if ( request.getMoveDelta().y > 0 || (request.getSizeDelta().height > 0 && ((request.getResizeDirection() & PositionConstants.SOUTH) != 0) ) ) { // 아래로 이동하거나 아래로 확대 Resize 하는 경우
// 넘겨받은 AbstractGraphicalEditPart 보다 아래에 있는 belowList 구성
// List belowEditPartList = ApexSequenceUtil.apexGetMovableEditPartList(abstractGraphicalEditPart);
List<IGraphicalEditPart> belowEditPartList = ApexSequenceUtil.apexGetNextSiblingEditParts(abstractGraphicalEditPart);
if ( belowEditPartList.size() > 0 ) {
// move/resize할 위치
// 다른 element의 move에 의한 경우 moveDelta에서,
// 다른 element의 resize에 의한 경우 sizeDelta에서 산정
//Point moveDelta = request.getMoveDelta().y != 0 ? request.getMoveDelta() : new Point(0, request.getSizeDelta().height);
int deltaY = request.getMoveDelta().y != 0 ? request.getMoveDelta().y : request.getSizeDelta().height;
IFigure thisFigure = abstractGraphicalEditPart.getFigure();
Rectangle origCFBounds = thisFigure.getBounds().getCopy();
thisFigure.translateToAbsolute(origCFBounds);
// 넘겨받은 AbstractGraphicalEditPart 의 이동/Resize 후 bottom 위치
int bottom = origCFBounds.getBottom().y+deltaY;
// 넘겨받은 AbstractGraphicalEditPart 바로 아래의 EditPart 구성
// IGraphicalEditPart beneathEditPart = ApexSequenceUtil.apexGetBeneathEditPart(abstractGraphicalEditPart);
IGraphicalEditPart beneathEditPart = belowEditPartList.get(0);
int topOfBeneathEditPart = ApexSequenceUtil.apexGetAbsolutePosition(beneathEditPart, SWT.TOP);
// beneathEditPart 보다 아래로 내릴 경우(그냥 내리기만 하면 밀려내려가게 변경 아래 if행 주석처리)
// if (bottom >= topOfBeneathEditPart) {
if ( beneathEditPart instanceof IGraphicalEditPart ) {
if ( beneathEditPart instanceof CombinedFragmentEditPart ) {
// beneathEditPart Move 처리
ChangeBoundsRequest cbRequest = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
cbRequest.setMoveDelta(new Point(0, deltaY));
cbRequest.setEditParts(beneathEditPart);
ApexSequenceUtil.apexCompoundCommandToCompoundCommand(getCombinedFragmentResizeChildrenCommand(cbRequest, (GraphicalEditPart)beneathEditPart), compoundCmd);
// beneathEditpart 가 아래로 밀려 내려가서 beneathEditPart의 Parent의 Resize 필요한 경우
apexResizeParentCombinedFragments(cbRequest, (GraphicalEditPart)beneathEditPart, compoundCmd);
} else if ( beneathEditPart instanceof MessageEditPart ) { // message의 경우 상단은 Activation(Message보다 1px 높음) 또는 LabelEditPart임
MessageEditPart mEditPart = (MessageEditPart)beneathEditPart;
ChangeBoundsRequest cbRequest = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
cbRequest.setMoveDelta(new Point(0, deltaY));
cbRequest.setEditParts(beneathEditPart);
ApexSequenceUtil.apexCompoundCommandToCompoundCommand(mEditPart.getCommand(cbRequest), compoundCmd);
//compoundCmd.add(mEditPart.getCommand(cbRequest));
// ApexConnectionMoveEditPolicy.apexGetMoveConnectionCommand(request, connectionPart, false);
} else { // CF도 Message도 아닌 경우
/*8
System.out
.println("InteractionCompartmentXYLayoutEditPolicy.apexMoveBelowItems(), line : "
+ Thread.currentThread()
.getStackTrace()[1]
.getLineNumber());
System.out.println("beneatEditPart : " + beneathEditPart);
//*/
IFigure figure = beneathEditPart.getFigure();
Rectangle rect = figure.getBounds().getCopy();
rect.translate(0, deltaY);
SetBoundsCommand setBoundsCmd = new SetBoundsCommand(beneathEditPart.getEditingDomain(),
ApexSequenceRequestConstants.APEX_COMMAND_LABEL_RELOCATION_BY_ABOVE_ELEMENT,
beneathEditPart,
rect);
compoundCmd.add(new ICommandProxy(setBoundsCmd));
// beneathEditPart가 CombinedFragment가 아닐 경우 beneathEditPart 아래의 beneathEditPart에 대한 처리
apexMoveBelowItems(request, (GraphicalEditPart)beneathEditPart, compoundCmd);
}
}
// }
} else { // belowEditPart 가 없는 경우
// 본 CF의 이동에 의한 parent resize 처리
apexResizeParentCombinedFragments(request, (GraphicalEditPart)abstractGraphicalEditPart, compoundCmd);
}
}
}
/**
* 넘겨받은 GraphicalEditPart가 중첩되어 있는 child 인 경우
* parent CF의 경계 변경여부 결정
*
* @param request
* @param graphicalEditPart
* @param compoundCmd
*/
public static void apexResizeParentCombinedFragments(ChangeBoundsRequest request, GraphicalEditPart graphicalEditPart, CompoundCommand compoundCmd) {
Point moveDelta = request.getMoveDelta();
Dimension sizeDelta = request.getSizeDelta();
int direction = request.getResizeDirection();
IFigure cfFigure = graphicalEditPart.getFigure();
Rectangle origCFBounds = cfFigure.getBounds().getCopy();
// origCFBounds 를 화면 좌상단을 원점으로 하는 절대좌표값으로 변경
cfFigure.translateToAbsolute(origCFBounds);
// origCFBounds 를 cfFigure.getParent()의 좌상단 절대좌표값만큼 더하여 변경, 즉 parent의 변경만큼 origCFBounds도 변경
//origCFBounds.translate(cfFigure.getParent().getBounds().getLocation());
// Resize된 CF의 새 Bounds
Rectangle newBoundsCF = origCFBounds.getCopy();
newBoundsCF.translate(moveDelta);
newBoundsCF.resize(sizeDelta);
// parent Operand(또는 InteractionInteractionCompartmentEditPart)가 있고, 즉 중첩되어 있고
EditPart pEditPart = graphicalEditPart.getParent();
if ( pEditPart instanceof InteractionOperandEditPart || pEditPart instanceof InteractionInteractionCompartmentEditPart ) {
GraphicalEditPart parentEditPart = (GraphicalEditPart)pEditPart.getParent().getParent();
// Resize결과 parentOperand보다 크면 parentCF도 Resize 처리
if ( pEditPart instanceof InteractionOperandEditPart ) {
InteractionOperandEditPart ioep = (InteractionOperandEditPart)pEditPart;
Rectangle parentOperandBounds = ioep.getFigure().getBounds().getCopy();
ioep.getFigure().translateToAbsolute(parentOperandBounds);
// 좌측으로 확대로 parentCF보다 커질 경우
// parent는 move와resize를 함께 해야한다.
if ( newBoundsCF.x < parentOperandBounds.x ) {
ChangeBoundsRequest cbRequest = new ChangeBoundsRequest(ApexSequenceRequestConstants.APEX_REQUEST_MOVE_AND_RESIZE_COMBINEDFRAGMENT);
cbRequest.setEditParts(parentEditPart);
int deltaX = 0;
// Child CF가 좌측으로 resize 확대된 경우
if ( sizeDelta.width > 0 ) { // resize 시에도 moveDelta가 존재한다.
if ( (direction & PositionConstants.WEST) == 0 ) {
compoundCmd.add(UnexecutableCommand.INSTANCE);
} else {
cbRequest.setMoveDelta(new Point(-sizeDelta.width, 0));
cbRequest.setSizeDelta(sizeDelta);
cbRequest.setResizeDirection(direction);
}
}
apexCombinedFragmentResizeChildren(cbRequest, parentEditPart, graphicalEditPart, compoundCmd);
int a = 0;
// parent의 좌측이동에 따라 child도 함께 자동이동되므로
// 자동이동 후 원위치되도록 child를 우측으로 미리 이동
// cfFigure.translateToRelative(origCFBounds);
// System.out
// .println("InteractionCompartmentXYLayoutEditPolicy.apexResizeParentCombinedFragments(), line : "
// + Thread.currentThread().getStackTrace()[1]
// .getLineNumber());
// System.out.println("origCFBounds : " + origCFBounds);
// //origCFBounds.x += parentOperandBounds.x - newBoundsCF.x;
// origCFBounds.x += sizeDelta.width;
// System.out.println("origCFBounds : " + origCFBounds);
// SetBoundsCommand moveChildRight = new SetBoundsCommand(graphicalEditPart.getEditingDomain(),
// "move child to the right to compensate for the automatic left movement due to parents's left move",
// graphicalEditPart,
// origCFBounds);
// compoundCmd.add(new ICommandProxy(moveChildRight));
} else if ( newBoundsCF.right() > parentOperandBounds.right()
|| newBoundsCF.bottom() > parentOperandBounds.bottom() ) {
ChangeBoundsRequest cbRequest = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
Dimension resizeParentDimension = moveDelta.y != 0 ? new Dimension(0, moveDelta.y) : sizeDelta;
cbRequest.setSizeDelta(resizeParentDimension);
cbRequest.setResizeDirection(PositionConstants.SOUTH_EAST);
apexCombinedFragmentResizeChildren(cbRequest, parentEditPart, graphicalEditPart, compoundCmd);
}
}
} else if ( pEditPart instanceof LifelineEditPart ) { // ApexConnectionMoveEditPolicy.apexGetMoveConnectionCommand()에서 호출된 경우 ActivationEP가 넘어옴
ShapeNodeEditPart ioep = ApexSequenceUtil.apexGetEnclosingInteractionOperandEditpart(graphicalEditPart);
if ( ioep != null ) {
Rectangle parentOperandBounds = ioep.getFigure().getBounds().getCopy();
ioep.getFigure().translateToAbsolute(parentOperandBounds);
if ( newBoundsCF.right() > parentOperandBounds.right()
|| newBoundsCF.bottom() > parentOperandBounds.bottom() ) {
ChangeBoundsRequest cbRequest = new ChangeBoundsRequest(RequestConstants.REQ_RESIZE);
Dimension resizeParentDimension = moveDelta.y != 0 ? new Dimension(0, moveDelta.y) : sizeDelta;
cbRequest.setSizeDelta(resizeParentDimension);
cbRequest.setResizeDirection(PositionConstants.SOUTH);
CombinedFragmentEditPart parentCFEditPart = (CombinedFragmentEditPart)ioep.getParent().getParent();
apexCombinedFragmentResizeChildren(cbRequest, parentCFEditPart, graphicalEditPart, compoundCmd);
}
}
}
}
/**
* Lifeline 이나 CombinedFragment 에 의한 InteractionOperand 의 경계 변경 처리
*
* @param request
* @param combinedFragmentEditPart
* @param childEditPart
* @param compoundCmd
*/
public static void apexUpdateChildrenIOBoundsByLifelineOrCombinedFragment(ChangeBoundsRequest request,
GraphicalEditPart combinedFragmentEditPart,
GraphicalEditPart childEditPart,
CompoundCommand compoundCmd) {
Point moveDelta = request.getMoveDelta();
Dimension sizeDelta = request.getSizeDelta();
int direction = request.getResizeDirection();
EditPart parentEP = childEditPart!=null ? childEditPart.getParent() : combinedFragmentEditPart.getParent();
ShapeNodeEditPart ioep = null;
// CF의 상변에서의 resize의 경우 아래의 Op들이 이동되지 않도록 하는 flag
boolean isResizeByNorthOfCombinedFragment = false;
// CF의 하변에서의 resize의 경우 위의 Op들의 width도 수정되도록 하는 flag
boolean isResizeBySouthOfCombinedFragment = false;
// 자기 CF의 resize이면서 message move에 의한 resize가 아닌 경우
// message move에 의한 resize는 ApexConnectionMoveEditPolicy에서 ioep.getCommand()를 통해 수행됨
if ( childEditPart == null ) {
CombinedFragmentCombinedFragmentCompartmentEditPart cfcfep = (CombinedFragmentCombinedFragmentCompartmentEditPart)combinedFragmentEditPart.getChildren().get(0);
List ioeps = cfcfep.getChildren();
if ( (direction & PositionConstants.NORTH) != 0 ) {
ioep = (InteractionOperandEditPart)ioeps.get(0);
isResizeByNorthOfCombinedFragment = true;
} else if ( (direction & PositionConstants.SOUTH) != 0 ) {
ioep = (InteractionOperandEditPart)ioeps.get(ioeps.size()-1);
isResizeBySouthOfCombinedFragment = true;
} else if ( (direction & PositionConstants.EAST_WEST) != 0 ) {
ioep = (InteractionOperandEditPart)ioeps.get(0);
}
} else if ( parentEP instanceof InteractionOperandEditPart ) {
ioep = (InteractionOperandEditPart)parentEP;
} else if ( parentEP instanceof LifelineEditPart ) { // Activation 이 CF의 resize를 유발한 경우
ioep = ApexSequenceUtil.apexGetEnclosingInteractionOperandEditpart(childEditPart);
}
compoundCmd.add(OperandBoundsComputeHelper.createIOEPResizeCommand(request, (InteractionOperandEditPart)ioep, true));
}
/**
* apex updated
*
* CF의 Move/Resize 처리
*
* @param request
* @param combinedFragmentEditPart
* @return
*/
@SuppressWarnings("unchecked")
public static Command getCombinedFragmentResizeChildrenCommand(ChangeBoundsRequest request, GraphicalEditPart combinedFragmentEditPart) {
return getCombinedFragmentResizeChildrenCommand(request, combinedFragmentEditPart, null);
}
/**
* apex updated
*
* CF의 Move/Resize 처리
*
* Handle the owning of interaction fragments when moving or resizing a CF.
*
* @param request
* @param combinedFragmentEditPart
* @param childEditPart
* @return
*/
@SuppressWarnings("unchecked")
public static Command getCombinedFragmentResizeChildrenCommand(ChangeBoundsRequest request,
GraphicalEditPart combinedFragmentEditPart,
GraphicalEditPart childEditPart) {
Point moveDelta = request.getMoveDelta();
Dimension sizeDelta = request.getSizeDelta();
IFigure cfFigure = combinedFragmentEditPart.getFigure();
Rectangle origCFBounds = cfFigure.getBounds().getCopy();
/* apex improved start */
cfFigure.translateToAbsolute(origCFBounds);
/* apex improved end */
/* apex replaced
cfFigure.getParent().translateToAbsolute(origCFBounds);
origCFBounds.translate(cfFigure.getParent().getBounds().getLocation());
*/
CompoundCommand compoundCmd = new CompoundCommand(ApexSequenceRequestConstants.APEX_COMMAND_LABEL_RESIZE_MOVE_COMBINEDFRAGMENT);
// specific case for move :
// we want the execution specifications graphically owned by the lifeline to move with the combined fragment, and the contained messages too
/* apex replaced
*/
if ( (childEditPart != null && ( moveDelta.x != 0 || moveDelta.y != 0 )) // resizeParent로 온 경우 moveDelta값이 있으면 수행
|| ( childEditPart == null && sizeDelta.equals(0, 0) && !moveDelta.equals(0, 0) ) ) { // childEditPart없이 직접 자기 CF를 변경하는 경우 sizeDelta값이 없고 moveDelta 값이 있을 때만 수행
/* apex added start */
//this CF, IO의 bound Resize
//boolean isResizeByChild = false;
//if ( childEditPart != null ) {
//isResizeByChild = true;
//}
CompoundCommand ccmd = apexGetResizeCombinedFragmentBoundsCommand(request, combinedFragmentEditPart, childEditPart, true);
List<Command> resizeCmds = ccmd.getCommands();
for ( Command cmd : resizeCmds ) {
if ( !cmd.canExecute() ) {
return UnexecutableCommand.INSTANCE;
} else {
compoundCmd.add(cmd);
}
}
/* apex added end */
// retrieve all the edit parts in the registry
/* apex replaced
Set<Entry<Object, EditPart>> allEditPartEntries = combinedFragmentEditPart.getViewer().getEditPartRegistry().entrySet();
for(Entry<Object, EditPart> epEntry : allEditPartEntries) {
*/
List<EditPart> coveredChildrenEditParts = ApexSequenceUtil.apexGetCombinedFragmentChildrenEditParts((CombinedFragmentEditPart)combinedFragmentEditPart);
for ( EditPart ep : coveredChildrenEditParts ) {
//EditPart ep = epEntry.getValue();
// handle move of object graphically owned by the lifeline
// ExecSpec은 아래 로직을 따라 이동
if(ep instanceof ShapeEditPart) {
ShapeEditPart sep = (ShapeEditPart)ep;
EObject elem = sep.getNotationView().getElement();
if(elem instanceof InteractionFragment) {
IFigure figure = sep.getFigure();
Rectangle figureBounds = figure.getBounds().getCopy();
/* apex improved start */
figure.translateToAbsolute(figureBounds);
/* apex improved end */
/* apex replaced
figure.getParent().translateToAbsolute(figureBounds);
*/
/* apex improved start */
// sep 가 CFBounds에 포함되거나
// sep 가 CFBounds에 포함되지 않고 잘리더라도, ExecSpec이면 이동시킴
if (origCFBounds.contains(figureBounds)
|| (origCFBounds.intersects(figureBounds)
&& (sep instanceof ActionExecutionSpecificationEditPart || sep instanceof BehaviorExecutionSpecificationEditPart))) {
EditPart parentEP = sep.getParent();
if(parentEP instanceof LifelineEditPart) {
ChangeBoundsRequest esRequest = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
esRequest.setEditParts(sep);
esRequest.setMoveDelta(moveDelta);
Command moveESCommand = LifelineXYLayoutEditPolicy.getResizeOrMoveChildrenCommand((LifelineEditPart)parentEP, esRequest, true, false, true);
if(moveESCommand != null && !moveESCommand.canExecute()) {
// forbid move if the es can't be moved correctly
return UnexecutableCommand.INSTANCE;
} else if(moveESCommand != null) {
compoundCmd.add(moveESCommand);
}
}
}
/* apex improved end */
/* apex replaced
if(origCFBounds.contains(figureBounds)) {
EditPart parentEP = sep.getParent();
if(parentEP instanceof LifelineEditPart) {
ChangeBoundsRequest esRequest = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
esRequest.setEditParts(sep);
esRequest.setMoveDelta(moveDelta);
Command moveESCommand = LifelineXYLayoutEditPolicy.getResizeOrMoveChildrenCommand((LifelineEditPart)parentEP, esRequest, true, false, true);
if(moveESCommand != null && !moveESCommand.canExecute()) {
// forbid move if the es can't be moved correctly
return UnexecutableCommand.INSTANCE;
} else if(moveESCommand != null) {
compoundCmd.add(moveESCommand);
}
}
}
*/
}
}
// handle move of messages directly attached to a lifeline
if(ep instanceof ConnectionEditPart) {
ConnectionEditPart cep = (ConnectionEditPart)ep;
Connection msgFigure = cep.getConnectionFigure();
ConnectionAnchor sourceAnchor = msgFigure.getSourceAnchor();
ConnectionAnchor targetAnchor = msgFigure.getTargetAnchor();
Point sourcePoint = sourceAnchor.getReferencePoint();
Point targetPoint = targetAnchor.getReferencePoint();
Edge edge = (Edge)cep.getModel();
if(origCFBounds.contains(sourcePoint) && cep.getSource() instanceof LifelineEditPart) {
IdentityAnchor gmfAnchor = (IdentityAnchor)edge.getSourceAnchor();
Rectangle figureBounds = sourceAnchor.getOwner().getBounds();
compoundCmd.add(new ICommandProxy(getMoveAnchorCommand(moveDelta.y, figureBounds, gmfAnchor)));
}
if(origCFBounds.contains(targetPoint) && cep.getTarget() instanceof LifelineEditPart) {
IdentityAnchor gmfAnchor = (IdentityAnchor)edge.getTargetAnchor();
Rectangle figureBounds = targetAnchor.getOwner().getBounds();
compoundCmd.add(new ICommandProxy(getMoveAnchorCommand(moveDelta.y, figureBounds, gmfAnchor)));
}
/* apex added start */
// target ExecSpec이 잘려있는 경우 위의 438 line 이하 로직에 의해 이동하지 않으므로
// Target 이 ExecSpec 이고
// targetPoint가 CF에 포함되기만 하면(즉, ExecSpec 전체의 포함/잘림 여부와 관계없이) target Anchor 이동하도록 처리
if ( cep.getTarget() instanceof BehaviorExecutionSpecificationEditPart ||
cep.getTarget() instanceof ActionExecutionSpecificationEditPart ) {
ShapeNodeEditPart snep = (ShapeNodeEditPart)cep.getTarget();
IFigure execSpecFigure = snep.getFigure();
Rectangle execSpecBounds = snep.getFigure().getBounds().getCopy();
execSpecFigure.translateToAbsolute(execSpecBounds);
// ExecSpec이 CF에 포함되지 않고 잘려있는 경우에만 anchor 이동
if(!origCFBounds.contains(execSpecBounds) &&
origCFBounds.intersects(execSpecBounds)) {
IdentityAnchor gmfAnchor = (IdentityAnchor)edge.getTargetAnchor();
Rectangle figureBounds = targetAnchor.getOwner().getBounds();
//compoundCmd.add(new ICommandProxy(getMoveAnchorCommand(moveDelta.y, figureBounds, gmfAnchor)));
}
}
/* apex added end */
}
}
/* apex added start */
if ( moveDelta.y > 0 ) { // 아래로 이동 시
// belowEditPart, beneathEditPart를 구성하여 beneathEditPart보다 아래로 이동하는 경우 belowEditPart 모두 이동
apexMoveBelowItems(request, combinedFragmentEditPart, compoundCmd);
}
/* apex added end */
// 이동 끝
}
//} else { // resize 시작
if (sizeDelta.width != 0 || sizeDelta.height != 0 ) { // resize 시작
// calculate the new CF bounds
Rectangle newBoundsCF = origCFBounds.getCopy();
// 아래 translate는 moveDelta가 늘 0이므로 수행할 필요 없음
/* apex replaced
newBoundsCF.translate(moveDelta);
*/
/* apex added start */
//this CF, IO의 bound Resize
//boolean isResizeByChild = false;
//if ( childEditPart != null ) {
//isResizeByChild = true;
//}
CompoundCommand ccmd = apexGetResizeCombinedFragmentBoundsCommand(request, combinedFragmentEditPart, childEditPart, false);
List<Command> resizeCmds = ccmd.getCommands();
for ( Command cmd : resizeCmds ) {
if ( !cmd.canExecute() ) {
return UnexecutableCommand.INSTANCE;
} else {
compoundCmd.add(cmd);
}
}
/* apex added end */
/* apex replaced
newBoundsCF.resize(sizeDelta);
*/
CombinedFragment cf = (CombinedFragment)((CombinedFragmentEditPart)combinedFragmentEditPart).resolveSemanticElement();
// 아래 기존 로직은 CF의 첫번째 InteractionOperand의 상단에서의 resize 처리, 즉 두번째 이후 IOEP는 아래 로직 타지 않음
// 최종적인 IOEP의 경계처리는 CF생성때처럼 OperandBoundsComputeHelper.createUpdateIOBoundsForCFResizeCommand()에 의해 수행됨 - 146line 참조
// 그 외의 IOEP resize(첫번째 Op의 하단에서의 resize 나 두번째 이후 Op의 상/하단에서의 resize 처리는
// OperandBoundsComputeHelper.createIOEPResizeCommand()에 의해 처리
// InteractionOperandDragDropEditPolicy.getResizeCommand() 참조
if(combinedFragmentEditPart.getChildren().size() > 0 && combinedFragmentEditPart.getChildren().get(0) instanceof CombinedFragmentCombinedFragmentCompartmentEditPart) {
CombinedFragmentCombinedFragmentCompartmentEditPart compartment = (CombinedFragmentCombinedFragmentCompartmentEditPart)combinedFragmentEditPart.getChildren().get(0);
List<EditPart> combinedFragmentChildrenEditParts = compartment.getChildren();
List<InteractionOperandEditPart> interactionOperandEditParts = new ArrayList<InteractionOperandEditPart>();
InteractionOperand firstOperand = cf.getOperands().get(0);
// interaction fragments which will not be covered by the operands
Set<InteractionFragment> notCoveredAnymoreInteractionFragments = new HashSet<InteractionFragment>();
int headerHeight = 0;
// InteractionOperands 에 대해
for(EditPart ep : combinedFragmentChildrenEditParts) {
if(ep instanceof InteractionOperandEditPart) {
InteractionOperandEditPart ioEP = (InteractionOperandEditPart)ep;
InteractionOperand io = (InteractionOperand)ioEP.resolveSemanticElement();
// 이 InteractionOperand가 넘겨받은 CF의 Operands에 포함되는 경우
if(cf.getOperands().contains(io)) {
// interactionOperandEditParts에 이 InteractonOperandEditPart를 add하고
interactionOperandEditParts.add(ioEP);
// 이 Operand의 모든 Fragments를 notCovered List에 추가
// fill with all current fragments (filter later)
notCoveredAnymoreInteractionFragments.addAll(io.getFragments());
// 이 Operand가 첫번째 Operand이면
if(firstOperand.equals(io)) {
Rectangle boundsIO = ioEP.getFigure().getBounds().getCopy();
/* apex improved start */
// 이 Operand의 좌표를 절대좌표로 변환
ioEP.getFigure().translateToAbsolute(boundsIO);
/* apex improved end */
/* apex replacedd
ioEP.getFigure().getParent().translateToAbsolute(boundsIO);
*/
// 넘겨받은 CF와 이 Operand의 y차이만큼이 header Height
headerHeight = boundsIO.y - origCFBounds.y;
}
}
}
}
double heightRatio = (double)(newBoundsCF.height - headerHeight) / (double)(origCFBounds.height - headerHeight);
double widthRatio = (double)newBoundsCF.width / (double)origCFBounds.width;
for(InteractionOperandEditPart ioEP : interactionOperandEditParts) {
InteractionOperand io = (InteractionOperand)ioEP.resolveSemanticElement();
// 이 IO의 절대좌표
Rectangle newBoundsIO = SequenceUtil.getAbsoluteBounds(ioEP);
// moveDelta만큼 이동
// apply the move delta which will impact all operands
//newBoundsIO.translate(moveDelta);
// 경계값 변경
// calculate the new bounds of the interaction operand
// scale according to the ratio
newBoundsIO.height = (int)(newBoundsIO.height * heightRatio);
newBoundsIO.width = (int)(newBoundsIO.width * widthRatio);
// 첫번째 Operand의 경우 Header영역도 Operand에 포함(io의 y값은 감소시키고, 그만큼 height는 확장)
if(firstOperand.equals(io)) {
// ioep 의 highestChild의 top 아래로 축소 resize 금지
if (sizeDelta.height < 0 && (request.getResizeDirection() & PositionConstants.NORTH) != 0 ) {
IGraphicalEditPart highestChildEditPart = ApexSequenceUtil.apexGetHighestEditPartFromList(ioEP.getChildren());
if ( highestChildEditPart != null ) {
int topHighestChildEP = ApexSequenceUtil.apexGetAbsolutePosition(highestChildEditPart, SWT.TOP);
int topCurrentIOEP = ApexSequenceUtil.apexGetAbsolutePosition(ioEP, SWT.TOP) - sizeDelta.height;
if ( topCurrentIOEP >= topHighestChildEP ) {
return UnexecutableCommand.INSTANCE;
}
}
}
// ioep의 child가 ioep의 하단 아래로 밀려내려가는 것 방지
if ( OperandBoundsComputeHelper.apexIsInvadingTargetChildren(ioEP, compartment, PositionConstants.NORTH, sizeDelta.height) ) {
return UnexecutableCommand.INSTANCE;
}
// used to compensate the height of the "header" where the OperandKind is stored
newBoundsIO.y -= headerHeight;
newBoundsIO.height += headerHeight;
}
// 넘겨받은 CF와 그 Operands를 ignoreSet에 추가(새 경계에 새로 포함되는 fragment만 나중에 추출하기 위해 기존 Fragment는 ignoreSet에 추가)
// ignore current CF and enclosed IO
Set<InteractionFragment> ignoreSet = new HashSet<InteractionFragment>();
ignoreSet.add(cf);
ignoreSet.addAll(cf.getOperands());
// 새 경계에 포함되는 Fragments 추출
Set<InteractionFragment> coveredInteractionFragments = SequenceUtil.getCoveredInteractionFragments(newBoundsIO, combinedFragmentEditPart, ignoreSet);
// 새 경계에 잘리는 Fragments가 있을 경우 null
if(coveredInteractionFragments == null) {
return UnexecutableCommand.INSTANCE;
}
// notCovered에서 새 경계에 포함되는 Fragments는 제외, 즉 기존 경계에 포함되었던 Fragment를 notCovered에서 제외, 즉 covered로 처리
// remove fragments that are covered by this operand from the notCovered set
notCoveredAnymoreInteractionFragments.removeAll(coveredInteractionFragments);
// 새 경계에 포함되는 Fragments의 EnclosingInteraction으로 io를 setting
// set the enclosing operand to the moved/resized one if the current enclosing interaction is the enclosing interaction
// of the moved/resized operand or of another.
// => the interaction fragment that are inside an other container (like an enclosed CF) are not modified
for(InteractionFragment ift : coveredInteractionFragments) {
if(!cf.equals(ift)) {
Interaction interactionOwner = ift.getEnclosingInteraction();
InteractionOperand ioOwner = ift.getEnclosingOperand();
// 포함하는 op가 null이 아니고 (포함하는 op가 cf를 포함하는 op와 같거나-이럴경우가 있나? cf가 포함하는 op의 owner인 경우)
// 또는
// 포함하는 interaction이 null이 아니고 (포함하는 interaction이 cf를 포함하는 interaction과 같거나 cf가 포함하는 interaction의 owner인 경우-이럴경우가 있나?)
if ((ioOwner != null && (ioOwner.equals(cf.getEnclosingOperand()) || cf.equals(ioOwner.getOwner())))
|| (interactionOwner != null && (interactionOwner.equals(cf.getEnclosingInteraction()) || cf.equals(interactionOwner.getOwner())))
) {
// io를 ift를 포함하는 interaction으로 set해주는 command를 compoundCmd에 추가
compoundCmd.add(new ICommandProxy(SequenceUtil.getSetEnclosingInteractionCommand(ioEP.getEditingDomain(), ift, io)));
}
}
}
/* apex replaced
for(InteractionFragment ift : coveredInteractionFragments) {
if(!cf.equals(ift)) {
Interaction interactionOwner = ift.getEnclosingInteraction();
InteractionOperand ioOwner = ift.getEnclosingOperand();
if((ioOwner != null && (ioOwner.equals(cf.getEnclosingOperand()) || cf.equals(ioOwner.getOwner()))) || (interactionOwner != null && (interactionOwner.equals(cf.getEnclosingInteraction()) || cf.equals(interactionOwner.getOwner())))) {
compoundCmd.add(new ICommandProxy(SequenceUtil.getSetEnclosingInteractionCommand(ioEP.getEditingDomain(), ift, io)));
}
}
}
*/
}
// notCovered에 포함된 ift는 원래 포함하는 operand나 interaction을 EnclosingInteraction으로 setting
for(InteractionFragment ift : notCoveredAnymoreInteractionFragments) {
if(cf.getEnclosingOperand() != null) {
compoundCmd.add(new ICommandProxy(SequenceUtil.getSetEnclosingInteractionCommand(combinedFragmentEditPart.getEditingDomain(), ift, cf.getEnclosingOperand())));
} else {
compoundCmd.add(new ICommandProxy(SequenceUtil.getSetEnclosingInteractionCommand(combinedFragmentEditPart.getEditingDomain(), ift, cf.getEnclosingInteraction())));
}
}
}
/* apex added start */
// 하향 확대 resize 시 아래에 있는 요소 이동 처리
if ( sizeDelta.height > 0 && (request.getResizeDirection() & PositionConstants.SOUTH) != 0) {
ChangeBoundsRequest moveBelowByResizeRequest = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
moveBelowByResizeRequest.setSizeDelta(sizeDelta);
moveBelowByResizeRequest.setResizeDirection(request.getResizeDirection());
moveBelowByResizeRequest.setEditParts(combinedFragmentEditPart);
apexMoveBelowItems(moveBelowByResizeRequest, combinedFragmentEditPart, compoundCmd);
}
if ( sizeDelta.width > 0
&& ((request.getResizeDirection() & PositionConstants.WEST) != 0
|| (request.getResizeDirection() & PositionConstants.EAST) != 0)) { // width 확대 시 포함하는 CF Resize
apexResizeParentCombinedFragments(request, combinedFragmentEditPart, compoundCmd);
}
/* apex added end */
}
/* apex replaced
// CombinedFragmentCombinedFragmentCompartmentItemSemanticEditPolicy 에서
// operand가 복수인 경우에 대한 validation이 있으므로
// operand가 복수일 경우 무조건 Warning 하는 아래 로직은 불필요하여 주석 처리
// Print a user notification when we are not sure the command is appropriated
EObject combinedFragment = combinedFragmentEditPart.resolveSemanticElement();
if(combinedFragment instanceof CombinedFragment && !sizeDelta.equals(0, 0)) {
if(((CombinedFragment)combinedFragment).getOperands().size() > 1) {
// append a command which notifies
Command notifyCmd = new Command() {
@Override
public void execute() {
NotificationBuilder warning = NotificationBuilder.createAsyncPopup(Messages.Warning_ResizeInteractionOperandTitle, NLS.bind(Messages.Warning_ResizeInteractionOperandTxt, System.getProperty("line.separator")));
warning.run();
}
@Override
public void undo() {
execute();
}
};
if(notifyCmd.canExecute()) {
compoundCmd.add(notifyCmd);
}
}
}
//*/
// return null instead of unexecutable empty compound command
if(compoundCmd.isEmpty()) {
return null;
}
return compoundCmd;
}
/* apex replaced
public static Command getCombinedFragmentResizeChildrenCommand(ChangeBoundsRequest request, CombinedFragmentEditPart combinedFragmentEditPart) {
Point moveDelta = request.getMoveDelta();
Dimension sizeDelta = request.getSizeDelta();
IFigure cfFigure = combinedFragmentEditPart.getFigure();
Rectangle origCFBounds = cfFigure.getBounds().getCopy();
cfFigure.getParent().translateToAbsolute(origCFBounds);
origCFBounds.translate(cfFigure.getParent().getBounds().getLocation());
CompoundCommand compoundCmd = new CompoundCommand();
// specific case for move :
// we want the execution specifications graphically owned by the lifeline to move with the combined fragment, and the contained messages too
if(sizeDelta.equals(0, 0)) {
// retrieve all the edit parts in the registry
Set<Entry<Object, EditPart>> allEditPartEntries = combinedFragmentEditPart.getViewer().getEditPartRegistry().entrySet();
for(Entry<Object, EditPart> epEntry : allEditPartEntries) {
EditPart ep = epEntry.getValue();
// handle move of object graphically owned by the lifeline
if(ep instanceof ShapeEditPart) {
ShapeEditPart sep = (ShapeEditPart)ep;
EObject elem = sep.getNotationView().getElement();
if(elem instanceof InteractionFragment) {
IFigure figure = sep.getFigure();
Rectangle figureBounds = figure.getBounds().getCopy();
figure.getParent().translateToAbsolute(figureBounds);
if(origCFBounds.contains(figureBounds)) {
EditPart parentEP = sep.getParent();
if(parentEP instanceof LifelineEditPart) {
ChangeBoundsRequest esRequest = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
esRequest.setEditParts(sep);
esRequest.setMoveDelta(moveDelta);
Command moveESCommand = LifelineXYLayoutEditPolicy.getResizeOrMoveChildrenCommand((LifelineEditPart)parentEP, esRequest, true, false, true);
if(moveESCommand != null && !moveESCommand.canExecute()) {
// forbid move if the es can't be moved correctly
return UnexecutableCommand.INSTANCE;
} else if(moveESCommand != null) {
compoundCmd.add(moveESCommand);
}
}
}
}
}
// handle move of messages directly attached to a lifeline
if(ep instanceof ConnectionEditPart) {
ConnectionEditPart cep = (ConnectionEditPart)ep;
Connection msgFigure = cep.getConnectionFigure();
ConnectionAnchor sourceAnchor = msgFigure.getSourceAnchor();
ConnectionAnchor targetAnchor = msgFigure.getTargetAnchor();
Point sourcePoint = sourceAnchor.getReferencePoint();
Point targetPoint = targetAnchor.getReferencePoint();
Edge edge = (Edge)cep.getModel();
if(origCFBounds.contains(sourcePoint) && cep.getSource() instanceof LifelineEditPart) {
IdentityAnchor gmfAnchor = (IdentityAnchor)edge.getSourceAnchor();
Rectangle figureBounds = sourceAnchor.getOwner().getBounds();
compoundCmd.add(new ICommandProxy(getMoveAnchorCommand(moveDelta.y, figureBounds, gmfAnchor)));
}
if(origCFBounds.contains(targetPoint) && cep.getTarget() instanceof LifelineEditPart) {
IdentityAnchor gmfAnchor = (IdentityAnchor)edge.getTargetAnchor();
Rectangle figureBounds = targetAnchor.getOwner().getBounds();
compoundCmd.add(new ICommandProxy(getMoveAnchorCommand(moveDelta.y, figureBounds, gmfAnchor)));
}
}
if (ep instanceof DurationConstraintEditPart) {
DurationConstraintEditPart dcp = (DurationConstraintEditPart) ep;
moveCoveredDurationConstraint(dcp, compoundCmd, origCFBounds, moveDelta);
}
}
} else {
// calculate the new CF bounds
Rectangle newBoundsCF = origCFBounds.getCopy();
newBoundsCF.translate(moveDelta);
newBoundsCF.resize(sizeDelta);
CombinedFragment cf = (CombinedFragment)((CombinedFragmentEditPart)combinedFragmentEditPart).resolveSemanticElement();
if(combinedFragmentEditPart.getChildren().size() > 0 && combinedFragmentEditPart.getChildren().get(0) instanceof CombinedFragmentCombinedFragmentCompartmentEditPart) {
CombinedFragmentCombinedFragmentCompartmentEditPart compartment = (CombinedFragmentCombinedFragmentCompartmentEditPart)combinedFragmentEditPart.getChildren().get(0);
List<EditPart> combinedFragmentChildrenEditParts = compartment.getChildren();
List<InteractionOperandEditPart> interactionOperandEditParts = new ArrayList<InteractionOperandEditPart>();
InteractionOperand firstOperand = cf.getOperands().get(0);
// interaction fragments which will not be covered by the operands
Set<InteractionFragment> notCoveredAnymoreInteractionFragments = new HashSet<InteractionFragment>();
int headerHeight = 0;
for(EditPart ep : combinedFragmentChildrenEditParts) {
if(ep instanceof InteractionOperandEditPart) {
InteractionOperandEditPart ioEP = (InteractionOperandEditPart)ep;
InteractionOperand io = (InteractionOperand)ioEP.resolveSemanticElement();
if(cf.getOperands().contains(io)) {
interactionOperandEditParts.add(ioEP);
// fill with all current fragments (filter later)
notCoveredAnymoreInteractionFragments.addAll(io.getFragments());
if(firstOperand.equals(io)) {
Rectangle boundsIO = ioEP.getFigure().getBounds().getCopy();
ioEP.getFigure().getParent().translateToAbsolute(boundsIO);
headerHeight = boundsIO.y - origCFBounds.y;
}
}
}
}
double heightRatio = (double)(newBoundsCF.height - headerHeight) / (double)(origCFBounds.height - headerHeight);
double widthRatio = (double)newBoundsCF.width / (double)origCFBounds.width;
for(InteractionOperandEditPart ioEP : interactionOperandEditParts) {
InteractionOperand io = (InteractionOperand)ioEP.resolveSemanticElement();
Rectangle newBoundsIO = SequenceUtil.getAbsoluteBounds(ioEP);
// apply the move delta which will impact all operands
newBoundsIO.translate(moveDelta);
// calculate the new bounds of the interaction operand
// scale according to the ratio
newBoundsIO.height = (int)(newBoundsIO.height * heightRatio);
newBoundsIO.width = (int)(newBoundsIO.width * widthRatio);
if(firstOperand.equals(io)) {
// used to compensate the height of the "header" where the OperandKind is stored
newBoundsIO.y -= headerHeight;
newBoundsIO.height += headerHeight;
}
// ignore current CF and enclosed IO
Set<InteractionFragment> ignoreSet = new HashSet<InteractionFragment>();
ignoreSet.add(cf);
ignoreSet.addAll(cf.getOperands());
Set<InteractionFragment> coveredInteractionFragments = SequenceUtil.getCoveredInteractionFragments(newBoundsIO, combinedFragmentEditPart, ignoreSet);
if(coveredInteractionFragments == null) {
return UnexecutableCommand.INSTANCE;
}
// remove fragments that are covered by this operand from the notCovered set
notCoveredAnymoreInteractionFragments.removeAll(coveredInteractionFragments);
// set the enclosing operand to the moved/resized one if the current enclosing interaction is the enclosing interaction
// of the moved/resized operand or of another.
// => the interaction fragment that are inside an other container (like an enclosed CF) are not modified
for(InteractionFragment ift : coveredInteractionFragments) {
if(!cf.equals(ift)) {
Interaction interactionOwner = ift.getEnclosingInteraction();
InteractionOperand ioOwner = ift.getEnclosingOperand();
if((ioOwner != null && (ioOwner.equals(cf.getEnclosingOperand()) || cf.equals(ioOwner.getOwner()))) || (interactionOwner != null && (interactionOwner.equals(cf.getEnclosingInteraction()) || cf.equals(interactionOwner.getOwner())))) {
compoundCmd.add(new ICommandProxy(SequenceUtil.getSetEnclosingInteractionCommand(ioEP.getEditingDomain(), ift, io)));
}
}
}
}
for(InteractionFragment ift : notCoveredAnymoreInteractionFragments) {
if(cf.getEnclosingOperand() != null) {
compoundCmd.add(new ICommandProxy(SequenceUtil.getSetEnclosingInteractionCommand(combinedFragmentEditPart.getEditingDomain(), ift, cf.getEnclosingOperand())));
} else {
compoundCmd.add(new ICommandProxy(SequenceUtil.getSetEnclosingInteractionCommand(combinedFragmentEditPart.getEditingDomain(), ift, cf.getEnclosingInteraction())));
}
}
}
}
// Print a user notification when we are not sure the command is appropriated
EObject combinedFragment = combinedFragmentEditPart.resolveSemanticElement();
if(combinedFragment instanceof CombinedFragment && !sizeDelta.equals(0, 0)) {
if(((CombinedFragment)combinedFragment).getOperands().size() > 1) {
// append a command which notifies
Command notifyCmd = new Command() {
@Override
public void execute() {
NotificationBuilder warning = NotificationBuilder.createAsyncPopup(Messages.Warning_ResizeInteractionOperandTitle, NLS.bind(Messages.Warning_ResizeInteractionOperandTxt, System.getProperty("line.separator")));
warning.run();
}
@Override
public void undo() {
execute();
}
};
if(notifyCmd.canExecute()) {
compoundCmd.add(notifyCmd);
}
}
}
// return null instead of unexecutable empty compound command
if(compoundCmd.isEmpty()) {
return null;
}
return compoundCmd;
}
*/
private static void moveCoveredDurationConstraint(DurationConstraintEditPart dcp, CompoundCommand compoundCmd,
Rectangle origCFBounds, Point moveDelta) {
Rectangle r = dcp.getFigure().getBounds().getCopy();
dcp.getFigure().translateToAbsolute(r);
if (origCFBounds.contains(r)) {
//see org.eclipse.gmf.runtime.diagram.ui.editpolicies.BorderItemSelectionEditPolicy.getMoveCommand(ChangeBoundsRequest)
IBorderItemEditPart borderItemEP = (IBorderItemEditPart) dcp;
IBorderItemLocator borderItemLocator = borderItemEP
.getBorderItemLocator();
Rectangle realLocation = borderItemLocator
.getValidLocation(dcp.getFigure().getBounds()
.getCopy(), borderItemEP.getFigure());
Point parentOrigin = borderItemEP.getFigure()
.getParent().getBounds().getTopLeft();
Dimension d = realLocation.getTopLeft().getDifference(
parentOrigin);
Point location = new Point(d.width, d.height);
location = location.translate(0, moveDelta.y);
ICommandProxy resize = new ICommandProxy(
new SetBoundsCommand(dcp.getEditingDomain(),
DiagramUIMessages.Commands_MoveElement,
new EObjectAdapter((View) dcp.getModel()),
location));
compoundCmd.add(resize);
}
}
private static ICommand getMoveAnchorCommand(int yDelta, Rectangle figureBounds, IdentityAnchor gmfAnchor) {
String oldTerminal = gmfAnchor.getId();
PrecisionPoint pp = BaseSlidableAnchor.parseTerminalString(oldTerminal);
int yPos = (int)Math.round(figureBounds.height * pp.preciseY);
yPos += yDelta;
pp.preciseY = (double)yPos / figureBounds.height;
if(pp.preciseY > 1.0) {
pp.preciseY = 1.0;
} else if(pp.preciseY < 0.0) {
pp.preciseY = 0.0;
}
String newTerminal = (new BaseSlidableAnchor(null, pp)).getTerminal();
return new SetValueCommand(new SetRequest(gmfAnchor, NotationPackage.Literals.IDENTITY_ANCHOR__ID, newTerminal));
}
/**
* Change constraint for comportment by return null if the resize is lower than the minimun
* size.
*/
@Override
protected Object getConstraintFor(ChangeBoundsRequest request, org.eclipse.gef.GraphicalEditPart child) {
Rectangle rect = new PrecisionRectangle(child.getFigure().getBounds());
child.getFigure().translateToAbsolute(rect);
rect = request.getTransformedRectangle(rect);
child.getFigure().translateToRelative(rect);
rect.translate(getLayoutOrigin().getNegated());
if(request.getSizeDelta().width == 0 && request.getSizeDelta().height == 0) {
Rectangle cons = getCurrentConstraintFor(child);
if(cons != null) {
rect.setSize(cons.width, cons.height);
}
} else { // resize editpart
boolean skipMinSize = false;
if(child instanceof LifelineEditPart)// && LifelineResizeHelper.isManualSize((LifelineEditPart)child))
skipMinSize = true;
Dimension minSize = getMinimumSizeFor(child);
if(rect.width < minSize.width && !skipMinSize) { // In manual mode, there is no minimal width
return null;
}
if(rect.height < minSize.height ) {
return null;
}
}
rect = (Rectangle)getConstraintFor(rect);
Rectangle cons = getCurrentConstraintFor(child);
if(request.getSizeDelta().width == 0) {
rect.width = cons.width;
}
if(request.getSizeDelta().height == 0) {
rect.height = cons.height;
}
return rect;
}
/**
* Handle mininum size for lifeline
*/
@Override
protected Dimension getMinimumSizeFor(org.eclipse.gef.GraphicalEditPart child) {
Dimension minimunSize;
if(child instanceof LifelineEditPart) {
minimunSize = getMinimumSizeFor((LifelineEditPart)child);
} else {
minimunSize = super.getMinimumSizeFor(child);
}
return minimunSize;
}
/**
* Get minimun for a lifeline
*
* @param child
* The lifeline
* @return The minimun size
*/
private Dimension getMinimumSizeFor(LifelineEditPart child) {
LifelineEditPart lifelineEditPart = child;
Dimension minimunSize = lifelineEditPart.getFigure().getMinimumSize();
for(LifelineEditPart lifelineEP : lifelineEditPart.getInnerConnectableElementList()) {
minimunSize.union(getMinimumSizeFor(lifelineEP));
}
for(ShapeNodeEditPart executionSpecificationEP : lifelineEditPart.getChildShapeNodeEditPart()) {
int minimunHeight = executionSpecificationEP.getFigure().getBounds().bottom();
minimunSize.setSize(new Dimension(minimunSize.width, Math.max(minimunSize.height, minimunHeight)));
}
return minimunSize;
}
/**
* Block adding element by movement on Interaction
*/
@Override
public Command getAddCommand(Request request) {
if(request instanceof ChangeBoundsRequest) {
return UnexecutableCommand.INSTANCE;
}
return super.getAddCommand(request);
}
/**
* Overrides to change the policy of connection anchors when resizing the lifeline.
* When resizing the lifeline, the connection must not move.
*
* @see org.eclipse.gmf.runtime.diagram.ui.editpolicies.XYLayoutEditPolicy#getCommand(org.eclipse.gef.Request)
*/
@SuppressWarnings("unchecked")
@Override
public Command getCommand(Request request) {
if(request instanceof ChangeBoundsRequest) {
ChangeBoundsRequest cbr = (ChangeBoundsRequest)request;
int resizeDirection = cbr.getResizeDirection();
CompoundCommand compoundCmd = new CompoundCommand("Resize of Interaction Compartment Elements");
for(EditPart ep : (List<EditPart>)cbr.getEditParts()) {
if(ep instanceof LifelineEditPart && isHorizontalMove(cbr)) {
// Lifeline EditPart
LifelineEditPart lifelineEP = (LifelineEditPart)ep;
int preserveY = PreserveAnchorsPositionCommand.PRESERVE_Y;
Dimension newSizeDelta = PreserveAnchorsPositionCommand.getSizeDeltaToFitAnchors(lifelineEP, cbr.getSizeDelta(), preserveY);
// SetBounds command modifying the sizeDelta
compoundCmd.add(getSetBoundsCommand(lifelineEP, cbr, newSizeDelta));
// PreserveAnchors command
compoundCmd.add(new ICommandProxy(new LifelineEditPart.PreserveAnchorsPositionCommandEx(lifelineEP, newSizeDelta, preserveY, lifelineEP.getPrimaryShape().getFigureLifelineDotLineFigure(), resizeDirection)));
}
}
if(compoundCmd.size() == 0) {
return super.getCommand(request);
} else {
return compoundCmd;
}
}
return super.getCommand(request);
}
/**
* It obtains an appropriate SetBoundsCommand for a LifelineEditPart. The
* newSizeDelta provided should be equal o less than the one contained in
* the request. The goal of this newDelta is to preserve the anchors'
* positions after the resize. It is recommended to obtain this newSizeDelta
* by means of calling
* PreserveAnchorsPositionCommand.getSizeDeltaToFitAnchors() operation
*
* @param lifelineEP
* The Lifeline that will be moved or resized
* @param cbr
* The ChangeBoundsRequest for moving or resized the lifelineEP
* @param newSizeDelta
* The sizeDelta to used instead of the one contained in the
* request
* @return The SetBoundsCommand
*/
@SuppressWarnings("rawtypes")
protected Command getSetBoundsCommand(LifelineEditPart lifelineEP, ChangeBoundsRequest cbr, Dimension newSizeDelta) {
// Modify request
List epList = cbr.getEditParts();
Dimension oldSizeDelta = cbr.getSizeDelta();
cbr.setEditParts(lifelineEP);
cbr.setSizeDelta(newSizeDelta);
// Obtain the command with the modified request
Command cmd = super.getCommand(cbr);
// Restore the request
cbr.setEditParts(epList);
cbr.setSizeDelta(oldSizeDelta);
// Return the SetBoundsCommand only for the Lifeline and with the
// sizeDelta modified in order to preserve the links' anchors positions
return cmd;
}
/**
* Align lifeline in vertical direction
* Fix https://bugs.eclipse.org/bugs/show_bug.cgi?id=364688
*/
protected Rectangle getBoundsOffest(CreateViewRequest request,
Rectangle bounds, CreateViewRequest.ViewDescriptor viewDescriptor) {
int translate = request.getViewDescriptors().indexOf(viewDescriptor) * 10;
Rectangle target = bounds.getCopy().translate(translate, translate);
if (((IHintedType) UMLElementTypes.Lifeline_3001).getSemanticHint()
.equals(viewDescriptor.getSemanticHint())) {
target.setY(SequenceUtil.LIFELINE_VERTICAL_OFFSET);
}
return target;
}
@Override
protected void showSizeOnDropFeedback(CreateRequest request) {
super.showSizeOnDropFeedback(request);
if(request instanceof CreateAspectUnspecifiedTypeRequest){
CreateAspectUnspecifiedTypeRequest req = (CreateAspectUnspecifiedTypeRequest)request;
if(req.getElementTypes().contains(UMLElementTypes.CombinedFragment_3004) || req.getElementTypes().contains(UMLElementTypes.ConsiderIgnoreFragment_3007)){
IFigure feedback = getSizeOnDropFeedback(request);
Rectangle b = feedback.getBounds().getCopy();
feedback.translateToAbsolute(b);
HighlightUtil.showSizeOnDropFeedback(request, getHost(),feedback,b);
}
}
}
@Override
protected void eraseSizeOnDropFeedback(Request request) {
HighlightUtil.eraseSizeOnDropFeedback(request, getHost());
super.eraseSizeOnDropFeedback(request);
}
}