/*****************************************************************************
* Copyright (c) 2009 CEA LIST.
*
*
* 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:
* Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.clazz.custom.edit.part;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.uml.diagram.clazz.custom.figure.AssociationFigure;
import org.eclipse.papyrus.uml.diagram.common.editparts.UMLConnectionNodeEditPart;
import org.eclipse.uml2.uml.AggregationKind;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Property;
/**
* this a abstract editpart use to add listeners
*/
public abstract class AbstractAssociationEditPart extends UMLConnectionNodeEditPart {
protected static final String ASSOCIATION_END_LISTENERS_SOURCE = "AssociationEndListenersSource";
protected static final String ASSOCIATION_END_LISTENERS_TARGET = "AssociationEndListenersTarget";
public AbstractAssociationEditPart(View view) {
super(view);
}
/**
*
* {@inheritDoc}
*/
@Override
public void activate() {
super.activate();
addAssociationEndListeners();
}
/**
* this methods add listeners on targets and sources
*/
protected void addAssociationEndListeners() {
EObject semanticElement = resolveSemanticElement();
if(semanticElement instanceof Association) {
Association association = (Association)semanticElement;
if(association.getMemberEnds().size() >= 2) {
EObject sourceEnd = association.getMemberEnds().get(0);
EObject targetEnd = association.getMemberEnds().get(1);
addListenerFilter(ASSOCIATION_END_LISTENERS_SOURCE, this, sourceEnd);
addListenerFilter(ASSOCIATION_END_LISTENERS_TARGET, this, targetEnd);
}
}
}
/**
*
* {@inheritDoc}
*/
@Override
public void deactivate() {
removeAssociationEndListeners();
super.deactivate();
}
/**
*
* {@inheritDoc}
*/
@Override
protected void handleNotificationEvent(Notification event) {
super.handleNotificationEvent(event);
// set the good ends for the association figure
if(resolveSemanticElement() != null) {
refreshVisuals();
}
}
/**
*
* {@inheritDoc}
*/
@Override
protected void refreshVisuals() {
if(resolveSemanticElement() != null) {
if(getSource() == null || getTarget() == null) {
return;
}
if(!(getSource() instanceof GraphicalEditPart && getTarget() instanceof GraphicalEditPart)) {
return;
}
//FIXME: This is a quick fix to avoid model corruption when an associationClass is drawn between an association and a Class.
//A better solution would probably be to forbid this behavior. Currently, it is not possible to draw directly an Association Class between
//an association and a class, but it is possible to retarget an AssociationClass' end to an Association (Which would lead to a diagram corruption)
if(((GraphicalEditPart)getSource()).resolveSemanticElement() == null || ((GraphicalEditPart)getTarget()).resolveSemanticElement() == null) {
return;
}
Property source = null;
Property target = null;
// Get the association
Element umlElement = getUMLElement();
if(umlElement instanceof Association) {
Association association = (Association)getUMLElement();
assert (association.getMemberEnds().size() >= 2);
if(association.getMemberEnds() != null && association.getMemberEnds().size() >= 2) {
if((association.getMemberEnds().get(0)).getType().equals(((GraphicalEditPart)getSource()).resolveSemanticElement())) {
source = ((association.getMemberEnds().get(0)));
target = ((association.getMemberEnds().get(1)));
} else {
source = ((association.getMemberEnds().get(1)));
target = ((association.getMemberEnds().get(0)));
}
int sourceType = 0;
int targetType = 0;
// to display the dot.
// owned?
if(!source.getOwner().equals(resolveSemanticElement())) {
sourceType += AssociationFigure.owned;
sourceType += AssociationFigure.navigable;
}
if(!target.getOwner().equals(resolveSemanticElement())) {
targetType += AssociationFigure.owned;
targetType += AssociationFigure.navigable;
}
// aggregation? for it the opposite is changed
if(source.getAggregation() == AggregationKind.SHARED_LITERAL) {
targetType += AssociationFigure.aggregation;
}
if(target.getAggregation() == AggregationKind.SHARED_LITERAL) {
sourceType += AssociationFigure.aggregation;
}
// composite? for it the opposite is changed
if(source.getAggregation() == AggregationKind.COMPOSITE_LITERAL) {
targetType += AssociationFigure.composition;
}
if(target.getAggregation() == AggregationKind.COMPOSITE_LITERAL) {
sourceType += AssociationFigure.composition;
}
// navigable?
if(association.getNavigableOwnedEnds().contains(source)) {
sourceType += AssociationFigure.navigable;
}
if(association.getNavigableOwnedEnds().contains(target)) {
targetType += AssociationFigure.navigable;
}
if(getPrimaryShape() instanceof AssociationFigure) {
((AssociationFigure)getPrimaryShape()).setEnd(sourceType, targetType);
}
}
}
}
super.refreshVisuals();
}
/**
* this method is used to remove listener on ends
*/
protected void removeAssociationEndListeners() {
removeListenerFilter(ASSOCIATION_END_LISTENERS_SOURCE);
removeListenerFilter(ASSOCIATION_END_LISTENERS_TARGET);
}
}