| /***************************************************************************** |
| * 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; |
| } |
| } |