Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 46c9bb2f8fb495a9c61998d8ba2d92a4a39fab9f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*****************************************************************************
 * Copyright (c) 2018 CEA LIST and others.
 *
 * 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:
 *   EclipseSource - Initial API and implementation
 *
 *****************************************************************************/

package org.eclipse.papyrus.uml.diagram.sequence.util;

import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewAndElementRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.uml.diagram.sequence.anchors.AnchorConstants;
import org.eclipse.uml2.uml.ExecutionSpecification;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.MessageEnd;
import org.eclipse.uml2.uml.OccurrenceSpecification;

/**
 * <p>
 * Util class related to the manipulation of Links targetting {@link OccurrenceSpecification}s,
 * typically used by {@link GraphicalNodeEditPolicy} or {@link EditPart}.
 * </p>
 *
 * @see DurationLinkUtil
 * @see GeneralOrderingUtil
 */
public class OccurrenceSpecificationUtil {


	/**
	 * Retrieve the semantic {@link CreateRelationshipRequest} from the given GEF {@link CreateConnectionRequest},
	 * or <code>null</code>.
	 *
	 * @param request
	 * @return
	 */
	public static CreateRelationshipRequest getCreateRelationshipRequest(CreateConnectionRequest request) {
		if (false == request instanceof CreateConnectionViewAndElementRequest) {
			return null;
		}
		CreateElementRequestAdapter requestAdapter = ((CreateConnectionViewAndElementRequest) request).getConnectionViewAndElementDescriptor().getCreateElementRequestAdapter();
		if (requestAdapter == null) {
			return null;
		}
		CreateRelationshipRequest createElementRequest = (CreateRelationshipRequest) requestAdapter.getAdapter(CreateRelationshipRequest.class);
		return createElementRequest;
	}

	/**
	 * Test whether the given request is closer to the start (top) or to the finish (bottom) point of the execution specification
	 *
	 * @param createRequest
	 *            The create request
	 * @return
	 * 		<code>true</code> if the given request is closer to the top of the figure; false if it is closer to the bottom
	 */
	public static boolean isStart(IFigure targetFigure, CreateRequest createRequest) {
		Point location = createRequest.getLocation();
		Rectangle bounds = targetFigure.getBounds().getCopy();
		targetFigure.translateToAbsolute(bounds);

		double distanceToTop = location.getDistance(bounds.getTop());
		double distanceToBottom = location.getDistance(bounds.getBottom());
		return distanceToTop < distanceToBottom;
	}

	/**
	 * Test whether the given request is closer to the source or to the target point of the message
	 *
	 * @param targetFigure
	 *            The connection figure representing the message
	 * @param createRequest
	 *            The create request
	 * @return
	 * 		<code>true</code> if the given request is closer to the source of the connection; false if it is closer to the target
	 */
	public static boolean isSource(IFigure targetFigure, CreateRequest createRequest) {
		Point location = createRequest.getLocation();
		IFigure connection = targetFigure;
		if (connection instanceof Connection) {
			PointList points = ((Connection) connection).getPoints();
			if (points.size() >= 2) {
				Point source = points.getFirstPoint();
				Point target = points.getLastPoint();
				double distanceToSource = location.getDistance(source);
				double distanceToTarget = location.getDistance(target);
				return distanceToSource < distanceToTarget;
			}
		}

		// Default; shouldn't happen, unless the Message figure is invalid,
		// in which case we can't determine the source/target).
		return true;
	}



	/**
	 * Find the semantic {@link OccurrenceSpecification} represented by the given <code>connectorEnd</code>.
	 * The connector should be the source or target of a DurationLink connector.
	 *
	 * @param connectorEnd
	 *            the source or target of a DurationLink connector
	 * @param anchorTerminal
	 *            The connection anchor corresponding to the given connector end.
	 * @return
	 * 		The semantic occurrence specification represented by the given connector end (View), or null
	 *         if the view doesn't represent a valid {@link OccurrenceSpecification}.
	 */
	public static OccurrenceSpecification findSemanticOccurrence(View connectorEnd, String anchorTerminal) {
		EObject semantic = connectorEnd.getElement();
		if (semantic instanceof OccurrenceSpecification) {
			return (OccurrenceSpecification) semantic;
		} else if (semantic instanceof ExecutionSpecification) {
			switch (anchorTerminal) {
			case AnchorConstants.START_TERMINAL:
				return ((ExecutionSpecification) semantic).getStart();
			case AnchorConstants.END_TERMINAL:
				return ((ExecutionSpecification) semantic).getFinish();
			default:
				return null;
			}
		} else if (semantic instanceof Message) {
			switch (anchorTerminal) {
			case AnchorConstants.START_TERMINAL:
				MessageEnd sendEvent = ((Message) semantic).getSendEvent();
				return sendEvent instanceof OccurrenceSpecification ? (OccurrenceSpecification) sendEvent : null;
			case AnchorConstants.END_TERMINAL:
				MessageEnd receiveEvent = ((Message) semantic).getReceiveEvent();
				return receiveEvent instanceof OccurrenceSpecification ? (OccurrenceSpecification) receiveEvent : null;
			default:
				return null;
			}
		}
		return null;
	}
}

Back to the top