blob: 7a7f36e00b9596c2743074e71a62f254cd1c0927 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2020 CEA LIST.
*
*
* 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:
* CEA LIST - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.robotics.xtext.compdef.ui.contribution;
import java.util.ArrayList;
import java.util.List;
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.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
import org.eclipse.papyrus.designer.uml.tools.utils.ElementUtils;
import org.eclipse.papyrus.infra.gmfdiag.extensionpoints.editors.configuration.ICustomDirectEditorConfiguration;
import org.eclipse.papyrus.robotics.core.utils.ParameterUtils;
import org.eclipse.papyrus.robotics.profile.robotics.components.Activity;
import org.eclipse.papyrus.robotics.profile.robotics.components.ActivityInstance;
import org.eclipse.papyrus.robotics.profile.robotics.components.ComponentPort;
import org.eclipse.papyrus.robotics.profile.robotics.components.ComponentService;
import org.eclipse.papyrus.robotics.profile.robotics.parameters.ParameterEntry;
import org.eclipse.papyrus.robotics.xtext.compdef.compDefText.Component;
import org.eclipse.papyrus.robotics.xtext.compdef.ui.internal.CompdefActivator;
import org.eclipse.papyrus.robotics.xtext.util.TrackNames;
import org.eclipse.papyrus.robotics.xtext.util.UpdateContextAdapter;
import org.eclipse.papyrus.uml.textedit.common.xtext.umlCommon.TypeRule;
import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil;
import org.eclipse.papyrus.uml.xtext.integration.AbstractXtextDirectEditorConfiguration;
import org.eclipse.papyrus.uml.xtext.integration.InvalidStringUtil;
import org.eclipse.papyrus.uml.xtext.integration.core.ContextElementAdapter.IContextElementProvider;
import org.eclipse.swt.SWT;
import org.eclipse.uml2.uml.AggregationKind;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Dependency;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.StructuredClassifier;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.UMLPackage;
import com.google.inject.Injector;
/**
* @author CEA LIST
*
* This class is used for contribution to the Papyrus extension point DirectEditor. It is used for the integration
* of an xtext generated editor for RobMoSys components
*/
@SuppressWarnings("nls")
public class CompDefEditorConfigurationContribution extends AbstractXtextDirectEditorConfiguration implements ICustomDirectEditorConfiguration {
TrackNames<Port> lastPorts;
TrackNames<Type> lastActivities;
TrackNames<Property> lastParams;
StructuredClassifier paramClass;
/**
* {@inheritDoc}
* Initialize lastNames map
*/
@Override
public Object preEditAction(Object objectToEdit) {
if (objectToEdit instanceof Class) {
// fill map with existing attribute and port names
Class umlComponent = (Class) objectToEdit;
// fill port names map
lastPorts = new TrackNames<Port>(umlComponent.getOwnedPorts());
// create activity list
EList<Type> activities = new BasicEList<Type>();
for (Property attribute : umlComponent.getOwnedAttributes()) {
Type type = attribute.getType();
if (type != null && StereotypeUtil.isApplied(type, Activity.class)) {
activities.add(type);
}
}
lastActivities = new TrackNames<Type>(activities);
// fill parameter names map
paramClass = ParameterUtils.getParameterClass(umlComponent);
EList<Property> parameters = new BasicEList<Property>();
if (paramClass != null) {
for (Property attribute : paramClass.getAttributes()) {
if (attribute.getName() != null) {
parameters.add(attribute);
}
}
}
lastParams = new TrackNames<Property>(parameters);
}
return super.preEditAction(objectToEdit);
}
@Override
public IContextElementProvider getContextProvider() {
return new UpdateContextAdapter(objectToEdit) {
@Override
public void updateLastNames() {
Component c = (Component) xtextResource.getContents().get(0);
List<String> portNameList = new ArrayList<String>();
for (org.eclipse.papyrus.robotics.xtext.compdef.compDefText.Port port : c.getPorts()) {
portNameList.add(port.getName());
}
lastPorts.update(portNameList);
List<String> activityNameList = new ArrayList<String>();
for (org.eclipse.papyrus.robotics.xtext.compdef.compDefText.Activity activity : c.getActivity()) {
activityNameList.add(activity.getName());
}
lastActivities.update(activityNameList);
List<String> paramNameList = new ArrayList<String>();
for (org.eclipse.papyrus.robotics.xtext.compdef.compDefText.Parameter parameter : c.getParameters()) {
paramNameList.add(parameter.getName());
}
lastParams.update(paramNameList);
}
};
}
/**
* Override to change style to {@link SWT}.MULTI
*/
@Override
public int getStyle() {
return SWT.MULTI | SWT.WRAP;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.papyrus.infra.gmfdiag.xtext.glue.PopupEditorConfiguration#getTextToEdit(java.lang.Object)
*/
@Override
public String getTextToEdit(Object editedObject) {
if (editedObject instanceof Class) {
Class clazz = (Class) editedObject;
String invalidStr = InvalidStringUtil.getTextualRepresentation(clazz);
if (invalidStr != null) {
return invalidStr;
}
return UnparseCompDef.getCompDefText(clazz).toString();
}
return "not a component";
}
/**
* @author CEA LIST
*
* A command for updating the context UML model
*/
protected class UpdateComponentCommand extends AbstractTransactionalCommand {
private Class clazz;
private final Component component;
public UpdateComponentCommand(TransactionalEditingDomain domain, Class clazz, Component component) {
super(domain, "Update component", getWorkspaceFiles(clazz)); //$NON-NLS-1$
this.clazz = clazz;
this.component = component;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand#doExecuteWithResult(org.eclipse.core.runtime.IProgressMonitor
* , org.eclipse.core.runtime.IAdaptable)
*/
@Override
protected CommandResult doExecuteWithResult(IProgressMonitor arg0, IAdaptable arg1) throws ExecutionException {
// extract information from the component, and update class
// Create the new component
if (component != null) {
clazz.setName(component.getName());
for (org.eclipse.papyrus.robotics.xtext.compdef.compDefText.Port port : component.getPorts()) {
String portName = port.getName();
Port existingPort = lastPorts.get(portName);
Type componentSvc = null;
if (existingPort != null) {
existingPort.setName(portName);
componentSvc = existingPort.getType();
}
if (componentSvc == null) {
componentSvc = clazz.createNestedClassifier(null, UMLPackage.eINSTANCE.getClass_());
StereotypeUtil.apply(componentSvc, ComponentService.class);
if (existingPort == null) {
existingPort = clazz.createOwnedPort(port.getName(), componentSvc);
existingPort.setAggregation(AggregationKind.COMPOSITE_LITERAL);
StereotypeUtil.apply(existingPort, ComponentPort.class);
}
existingPort.setType(componentSvc);
}
if (port.getProv() != null) {
NamedElement provided = ElementUtils.getQualifiedElementFromRS(clazz, port.getProv().getType().getQualifiedName());
if (provided instanceof Interface) {
for (Dependency dep : componentSvc.getClientDependencies()) {
dep.destroy();
}
((Class) componentSvc).createInterfaceRealization(null, (Interface) provided);
}
}
if (port.getReq() != null) {
NamedElement required = ElementUtils.getQualifiedElementFromRS(clazz, port.getReq().getType().getQualifiedName());
if (required != null) {
for (Dependency dep : componentSvc.getClientDependencies()) {
dep.destroy();
}
((Class) componentSvc).createUsage(required);
}
}
}
// update activities
// TODO - support reordering.
List<Property> activities = new ArrayList<Property>();
activities.addAll(clazz.getOwnedAttributes());
for (Property activity : activities) {
Type type = activity.getType();
if (type != null && StereotypeUtil.isApplied(type, Activity.class)) {
if (!lastActivities.containsValue(activity.getType())) {
activity.getType().destroy();
activity.destroy();
} else {
// clazz.getOwnedAttributes().remove(activity);
}
}
}
for (org.eclipse.papyrus.robotics.xtext.compdef.compDefText.Activity activityXt : component.getActivity()) {
String activityName = activityXt.getName().trim();
Type activity = lastActivities.get(activityName);
if (activity != null) {
activity.setName(activityName);
} else {
activity = clazz.createNestedClassifier(activityName, UMLPackage.eINSTANCE.getActivity());
StereotypeUtil.apply(activity, Activity.class);
Property activityAttr = clazz.createOwnedAttribute(activityName.toLowerCase(), activity);
StereotypeUtil.apply(activityAttr, ActivityInstance.class);
}
}
// update parameters
List<Property> attributes = new ArrayList<Property>();
attributes.addAll(paramClass.getOwnedAttributes());
for (Property paramEntry : attributes) {
if (!lastParams.containsValue(paramEntry)) {
paramEntry.destroy();
}
}
paramClass.getOwnedAttributes().clear();
for (org.eclipse.papyrus.robotics.xtext.compdef.compDefText.Parameter parameter : component.getParameters()) {
String paramName = parameter.getName().trim();
TypeRule typeRule = parameter.getType();
Property paramEntry = lastParams.get(paramName);
if (paramEntry != null) {
paramEntry.setName(paramName);
paramEntry.setType(typeRule != null ? typeRule.getType() : null);
paramClass.getOwnedAttributes().add(paramEntry);
} else {
paramEntry = paramClass.createOwnedAttribute(parameter.getName(), typeRule != null ? typeRule.getType() : null);
}
ParameterEntry pe = StereotypeUtil.applyApp(paramEntry, ParameterEntry.class);
String comment = parameter.getComment();
if (pe != null && comment != null) {
comment = comment.substring(2).trim();
pe.setDescription(comment);
}
}
}
return CommandResult.newOKCommandResult(clazz);
}
}
@Override
public Injector getInjector() {
return CompdefActivator.getInstance().getInjector(CompdefActivator.ORG_ECLIPSE_PAPYRUS_ROBOTICS_XTEXT_COMPDEF_COMPDEF);
}
@Override
public ICommand getParseCommand(EObject modelObject, EObject xtextObject) {
if (!(modelObject instanceof Class)) {
return null;
}
Class clazz = (Class) modelObject;
Component componentDef = (Component) xtextObject;
// component may be null, if we have no input left
// Creates and executes the update command
TransactionalEditingDomain dom = TransactionUtil.getEditingDomain(clazz);
UpdateComponentCommand updateCommand = new UpdateComponentCommand(dom, clazz, componentDef);
return updateCommand;
}
}