blob: 2e1a6cac3178aec93e645f677bd181b5b35b11fd [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2011-2012 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:
*
* CEA LIST - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.sysml.service.types.helper.advice;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
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.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
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.UnexecutableCommand;
import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.commands.ConfigureElementCommand;
import org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice;
import org.eclipse.gmf.runtime.emf.type.core.requests.ConfigureRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyDependentsRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyReferenceRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.MoveRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.ReorientRelationshipRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.ReorientRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils;
import org.eclipse.papyrus.infra.services.edit.service.IElementEditService;
import org.eclipse.papyrus.sysml.service.types.element.SysMLElementTypes;
import org.eclipse.papyrus.uml.service.types.utils.ElementUtil;
import org.eclipse.papyrus.uml.service.types.utils.RequestParameterUtils;
import org.eclipse.papyrus.uml.tools.databinding.OwnedAttributeHelper;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.UMLPackage;
/** Association edit helper advice */
public class AssociationEditHelperAdvice extends AbstractEditHelperAdvice {
/**
* <pre>
* {@inheritDoc}
*
* avoid creation of association on another association
*
* </pre>
*/
@Override
protected ICommand getBeforeCreateRelationshipCommand(CreateRelationshipRequest request) {
IElementType type = request.getElementType();
if (SysMLElementTypes.ASSOCIATION.equals(type)) {
return UnexecutableCommand.INSTANCE;
}
if (type != null) {
List<IElementType> superTypes = Arrays.asList(type.getAllSuperTypes());
if (superTypes.contains(SysMLElementTypes.ASSOCIATION)) {
return UnexecutableCommand.INSTANCE;
}
}
return super.getBeforeCreateRelationshipCommand(request);
}
/**
* <pre>
* {@inheritDoc}
*
* Add a command to destroy {@link Association} when only 1 end remains.
*
* </pre>
*/
@Override
protected ICommand getBeforeDestroyReferenceCommand(DestroyReferenceRequest request) {
ICommand gmfCommand = super.getBeforeDestroyReferenceCommand(request);
Association association = (Association) request.getContainer();
if ((request.getContainingFeature() == UMLPackage.eINSTANCE.getAssociation_MemberEnd()) && (association.getMemberEnds().contains(request.getReferencedObject()))) {
Set<Property> ends = new HashSet<Property>();
ends.addAll(association.getMemberEnds());
ends.remove(request.getReferencedObject());
if (ends.size() <= 2) {
DestroyElementRequest destroyRequest = new DestroyElementRequest(association, false);
IElementEditService provider = ElementEditServiceUtils.getCommandProvider(association);
if (provider != null) {
ICommand destroyCommand = provider.getEditCommand(destroyRequest);
gmfCommand = CompositeCommand.compose(gmfCommand, destroyCommand);
}
}
}
return gmfCommand;
}
/**
* <pre>
* {@inheritDoc}
*
* Add SysML Nature on the {@link Association}.
*
* </pre>
*/
@Override
protected ICommand getBeforeConfigureCommand(ConfigureRequest request) {
final Association association = (Association) request.getElementToConfigure();
return new ConfigureElementCommand(request) {
@Override
protected CommandResult doExecuteWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
// Add SysML Nature on the new Association
ElementUtil.addNature(association, SysMLElementTypes.SYSML_NATURE);
return CommandResult.newOKCommandResult(association);
}
};
}
/**
* <pre>
* {@inheritDoc}
*
* Add a command to destroy {@link Association} ends referenced by the {@link Association}
* to delete.
*
* </pre>
*/
@Override
protected ICommand getBeforeDestroyDependentsCommand(DestroyDependentsRequest req) {
List<EObject> dependentsToDestroy = new ArrayList<EObject>();
List<EObject> dependentsToKeep = (RequestParameterUtils.getDependentsToKeep(req) != null) ? RequestParameterUtils.getDependentsToKeep(req) : new ArrayList<EObject>();
Association association = (Association) req.getElementToDestroy();
for (Property end : association.getMemberEnds()) {
if (!dependentsToKeep.contains(end)) {
dependentsToDestroy.add(end);
}
}
// Return command to destroy dependents ends
if (!dependentsToDestroy.isEmpty()) {
return req.getDestroyDependentsCommand(dependentsToDestroy);
}
return super.getBeforeDestroyDependentsCommand(req);
}
/**
* <pre>
* {@inheritDoc}
*
* Add a command to related association end during re-orient.
*
* </pre>
*/
@Override
protected ICommand getBeforeReorientRelationshipCommand(ReorientRelationshipRequest request) {
ICommand gmfCommand = super.getBeforeReorientRelationshipCommand(request);
MoveRequest moveRequest = null;
SetRequest setTypeRequest = null;
// Retrieve re-oriented association and add it to the list of re-factored elements
Association association = (Association) request.getRelationship();
List<EObject> currentlyRefactoredElements = (RequestParameterUtils.getAssociationRefactoredElements(request) != null) ? RequestParameterUtils.getAssociationRefactoredElements(request) : new ArrayList<EObject>();
if (currentlyRefactoredElements.contains(association)) {
// Abort - already treated
return null;
} else {
RequestParameterUtils.addAssociationRefactoredElement(request, association);
}
// not possible to have an association on another association, so reorient is forbidden here
if (request.getNewRelationshipEnd() instanceof Association) {
return UnexecutableCommand.INSTANCE;
}
// Retrieve property ends of the Association (assumed to be binary)
Property semanticSource = association.getMemberEnds().get(0);
Property semanticTarget = association.getMemberEnds().get(1);
EObject modifiedPropertyType = null;
if (request.getDirection() == ReorientRequest.REORIENT_SOURCE) {
if (!association.getOwnedEnds().contains(semanticSource)) {
moveRequest = new MoveRequest(request.getNewRelationshipEnd(), semanticSource);
}
modifiedPropertyType = semanticTarget;
setTypeRequest = new SetRequest(modifiedPropertyType, UMLPackage.eINSTANCE.getTypedElement_Type(), request.getNewRelationshipEnd());
}
if (request.getDirection() == ReorientRequest.REORIENT_TARGET) {
if (!association.getOwnedEnds().contains(semanticTarget)) {
moveRequest = new MoveRequest(request.getNewRelationshipEnd(), semanticTarget);
}
modifiedPropertyType = semanticSource;
setTypeRequest = new SetRequest(modifiedPropertyType, UMLPackage.eINSTANCE.getTypedElement_Type(), request.getNewRelationshipEnd());
}
if (moveRequest != null) {
// Propagate parameters to the move request
moveRequest.addParameters(request.getParameters());
IElementEditService provider = ElementEditServiceUtils.getCommandProvider(request.getNewRelationshipEnd());
if (provider != null) {
ICommand moveCommand = provider.getEditCommand(moveRequest);
gmfCommand = CompositeCommand.compose(gmfCommand, moveCommand);
}
}
if (setTypeRequest != null) {
// Propagate parameters to the set request
setTypeRequest.addParameters(request.getParameters());
IElementEditService provider = ElementEditServiceUtils.getCommandProvider(modifiedPropertyType);
if (provider != null) {
ICommand setTypeCommand = provider.getEditCommand(setTypeRequest);
gmfCommand = CompositeCommand.compose(gmfCommand, setTypeCommand);
}
}
// Destroy inconsistent views of the association
Set<View> viewsToDestroy = new HashSet<View>();
viewsToDestroy.addAll(getViewsToDestroy(association, request));
// return the command to destroy all these views
if (!viewsToDestroy.isEmpty()) {
DestroyDependentsRequest ddr = new DestroyDependentsRequest(request.getEditingDomain(), request.getRelationship(), false);
ddr.setClientContext(request.getClientContext());
ddr.addParameters(request.getParameters());
ICommand destroyViewsCommand = ddr.getDestroyDependentsCommand(viewsToDestroy);
gmfCommand = CompositeCommand.compose(gmfCommand, destroyViewsCommand);
}
if (gmfCommand != null) {
gmfCommand.reduce();
}
return gmfCommand;
}
/**
* Returns all views referencing Association except the view currently re-oriented.
*
* @param association
* the association referenced by views
* @param request
* the re-orient relationship request
* @return the list of views to be destroy
*/
private Set<View> getViewsToDestroy(Association association, ReorientRelationshipRequest request) {
Set<View> viewsToDestroy = new HashSet<View>();
// Find all views representing the Associations
EReference[] refs = new EReference[] { NotationPackage.eINSTANCE.getView_Element() };
@SuppressWarnings("unchecked")
Collection<View> associationViews = EMFCoreUtil.getReferencers(association, refs);
View currentlyReorientedView = RequestParameterUtils.getReconnectedEdge(request);
viewsToDestroy.addAll(associationViews);
viewsToDestroy.remove(currentlyReorientedView);
return viewsToDestroy;
}
/**
* Change owners for navigable OwnedEnd in association. For SysML diagrams only.
* Bug 364066
*/
@Override
protected ICommand getAfterSetCommand(SetRequest request) {
if (request.getElementToEdit() instanceof Association) {
Association association = (Association) request.getElementToEdit();
if (request.getFeature() == UMLPackage.eINSTANCE.getAssociation_NavigableOwnedEnd()) {
return changeAllNavigableElementsOwners((List<?>) request.getValue(), association);
}
}
return super.getAfterSetCommand(request);
}
private ICommand changeAllNavigableElementsOwners(List<?> members, Association association) {
if (members.isEmpty()) {
return null;
}
CompositeCommand cc = new CompositeCommand("Change association's properties owners"); //$NON-NLS-1$
for (Object member : members) {
if (member instanceof Property) {
cc.add(OwnedAttributeHelper.getSetTypeOwnerForAssociationAttributeCommand(association, (Property)member));
}
}
return cc.isEmpty() ? null : cc.reduce();
}
}