package org.eclipse.papyrus.uml.diagram.sequence.edit.parts;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Locator;
import org.eclipse.draw2d.RelativeLocator;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.NonResizableEditPolicy;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gef.requests.DropRequest;
import org.eclipse.gef.requests.ReconnectRequest;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.core.util.Log;
import org.eclipse.gmf.runtime.common.core.util.Trace;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionNodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.EditPolicyRoles;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.SemanticEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIDebugOptions;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIPlugin;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIStatusCodes;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateUnspecifiedTypeConnectionRequest;
import org.eclipse.gmf.runtime.draw2d.ui.figures.IAnchorableFigure;
import org.eclipse.gmf.runtime.emf.type.core.commands.EditElementCommand;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.IEditCommandRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.ReorientReferenceRelationshipRequest;
import org.eclipse.gmf.runtime.gef.ui.figures.SlidableOvalAnchor;
import org.eclipse.gmf.runtime.gef.ui.internal.figures.CircleFigure;
import org.eclipse.gmf.runtime.notation.Anchor;
import org.eclipse.gmf.runtime.notation.DecorationNode;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.IdentityAnchor;
import org.eclipse.gmf.runtime.notation.NotationFactory;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.Shape;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.gmf.runtime.notation.impl.ShapeImpl;
import org.eclipse.papyrus.uml.diagram.sequence.edit.commands.CommentAnnotatedElementCreateCommand;
import org.eclipse.papyrus.uml.diagram.sequence.edit.commands.ConstraintConstrainedElementCreateCommand;
import org.eclipse.papyrus.uml.diagram.sequence.providers.UMLElementTypes;
import org.eclipse.papyrus.uml.diagram.sequence.util.CommandHelper;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.OccurrenceSpecification;
public class ExecutionSpecificationEndEditPart extends GraphicalEditPart
implements INodeEditPart {
private static final String DUMMY_TYPE = "999998";
private static final int DEFAULT_SIZE = 16;
private Locator locator;
private OccurrenceSpecification executionSpecificationEnd;
public ExecutionSpecificationEndEditPart(OccurrenceSpecification occurrenceSpecification, ShapeNodeEditPart parent, RelativeLocator locator ) {
super(createDummyView(parent, occurrenceSpecification) );
this.executionSpecificationEnd = occurrenceSpecification;
this.setParent(parent);
this.locator = locator;
addToResource(parent.getNotationView(), this.getNotationView());
}
/**
* apex updated
*/
private static EObject createDummyView(ShapeNodeEditPart parent,
EObject model) {
/* apex added start */
if (parent instanceof AbstractExecutionSpecificationEditPart) {
View view = ((AbstractExecutionSpecificationEditPart)parent).apexFindChildByModel(model);
if(view != null)
return view;
}
/* apex added end */
final Shape node = new ShapeImpl() {
public boolean eNotificationRequired() {
return true;
}
};
node.setLayoutConstraint(NotationFactory.eINSTANCE.createBounds());
node.setType(DUMMY_TYPE);
node.setElement(model);
return node;
}
protected void handleNotificationEvent(Notification notification) {
Object feature = notification.getFeature();
if (NotationPackage.eINSTANCE.getView_SourceEdges().equals(feature))
refreshSourceConnections();
else if (NotationPackage.eINSTANCE.getView_TargetEdges()
.equals(feature))
refreshTargetConnections();
else
super.handleNotificationEvent(notification);
}
protected void addNotationalListeners() {
if (hasNotationView()) {
addListenerFilter("View", this,(View)getModel());
}
}
static class DummyCommand extends org.eclipse.emf.common.command.AbstractCommand {
public void execute() {
}
public void redo() {
}
public void undo() {
}
protected boolean prepare() {
return true;
}
}
private void addToResource(final View container, final View view) {
CommandHelper.executeCommandWithoutHistory(getEditingDomain(), new DummyCommand() {
public void execute() {
ViewUtil.insertChildView(container, view,-1, false);
}
},true);
}
protected void createDefaultEditPolicies() {
super.createDefaultEditPolicies();
installEditPolicy(EditPolicyRoles.SEMANTIC_ROLE, new ExecutionSpecificationEndSemanticEditPolicy());
installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new ExecutionSpecificationEndGraphicalNodeEditPolicy());
installEditPolicy(EditPolicy.PRIMARY_DRAG_ROLE, new NonResizableEditPolicy(){
protected void addSelectionHandles() { // remove handles
}
});
}
public void rebuildLinks(Diagram diagram) {
helper.collectViews(diagram);
EObject semanticModel = this.resolveSemanticElement();
EAnnotation annotation = executionSpecificationEnd.getEAnnotation("Connections");
if (annotation != null) {
for (EObject eo : annotation.getReferences()) {
View view = helper.findView(eo);
if (view == null)
continue; // should not happen
EList edges = view.getSourceEdges();
for (Object o : edges) {
if (o instanceof Edge ) {
if(needRestoreLink((Edge) o)) {
restoreEdgeTarget((Edge) o);
break;
}
}
}
}
}
}
private boolean needRestoreLink(Edge e) {
if(e.getTarget() == null)
return true;
EObject model = e.getTarget().getElement();
if(!(model instanceof OccurrenceSpecification))
return false;
if(model == this.resolveSemanticElement()) {
System.out.println( ((OccurrenceSpecification) model).getName() );
if(!this.getNotationView().equals( e.getTarget()))
return true;
}
return false;
}
private void restoreEdgeTarget(final Edge edge) {
CommandHelper.executeCommandWithoutHistory(this.getEditingDomain(), new DummyCommand() {
public void execute() {
edge.setTarget((View) ExecutionSpecificationEndEditPart.this
.getModel());
}
},true);
}
static ViewHelper helper = new ViewHelper();
static class ViewHelper {
Diagram diagram = null;
Set<View> allViews = new HashSet<View>();
Map<EObject, View> viewMaps = new HashMap<EObject, View>();
View findView(EObject key) {
return viewMaps.get(key);
}
void collectViews(Diagram d) {
if (diagram != d) { // compare pointer ref
diagram = d;
allViews.clear();
viewMaps.clear();
getAllNestedViews(diagram, allViews);
for (View v : allViews) {
if (v instanceof DecorationNode)
continue;
viewMaps.put(v.getElement(), v);
}
}
}
static private void getAllNestedViews(View view, Set<View> allViews) {
for (View childView : (List<View>) view.getChildren()) {
getAllNestedViews(childView, allViews);
allViews.add(childView);
}
}
}
static class ExecutionSpecificationEndGraphicalNodeEditPolicy extends GraphicalNodeEditPolicy {
IFigure executionSpecificationEndFeedback;
@Override
public void eraseTargetFeedback(Request request) {
super.eraseSourceFeedback(request);
if (executionSpecificationEndFeedback != null)
removeFeedback(executionSpecificationEndFeedback);
executionSpecificationEndFeedback = null;
}
protected void showTargetConnectionFeedback(
DropRequest request) {
if (executionSpecificationEndFeedback == null) {
CircleFigure c = new CircleFigure(DEFAULT_SIZE,
DEFAULT_SIZE);
c.setForegroundColor(ColorConstants.black);
ExecutionSpecificationEndEditPart p = (ExecutionSpecificationEndEditPart) getHost();
IFigure parent = p.getFigure().getParent();
Rectangle targetBounds = p.getFigure().getBounds().getCopy();
p.getFigure().translateToAbsolute(targetBounds);
//targetBounds.translate(0, DEFAULT_SIZE /2 );
getFeedbackLayer().translateToRelative(targetBounds);
getFeedbackLayer().translateFromParent(targetBounds);
c.setBounds(targetBounds);
addFeedback(c);
executionSpecificationEndFeedback = c;
}
}
}
static class ReorientExecutionSpecificationEndCommand extends EditElementCommand{
private ReorientReferenceRelationshipRequest request;
public ReorientExecutionSpecificationEndCommand(ReorientReferenceRelationshipRequest request) {
super(request.getLabel(), request.getNewRelationshipEnd(), request);
this.request = request;
}
public boolean canExecute() {
return true;
}
@Override
protected CommandResult doExecuteWithResult(IProgressMonitor monitor,
IAdaptable info) throws ExecutionException {
// adding new end
if(request.getNewRelationshipEnd() instanceof OccurrenceSpecification) {
ExecutionSpecificationEndHelper.addConnectionSourceToExecutionSpecificationEnd((OccurrenceSpecification) request.getNewRelationshipEnd(), request.getReferenceOwner());
// update uml model reference
if(request.getReferenceOwner() instanceof Constraint) {
((Constraint)request.getReferenceOwner()).getConstrainedElements().add((OccurrenceSpecification) request.getNewRelationshipEnd());
}else if(request.getReferenceOwner() instanceof Comment) {
((Comment) request.getReferenceOwner()).getAnnotatedElements().add( (OccurrenceSpecification) request.getNewRelationshipEnd());
}
}
// removing old end
if(request.getOldRelationshipEnd() instanceof OccurrenceSpecification) {
ExecutionSpecificationEndHelper.removeConnectionSourceFromExecutionSpecificationEnd((OccurrenceSpecification) request.getOldRelationshipEnd(), request.getReferenceOwner());
// update uml model reference
if(request.getReferenceOwner() instanceof Constraint) {
((Constraint)request.getReferenceOwner()).getConstrainedElements().remove((OccurrenceSpecification) request.getOldRelationshipEnd());
}else if(request.getReferenceOwner() instanceof Comment) {
((Comment) request.getReferenceOwner()).getAnnotatedElements().remove( (OccurrenceSpecification) request.getOldRelationshipEnd());
}
}
return CommandResult.newOKCommandResult();
}
}
static class ExecutionSpecificationEndSemanticEditPolicy extends SemanticEditPolicy{
protected Command getSemanticCommand(
final IEditCommandRequest request) {
if (request instanceof CreateRelationshipRequest) {
return getCreateRelationshipCommand((CreateRelationshipRequest) request);
}
else if( request instanceof ReorientReferenceRelationshipRequest) {
return getGEFWrapper(new ReorientExecutionSpecificationEndCommand((ReorientReferenceRelationshipRequest) request ) ) ;
}
Command cmd = super.getSemanticCommand(request);
return cmd;
}
protected Command getStartCreateRelationshipCommand(
CreateRelationshipRequest req) {
if (UMLElementTypes.ConstraintConstrainedElement_4011 == req
.getElementType()) {
return getGEFWrapper(new ConstraintConstrainedElementCreateCommandEx(
req, req.getSource(), req.getTarget()));
}
return null;
}
protected Command getCompleteCreateRelationshipCommand(
CreateRelationshipRequest req) {
if (UMLElementTypes.ConstraintConstrainedElement_4011 == req
.getElementType()) {
return getGEFWrapper(new ConstraintConstrainedElementCreateCommandEx(
req, req.getSource(), req.getTarget()));
}else if(UMLElementTypes.CommentAnnotatedElement_4010 == req
.getElementType()) {
return getGEFWrapper(new CommentAnnotatedElementCreateCommandEx(req, req.getSource(), req.getTarget()));
}
return null;
}
protected Command getCreateRelationshipCommand(
CreateRelationshipRequest req) {
Command command = req.getTarget() == null ? getStartCreateRelationshipCommand(req)
: getCompleteCreateRelationshipCommand(req);
return command;
}
protected final Command getGEFWrapper(ICommand cmd) {
return new ICommandProxy(cmd);
}
}
public static class ExecutionSpecificationEndHelper{
public static void removeConnectionSourceFromExecutionSpecificationEnd(OccurrenceSpecification executionOccurrence , EObject connectionSource) {
EAnnotation annotation = executionOccurrence
.getEAnnotation("Connections");
if (annotation != null) {
annotation.getReferences().remove( connectionSource);
}
}
public static void addConnectionSourceToExecutionSpecificationEnd(OccurrenceSpecification executionOccurrence,EObject connectionSource) {
EAnnotation annotation = executionOccurrence
.getEAnnotation("Connections");
if (annotation == null) {
annotation = EcoreFactory.eINSTANCE.createEAnnotation();
annotation.setSource("Connections"); //$NON-NLS-1$
executionOccurrence.getEAnnotations().add(annotation);
}
if( !annotation.getReferences().contains( connectionSource) )
annotation.getReferences().add(connectionSource);
}
}
static class CommentAnnotatedElementCreateCommandEx extends CommentAnnotatedElementCreateCommand{
public CommentAnnotatedElementCreateCommandEx(
CreateRelationshipRequest request, EObject source,
EObject target) {
super(request, source, target);
}
protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
CommandResult res = super.doExecuteWithResult(monitor, info);
if (getTarget() instanceof OccurrenceSpecification) {
ExecutionSpecificationEndHelper.addConnectionSourceToExecutionSpecificationEnd((OccurrenceSpecification) getTarget(), getSource());
}
return res;
}
}
static class ConstraintConstrainedElementCreateCommandEx extends
ConstraintConstrainedElementCreateCommand {
public ConstraintConstrainedElementCreateCommandEx(
CreateRelationshipRequest request, EObject source,
EObject target) {
super(request, source, target);
}
@Override
protected CommandResult doExecuteWithResult(IProgressMonitor monitor,
IAdaptable info) throws ExecutionException {
CommandResult res = super.doExecuteWithResult(monitor, info);
if (getTarget() instanceof OccurrenceSpecification) {
ExecutionSpecificationEndHelper.addConnectionSourceToExecutionSpecificationEnd((OccurrenceSpecification) getTarget(), getSource());
}
return res;
}
}
public Locator getLocator() {
return locator;
}
protected IFigure createFigure() {
IFigure fig = new ExecutionSpecificationEndFigure();
fig.setForegroundColor(ColorConstants.black);
// Rectangle b = fig.getBounds();
// final ExecutionOccurrenceSpecification model = (ExecutionOccurrenceSpecification) this.resolveSemanticElement();
// Label tooltip = new Label();
// tooltip.setText(model.getName());
// fig.setToolTip(tooltip);
fig.setOpaque(false);
return fig;
}
public boolean hasNotationView() {
return true;
}
public ConnectionAnchor getSourceConnectionAnchor(
ConnectionEditPart connection) {
return null;
}
public ConnectionAnchor getTargetConnectionAnchor(
ConnectionEditPart connEditPart) {
final ConnectionNodeEditPart connection = (ConnectionNodeEditPart) connEditPart;
String t = ""; //$NON-NLS-1$
try {
t = (String) getEditingDomain().runExclusive(
new RunnableWithResult.Impl() {
public void run() {
Anchor a = ((Edge) connection.getModel())
.getTargetAnchor();
if (a instanceof IdentityAnchor)
setResult(((IdentityAnchor) a).getId());
else
setResult(""); //$NON-NLS-1$
}
});
} catch (InterruptedException e) {
Trace.catching(DiagramUIPlugin.getInstance(),
DiagramUIDebugOptions.EXCEPTIONS_CATCHING, getClass(),
"getTargetConnectionAnchor", e); //$NON-NLS-1$
Log.error(DiagramUIPlugin.getInstance(),
DiagramUIStatusCodes.IGNORED_EXCEPTION_WARNING,
"getTargetConnectionAnchor", e); //$NON-NLS-1$
}
IAnchorableFigure fig = ((IAnchorableFigure) getFigure());
ConnectionAnchor a = fig.getConnectionAnchor(t);
return a;
}
public ConnectionAnchor getTargetConnectionAnchor(Request request) {
Point center = getFigure().getBounds().getCenter();
getFigure().translateToAbsolute(center);
Point pt = ((DropRequest) request).getLocation() == null ? center
: new Point(((DropRequest) request).getLocation());
if (request instanceof CreateRequest) {
getFigure().translateToRelative(pt);
}
ConnectionAnchor a = ((IAnchorableFigure) getFigure())
.getTargetConnectionAnchorAt(pt);
return a;
}
public ConnectionAnchor getSourceConnectionAnchor(Request request) {
return null;
}
public boolean canAttachNote() {
return true;
}
public String mapConnectionAnchorToTerminal(ConnectionAnchor c) {
return ((IAnchorableFigure) getFigure()).getConnectionAnchorTerminal(c);
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart#mapTerminalToConnectionAnchor(String)
*/
public ConnectionAnchor mapTerminalToConnectionAnchor(String terminal) {
return ((IAnchorableFigure) getFigure()).getConnectionAnchor(terminal);
}
protected List getModelSourceConnections() {
return ViewUtil
.getSourceConnectionsConnectingVisibleViews((View) getModel());
}
protected List getModelTargetConnections() {
List list = ViewUtil
.getTargetConnectionsConnectingVisibleViews((View) getModel());
return list;
}
@Override
public EditPart getTargetEditPart(Request request) {
if(request instanceof CreateUnspecifiedTypeConnectionRequest){
List types = ((CreateUnspecifiedTypeConnectionRequest) request).getElementTypes();
if(types.contains(UMLElementTypes.CommentAnnotatedElement_4010) || types.contains(UMLElementTypes.ConstraintConstrainedElement_4011)){
return super.getTargetEditPart(request);
}
}else if(request instanceof ReconnectRequest){
ConnectionEditPart con = ((ReconnectRequest)request).getConnectionEditPart();
if(con instanceof CommentAnnotatedElementEditPart || con instanceof ConstraintConstrainedElementEditPart){
return super.getTargetEditPart(request);
}
}
return null;
}
static class ExecutionSpecificationEndAnchor extends SlidableOvalAnchor {
public ExecutionSpecificationEndAnchor(CircleFigure circleFigure, PrecisionPoint p) {
super(circleFigure, p);
}
public ExecutionSpecificationEndAnchor(CircleFigure circleFigure) {
super(circleFigure);
}
public Point getLocation(Point reference) {
return getBox().getCenter();
}
}
class ExecutionSpecificationEndFigure extends CircleFigure {
ExecutionSpecificationEndFigure() {
super(DEFAULT_SIZE, DEFAULT_SIZE);
}
@Override
protected void paintFigure(Graphics g) {
Rectangle r = Rectangle.SINGLETON;
r.setBounds(getBounds());
r.width--;
r.height--;
// Hide
//g.drawOval(r);
}
protected ConnectionAnchor createAnchor(PrecisionPoint p) {
if (p == null)
return createDefaultAnchor();
return new ExecutionSpecificationEndAnchor(this, p);
}
protected ConnectionAnchor createDefaultAnchor() {
return new ExecutionSpecificationEndAnchor(this);
}
public ConnectionAnchor getTargetConnectionAnchorAt(Point p) {
try {
return super.getTargetConnectionAnchorAt(p);
} catch (Exception e) {
return null;
}
};
@Override
public void validate() {
locator.relocate(this); //place figure at north or south, ignore layout manager
super.validate();
}
}
}