/*****************************************************************************
* 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.parts;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.notation.Bounds;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.Shape;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.uml.diagram.sequence.apex.util.ApexSequenceUtil;
import org.eclipse.papyrus.uml.diagram.sequence.apex.util.LifelineFigureHelper;
import org.eclipse.papyrus.uml.diagram.sequence.figures.LifelineDotLineCustomFigure;
import org.eclipse.papyrus.uml.diagram.sequence.util.CommandHelper;
import org.eclipse.papyrus.uml.diagram.sequence.util.SequenceUtil;
import org.eclipse.uml2.uml.CombinedFragment;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.Lifeline;
import org.eclipse.uml2.uml.PartDecomposition;
import org.eclipse.uml2.uml.UMLPackage;
public abstract class InteractionFragmentEditPart extends ShapeNodeEditPart {
public InteractionFragmentEditPart(View view) {
super(view);
}
@Override
public void activate() {
super.activate();
/* apex added start */
apexUpdateCoveredFigures();
/* apex added end */
}
@Override
public void deactivate() {
/* apex added start */
Rectangle region = getFigure().getBounds().getCopy();
LifelineFigureHelper.showAllRegion(region);
/* apex added end */
super.deactivate();
}
/**
* View의 Bounds 프로퍼티를 구함
*
* @param view
* @return
*/
private Rectangle apexGetViewBounds(View view) {
if (view instanceof Node && ((Node)view).getLayoutConstraint() instanceof Bounds) {
Bounds b = (Bounds)((Node)view).getLayoutConstraint();
return new Rectangle(b.getX(), b.getY(), b.getWidth(), b.getHeight());
}
return new Rectangle(0, 0, 0, 0);
}
/**
* InteractionFragment가 생성될 때 covereds가 아닌 Lifeline들에 hide될 region을 등록
* InteractionFragment의 EditPart/Figure가 생성이 안되었을 수도 있으므로 View의 Bounds를 통해 영역을 구함
*/
private void apexUpdateCoveredFigures() {
InteractionFragment ift = (InteractionFragment)resolveSemanticElement();
Interaction interaction = ift.getEnclosingInteraction();
EList<Lifeline> coveredLifelines = ift.getCovereds();
View view = getNotationView();
EObject container = view.eContainer();
while (container != null && container instanceof View == false) {
if (interaction == ((View)container).getElement()) {
break;
}
container = container.eContainer();
}
if (container instanceof View == false) {
return;
}
View parent = (View)container;
for (Object child : parent.getChildren()) {
if (child instanceof View) {
EObject element = ((View)child).getElement();
if (element instanceof Lifeline && !coveredLifelines.contains(element)) {
Rectangle lifelineRect = apexGetViewBounds((View)child);
Rectangle centralLineRect = new Rectangle(lifelineRect.x() + lifelineRect.width() / 2, lifelineRect.y(),
1, lifelineRect.height());
apexUpdateCoveredFigure(view, (Lifeline)element, centralLineRect);
}
}
}
}
/**
* InteractionFragment가 생성될 때 covereds가 아닌 Lifeline들에 hide될 region을 등록
* InteractionFragment의 EditPart/Figure가 생성이 안되었을 수도 있으므로 View의 Bounds를 통해 영역을 구함
*
* @param view InteractionFragment의 View
* @param lifeline 현재 선택된 lifeline
* @param bounds lifeline의 central bounds
*/
private void apexUpdateCoveredFigure(View view, Lifeline lifeline, Rectangle bounds) {
LifelineEditPart lifelineEP = (LifelineEditPart)SequenceUtil.getEditPart(this, lifeline, LifelineEditPart.class);
if (lifelineEP == null) {
return;
}
IFigure figure = lifelineEP.getPrimaryShape().getFigureLifelineDotLineFigure();
Rectangle region = apexGetViewBounds(view);
if (region.width > 0 && region.height > 0) {
if (bounds.height <= 0) {
bounds.height = region.height;
}
if (region.intersects(bounds)) {
LifelineFigureHelper.hideRegion(figure, region);
}
}
}
/**
* Resize the InteractionFragmentFigure when the covered lifelines are selected in the
* properties view.
*/
public void resizeInteractionFragmentFigure() {
Object obj = getModel();
if(obj instanceof Shape) {
// we get the element linked to this editpart
EObject element = ((Shape)obj).getElement();
if(element instanceof InteractionFragment) {
// we get the list of the covered lifelinnes by the InteractionUse
List<Lifeline> lifelineCoveredList = ((InteractionFragment)element).getCovereds();
if(lifelineCoveredList != null && getParent() != null) {
// we get the interactionCompartimentEditPart to have access to all lifelines
// EditParts
List<EditPart> childrenEditPart = getParent().getChildren();
if(childrenEditPart != null) {
// The max value guarantee that the first figure will set the minX value
int minX = Integer.MAX_VALUE;
int maxX = -Integer.MAX_VALUE;
int maxR = -Integer.MAX_VALUE;
for(EditPart childEditPart : childrenEditPart) {
// we check all the EditParts to select only the lifelineEditParts
if(childEditPart instanceof LifelineEditPart) {
Object childModel = childEditPart.getModel();
if(childModel instanceof Shape) {
// we get the object Lifeline linked the selected
// lifelineEditPart
EObject childElement = ((Shape)childModel).getElement();
if(childElement instanceof Lifeline) {
Lifeline lifeline = (Lifeline)childElement;
for(Lifeline lfn : lifelineCoveredList) {
// we check if the lifeLine in the intreactionUse's
// parent Interaction is a covered Lifeline
if(lifeline.equals(lfn)) {
LifelineEditPart liflelineEditPart = (LifelineEditPart)childEditPart;
if(liflelineEditPart.getFigure().getBounds().x > maxX) {
maxX = liflelineEditPart.getFigure().getBounds().x;
// the maxR will represent the futur value of
// the rectangle right value.
maxR = liflelineEditPart.getFigure().getBounds().right();
}
if(liflelineEditPart.getFigure().getBounds().x < minX) {
// the min value will represent the rectangle x
// value.
minX = liflelineEditPart.getFigure().getBounds().x;
}
}
}
}
}
}
}
if(minX != Integer.MAX_VALUE || maxR != -Integer.MAX_VALUE) {
// after this loop we have the coordinate of two lifeline figure ,
// even if we have more than two covered Lifelne we choose the
// extremities.
getNewSize(minX, maxR);
}
}
}
}
}
}
/**
* resize the interactinUse figure
*
* @param min
* the min x position of a covered lifline
* @param max
* the max x position of a coverd lifeline
*
*/
private void getNewSize(int min, int max) {
int h = getFigure().getBounds().height;
int y = getFigure().getBounds().y;
Dimension size = new Dimension(max - min, h);
Point loc = new Point(min, y);
((GraphicalEditPart)getParent()).setLayoutConstraint(this, getFigure(), new Rectangle(loc, size));
}
/**
* apex updated
*
* CombinedFragmentEditPart.handleNotificationEvent()에서 호출되지 않아서
* 호출하도록 CombinedFragmentEditPart 수정
*
* Update covered lifelines of a Interaction fragment
*
* @param newBounds
*/
public void updateCoveredLifelines(Bounds newBounds) {
Rectangle newBound = new Rectangle(newBounds.getX(), newBounds.getY(), newBounds.getWidth(), newBounds.getHeight());
InteractionFragment combinedFragment = (InteractionFragment)resolveSemanticElement();
EList<Lifeline> coveredLifelines = combinedFragment.getCovereds();
List<Lifeline> coveredLifelinesToAdd = new ArrayList<Lifeline>();
List<Lifeline> coveredLifelinesToRemove = new ArrayList<Lifeline>();
EditPart interactionCompartment = getInteractionCompartment();
if(interactionCompartment != null) {
/* apex improved start */
Rectangle origRect = this.getFigure().getBounds().getCopy();
Rectangle newRect = newBound.getCopy();
this.getFigure().translateToAbsolute(origRect);
this.getFigure().translateToAbsolute(newRect);
List<LifelineEditPart> lifelineEditPartsToCheck = new ArrayList<LifelineEditPart>();
// Jiho start
EObject container = resolveSemanticElement().eContainer();
List<Lifeline> coveredLifelinesByParent = new ArrayList<Lifeline>();
if (container instanceof Interaction) {
coveredLifelinesByParent.addAll(((Interaction)container).getLifelines());
} else if (container instanceof InteractionFragment) {
coveredLifelinesByParent.addAll(((InteractionFragment)container).getCovereds());
}
if (origRect.width == 0 && origRect.height == 0) { // 새 CombinedFragment 생성하는 경우 Interaction 내 모든 Lifeline을 check
Set<Entry<Object, EditPart>> allEditPartEntries = getViewer().getEditPartRegistry().entrySet();
for(Entry<Object, EditPart> epEntry : allEditPartEntries) {
EditPart ep = epEntry.getValue();
if (ep instanceof LifelineEditPart) {
LifelineEditPart lifelineEP = (LifelineEditPart)ep;
Lifeline lifeline = (Lifeline)lifelineEP.resolveSemanticElement();
if (coveredLifelinesByParent.contains(lifeline)) {
lifelineEditPartsToCheck.add(lifelineEP);
coveredLifelinesToAdd.add((Lifeline)lifelineEP.resolveSemanticElement());
}
}
}
} else { // 새로 생성이 아닌 CF 경계 변경인 경우
List<LifelineEditPart> coveredLifelineEditParts = null;
if (origRect.width > newRect.width) { // width 축소 시 원래 경계 내에 있던 lifeline을 check
coveredLifelineEditParts = ApexSequenceUtil.apexGetPositionallyCoveredLifelineEditParts(origRect, this);
} else if (origRect.width < newRect.width) { // width 확대 시 새 경계내에 있는 lifeline을 check
coveredLifelineEditParts = ApexSequenceUtil.apexGetPositionallyCoveredLifelineEditParts(newRect, this);
} else {
coveredLifelineEditParts = new ArrayList<LifelineEditPart>(0);
}
for (LifelineEditPart lifelineEP : coveredLifelineEditParts) {
Lifeline lifeline = (Lifeline)lifelineEP.resolveSemanticElement();
if (coveredLifelinesByParent.contains(lifeline)) {
lifelineEditPartsToCheck.add(lifelineEP);
}
}
}
// Jiho end
/*
if (origRect.width == 0 && origRect.height == 0) { // 새 CombinedFragment 생성하는 경우 Interaction 내 모든 Lifeline을 check
Set<Entry<Object, EditPart>> allEditPartEntries = getViewer().getEditPartRegistry().entrySet();
for(Entry<Object, EditPart> epEntry : allEditPartEntries) {
EditPart ep = epEntry.getValue();
if( ep instanceof LifelineEditPart ) {
LifelineEditPart lifelineEditPart = (LifelineEditPart)ep;
lifelineEditPartsToCheck.add(lifelineEditPart);
coveredLifelinesToAdd.add((Lifeline)lifelineEditPart.resolveSemanticElement());
}
}
} else { // 새로 생성이 아닌 CF 경계 변경인 경우
if (origRect.width > newRect.width ) { // width 축소 시 원래 경계 내에 있던 lifeline을 check
lifelineEditPartsToCheck = ApexSequenceUtil.apexGetPositionallyCoveredLifelineEditParts(origRect, this);
} else if (origRect.width < newRect.width) { // width 확대 시 새 경계내에 있는 lifeline을 check
lifelineEditPartsToCheck = ApexSequenceUtil.apexGetPositionallyCoveredLifelineEditParts(newRect, this);
}
}
*/
// 상하이동의 경우 covereds가 바뀔 일이 없으므로
// 상하이동이 아닌 경우만 updateCoveredLifelines 호출
for(Object lifelineEditPartToCheck : lifelineEditPartsToCheck) {
if(lifelineEditPartToCheck instanceof LifelineEditPart) {
LifelineEditPart lifelineEditPart = (LifelineEditPart)lifelineEditPartToCheck;
updateCoveredLifelines(lifelineEditPart, newBound, coveredLifelinesToAdd, coveredLifelinesToRemove, coveredLifelines);
}
}
/* apex improved end */
/* apex replaced
this.getFigure().translateToAbsolute(newBound);
for(Object child : interactionCompartment.getChildren()) {
if(child instanceof LifelineEditPart) {
LifelineEditPart lifelineEditPart = (LifelineEditPart)child;
updateCoveredLifelines(lifelineEditPart, newBound, coveredLifelinesToAdd, coveredLifelinesToRemove, coveredLifelines);
}
}
*/
}
if(!coveredLifelinesToAdd.isEmpty()) {
CommandHelper.executeCommandWithoutHistory(getEditingDomain(), AddCommand.create(getEditingDomain(), combinedFragment, UMLPackage.eINSTANCE.getInteractionFragment_Covered(), coveredLifelinesToAdd), true);
}
if(!coveredLifelinesToRemove.isEmpty()) {
/* apex added start */
// Jiho - bounds에서 제외되어 삭제되는 lifeline이 이미 covered가 아닌 경우
Rectangle origRect = getFigure().getBounds().getCopy();
for (Lifeline lifeline : coveredLifelinesToRemove) {
LifelineEditPart lifelineEP = (LifelineEditPart)SequenceUtil.getEditPart(this, lifeline, LifelineEditPart.class);
if (!coveredLifelines.contains(lifeline) && lifelineEP != null) {
LifelineDotLineCustomFigure customFigure = lifelineEP.getPrimaryShape().getFigureLifelineDotLineFigure();
LifelineFigureHelper.showRegion(customFigure, origRect);
}
}
/* apex added end */
CommandHelper.executeCommandWithoutHistory(getEditingDomain(), RemoveCommand.create(getEditingDomain(), combinedFragment, UMLPackage.eINSTANCE.getInteractionFragment_Covered(), coveredLifelinesToRemove), true);
}
/* apex added start */
if (coveredLifelinesToAdd.isEmpty() && coveredLifelinesToRemove.isEmpty() && !coveredLifelines.isEmpty()) {
coveredLifelinesToRemove.addAll(coveredLifelines);
coveredLifelinesToAdd.addAll(coveredLifelines);
CommandHelper.executeCommandWithoutHistory(getEditingDomain(), RemoveCommand.create(getEditingDomain(), combinedFragment, UMLPackage.eINSTANCE.getInteractionFragment_Covered(), coveredLifelinesToRemove), true);
CommandHelper.executeCommandWithoutHistory(getEditingDomain(), AddCommand.create(getEditingDomain(), combinedFragment, UMLPackage.eINSTANCE.getInteractionFragment_Covered(), coveredLifelinesToAdd), true);
}
/* apex added end */
}
/**
* apex updated
*
* 0.9에서 추가된 메서드
* check lifelines in PartDecomposition, see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=364813
*
* @param lifelineEditPart
* @param newCFBounds
* @param coveredLifelinesToAdd
* @param coveredLifelinesToRemove
* @param coveredLifelines
*/
// check lifelines in PartDecomposition, see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=364813
private void updateCoveredLifelines(LifelineEditPart lifelineEditPart, Rectangle newCFBounds, List<Lifeline> coveredLifelinesToAdd, List<Lifeline> coveredLifelinesToRemove, EList<Lifeline> coveredLifelines) {
Lifeline lifeline = (Lifeline)lifelineEditPart.resolveSemanticElement();
LifelineDotLineCustomFigure dotLineFigure = lifelineEditPart.getPrimaryShape().getFigureLifelineDotLineFigure();
Rectangle dotLineBounds = dotLineFigure.getBounds().getCopy();
Rectangle centralLineBounds = new Rectangle(dotLineBounds.x() + dotLineBounds.width() / 2, dotLineBounds.y(), 1, dotLineBounds.height());
dotLineFigure.translateToAbsolute(centralLineBounds);
/* apex improved start */
Rectangle origRect = this.getFigure().getBounds().getCopy();
Rectangle newRect = newCFBounds.getCopy();
this.getFigure().translateToAbsolute(origRect);
this.getFigure().translateToAbsolute(newRect);
Rectangle lifelineRect = lifelineEditPart.getFigure().getBounds().getCopy();
lifelineEditPart.getFigure().translateToAbsolute(lifelineRect);
// 새 경계와 lifeline 경계가 교차되고
if (newRect.intersects(centralLineBounds)) { // Jiho: lifelineRect -> centralLineBounds
// 원래의 covered에 없던 lifeline이면
if(!coveredLifelines.contains(lifeline)) {
// 원래 CF에 포함되어 있으면서 coveredLifelines에 없는 것은
// Property창에서 수동으로 covereds에서 제외한 것이므로
// 원래 CF에 포함되지 않았던 경우에만 add
if (!origRect.intersects(centralLineBounds)) { // Jiho: lifelineRect -> centralLineBounds
if (!coveredLifelinesToAdd.contains(lifeline)) {
coveredLifelinesToAdd.add(lifeline);
}
}
}
// 새 경계와 lifeline 경계가 교차되지 않고
// 원래 covered에 있던 lifeline은 remove
} else {
coveredLifelinesToRemove.add(lifeline);
}
/* apex improved end */
/* apex replaced
if(newBound.intersects(centralLineBounds)) {
if(!coveredLifelines.contains(lifeline)) {
coveredLifelinesToAdd.add(lifeline);
}
} else if(coveredLifelines.contains(lifeline)) {
coveredLifelinesToRemove.add(lifeline);
}
*/
PartDecomposition partDecomposition = lifeline.getDecomposedAs();
if(partDecomposition != null) {
List subLifelines = lifelineEditPart.getChildren();
for(Object child : subLifelines) {
if(child instanceof LifelineEditPart) {
updateCoveredLifelines((LifelineEditPart)child, newCFBounds, coveredLifelinesToAdd, coveredLifelinesToRemove, coveredLifelines);
}
}
}
}
/**
* Find parent editpart of lifeline
* @return EditPart
*/
public EditPart getInteractionCompartment() {
EditPart editPart = getParent();
while (editPart != null
&& !(editPart instanceof InteractionInteractionCompartmentEditPart)) {
editPart = editPart.getParent();
}
return editPart;
}
}