/*****************************************************************************
* Copyright (c) 2010 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:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.profile.custom.helper;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.command.IdentityCommand;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.emf.type.core.commands.DestroyElementCommand;
import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.commands.wrappers.EMFtoGEFCommandWrapper;
import org.eclipse.papyrus.editor.PapyrusMultiDiagramEditor;
import org.eclipse.papyrus.infra.core.editor.CoreMultiDiagramEditor;
import org.eclipse.papyrus.uml.diagram.common.helper.ElementHelper;
import org.eclipse.papyrus.uml.diagram.common.helper.NamedElementHelper;
import org.eclipse.papyrus.uml.diagram.common.util.DiagramEditPartsUtil;
import org.eclipse.papyrus.uml.diagram.common.util.MDTUtil;
import org.eclipse.papyrus.uml.diagram.common.util.Util;
import org.eclipse.papyrus.uml.diagram.profile.custom.policies.ExtensionCustomNameEditPolicy;
import org.eclipse.papyrus.uml.diagram.profile.edit.parts.ExtensionEditPart;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.AggregationKind;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Extension;
import org.eclipse.uml2.uml.ExtensionEnd;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.UMLFactory;
/**
* Helper for the Extensions
*/
public class ExtensionHelper extends ElementHelper {
/**
* the extension's name begins by this string
*/
final static public String EXTENSION = "Extension_"; //$NON-NLS-1$
/**
* the property's name in the stereotype begins by base_
*/
final static public String BASE = "base_"; //$NON-NLS-1$
/** the source position in Extension.getMembersEnds() */
public static int source = 0;
/** the target position in Extension.getMembersEnds() */
public static int target = 1;
/**
*
*
* @param metaclass
* @return the command to destroy the metaclass, the metaclass's extension and the stereotype's property
*/
static public Command getDestroyExtensionCommand(Class metaclass) {
CompoundCommand cc = new CompoundCommand("Destroy Extension"); //$NON-NLS-1$
/* get all the profile and sub-profile for the diagram */
CoreMultiDiagramEditor editor = (CoreMultiDiagramEditor)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
DiagramEditPart rootProfileEP = editor.getDiagramEditPart();
Profile rootProfile = (Profile)((View)rootProfileEP.getModel()).getElement();
List<?> profileList = Util.getInstancesFilteredByType(rootProfile, rootProfile.getClass(), null);
/*
* get all the extension of the metaclass
* /!\ some of them comes from the UML MetaModel
*/
EList<Extension> extensionList = metaclass.getExtensions();
/*
* get the extensions to destroy
*
* All the user's extension are owned by the rootProfile or a sub-profile
*/
ArrayList<Extension> extensionsToDestroy = new ArrayList<Extension>();
for(Extension extension : extensionList) {
EObject containerExt = extension.eContainer();
//test if it's a user extension or a metamodel extension
if(profileList.contains(containerExt) || containerExt == rootProfile) {
extensionsToDestroy.add(extension);
}
}
/*
* Destroy the property in the stereotypes
*/
for(int iterExt = 0; iterExt < extensionsToDestroy.size(); iterExt++) {
cc.add(StereotypeHelper.getRemovePropertyCommand(extensionsToDestroy.get(iterExt)));
}
/*
* Destroy the extensions
*/
for(Extension extension : extensionsToDestroy) {
DestroyElementRequest destroyElementRequest = new DestroyElementRequest(extension, false);
DestroyElementCommand destroyElementCommand = new DestroyElementCommand(destroyElementRequest);
cc.add(new ICommandProxy(destroyElementCommand));
}
if(cc.isEmpty()) {
//this command does nothing!
cc.add(new EMFtoGEFCommandWrapper(new IdentityCommand()));
}
return cc;
}
/**
* This method re-targets the source for an Extension.
*
*
* @param link
* @param newSource
* @return
*/
public static CommandResult reconnectSource(Extension link, Stereotype newSource) {
String deducedName = deduceExtensionNameFromProperties(link);
String oldName = link.getName();
EditPolicy policy = null;
//find the ExtensionEditPart
List<?> view = DiagramEditPartsUtil.getEObjectViews(link);
if(!view.isEmpty()) {
IEditorPart editor = MDTUtil.getActiveEditor();
DiagramEditPart diagram = ((PapyrusMultiDiagramEditor)editor).getDiagramEditPart();
EditPart extensionEP = DiagramEditPartsUtil.getEditPartFromView((View)view.get(0), diagram);
if(extensionEP instanceof ExtensionEditPart) {
policy = extensionEP.getEditPolicy(ExtensionCustomNameEditPolicy.SPECIFIC_EXTENSION_NAME_POLICY);
}
//we change the stereotype to listen!
if(policy != null) {
policy.deactivate();
}
}
Type sourceType = link.getEndTypes().get(source);
Type targetType = link.getEndTypes().get(target);
//unactive the editpolicy for this old stereotype
//remove the corresponding property in the old stereotype
if(sourceType instanceof Stereotype) {
EList<Property> attributes = ((Stereotype)sourceType).getOwnedAttributes();
for(Property property : attributes) {
if(property.getAssociation() == link) {
//remove the property from the stereotype
((Stereotype)sourceType).getOwnedAttributes().remove(property);
//remove the property from the extension
link.getMemberEnds().remove(property);
break;
}
}
}
//change the ExtensionEnd name
EList<Property> ends = link.getOwnedEnds();
for(Property endSource : ends) {
if(endSource instanceof ExtensionEnd) {
endSource.setName(ExtensionHelper.EXTENSION.replaceFirst("E", "e") + newSource.getName()); //$NON-NLS-1$ //$NON-NLS-2$
endSource.setType(newSource);
break;
}
}
//create the new source property (stereotype)
Property property = UMLFactory.eINSTANCE.createProperty();
property.setName(ExtensionHelper.BASE + targetType.getName());
property.setType(targetType);
property.setAssociation(link);
property.setAggregation(AggregationKind.NONE_LITERAL);
link.getMemberEnds().add(property);
newSource.getOwnedAttributes().add(property);
//change the extension name, if the user doesn't have rename the extension!
if(oldName.contains(deducedName)) {
if(oldName.indexOf(deducedName) == 0) {
oldName = oldName.substring(deducedName.length());
try {
Integer test = Integer.parseInt(oldName);
//if there is not exception, the name has not been edited by the user
link.setName(getExtensionName((Element)link.eContainer(), newSource, (Class)targetType));
} catch (NumberFormatException e) {
//do nothing
}
}
}
//the stereotype as change, now the edit policy is going to listen to this new stereotype
if(policy != null) {
policy.activate();
}
return CommandResult.newOKCommandResult(link);
}
/**
* Change the target for an {@link Extension}
*
* @param link
* the extension to modify
* @param newTarget
* the new target (metaclass) for this extension
* @param oldEnd
* @return
*/
public static CommandResult reconnectTarget(Extension link, Class newTarget) {
String deducedName = deduceExtensionNameFromProperties(link);
String oldName = link.getName();
Type sourceType = link.getEndTypes().get(source);
//change the name and the type of the property
if(sourceType instanceof Stereotype) {
EList<Property> attributes = ((Stereotype)sourceType).getOwnedAttributes();
for(Property property : attributes) {
if(property.getAssociation() == link) {
property.setType(newTarget);
property.setName(ExtensionHelper.BASE + newTarget.getName());
break;
}
}
//change the extension name, if the user doesn't have rename the extension!
if(oldName.contains(deducedName)) {
if(oldName.indexOf(deducedName) == 0) {
oldName = oldName.substring(deducedName.length());
try {
Integer test = Integer.parseInt(oldName);
//if there is not exception, the name didn't edited by the user
link.setName(getExtensionName((Element)link.eContainer(), (Stereotype)sourceType, newTarget));
} catch (NumberFormatException e) {
//do nothing
}
}
}
}
return CommandResult.newOKCommandResult(link);
}
/**
* Returns a name for the extension
*
* @param link
* the extension to name
* @param target
* the target
* @param source
* the source
* @return
* Returns a name for this extension
*/
public static String getExtensionName(Element extensionParent, Stereotype source, Class target) {
String name = "E_"; //$NON-NLS-1$
name += source.getName() + "_" + target.getName(); //$NON-NLS-1$
NamedElementHelper helper = new NamedElementHelper();
name = helper.getNewUMLElementName(extensionParent, name);//to add a number after the name!
return name;
}
/**
* Returns the name deduced from the ends of the extension
*
* @param extension
* the extension
* @return
* the name deduces from the properties
*/
public static String deduceExtensionNameFromProperties(Extension extension) {
//determine the name, if the user doesn't edit it
String logicName = "E_"; //$NON-NLS-1$
String stereotypeName = null;
stereotypeName = extension.getStereotype().getName();
String metaclassName = extension.getMetaclass().getName();
logicName += stereotypeName + "_" + metaclassName; //$NON-NLS-1$
return logicName;
}
}