Bug 560114 - [Robotics] Provide a CDT editor integration
- Provide an initial version of the texteditor integration plugin
- Add it to the parent POM
- Add it to the ROS2 feature
Change-Id: Icf58f1a0da1feac5d313faae931b7fac9feaf550
Signed-off-by: Ansgar Radermacher <ansgar.radermacher@cea.fr>
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.classpath b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.classpath
new file mode 100644
index 0000000..43b9862
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.project b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.project
new file mode 100644
index 0000000..aa4f730
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.robotics.cdt.texteditor</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.core.resources.prefs b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.jdt.core.prefs b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..0c68a61
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.m2e.core.prefs b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/META-INF/MANIFEST.MF b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b708ab3
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/META-INF/MANIFEST.MF
@@ -0,0 +1,39 @@
+Manifest-Version: 1.0
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.ui.editors;bundle-version="3.7.0",
+ org.eclipse.uml2.uml;bundle-version="3.2.0",
+ org.eclipse.cdt.core;bundle-version="5.4.0",
+ org.eclipse.cdt.ui;bundle-version="5.4.0",
+ org.eclipse.cdt.codan.ui.cxx;bundle-version="3.2.0",
+ org.eclipse.papyrus.infra.core.log;bundle-version="1.2.0",
+ org.eclipse.papyrus.designer.languages.cpp.profile;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.tools;bundle-version="1.2.0",
+ org.eclipse.papyrus.designer.languages.common.texteditor.model;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.tools.utils;bundle-version="1.2.0",
+ org.eclipse.papyrus.uml.diagram.common;bundle-version="1.2.0",
+ org.eclipse.papyrus.designer.languages.common.extensionpoints;bundle-version="1.1.0",
+ org.eclipse.papyrus.designer.languages.cpp.codegen;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.core.sasheditor;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.core.sasheditor.di;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.core.sashwindows.di;bundle-version="1.2.0",
+ org.eclipse.papyrus.designer.transformation.base;bundle-version="0.8.0",
+ org.eclipse.papyrus.designer.languages.cpp.library;bundle-version="1.1.0",
+ org.eclipse.papyrus.designer.languages.common.base;bundle-version="1.1.0",
+ org.eclipse.papyrus.designer.languages.common.codegen.ui;bundle-version="1.1.0",
+ org.eclipse.papyrus.designer.languages.cpp.cdt.texteditor;bundle-version="1.1.0",
+ org.eclipse.papyrus.robotics.transformation.ros2.library;bundle-version="0.7.0",
+ org.eclipse.papyrus.designer.transformation.core;bundle-version="0.8.0",
+ org.eclipse.papyrus.robotics.profile;bundle-version="0.7.0"
+Bundle-Vendor: %providerName
+Bundle-ActivationPolicy: lazy
+Bundle-Version: 0.7.0.qualifier
+Bundle-Localization: plugin
+Bundle-Name: %pluginName
+Bundle-Activator: org.eclipse.papyrus.robotics.cdt.texteditor.Activator
+Bundle-ManifestVersion: 2
+Bundle-Description: %pluginDescription
+Bundle-SymbolicName: org.eclipse.papyrus.robotics.cdt.texteditor;singleton:=true
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.eclipse.papyrus.robotics.cdt.texteditor
+Automatic-Module-Name: org.eclipse.papyrus.robotics.cdt.texteditor
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/build.properties b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/build.properties
new file mode 100644
index 0000000..883d0e1
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/build.properties
@@ -0,0 +1,8 @@
+source.. = src/
+output.. = target/classes/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ build.properties,\
+ icons/,\
+ plugin.properties
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/icons/texteditor.gif b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/icons/texteditor.gif
new file mode 100644
index 0000000..0d1a289
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/icons/texteditor.gif
Binary files differ
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/icons/texteditor.xcf b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/icons/texteditor.xcf
new file mode 100644
index 0000000..1749c42
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/icons/texteditor.xcf
Binary files differ
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/plugin.properties b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/plugin.properties
new file mode 100644
index 0000000..c22c525
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/plugin.properties
@@ -0,0 +1,12 @@
+# Copyright (c) CEA LIST.
+#
+# This program and the accompanying materials are made
+# available under the terms of the Eclipse Public License 2.0
+# which is available at https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+pluginName=Papyrus for Robotics CDT editor integration
+providerName=Eclipse Modeling Project
+
+pluginDescription=This plugin provides a CDT editor integration for Papyrus for Robotics
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/plugin.xml b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/plugin.xml
new file mode 100644
index 0000000..7d68dcd
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/plugin.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension point="org.eclipse.ui.commands">
+ <command
+ description="Open a Robotics CDT Editor"
+ defaultHandler="org.eclipse.papyrus.robotics.cdt.texteditor.handler.SyncRoboticsCDTEditorHandler"
+ id="org.eclipse.papyrus.robotics.cdt.texteditor.cmd.SyncCDTEditor"
+ name="Open a Robotics CDT Editor">
+ </command>
+ </extension>
+
+ <extension point="org.eclipse.ui.menus">
+ <menuContribution
+ allPopups="false"
+ locationURI="popup:org.eclipse.papyrus.robotics.simplifiedui.ui.menu">
+ <command
+ commandId="org.eclipse.papyrus.robotics.cdt.texteditor.cmd.SyncCDTEditor"
+ id="org.eclipse.papyrus.robotics.cdt.texteditor.menu.SyncCDTEditor"
+ icon="icons/texteditor.gif"
+ style="push">
+ <visibleWhen checkEnabled="false">
+ <iterate>
+ <adapt type="org.eclipse.emf.ecore.EObject">
+ <or>
+ <test property="org.eclipse.papyrus.uml.stereotype" value="robotics::components::ComponentDefinition"/>
+ <test property="org.eclipse.papyrus.uml.stereotype" value="robotics::components::Activity"/>
+ <test property="org.eclipse.papyrus.uml.stereotype" value="robotics::components::System"/>
+ </or>
+ </adapt>
+ </iterate>
+ </visibleWhen>
+ </command>
+ </menuContribution>
+ </extension>
+</plugin>
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/pom.xml b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/pom.xml
new file mode 100644
index 0000000..8d251fe
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/pom.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.papyrus.robotics</groupId>
+ <artifactId>org.eclipse.papyrus.robotics.reverse</artifactId>
+ <version>0.7.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.eclipse.papyrus.robotics.cdt.texteditor</artifactId>
+ <packaging>eclipse-plugin</packaging>
+ <description>This module contains the Papyrus CDT integration for C++ (definition for model-explorer)</description>
+</project>
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/Activator.java b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/Activator.java
new file mode 100644
index 0000000..220f852
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/Activator.java
@@ -0,0 +1,73 @@
+/*****************************************************************************
+ * Copyright (c) 2012 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:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.robotics.cdt.texteditor;
+
+import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.robotics.cdt.texteditor"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ public static LogHelper log;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ log = new LogHelper(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/AddProfileAndModelLibsHandler.java b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/AddProfileAndModelLibsHandler.java
new file mode 100644
index 0000000..a96602e
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/AddProfileAndModelLibsHandler.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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:
+ * Ansgar Radermacher - ansgar.radermacher@cea.fr CEA LIST - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.papyrus.robotics.cdt.texteditor;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.command.CommandStack;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.PackageImport;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.UMLFactory;
+import org.eclipse.uml2.uml.resource.UMLResource;
+
+/**
+ * This class adds the C++ profile as well as the ANSI-C library to your model.
+ *
+ * TODO: currently not used.
+ */
+public class AddProfileAndModelLibsHandler {
+
+ static final String CPP_PROFILE_URI = "pathmap://CPP_PROFILES/C_Cpp.profile.uml"; //$NON-NLS-1$
+
+ static final String ANSIC_LIBRARY_URI = "pathmap://CPP_LIBRARIES/Ansi_C.library.uml"; //$NON-NLS-1$
+
+ /**
+ * Retrieve a model library from the repository
+ *
+ * @param uri
+ * the URI of the repository
+ * @param domain
+ * the editing library
+ *
+ * @return the package import created for a model library
+ */
+ public PackageImport getModelLibraryImportFromURI(URI uri, EditingDomain domain) {
+ // Try to reach model
+ Element root = getContent(uri, domain);
+ if (root instanceof Package) {
+
+ // Import model library
+ Package libToImport = (Package) root;
+ // create import package
+ PackageImport modelLibImport = UMLFactory.eINSTANCE.createPackageImport();
+ modelLibImport.setImportedPackage(libToImport);
+
+ return modelLibImport;
+ }
+ return null;
+ }
+
+ public static Element getContent(URI uri, EditingDomain domain) {
+ // Resource resource = getTransactionalEditingDomain ().getResourceSet().getResource (uri, true);
+ Resource resource = domain.getResourceSet().getResource(uri, true);
+ return getContent(resource);
+ }
+
+ public static Element getContent(Resource resource) {
+ EList<EObject> contentObj = resource.getContents();
+ if ((contentObj.size() > 0) && (contentObj.get(0) instanceof Element)) {
+ return (Element) contentObj.get(0);
+ }
+ return null;
+ }
+
+ /**
+ * Check whether a package import is already done
+ *
+ * @param selectedPkg
+ * @param pi
+ * @return
+ */
+ boolean isAlreadyImported(Package selectedPkg, PackageImport pi) {
+ for (PackageImport existingPI : selectedPkg.getPackageImports()) {
+ if ((existingPI.getImportedPackage() == null) ||
+ (pi.getImportedPackage() == null)) {
+ // import package are null (should not happen?!)
+ continue;
+ }
+ if ((existingPI.getImportedPackage().getName() == null) ||
+ (pi.getImportedPackage().getName() == null)) {
+ // import package name not set (should not happen?!)
+ continue;
+ } else if (existingPI.getImportedPackage().getName().equals(pi.getImportedPackage().getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add C++ profile and package import for ANSI-C library
+ *
+ * @param selectedPkg
+ * the package to which the profile should be applied
+ * @throws ExecutionException
+ */
+ public void addProfileAndImport(final Package selectedPkg) throws ExecutionException {
+
+ final TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(selectedPkg);
+ CommandStack stack = domain.getCommandStack();
+ stack.execute(new RecordingCommand(domain, "Add C++ profile & ANSI-C library") { //$NON-NLS-1$
+ @Override
+ public void doExecute() {
+ // add primitive types
+ // create import package to primitiveType
+ PackageImport pi = getModelLibraryImportFromURI(URI.createURI(UMLResource.UML_PRIMITIVE_TYPES_LIBRARY_URI), domain);
+ selectedPkg.getPackageImports().add(pi);
+ addCppProfile(selectedPkg, domain);
+ };
+ });
+ }
+
+ public static void addCppProfile(Package selectedPkg, TransactionalEditingDomain domain) {
+
+ // Retrieve C++ profile
+ Profile cppProfile = (Profile) getContent(URI.createURI(CPP_PROFILE_URI), domain);
+
+ // Apply C++ profile to model
+ if (cppProfile instanceof Profile) {
+ Profile profile = selectedPkg.getAppliedProfile(cppProfile.getQualifiedName());
+ if ((profile == null) && (!cppProfile.getOwnedStereotypes().isEmpty())) {
+ selectedPkg.applyProfile(cppProfile);
+ }
+ }
+ }
+}
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/TextEditorConstants.java b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/TextEditorConstants.java
new file mode 100644
index 0000000..366204d
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/TextEditorConstants.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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:
+ * Ansgar Radermacher - ansgar.radermacher@cea.fr CEA LIST - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.papyrus.robotics.cdt.texteditor;
+
+import java.util.regex.Pattern;
+
+public class TextEditorConstants {
+
+ /**
+ * Regular expression for accepted language for compatible CDT code generators
+ */
+ public static final Pattern CPP = Pattern.compile("C\\+\\+|c\\+\\+|CPP|cpp|C|c"); //$NON-NLS-1$
+}
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/handler/SyncRoboticsCDTEditorHandler.java b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/handler/SyncRoboticsCDTEditorHandler.java
new file mode 100644
index 0000000..759f27d
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/handler/SyncRoboticsCDTEditorHandler.java
@@ -0,0 +1,155 @@
+/*****************************************************************************
+ * Copyright (c) 2012, 2016 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:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ * Ansgar Radermacher (CEA LIST) ansgar.radermacher@cea.fr
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.robotics.cdt.texteditor.handler;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.workspace.AbstractEMFOperation;
+import org.eclipse.papyrus.designer.languages.cpp.cdt.texteditor.editor.SyncCDTEditor;
+import org.eclipse.papyrus.designer.languages.cpp.cdt.texteditor.handler.SyncCDTEditorHandler;
+import org.eclipse.papyrus.infra.core.resource.NotFoundException;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
+import org.eclipse.papyrus.infra.emf.gmf.command.CheckedOperationHistory;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForHandlers;
+import org.eclipse.papyrus.robotics.cdt.texteditor.Activator;
+import org.eclipse.papyrus.robotics.cdt.texteditor.sync.SyncRoboticsCDTtoModel;
+import org.eclipse.papyrus.robotics.cdt.texteditor.sync.SyncRoboticsModelToCDT;
+import org.eclipse.papyrus.robotics.profile.robotics.components.Activity;
+import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.uml2.uml.Classifier;
+
+
+/**
+ * The handler creates a new CDT editor
+ */
+public class SyncRoboticsCDTEditorHandler extends SyncCDTEditorHandler {
+
+
+ public SyncRoboticsCDTEditorHandler() {
+ }
+
+ /**
+ * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ *
+ * @param event
+ * an execution event
+ * @return the execution result
+ * @throws ExecutionException
+ */
+ @Override
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ try {
+ final ServicesRegistry serviceRegistry = ServiceUtilsForHandlers.getInstance().getServiceRegistry(event);
+ TransactionalEditingDomain domain = ServiceUtils.getInstance().getTransactionalEditingDomain(serviceRegistry);
+
+
+ // Create the transactional command
+ AbstractEMFOperation command = new AbstractEMFOperation(domain, "Create CDT editor") { //$NON-NLS-1$
+
+ @Override
+ protected IStatus doExecute(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
+ try {
+ SyncRoboticsCDTEditorHandler.this.doExecute(serviceRegistry);
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ return Status.CANCEL_STATUS;
+ } catch (NotFoundException e) {
+ Activator.log.error(e);
+ return Status.CANCEL_STATUS;
+ }
+ return Status.OK_STATUS;
+ }
+ };
+
+ // Execute the command
+ CheckedOperationHistory.getInstance().execute(command, new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+ Activator.log.error("Can't create a CDT editor", e); //$NON-NLS-1$
+ } catch (ServiceException e) {
+ Activator.log.error("Service exception during creation of CDT editor", e); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+
+ /**
+ * Do the execution of the command.
+ *
+ * @param serviceRegistry
+ * @throws ServiceException
+ * @throws NotFoundException
+ */
+ public void doExecute(final ServicesRegistry serviceRegistry) throws ServiceException, NotFoundException {
+ Classifier classifierToEdit = getClassifierToEdit();
+
+ IFile srcFile = SyncRoboticsModelToCDT.syncModelToCDT(classifierToEdit, "Standard C++");
+ if (srcFile == null) {
+ return;
+ }
+
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ try {
+ // IEditorPart editorPart = page.openEditor(new FileEditorInput(srcFile), "org.eclipse.cdt.ui.editor.CEditor");
+
+ IEditorInput input = new FileEditorInput(srcFile);
+ IEditorPart editorPart = page.openEditor(input, "org.eclipse.papyrus.designer.languages.cpp.cdt.texteditor.editor.SyncCDTEditor");
+ if (editorPart instanceof SyncCDTEditor) {
+ // TODO: use editorPart.setInitializationData(cfig, propertyName, data);
+ URI uri = selectedEObject.eResource().getURI();
+ SyncRoboticsCDTtoModel syncCpp =
+ new SyncRoboticsCDTtoModel(input, classifierToEdit, uri.segment(1), "Standard C++");
+
+ ((SyncCDTEditor) editorPart).setEditorData(serviceRegistry, syncCpp);
+ }
+ } catch (PartInitException e) {
+ Activator.log.error(e);
+ }
+ }
+ });
+ }
+
+ @Override
+ protected Classifier getClassifierToEdit() {
+ Classifier cl = super.getClassifierToEdit();
+ if (StereotypeUtil.isApplied(cl, Activity.class)) {
+ // activities are always within components
+ return (Classifier) cl.getOwner();
+ }
+ return cl;
+ }
+}
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/PortInfo.java b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/PortInfo.java
new file mode 100644
index 0000000..ded5f6c
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/PortInfo.java
@@ -0,0 +1,12 @@
+package org.eclipse.papyrus.robotics.cdt.texteditor.sync;
+
+public class PortInfo {
+
+ public enum ProviderKind {
+ PUBLISHER, SUBSCRIBER, CLIENT, SERVER, ACTION_CLI, ACTION_SRV
+ }
+
+ public ProviderKind pk;
+ public String dtQName;
+ public String topic;
+}
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncPortsFromSource.java b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncPortsFromSource.java
new file mode 100644
index 0000000..c216d80
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncPortsFromSource.java
@@ -0,0 +1,173 @@
+package org.eclipse.papyrus.robotics.cdt.texteditor.sync;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTExpressionList;
+import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.papyrus.commands.Activator;
+import org.eclipse.papyrus.robotics.cdt.texteditor.sync.PortInfo.ProviderKind;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.uml2.uml.Classifier;
+
+public class SyncPortsFromSource {
+
+ private static final String CREATE_PUBLISHER = "create_publisher"; //$NON-NLS-1$
+ private static final String CREATE_SUBSCRIPTION = "create_subscription"; //$NON-NLS-1$
+ private static final String CREATE_SERVICE = "create_service"; //$NON-NLS-1$
+ private static final String CREATE_CLIENT = "create_client"; //$NON-NLS-1$
+
+ private static final String EXTERNAL_FILES = "External Files"; //$NON-NLS-1$
+
+ public static void updatePorts(Classifier cl, IASTNode node) {
+ List<PortInfo> portInfoList = new ArrayList<PortInfo>();
+ scanFunctions(node, portInfoList);
+ for (PortInfo pi : portInfoList) {
+ System.err.println(pi.dtQName);
+ // NamedElement namedElemParamType = ElementUtils.getQualifiedElementFromRS(element, expr2);
+ }
+ }
+
+ public static void scanFunctions(IASTNode node, List<PortInfo> portInfoList) {
+
+ for (IASTNode child : node.getChildren()) {
+ if (child instanceof IASTFunctionDefinition) {
+ IASTFunctionDefinition definition = (IASTFunctionDefinition) child;
+ scanBody(definition.getBody(), portInfoList);
+ }
+ if (child instanceof ICPPASTNamespaceDefinition) {
+ // recurse into namespaces
+ scanFunctions(child, portInfoList);
+ }
+ }
+ }
+ public static String getASTName(IASTExpression expr) {
+ if (expr instanceof IASTFieldReference) {
+ IASTName fieldName = ((IASTFieldReference) expr).getFieldName();
+ if (fieldName != null) {
+ return fieldName.toString();
+ }
+ return ""; //$NON-NLS-1$
+ } else {
+ return expr.toString();
+ }
+ }
+
+ public static ProviderKind getProviderFromCall(String fctName) {
+ if (fctName.equals(CREATE_CLIENT)) {
+ return ProviderKind.CLIENT;
+ }
+ if (fctName.equals(CREATE_SERVICE)) {
+ return ProviderKind.SERVER;
+ }
+ if (fctName.equals(CREATE_SUBSCRIPTION)) {
+ return ProviderKind.SUBSCRIBER;
+ }
+ if (fctName.equals(CREATE_PUBLISHER)) {
+ return ProviderKind.PUBLISHER;
+ }
+ return null;
+ }
+
+ public static PortInfo obtainCallDetails(ProviderKind pk, IASTExpression expr1, IASTExpression expr2) {
+ IASTExpression expr2b = ((IASTBinaryExpression) expr1).getOperand2();
+ IASTExpression topicExpr = null;
+ if (expr2 instanceof IASTUnaryExpression) {
+ IASTExpression arguments = ((IASTUnaryExpression) expr2).getOperand();
+ if (arguments instanceof IASTExpressionList) {
+ topicExpr = ((IASTExpressionList) arguments).getExpressions()[0];
+ } else {
+ topicExpr = arguments;
+ }
+ }
+ String topicName = topicExpr.toString();
+ // remove quotes
+ if (topicName.startsWith("\"") && topicName.length()>=2) { //$NON-NLS-1$
+ topicName = topicName.substring(1, topicName.length()-1);
+ }
+ PortInfo portInfo = new PortInfo();
+ portInfo.pk = pk;
+ portInfo.dtQName = getASTName(expr2b);
+ portInfo.topic = topicName;
+ return portInfo;
+}
+
+ public static void scanBody(IASTNode node, List<PortInfo> portList) {
+ if (node instanceof IASTBinaryExpression) {
+ IASTBinaryExpression expr = (IASTBinaryExpression) node;
+ IASTExpression expr1 = expr.getOperand1();
+ IASTExpression expr2 = expr.getOperand2();
+ if (expr1 instanceof IASTBinaryExpression) {
+ IASTExpression expr1b = ((IASTBinaryExpression) expr1).getOperand1();
+ String fieldName = getASTName(expr1b);
+
+ if (fieldName != null) {
+ ProviderKind pk = getProviderFromCall(fieldName);
+ if (pk != null) {
+ PortInfo portInfo = obtainCallDetails(pk, expr1, expr2);
+ if (portInfo != null) {
+ portList.add(portInfo);
+ }
+ }
+ }
+ }
+ }
+ for (IASTNode child : node.getChildren()) {
+ // recurse into all children
+ scanBody(child, portList);
+ }
+ }
+
+ public static void tst() {
+ IWorkspace ws = ResourcesPlugin.getWorkspace();
+ IProject project = ws.getRoot().getProject(EXTERNAL_FILES);
+
+ try {
+ if (!project.exists())
+ project.create(null);
+ if (!project.isOpen())
+ project.open(null);
+ Shell shell = Display.getDefault().getActiveShell();
+ String name = (1 == 0) ? "/local/home/ansgar/prog/ros2/demos/demo_nodes_cpp/src/services/add_two_ints_client.cpp" : new FileDialog(shell, SWT.OPEN).open();
+ if (name == null)
+ return;
+ IPath location = new Path(name);
+ IFile srcFile = project.getFile(location.lastSegment());
+ boolean exists = srcFile.exists();
+ if (exists) {
+ srcFile.delete(false, null);
+ }
+ srcFile.createLink(location, IResource.NONE, null);
+
+
+ ITranslationUnit itu = (ITranslationUnit) CoreModel.getDefault().create(srcFile);
+
+ IASTTranslationUnit ast = itu.getAST();
+ scanFunctions(ast, new ArrayList<PortInfo>());
+
+ } catch (CoreException e) {
+ Activator.log.error(e);
+ }
+ }
+}
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncRoboticsCDTtoModel.java b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncRoboticsCDTtoModel.java
new file mode 100644
index 0000000..6977980
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncRoboticsCDTtoModel.java
@@ -0,0 +1,468 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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:
+ * Ansgar Radermacher - ansgar.radermacher@cea.fr CEA LIST - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.papyrus.robotics.cdt.texteditor.sync;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
+import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
+import org.eclipse.cdt.core.dom.ast.IASTStatement;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.index.IIndex;
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
+import org.eclipse.cdt.core.model.IMethodDeclaration;
+import org.eclipse.cdt.core.model.IParent;
+import org.eclipse.cdt.core.model.ISourceRange;
+import org.eclipse.cdt.core.model.ISourceReference;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.model.IWorkingCopy;
+import org.eclipse.cdt.ui.CDTUITools;
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.papyrus.designer.languages.common.extensionpoints.ILangCodegen;
+import org.eclipse.papyrus.designer.languages.common.extensionpoints.ILangCodegen2;
+import org.eclipse.papyrus.designer.languages.common.extensionpoints.SyncInformation;
+import org.eclipse.papyrus.designer.languages.cpp.cdt.texteditor.Utils;
+import org.eclipse.papyrus.designer.languages.cpp.cdt.texteditor.listener.ModelListener;
+import org.eclipse.papyrus.designer.languages.cpp.cdt.texteditor.sync.SyncCDTtoModel;
+import org.eclipse.papyrus.designer.languages.cpp.codegen.Constants;
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Include;
+import org.eclipse.papyrus.infra.core.Activator;
+import org.eclipse.papyrus.robotics.cdt.texteditor.TextEditorConstants;
+import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil;
+import org.eclipse.papyrus.uml.tools.utils.UMLUtil;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.uml2.uml.Behavior;
+import org.eclipse.uml2.uml.BehavioralFeature;
+import org.eclipse.uml2.uml.Class;
+import org.eclipse.uml2.uml.Classifier;
+import org.eclipse.uml2.uml.Comment;
+import org.eclipse.uml2.uml.NamedElement;
+import org.eclipse.uml2.uml.OpaqueBehavior;
+import org.eclipse.uml2.uml.Operation;
+import org.eclipse.uml2.uml.PackageableElement;
+import org.eclipse.uml2.uml.Parameter;
+import org.eclipse.uml2.uml.ParameterDirectionKind;
+import org.eclipse.uml2.uml.Type;
+import org.eclipse.uml2.uml.UMLFactory;
+import org.eclipse.uml2.uml.UMLPackage;
+
+public class SyncRoboticsCDTtoModel extends SyncCDTtoModel {
+
+ public SyncRoboticsCDTtoModel(IEditorInput input, Classifier classifier, String projectName, String generatorID) {
+ super(input, classifier, projectName, generatorID);
+ }
+
+
+ @Override
+ public void run() {
+ ICElement ice = CDTUITools.getEditorInputCElement(m_input);
+ ModelListener.syncFromEditor = true;
+
+ if (ice instanceof ITranslationUnit) {
+ ICProject project = CoreModel.getDefault().getCModel().getCProject(m_projectName);
+
+ IIndex index = null;
+ try {
+ index = CCorePlugin.getIndexManager().getIndex(project);
+ index.acquireReadLock();
+
+ ITranslationUnit itu = (ITranslationUnit) ice;
+
+ IASTTranslationUnit ast = itu.getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
+ IASTNodeSelector selector = ast.getNodeSelector(null);
+
+ examineChildren(itu, selector, itu);
+ updateCppInclude(itu);
+ SyncPortsFromSource.updatePorts(m_classifier, ast);
+
+ CUIPlugin.getDefault().getProblemMarkerManager();
+ if (itu instanceof IWorkingCopy) {
+ ((IWorkingCopy) itu).reconcile(true, new NullProgressMonitor());
+ }
+
+ } catch (CModelException e) {
+ Activator.log.error(e);
+ } catch (Exception e) {
+ Activator.log.error(e);
+ } finally {
+ if (index != null) {
+ index.releaseReadLock();
+ }
+ }
+ }
+ ModelListener.syncFromEditor = false;
+ }
+
+ /**
+ * Examine the children of a translation unit in order to extract the
+ * methods that are defined within hte unit
+ *
+ * @param itu
+ * @param selector
+ * @param parent
+ * @throws CModelException
+ */
+ public void examineChildren(ITranslationUnit itu, IASTNodeSelector selector, IParent parent)
+ throws CModelException {
+
+ int position = 0;
+ // if (parent instanceof Namespace) {
+ for (ICElement child : parent.getChildren()) {
+ if (child instanceof IParent) {
+ examineChildren(itu, selector, (IParent) child);
+ }
+ ISourceRange range = null;
+ if (child instanceof ISourceReference) {
+ range = ((ISourceReference) child).getSourceRange();
+ }
+ if (child instanceof IFunctionDeclaration) {
+ // function declaration is a superclass for method declaration
+ // (but need to trace functions differently?)
+ String name = ((IFunctionDeclaration) child).getElementName();
+ IASTNode node = selector.findEnclosingNode(range.getStartPos(), range.getLength());
+ if (node instanceof IASTFunctionDefinition) {
+ IASTFunctionDefinition definition = (IASTFunctionDefinition) node;
+ IASTFunctionDeclarator declarator = definition.getDeclarator();
+ String unfilteredBody = getBody(itu, definition);
+ // get additional information about method synchronization from generator
+ SyncInformation syncInfo = null;
+ if (m_codegen instanceof ILangCodegen2) {
+ syncInfo = ((ILangCodegen2) m_codegen).getSyncInformation(name, unfilteredBody);
+ }
+ String body = Utils.removeGenerated(unfilteredBody);
+ if (syncInfo == null || !syncInfo.isGenerated) {
+ // only update method, if it is not generated
+ NamedElement ne = updateMethod(position, parent, name, body, declarator, syncInfo);
+ if (ne != null) {
+ updateComment(itu, definition, ne);
+ }
+ }
+ // System.err.println("body source <" + body + ">");
+ }
+ position++;
+ }
+ }
+ }
+
+ /**
+ * update the contents of the CppInclude directive
+ *
+ * @param itu
+ * the translation unit
+ */
+ public void updateCppInclude(ITranslationUnit itu) {
+ String contents = new String(itu.getContents());
+ int preBodyStart = contents.indexOf(Constants.cppIncPreBodyStart);
+ int preBodyEnd = contents.indexOf(Constants.cppIncPreBodyEnd);
+ String preBody = ""; //$NON-NLS-1$
+ String body = ""; //$NON-NLS-1$
+ if (preBodyStart != -1) {
+ preBodyStart += Constants.cppIncPreBodyStart.length();
+ if (preBodyEnd > preBodyStart) {
+ preBody = contents.substring(preBodyStart, preBodyEnd).trim();
+ }
+ }
+
+ int bodyStart = contents.indexOf(Constants.cppIncBodyStart);
+ int bodyEnd = contents.indexOf(Constants.cppIncBodyEnd);
+
+ if (bodyStart != -1) {
+ bodyStart += Constants.cppIncBodyStart.length() + 1;
+ if (bodyEnd > bodyStart) {
+ body = contents.substring(bodyStart, bodyEnd).trim();
+ }
+ }
+ if (body.length() > 0 || preBody.length() > 0) {
+ Include include = StereotypeUtil.applyApp(m_classifier, Include.class);
+ if (include != null) {
+ include.setPreBody(preBody);
+ include.setBody(body);
+ }
+ }
+ }
+
+ /**
+ * Update a method in the model based on the qualified name.
+ *
+ * @param position
+ * The position of the method within the file. Used to identify
+ * renaming operations
+ * @param parent
+ * the CDT parent which is used to get a list of children
+ * @param qualifiedName
+ * the qualified name of a method
+ * @param body
+ * the method body
+ * @param declarator
+ * the declarator for the method
+ * @return the operation or the behavior within the model that got updated. The latter is returned in
+ * case of behaviors that do not have a specification (e.g. the effect of a transition).
+ */
+ public NamedElement updateMethod(int position, IParent parent, String qualifiedName, String body,
+ IASTFunctionDeclarator declarator, SyncInformation syncInfo) {
+
+ String names[] = qualifiedName.split(Utils.nsSep);
+ String name = names[names.length - 1];
+
+ Operation operation = null;
+ Behavior behavior = null;
+
+ if (syncInfo == null || (syncInfo.behavior == null && syncInfo.createBehaviorName == null)) {
+ behavior = getModelBehaviorFromName(name, parent, position);
+ if (behavior != null) {
+ behavior.setName(name);
+ }
+ }
+ else if (syncInfo.behavior != null) {
+ // operation is still null (=> does not enter operation != null case below)
+ behavior = syncInfo.behavior;
+ }
+ else if ((syncInfo.createBehaviorName != null) && (m_classifier instanceof Class)) {
+ Class clazz = (Class) m_classifier;
+ behavior = (OpaqueBehavior) clazz.createOwnedBehavior(syncInfo.createBehaviorName,
+ UMLPackage.eINSTANCE.getOpaqueBehavior().eClass());
+ }
+ if (behavior == null) {
+ return null;
+ }
+
+ // Remove all parameters from operation / behavior (they will be added later).
+ // Calling parameters.clear() is not sufficient. Otherwise stereotype
+ // applications to unresolved elements remain in the model
+ List<Parameter> existingParameters = new BasicEList<Parameter>();
+ UMLUtil.destroyElements(behavior.getOwnedParameters());
+ if (behavior != null) {
+ for (Parameter existingParameter : behavior.getOwnedParameters()) {
+ Parameter existingParamCopy = UMLFactory.eINSTANCE.createParameter();
+ existingParamCopy.setName(existingParameter.getName());
+ existingParamCopy.setType(existingParameter.getType());
+ existingParamCopy.setDirection(existingParameter.getDirection());
+ existingParameters.add(existingParamCopy);
+ }
+ }
+
+ IASTFunctionDefinition definition = (IASTFunctionDefinition) declarator.getParent();
+ IASTDeclSpecifier declSpecifier = definition.getDeclSpecifier();
+ Type paramType = getParameterType(null, declSpecifier.toString(), existingParameters);
+ Parameter umlParameter = null;
+ umlParameter = behavior.createOwnedParameter("ret", paramType);
+ umlParameter.setDirection(ParameterDirectionKind.RETURN_LITERAL);
+ // applyParameterModifiers(parameterType, umlParameter, modifiers);
+
+ if (behavior instanceof OpaqueBehavior) {
+ OpaqueBehavior ob = (OpaqueBehavior) behavior;
+ if (ob.getBodies().size() == 0) {
+ ob.getLanguages().add(c_cpp_langID);
+ ob.getBodies().add(""); //$NON-NLS-1$
+ }
+ for (int i = 0; i < ob.getLanguages().size(); i++) {
+ // update first body of one of the languages supported by CDT. This implies that
+ // it is actually not possible to have separate C and C++ bodes in the same opaque
+ // behavior (which is rarely a good idea).
+ String language = ob.getLanguages().get(i);
+ if (TextEditorConstants.CPP.matcher(language).matches() || c_cpp_langID.equals(language)) {
+ if (i < ob.getBodies().size()) {
+ // should always be true, unless sync between
+ // languages/bodies is lost
+ ob.getBodies().set(i, body);
+ }
+ }
+ }
+ }
+ return behavior;
+ }
+
+ /**
+ * Obtain a behavior from the model. Similar to method getModelOperationFromName in
+ * superclass, but Robotics functions are currently defined by opaque behaviors
+ *
+ * @param name the operation name within CDT
+ * @param parent the parent of the CDT method within CDT editor model
+ * @param position the position within the other methods. This information is used to locate methods
+ * within the model that might have been renamed in the CDT editor.
+ * @return a UML operation
+ */
+ public Behavior getModelBehaviorFromName(String name, IParent parent, int position) {
+ // operation does not belong to component itself, but to one of the
+ // activities which in turn consist of functions. Currently, functions are defined
+ // in the package containing the component
+ PackageableElement beh = m_classifier.getNearestPackage().getPackagedElement(name);
+ if (beh instanceof OpaqueBehavior) {
+ return (OpaqueBehavior) beh;
+ }
+
+ List<Behavior> bl = new ArrayList<Behavior>();
+ for (PackageableElement pe : m_classifier.getNearestPackage().getPackagedElements()) {
+ if (pe instanceof Behavior) {
+ bl.add((Behavior) pe);
+ }
+ }
+ // operation is not found via name in the model. try to locate the operation in the model at the same
+ // "position" as the method in the file and
+ // verify that this method does not have the same name as any method
+ // in the CDT file.
+ Behavior be = null;
+ if (position < bl.size()) {
+ be = bl.get(position);
+ String modelName = be.getName();
+ try {
+ for (ICElement child : parent.getChildren()) {
+ if (child instanceof IMethodDeclaration) {
+ String cdtName = ((IMethodDeclaration) child).getElementName();
+ if (cdtName.equals(modelName)) {
+ // an existing operation in the CDT file already
+ // has this name
+ be = null;
+ break;
+ }
+ }
+ }
+ } catch (CModelException e) {
+ }
+ }
+ return be;
+ }
+
+ public static String getBody(ITranslationUnit itu, IASTFunctionDefinition definition) {
+ IASTStatement body = definition.getBody();
+
+ if (body instanceof IASTCompoundStatement) {
+ IASTCompoundStatement bodyComp = (IASTCompoundStatement) body;
+
+ IASTFileLocation bodyLoc = bodyComp.getFileLocation();
+ int start = bodyLoc.getNodeOffset();
+ int end = start + bodyLoc.getNodeLength();
+ char contents[] = itu.getContents();
+ // body contains enclosing { } which we need to remove (+2, -2). We
+ // cannot use the
+ // first and last statement, since leading and trailing comments are
+ // not part of the AST tree.
+ return Utils.decreaseIndent(contents, start + 2, end - 2);
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * update a comment of a named element. Besides the comment of the element itself, comments on contained
+ * parameters are handled.
+ *
+ * @param itu a translation unit
+ * @param definition
+ * @param ne a named element that is either an operation or a behavior (in order to update parameters)
+ */
+ public void updateComment(ITranslationUnit itu, IASTFunctionDefinition definition, NamedElement ne) {
+ IASTFileLocation bodyLoc = definition.getFileLocation();
+ int start = bodyLoc.getNodeOffset() - 1;
+ int end = start;
+ char contents[] = itu.getContents();
+ String comment = ""; //$NON-NLS-1$
+ // backward scan for beginning /*
+ while (start > 0) {
+ if (contents[start] == '/' && contents[start + 1] == '*') {
+ start += "/**".length(); // TODO: common string //$NON-NLS-1$
+ // constants with generator
+ for (int i = start; i < end; i++) {
+ comment += contents[i];
+ }
+ comment = comment.replace("\n * ", "\n"). //$NON-NLS-1$//$NON-NLS-2$
+ replace("*/", "").trim(); //$NON-NLS-1$//$NON-NLS-2$
+ break;
+ }
+ start--;
+ }
+ if (comment.length() > 0) {
+ // filter @param
+ int atParam = comment.indexOf(sAtParam);
+ String commentMethodOnly = (atParam != -1) ? comment.substring(0, atParam).trim() : comment;
+
+ EList<Comment> commentsUML = ne.getOwnedComments();
+ Comment commentUML;
+ if (commentsUML.size() == 0) {
+ commentUML = ne.createOwnedComment();
+ commentUML.getAnnotatedElements().add(commentUML);
+ } else {
+ commentUML = commentsUML.get(0);
+ }
+ while (atParam != -1) {
+ int currentAtParam = atParam;
+ atParam = comment.indexOf(sAtParam, atParam + 1);
+ String commentParam = (atParam != -1) ? comment.substring(currentAtParam, atParam)
+ : comment.substring(currentAtParam);
+ Comment commentParamUML;
+ int atParamName = sAtParam.length();
+
+ while ((atParamName < commentParam.length())
+ && Character.isWhitespace(commentParam.charAt(atParamName))) {
+ atParamName++;
+ }
+ int atParamNameEnd = atParamName;
+ while ((atParamNameEnd < commentParam.length())
+ && !Character.isWhitespace(commentParam.charAt(atParamNameEnd))) {
+ atParamNameEnd++;
+ }
+ if (atParamNameEnd < commentParam.length() - 1) {
+ String parameterName = commentParam.substring(atParamName, atParamNameEnd);
+ String commentParamText = commentParam.substring(atParamNameEnd).trim();
+ Parameter parameter = null;
+ if (ne instanceof BehavioralFeature) {
+ parameter = ((BehavioralFeature) ne).getOwnedParameter(parameterName, null, false, false);
+ }
+ else if (ne instanceof Behavior) {
+ parameter = ((Behavior) ne).getOwnedParameter(parameterName, null, false, false);
+ }
+ if (parameter != null) {
+ EList<Comment> commentsParamUML = parameter.getOwnedComments();
+ if (commentsParamUML.size() == 0) {
+ commentParamUML = parameter.createOwnedComment();
+ commentParamUML.getAnnotatedElements().add(commentParamUML);
+ } else {
+ commentParamUML = commentsParamUML.get(0);
+ }
+ commentParamUML.setBody(commentParamText);
+ } else {
+ // parameter is not found in model, e.g. either renamed
+ // or not yet existing
+ // store comment in operation comment
+ commentMethodOnly += "\n " + sAtParam + parameterName + //$NON-NLS-1$
+ " not found(!) " + commentParamText; //$NON-NLS-1$
+ }
+ }
+ }
+ commentUML.setBody(commentMethodOnly);
+ }
+ }
+
+ /**
+ * Accessor
+ * @return value of codegen attribute
+ */
+ public ILangCodegen getCodeGen() {
+ return m_codegen;
+ }
+}
diff --git a/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncRoboticsModelToCDT.java b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncRoboticsModelToCDT.java
new file mode 100644
index 0000000..a0f02c4
--- /dev/null
+++ b/plugins/reverse/org.eclipse.papyrus.robotics.cdt.texteditor/src/org/eclipse/papyrus/robotics/cdt/texteditor/sync/SyncRoboticsModelToCDT.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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:
+ * Ansgar Radermacher - ansgar.radermacher@cea.fr CEA LIST - initial API and implementation
+ *
+ *******************************************************************************/
+
+package org.eclipse.papyrus.robotics.cdt.texteditor.sync;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.papyrus.designer.languages.common.extensionpoints.ILangCodegen;
+import org.eclipse.papyrus.designer.languages.common.extensionpoints.ILangCodegen.FILE_KIND;
+import org.eclipse.papyrus.designer.languages.common.extensionpoints.ILangCodegen2;
+import org.eclipse.papyrus.designer.languages.common.extensionpoints.LanguageCodegen;
+import org.eclipse.papyrus.designer.languages.cpp.codegen.Constants;
+import org.eclipse.papyrus.designer.transformation.base.utils.ProjectManagement;
+import org.eclipse.papyrus.designer.transformation.core.transformations.ExecuteTransformationChain;
+import org.eclipse.papyrus.infra.core.Activator;
+import org.eclipse.papyrus.robotics.cdt.texteditor.TextEditorConstants;
+import org.eclipse.papyrus.robotics.transformation.ros2.library.commands.PrepareCodegenCmd;
+import org.eclipse.papyrus.uml.tools.utils.PackageUtil;
+import org.eclipse.ui.progress.UIJob;
+import org.eclipse.uml2.uml.Class;
+import org.eclipse.uml2.uml.Classifier;
+import org.eclipse.uml2.uml.Package;
+
+/**
+ * Main listener for model changes (registered via plugin.xml). It will delegate
+ * to the sub-listeners for specific sub-elements (type, operation, port, ...) that
+ * can be found in this package
+ *
+ */
+public class SyncRoboticsModelToCDT {
+
+ private static final String CPP_SUFFIX = "cpp"; //$NON-NLS-1$
+ /**
+ * set to true, if a synchronization from an CDT editor to the model is active
+ */
+ public static boolean syncFromEditor;
+
+ public static IFile syncModelToCDT(Classifier classifier, String generatorID) {
+ if (!(classifier instanceof Class) || classifier.eResource() == null) {
+ return null;
+ }
+
+ Package pkg = PackageUtil.getRootPackage((Class) classifier);
+ PrepareCodegenCmd prepareCmd = new PrepareCodegenCmd(pkg);
+ if (prepareCmd.prepare()) {
+ IProject modelProject = ProjectManagement.getCurrentProject();
+
+ Job job = new UIJob("Generate ROS code") {
+
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ // execute the task ...
+ new ExecuteTransformationChain(pkg, modelProject).executeTransformation(monitor, 0);
+ prepareCmd.undo();
+ return Status.OK_STATUS;
+ }
+ };
+ job.setUser(true);
+ job.schedule();
+
+ ILangCodegen codegen = LanguageCodegen.getGenerator(TextEditorConstants.CPP, generatorID);
+ IProject targetProject = ResourcesPlugin.getWorkspace().getRoot().getProject(classifier.getName());
+
+ IContainer srcPkg = null;
+ IFile cppFile = null;
+ try {
+
+ String suffix = (codegen instanceof ILangCodegen2) ? suffix = ((ILangCodegen2) codegen).getSuffix(FILE_KIND.BODY) : CPP_SUFFIX;
+
+ cppFile = targetProject.getFile(new Path(codegen.getFileName(targetProject, classifier) + Constants.DOT + suffix));
+
+ // IStorage storage = new TextStorage(string);
+ } finally {
+ // Refresh the container for the newly created files. This needs to be done even
+ // during error because of the possibility for partial results.
+ try {
+ if (srcPkg != null) {
+ srcPkg.refreshLocal(IResource.DEPTH_INFINITE, null);
+ }
+ } catch (CoreException e) {
+ Activator.log.error(e);
+ }
+ }
+ return cppFile;
+ }
+ return null;
+ }
+}
diff --git a/plugins/reverse/pom.xml b/plugins/reverse/pom.xml
index f82719e..7cc2426 100644
--- a/plugins/reverse/pom.xml
+++ b/plugins/reverse/pom.xml
@@ -15,6 +15,7 @@
<modules>
<module>org.eclipse.papyrus.robotics.reverse.ros2</module>
+ <module>org.eclipse.papyrus.robotics.cdt.texteditor</module>
</modules>
</project>
diff --git a/releng/org.eclipse.papyrus.robotics.feature/feature.xml b/releng/org.eclipse.papyrus.robotics.feature/feature.xml
index 4876fc9..7c49833 100644
--- a/releng/org.eclipse.papyrus.robotics.feature/feature.xml
+++ b/releng/org.eclipse.papyrus.robotics.feature/feature.xml
@@ -24,7 +24,7 @@
<import feature="org.eclipse.papyrus.sdk.feature" version="3.0.0" match="greaterOrEqual"/>
<import feature="org.eclipse.papyrus.marte.core.feature" version="1.2.2" match="greaterOrEqual"/>
<import feature="org.eclipse.papyrus.marte.textedit.feature" version="1.2.2" match="greaterOrEqual"/>
- <import feature="org.eclipse.papyrus.designer.languages.cpp.feature" version="1.0.5" match="greaterOrEqual"/>
+ <import feature="org.eclipse.papyrus.designer.languages.common.feature" version="1.1.1.qualifier"/>
</requires>
<plugin
diff --git a/releng/org.eclipse.papyrus.robotics.ros2.feature/feature.xml b/releng/org.eclipse.papyrus.robotics.ros2.feature/feature.xml
index 030122a..ef313e7 100644
--- a/releng/org.eclipse.papyrus.robotics.ros2.feature/feature.xml
+++ b/releng/org.eclipse.papyrus.robotics.ros2.feature/feature.xml
@@ -6,7 +6,8 @@
provider-name="%providerName">
<description url="https://eclipse.org/papyrus/components/robotics/">
- This feature provides ROS2 code generation and reverse for Papyrus for Robotics
+ This feature provides ROS2 code generation and reverse for Papyrus
+for Robotics. It also provides the integration of an Eclipse CDT editor.
</description>
<copyright url="https://www.eclipse.org/legal/epl-2.0/">
@@ -22,6 +23,7 @@
<requires>
<import feature="org.eclipse.papyrus.robotics.feature" version="0.7.0.qualifier"/>
+ <import feature="org.eclipse.papyrus.designer.languages.cpp.feature" version="1.1.0.qualifier"/>
</requires>
<plugin
@@ -45,4 +47,11 @@
version="0.0.0"
unpack="false"/>
+ <plugin
+ id="org.eclipse.papyrus.robotics.cdt.texteditor"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
</feature>