Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: eac5bee423a916ad841a4c0f2e452f332dd4f7b1 (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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*****************************************************************************
 * Copyright (c) 2011, 2015 CEA LIST, Christian W. Damus, and others.
 *    
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Yann Tanguy (CEA LIST) yann.tanguy@cea.fr - Initial API and implementation
 * 	 Patrik Nandorf (Ericsson AB) - bug 458042
 *   Christian W. Damus - bug 459701
 *
 *****************************************************************************/
package org.eclipse.papyrus.uml.service.types.helper;

import java.util.Arrays;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.core.command.IdentityCommand;
import org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand;
import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil;
import org.eclipse.gmf.runtime.emf.type.core.commands.ConfigureElementCommand;
import org.eclipse.gmf.runtime.emf.type.core.commands.CreateRelationshipCommand;
import org.eclipse.gmf.runtime.emf.type.core.requests.ConfigureRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.uml2.uml.DirectedRelationship;
import org.eclipse.uml2.uml.UMLPackage;

/**
 * This abstract helper is used to set the source and the target for a {@link DirectedRelationship}
 */
public abstract class DirectedRelationshipEditHelper extends ElementEditHelper {

	/**
	 * Subclasses should implement this method providing the EReference to be used as source.
	 * 
	 * @return the source EReference
	 */
	protected abstract EReference getSourceReference();

	/**
	 * Subclasses should implement this method providing the EReference to be used as target.
	 * 
	 * @return the target EReference
	 */
	protected abstract EReference getTargetReference();

	/**
	 * Test if the relationship creation is allowed.
	 * 
	 * @param source
	 *            the relationship source can be null
	 * @param target
	 *            the relationship target can be null
	 * @return true if the creation is allowed
	 */
	protected abstract boolean canCreate(EObject source, EObject target);

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected ICommand getCreateRelationshipCommand(CreateRelationshipRequest req) {
		EObject source = req.getSource();
		EObject target = req.getTarget();
		boolean noSourceOrTarget = (source == null || target == null);
		boolean noSourceAndTarget = (source == null && target == null);
		if (!noSourceAndTarget && !canCreate(source, target)) {
			// Abort creation.
			return UnexecutableCommand.INSTANCE;
		}
		if (noSourceOrTarget && !noSourceAndTarget) {
			// The request isn't complete yet. Return the identity command so
			// that the create relationship gesture is enabled.
			return IdentityCommand.INSTANCE;
		}

		// If the container is null or containmentFeature doesn't fit with container, try to find one that make sense
		if (req.getContainer() == null || (!req.getContainer().eClass().getEAllReferences().contains(req.getContainmentFeature())) || req.getContainmentFeature() == null) {
			// Propose a container.
			EObject proposedContainer = EMFCoreUtil.getLeastCommonContainer(Arrays.asList(new EObject[] { source, target }), UMLPackage.eINSTANCE.getPackage());

			// If no common container is found try source nearest package
			if (proposedContainer == null) {
				EObject sourcePackage = EMFCoreUtil.getContainer(source, UMLPackage.eINSTANCE.getPackage());
				if (!isReadOnly(sourcePackage)) {
					proposedContainer = sourcePackage;
				}
			}

			// If no common container is found try target nearest package
			if (proposedContainer == null) {
				EObject targetPackage = EMFCoreUtil.getContainer(target, UMLPackage.eINSTANCE.getPackage());
				if (!isReadOnly(targetPackage)) {
					proposedContainer = targetPackage;
				}
			}

			if (proposedContainer == null) {
				return UnexecutableCommand.INSTANCE;
			}
			req.setContainer(proposedContainer);
		}
		return new CreateRelationshipCommand(req);
	}

	protected boolean isReadOnly(EObject eObject) {
		EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(eObject);
		boolean isReadOnly = (eObject.eResource() != null) && (editingDomain.isReadOnly(eObject.eResource()));
		return isReadOnly;
	}

	/**
	 * This method provides the object to be use as source.
	 * 
	 * @return the source value (EList or EObject)
	 */
	protected Object getSourceObject(ConfigureRequest req) {
		Object result = null;
		if (getSourceReference().getUpperBound() != 1) {
			EList<EObject> objects = new BasicEList<EObject>();
			objects.add((EObject) req.getParameter(CreateRelationshipRequest.SOURCE));
			result = objects;
		} else {
			result = req.getParameter(CreateRelationshipRequest.SOURCE);
		}
		return result;
	}

	/**
	 * This method provides the object to be used as target.
	 * 
	 * @return the target value (EList or EObject)
	 */
	protected Object getTargetObject(ConfigureRequest req) {
		Object result = null;
		if (getTargetReference().getUpperBound() != 1) {
			EList<EObject> objects = new BasicEList<EObject>();
			objects.add((EObject) req.getParameter(CreateRelationshipRequest.TARGET));
			result = objects;
		} else {
			result = req.getParameter(CreateRelationshipRequest.TARGET);
		}
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected ICommand getConfigureCommand(final ConfigureRequest req) {
		return CompositeCommand.compose(getConfigureSourcesAndTargetsCommand(req), super.getConfigureCommand(req));
	}

	/**
	 * Creates the primitive component of the overall configure command that configures sources and targets
	 * of the new directed relationship.
	 * 
	 * @param req
	 *            the configure request
	 * @return a command to configure the new relationship's sources and targets
	 */
	protected ICommand getConfigureSourcesAndTargetsCommand(final ConfigureRequest req) {
		return new ConfigureElementCommand(req) {

			@Override
			protected CommandResult doExecuteWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
				DirectedRelationship element = (DirectedRelationship) req.getElementToConfigure();
				if (req.getParameter(CreateRelationshipRequest.SOURCE) != null) {
					element.eSet(getSourceReference(), getSourceObject(req));
				}
				if (req.getParameter(CreateRelationshipRequest.TARGET) != null) {
					element.eSet(getTargetReference(), getTargetObject(req));
				}
				return CommandResult.newOKCommandResult(element);
			}
		};
	}
}

Back to the top