Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2016-02-11 02:48:20 +0000
committerGerrit Code Review @ Eclipse.org2016-02-12 15:31:41 +0000
commitecd4928b327f5561364c5068c9ff5f1668e92d13 (patch)
tree7c34f46cf82a1d65ac753fa92c2a5d55371b8dba /plugins/infra/emf
parent751a204d74e15eb2db6b41c937691fc56dcc1252 (diff)
downloadorg.eclipse.papyrus-ecd4928b327f5561364c5068c9ff5f1668e92d13.tar.gz
org.eclipse.papyrus-ecd4928b327f5561364c5068c9ff5f1668e92d13.tar.xz
org.eclipse.papyrus-ecd4928b327f5561364c5068c9ff5f1668e92d13.zip
Bug 485220: [Architecture] Provide a more modular architecture
https://bugs.eclipse.org/bugs/show_bug.cgi?id=485220 Factor UI dependencies out of the UML Element Types bundle. This includes moving some advices that interact with the user into a new org.eclipse.papyrus.uml.service.types.ui bundle. Pull up the PasteCommandService and IPasteCommandProvider API into the Infra Diagram layer where the extension point is defined. Deprecate the old API in the UML layer. Introduce a service for participation of languages in CSS styling: * styling reset actions in the Reset Style command * access to semantic model classes and properties to make available to CSS Factor PapyrusObservableValue and cohorts out of the UML Tools bundle into the Infra Layer for more general reuse and to relieve the Diagram Infrastructure layer of UML dependencies. The old API remains as deprecated. Remove the Infra Diagram Layer dependency on UML Layer for property testers governing deletion in the diagram. Includes introduction of a new IGraphicalDeletionHelper OSGi service for delegation of the determination of whether an element can be deleted from the diagram and replacement of the XML expression properties * org.eclipse.papyrus.uml.diagram.common.isSemanticDeletion * org.eclipse.papyrus.uml.diagram.common.isReadOnly by * org.eclipse.papyrus.infra.gmfdiag.common.isSemanticDeletion * org.eclipse.papyrus.infra.gmfdiag.common.canDelete (where the latter is the negation of the property that it supersedes) Extract UML dependencies from the Diagram Outline and CSS Editor bundles. Remove unused MDTUtil APIs that referenced a UML-specific annotation. Move the Diagram Infrastructure CSS Palette bundle into the UML layer because it serves to provide extensions on the Palette Service, which is an overtly UML-specific capability. All client APIs for the Properties View are moved from org.eclipse.papyrus.views.properties bundle to a new org.eclipse.papyrus.infra.properties.ui bundle. This includes renaming of: * extension points * label-provider contexts * XWT namespaces Add an "all UI tests" suite. Define a componentized hierarchical build layout of the main plug-ins Change-Id: I43f8f3644857a18b69715f5a2f1da9b1cf286d67
Diffstat (limited to 'plugins/infra/emf')
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.appearance/pom.xml8
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/META-INF/MANIFEST.MF46
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/pom.xml8
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/src/org/eclipse/papyrus/infra/emf/diagram/common/handler/CreateDiagramHandler.java298
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.classpath7
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.project28
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.settings/org.eclipse.jdt.core.prefs291
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.settings/org.eclipse.jdt.ui.prefs68
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/META-INF/MANIFEST.MF20
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/about.html28
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/build.properties10
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/plugin.properties14
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/plugin.xml19
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/pom.xml12
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/schema/historyListeners.exsd91
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/schema/operationApprovers.exsd78
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/CheckedOperationHistory.java352
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/EMFtoGMFCommandWrapper.java204
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/GMFtoEMFCommandWrapper.java183
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/ICommandWrapper.java184
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/INonDirtying.java26
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/NestingNotifyingWorkspaceCommandStack.java231
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/NotifyingWorkspaceCommandStack.java670
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/CommandTreeIterator.java175
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/CommandUtils.java291
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/GMFUnsafe.java314
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/OperationHistoryDirtyState.java212
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/OperationUtils.java139
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/internal/gmf/Activator.java67
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF46
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml148
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml8
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java92
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java403
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/pom.xml8
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/Activator.java259
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/spi/resolver/EObjectResolverService.java48
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/pom.xml8
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/utils/ProviderHelper.java43
-rw-r--r--plugins/infra/emf/pom.xml22
40 files changed, 4454 insertions, 705 deletions
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.appearance/pom.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.appearance/pom.xml
index d9a0cdd53d4..d30fa69c8f1 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.appearance/pom.xml
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.appearance/pom.xml
@@ -2,13 +2,11 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
- <artifactId>org.eclipse.papyrus.releng</artifactId>
+ <artifactId>org.eclipse.papyrus.infra-emf</artifactId>
<groupId>org.eclipse.papyrus</groupId>
- <version>1.2.0-SNAPSHOT</version>
- <relativePath>../../../../releng/main</relativePath>
+ <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.papyrus.infra.emf.appearance</artifactId>
- <groupId>org.eclipse.papyrus</groupId>
<version>1.2.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
-</project> \ No newline at end of file
+</project>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/META-INF/MANIFEST.MF b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/META-INF/MANIFEST.MF
index e4acf402212..f1bffdb6c75 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/META-INF/MANIFEST.MF
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/META-INF/MANIFEST.MF
@@ -1,23 +1,23 @@
-Manifest-Version: 1.0
-Export-Package: org.eclipse.papyrus.infra.emf.diagram.common,
- org.eclipse.papyrus.infra.emf.diagram.common.handler
-Require-Bundle: org.eclipse.papyrus.infra.core;bundle-version="1.2.0",
- org.eclipse.gmf.runtime.notation;bundle-version="1.5.0",
- org.eclipse.emf.transaction;bundle-version="1.4.0",
- org.eclipse.papyrus.infra.core.sasheditor;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.core.sashwindows.di;bundle-version="1.2.0",
- org.eclipse.core.commands;bundle-version="3.6.1",
- org.eclipse.ui,
- org.eclipse.papyrus.infra.gmfdiag.common;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.emf;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.core.log;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.ui;bundle-version="1.2.0"
-Bundle-Vendor: %providerName
-Bundle-ActivationPolicy: lazy
-Bundle-Version: 1.2.0.qualifier
-Bundle-Name: %pluginName
-Bundle-Localization: plugin
-Bundle-Activator: org.eclipse.papyrus.infra.emf.diagram.common.Activator
-Bundle-ManifestVersion: 2
-Bundle-SymbolicName: org.eclipse.papyrus.infra.emf.diagram.common;singleton:=true
-Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Manifest-Version: 1.0
+Export-Package: org.eclipse.papyrus.infra.emf.diagram.common,
+ org.eclipse.papyrus.infra.emf.diagram.common.handler
+Require-Bundle: org.eclipse.papyrus.infra.core;bundle-version="1.2.0",
+ org.eclipse.gmf.runtime.notation;bundle-version="1.5.0",
+ org.eclipse.emf.transaction;bundle-version="1.4.0",
+ org.eclipse.papyrus.infra.core.sasheditor;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.core.sashwindows.di;bundle-version="1.2.0",
+ org.eclipse.core.commands;bundle-version="3.6.1",
+ org.eclipse.ui,
+ org.eclipse.papyrus.infra.emf.gmf;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.emf;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.core.log;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.ui;bundle-version="1.2.0"
+Bundle-Vendor: %providerName
+Bundle-ActivationPolicy: lazy
+Bundle-Version: 1.2.0.qualifier
+Bundle-Name: %pluginName
+Bundle-Localization: plugin
+Bundle-Activator: org.eclipse.papyrus.infra.emf.diagram.common.Activator
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.papyrus.infra.emf.diagram.common;singleton:=true
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/pom.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/pom.xml
index 3e7fe363b0e..a288294b391 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/pom.xml
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/pom.xml
@@ -2,13 +2,11 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
- <artifactId>org.eclipse.papyrus.releng</artifactId>
+ <artifactId>org.eclipse.papyrus.infra-emf</artifactId>
<groupId>org.eclipse.papyrus</groupId>
- <version>1.2.0-SNAPSHOT</version>
- <relativePath>../../../../releng/main</relativePath>
+ <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.papyrus.infra.emf.diagram.common</artifactId>
- <groupId>org.eclipse.papyrus</groupId>
<version>1.2.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
-</project> \ No newline at end of file
+</project>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/src/org/eclipse/papyrus/infra/emf/diagram/common/handler/CreateDiagramHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/src/org/eclipse/papyrus/infra/emf/diagram/common/handler/CreateDiagramHandler.java
index ae4978c24d0..3e2912620d5 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/src/org/eclipse/papyrus/infra/emf/diagram/common/handler/CreateDiagramHandler.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.diagram.common/src/org/eclipse/papyrus/infra/emf/diagram/common/handler/CreateDiagramHandler.java
@@ -1,149 +1,149 @@
-/*****************************************************************************
- * Copyright (c) 2008 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:
- * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
- *
- *****************************************************************************/
-package org.eclipse.papyrus.infra.emf.diagram.common.handler;
-
-import org.eclipse.core.commands.AbstractHandler;
-import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.core.commands.IHandler;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.transaction.RecordingCommand;
-import org.eclipse.emf.transaction.TransactionalEditingDomain;
-import org.eclipse.gmf.runtime.notation.Diagram;
-import org.eclipse.gmf.runtime.notation.NotationFactory;
-import org.eclipse.papyrus.infra.core.Activator;
-import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
-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.gmfdiag.common.model.NotationUtils;
-import org.eclipse.papyrus.infra.ui.extension.diagrameditor.IPluggableEditorFactory;
-import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForHandlers;
-
-/**
- * Base class for create diagram Handlers.
- *
- * @author cedric dumoulin
- *
- */
-// FIXME: Refactoring. This should not depend on GMF (NotationUtils depends on GMF).
-// This class is not in the Papyrus Build in 0.10
-public abstract class CreateDiagramHandler extends AbstractHandler implements IHandler {
-
- /**
- *
- * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
- *
- * @param event
- * @return
- * @throws ExecutionException
- */
- public Object execute(final ExecutionEvent event) throws ExecutionException {
-
- final ServicesRegistry registry;
-
- TransactionalEditingDomain editingDomain;
-
- try {
- registry = ServiceUtilsForHandlers.getInstance().getServiceRegistry(event);
- editingDomain = ServiceUtils.getInstance().getTransactionalEditingDomain(registry);
- } catch (ServiceException ex) {
- Activator.log.error(ex);
- return null;
- }
-
- RecordingCommand command = new RecordingCommand(editingDomain, "Create EMF Diagram") {
-
- @Override
- protected void doExecute() {
- addNewDiagram(registry);
- }
-
- };
-
- editingDomain.getCommandStack().execute(command);
- return null;
- }
-
- /**
- *
- * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
- *
- * @param event
- * @return
- * @throws ExecutionException
- */
- public Object execute(final ServicesRegistry servicesRegistry) throws ExecutionException {
-
- TransactionalEditingDomain editingDomain;
-
- try {
- editingDomain = ServiceUtils.getInstance().getTransactionalEditingDomain(servicesRegistry);
- } catch (ServiceException ex) {
- Activator.log.error(ex);
- return null;
- }
-
- RecordingCommand command = new RecordingCommand(editingDomain, "Create EMF Diagram") {
-
- @Override
- protected void doExecute() {
- addNewDiagram(servicesRegistry);
- }
-
- };
-
- editingDomain.getCommandStack().execute(command);
- return null;
- }
-
- /**
- * Subclasses should implements this method.
- */
- protected abstract void addNewDiagram(ServicesRegistry registry);
-
- /**
- * Add a new Diagram to the graphical model.
- *
- * @param diagram
- * The diagram to add to graphical model. This will be the diagram provided to {@link IPluggableEditorFactory#createIPageModel(Object, org.eclipse.papyrus.infra.core.services.ServicesRegistry)}
- */
- protected void addNewDiagram(String name, String type, EObject diagram, ServicesRegistry registry) {
-
- // TODO Create a special node inside the sash model (di) instead of introducing
- // a dependence on notation.
- // This implies to change the factory also.
- // The special node creation should be done by methods from sash
- // create di2node
- Diagram di2Diagram = NotationFactory.eINSTANCE.createDiagram();
- di2Diagram.setVisible(true);
- di2Diagram.setType(type);
- if (name != null) {
- di2Diagram.setName(name);
- }
-
- // Add it to resource, so that it will be saved.
- // NotationUtils.getNotationResource().getContents().add(di2Diagram);
- NotationUtils.getNotationModel().addDiagram(di2Diagram);
-
- // Attach to sash in order to show it
- // Add the diagram as a page to the current sash folder
- try {
- registry.getService(IPageManager.class).openPage(di2Diagram);
- } catch (ServiceException ex) {
- Activator.log.error(ex);
- }
- }
-
-}
+/*****************************************************************************
+ * Copyright (c) 2008, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf.diagram.common.handler;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.NotationFactory;
+import org.eclipse.papyrus.infra.core.Activator;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
+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.ui.extension.diagrameditor.IPluggableEditorFactory;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForHandlers;
+
+/**
+ * Base class for create diagram Handlers.
+ *
+ * @author cedric dumoulin
+ *
+ */
+// FIXME: Refactoring. This should not depend on GMF (NotationUtils depends on GMF).
+// This class is not in the Papyrus Build in 0.10
+public abstract class CreateDiagramHandler extends AbstractHandler implements IHandler {
+
+ /**
+ *
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ *
+ * @param event
+ * @return
+ * @throws ExecutionException
+ */
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+
+ final ServicesRegistry registry;
+
+ TransactionalEditingDomain editingDomain;
+
+ try {
+ registry = ServiceUtilsForHandlers.getInstance().getServiceRegistry(event);
+ editingDomain = ServiceUtils.getInstance().getTransactionalEditingDomain(registry);
+ } catch (ServiceException ex) {
+ Activator.log.error(ex);
+ return null;
+ }
+
+ RecordingCommand command = new RecordingCommand(editingDomain, "Create EMF Diagram") {
+
+ @Override
+ protected void doExecute() {
+ addNewDiagram(registry);
+ }
+
+ };
+
+ editingDomain.getCommandStack().execute(command);
+ return null;
+ }
+
+ /**
+ *
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ *
+ * @param event
+ * @return
+ * @throws ExecutionException
+ */
+ public Object execute(final ServicesRegistry servicesRegistry) throws ExecutionException {
+
+ TransactionalEditingDomain editingDomain;
+
+ try {
+ editingDomain = ServiceUtils.getInstance().getTransactionalEditingDomain(servicesRegistry);
+ } catch (ServiceException ex) {
+ Activator.log.error(ex);
+ return null;
+ }
+
+ RecordingCommand command = new RecordingCommand(editingDomain, "Create EMF Diagram") {
+
+ @Override
+ protected void doExecute() {
+ addNewDiagram(servicesRegistry);
+ }
+
+ };
+
+ editingDomain.getCommandStack().execute(command);
+ return null;
+ }
+
+ /**
+ * Subclasses should implements this method.
+ */
+ protected abstract void addNewDiagram(ServicesRegistry registry);
+
+ /**
+ * Add a new Diagram to the graphical model.
+ *
+ * @param diagram
+ * The diagram to add to graphical model. This will be the diagram provided to {@link IPluggableEditorFactory#createIPageModel(Object, org.eclipse.papyrus.infra.core.services.ServicesRegistry)}
+ */
+ protected void addNewDiagram(String name, String type, EObject diagram, ServicesRegistry registry) {
+
+ // TODO Create a special node inside the sash model (di) instead of introducing
+ // a dependence on notation.
+ // This implies to change the factory also.
+ // The special node creation should be done by methods from sash
+ // create di2node
+ Diagram di2Diagram = NotationFactory.eINSTANCE.createDiagram();
+ di2Diagram.setVisible(true);
+ di2Diagram.setType(type);
+ if (name != null) {
+ di2Diagram.setName(name);
+ }
+
+ // Attach to sash in order to show it
+ // Add the diagram as a page to the current sash folder
+ try {
+ // Persist the new diagram. This should find the Notation Model.
+ // If there is no Notation Model, we shouldn't even be here
+ registry.getService(ModelSet.class).getModelToPersist(di2Diagram).persist(di2Diagram);
+
+ registry.getService(IPageManager.class).openPage(di2Diagram);
+ } catch (ServiceException ex) {
+ Activator.log.error(ex);
+ }
+ }
+
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.classpath b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.classpath
new file mode 100644
index 00000000000..eca7bdba8f0
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.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="bin"/>
+</classpath>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.project b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.project
new file mode 100644
index 00000000000..d198355a356
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.infra.emf.gmf</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>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.settings/org.eclipse.jdt.core.prefs b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..b3aa6d60f94
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,291 @@
+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
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=260
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=260
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=5
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.settings/org.eclipse.jdt.ui.prefs b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..954281dbc31
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,68 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Papyrus
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Papyrus
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * Constructor.\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*****************************************************************************\n * Copyright (c) ${year} CEA LIST and others.\n * \n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *\n * Contributors\:\n * CEA LIST - Initial API and implementation\n * \n *****************************************************************************/\n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/**\n * ${see_to_overridden}\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${see_to_target}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/META-INF/MANIFEST.MF b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..36c601e282b
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Export-Package: org.eclipse.papyrus.infra.emf.gmf.command,
+ org.eclipse.papyrus.infra.emf.gmf.util,
+ org.eclipse.papyrus.infra.emf.internal.gmf;x-internal:=true
+Require-Bundle: org.eclipse.papyrus.infra.core.log;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.tools;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.core;bundle-version="1.2.0",
+ org.eclipse.core.expressions;bundle-version="3.4.400",
+ org.eclipse.gmf.runtime.emf.type.core;bundle-version="1.7.0",
+ com.google.guava;bundle-version="11.0.0",
+ org.eclipse.papyrus.emf.facet.custom.core;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.core.sashwindows.di;bundle-version="1.2.0"
+Bundle-Vendor: %providerName
+Bundle-ActivationPolicy: lazy
+Bundle-Version: 1.2.0.qualifier
+Bundle-Name: %pluginName
+Bundle-Activator: org.eclipse.papyrus.infra.emf.internal.gmf.Activator
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.papyrus.infra.emf.gmf;singleton:=true
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/about.html b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/about.html
new file mode 100644
index 00000000000..dd3c089a94c
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>November 14, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/build.properties b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/build.properties
new file mode 100644
index 00000000000..525a89f2c33
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/build.properties
@@ -0,0 +1,10 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html,\
+ build.properties,\
+ plugin.xml,\
+ schema/
+src.includes = about.html,\
+ schema/
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/plugin.properties b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/plugin.properties
new file mode 100644
index 00000000000..a9f119d526c
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/plugin.properties
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2016 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 v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Christian W. Damus - initial API and implementation
+#
+
+pluginName = Papyrus GMF Run-time Core
+providerName = Eclipse Modeling Project
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/plugin.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/plugin.xml
new file mode 100644
index 00000000000..035a271ff6f
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/plugin.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ Copyright (c) 2016 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 v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html
+
+ Contributors:
+ Christian W. Damus - Initial API and implementation
+
+-->
+<plugin>
+ <extension-point id="operationApprovers" name="Operation Approvers" schema="schema/operationApprovers.exsd"/>
+ <extension-point id="historyListeners" name="Operation History Listeners" schema="schema/historyListeners.exsd"/>
+
+</plugin>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/pom.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/pom.xml
new file mode 100644
index 00000000000..89242377479
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/pom.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>org.eclipse.papyrus.infra-emf</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>org.eclipse.papyrus.infra.emf.gmf</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/schema/historyListeners.exsd b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/schema/historyListeners.exsd
new file mode 100644
index 00000000000..89364178775
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/schema/historyListeners.exsd
@@ -0,0 +1,91 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.papyrus.infra.gmfdiag.commands" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.papyrus.infra.gmfdiag.commands" id="historyListeners" name="historyListeners"/>
+ </appinfo>
+ <documentation>
+ Registration of history listeners to be attached to the operation history used by the Papyrus GMF diagrams (and transactional editing domains in general).
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="historyListener" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="historyListener">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The Java class implementing of the history listener.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.core.commands.operations.IOperationHistoryListener"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 2.0
+ </documentation>
+ </annotation>
+
+
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2014 CEA and others.
+
+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
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/schema/operationApprovers.exsd b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/schema/operationApprovers.exsd
new file mode 100644
index 00000000000..cfb6863fcb5
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/schema/operationApprovers.exsd
@@ -0,0 +1,78 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.papyrus.infra.emf.gmf" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.papyrus.infra.emf.gmf" id="operationApprovers" name="Operation Approviders"/>
+ </appinfo>
+ <documentation>
+
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="operationApprover" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="operationApprover">
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.core.commands.operations.IOperationApprover2"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="priority" type="string">
+ <annotation>
+ <documentation>
+ An integer value representing the priority of the operationApprover.
+High value means the operationApprover will be checked before those with lower value.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+
+
+
+
+
+</schema>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/CheckedOperationHistory.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/CheckedOperationHistory.java
new file mode 100644
index 00000000000..a9cc62ba62a
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/CheckedOperationHistory.java
@@ -0,0 +1,352 @@
+/*****************************************************************************
+ * Copyright (c) 2011, 2016 Atos, CEA, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathieu Velten (Atos) - Initial API and implementation
+ * Christian W. Damus (CEA) - bugs 357250, 323802
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf.gmf.command;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.operations.ICompositeOperation;
+import org.eclipse.core.commands.operations.IOperationApprover;
+import org.eclipse.core.commands.operations.IOperationApprover2;
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IOperationHistoryListener;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.commands.operations.OperationHistoryFactory;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.workspace.EMFCommandOperation;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.papyrus.infra.emf.internal.gmf.Activator;
+
+import com.google.common.collect.ObjectArrays;
+
+public class CheckedOperationHistory implements IOperationHistory {
+
+ private static class CheckedOperationHistoryHolder {
+
+ public static final CheckedOperationHistory instance = new CheckedOperationHistory();
+ }
+
+ public static CheckedOperationHistory getInstance() {
+ return CheckedOperationHistoryHolder.instance;
+ }
+
+ protected static final IOperationApprover2[] approversArray;
+
+ protected IOperationHistory history;
+
+ private static class ApproverPriorityPair implements Comparable<ApproverPriorityPair> {
+
+ public IOperationApprover2 approver;
+
+ public int priority;
+
+ @Override
+ public int compareTo(ApproverPriorityPair o) {
+ if (o.priority > priority) {
+ return 1;
+ } else if (o.priority < priority) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ }
+
+ static {
+ IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(Activator.PLUGIN_ID, "operationApprovers"); //$NON-NLS-1$
+ // Pre-2.0 extension point
+ IConfigurationElement[] legacyElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.papyrus.infra.gmfdiag.commands", "operationApprover"); // Platform.getExtensionRegistry().getConfigurationElementsFor(Activator.PLUGIN_ID, //$NON-NLS-1$
+ // "operationApprover");
+ configElements = ObjectArrays.concat(configElements, legacyElements, IConfigurationElement.class);
+
+ List<ApproverPriorityPair> approverPriorityPairs = new LinkedList<ApproverPriorityPair>();
+ for (IConfigurationElement elem : configElements) {
+ if ("operationApprover".equals(elem.getName())) { //$NON-NLS-1$
+ try {
+ ApproverPriorityPair approverPriorityPair = new ApproverPriorityPair();
+ approverPriorityPair.approver = (IOperationApprover2) elem.createExecutableExtension("class"); //$NON-NLS-1$
+ approverPriorityPair.priority = Integer.parseInt(elem.getAttribute("priority")); //$NON-NLS-1$
+
+ approverPriorityPairs.add(approverPriorityPair);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in instantiation of operation approver.", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ Collections.sort(approverPriorityPairs);
+
+ approversArray = new IOperationApprover2[approverPriorityPairs.size()];
+
+ for (int i = 0; i < approversArray.length; i++) {
+ approversArray[i] = approverPriorityPairs.get(i).approver;
+ }
+ }
+
+ private CheckedOperationHistory() {
+ history = OperationHistoryFactory.getOperationHistory();
+
+ addRegisteredListeners(history);
+ }
+
+ /*
+ * Consult the IOperationApprovers to see if the proposed redo should be
+ * allowed.
+ */
+ protected IStatus getRedoApproval(IUndoableOperation operation, IAdaptable info) {
+ operation = unwrap(operation);
+ for (int i = 0; i < approversArray.length; i++) {
+ IStatus approval = approversArray[i].proceedRedoing(operation, this, info);
+ if (!approval.isOK()) {
+ return approval;
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ /*
+ * Consult the IOperationApprovers to see if the proposed undo should be
+ * allowed.
+ */
+ protected IStatus getUndoApproval(IUndoableOperation operation, IAdaptable info) {
+ operation = unwrap(operation);
+ for (int i = 0; i < approversArray.length; i++) {
+ IStatus approval = approversArray[i].proceedUndoing(operation, this, info);
+ if (!approval.isOK()) {
+ return approval;
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ /*
+ * Consult the IOperationApprovers to see if the proposed execution should
+ * be allowed.
+ *
+ * @since 3.2
+ */
+ protected IStatus getExecuteApproval(IUndoableOperation operation, IAdaptable info) {
+ operation = unwrap(operation);
+ for (int i = 0; i < approversArray.length; i++) {
+ IStatus approval = approversArray[i].proceedExecuting(operation, this, info);
+ if (!approval.isOK()) {
+ return approval;
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ /**
+ * the unified command stack wraps ICommand GMFtoEMFCommandWrapper
+ * which are wrapped in EMFCommandOperation,
+ * unwrap it before validation
+ *
+ * @param operation
+ * @return
+ */
+ protected IUndoableOperation unwrap(IUndoableOperation operation) {
+ if (operation instanceof EMFCommandOperation) {
+ Command emfCommand = ((EMFCommandOperation) operation).getCommand();
+ if (emfCommand instanceof GMFtoEMFCommandWrapper) {
+ ICommand gmfCommand = ((GMFtoEMFCommandWrapper) emfCommand).getGMFCommand();
+ if (gmfCommand != null) {
+ return gmfCommand;
+ }
+ }
+ }
+
+ return operation;
+ }
+
+ @Override
+ public IStatus execute(IUndoableOperation operation, IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ // check with the operation approvers
+ IStatus status = getExecuteApproval(operation, info);
+ if (!status.isOK()) {
+ // not approved. No notifications are sent, just return the status.
+ return status;
+ }
+ return history.execute(operation, monitor, info);
+ }
+
+ @Override
+ public IStatus undo(IUndoContext context, IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ Assert.isNotNull(context);
+ IUndoableOperation operation = getUndoOperation(context);
+
+ // info if there is no operation
+ if (operation == null) {
+ return IOperationHistory.NOTHING_TO_UNDO_STATUS;
+ }
+
+ // check with the operation approvers
+ IStatus status = getUndoApproval(operation, info);
+ if (!status.isOK()) {
+ // not approved. No notifications are sent, just return the status.
+ return status;
+ }
+ return history.undo(context, monitor, info);
+ }
+
+ @Override
+ public IStatus redo(IUndoContext context, IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ Assert.isNotNull(context);
+ IUndoableOperation operation = getRedoOperation(context);
+
+ // info if there is no operation
+ if (operation == null) {
+ return IOperationHistory.NOTHING_TO_REDO_STATUS;
+ }
+
+ // check with the operation approvers
+ IStatus status = getRedoApproval(operation, info);
+ if (!status.isOK()) {
+ // not approved. No notifications are sent, just return the status.
+ return status;
+ }
+ return history.redo(context, monitor, info);
+ }
+
+ private static void addRegisteredListeners(IOperationHistory history) {
+ IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(Activator.PLUGIN_ID, "historyListeners"); //$NON-NLS-1$
+ // Pre-2.0 extension point
+ IConfigurationElement[] legacyElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.papyrus.infra.gmfdiag.commands", "historyListeners"); //$NON-NLS-1$
+ configElements = ObjectArrays.concat(configElements, legacyElements, IConfigurationElement.class);
+
+ for (IConfigurationElement elem : configElements) {
+ if ("historyListener".equals(elem.getName())) { //$NON-NLS-1$
+ try {
+ IOperationHistoryListener listener = (IOperationHistoryListener) elem.createExecutableExtension("class"); //$NON-NLS-1$
+ history.addOperationHistoryListener(listener);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in instantiation of operation history listener.", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ // all the following methods are pure delegation
+
+ @Override
+ public IStatus undoOperation(IUndoableOperation operation, IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ return history.undoOperation(operation, monitor, info);
+ }
+
+ @Override
+ public void setLimit(IUndoContext context, int limit) {
+ history.setLimit(context, limit);
+ }
+
+ @Override
+ public void replaceOperation(IUndoableOperation operation, IUndoableOperation[] replacements) {
+ history.replaceOperation(operation, replacements);
+ }
+
+ @Override
+ public void removeOperationHistoryListener(IOperationHistoryListener listener) {
+ history.removeOperationHistoryListener(listener);
+ }
+
+ @Override
+ public void removeOperationApprover(IOperationApprover approver) {
+ history.removeOperationApprover(approver);
+ }
+
+ @Override
+ public IStatus redoOperation(IUndoableOperation operation, IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ return history.redoOperation(operation, monitor, info);
+ }
+
+ @Override
+ public void operationChanged(IUndoableOperation operation) {
+ history.operationChanged(operation);
+ }
+
+ @Override
+ public void openOperation(ICompositeOperation operation, int mode) {
+ history.openOperation(operation, mode);
+ }
+
+ @Override
+ public IUndoableOperation getUndoOperation(IUndoContext context) {
+ return history.getUndoOperation(context);
+ }
+
+ @Override
+ public IUndoableOperation[] getUndoHistory(IUndoContext context) {
+ return history.getUndoHistory(context);
+ }
+
+ @Override
+ public IUndoableOperation getRedoOperation(IUndoContext context) {
+ return history.getRedoOperation(context);
+ }
+
+ @Override
+ public IUndoableOperation[] getRedoHistory(IUndoContext context) {
+ return history.getRedoHistory(context);
+ }
+
+ @Override
+ public int getLimit(IUndoContext context) {
+ return history.getLimit(context);
+ }
+
+ @Override
+ public void dispose(IUndoContext context, boolean flushUndo, boolean flushRedo, boolean flushContext) {
+ history.dispose(context, flushUndo, flushRedo, flushContext);
+ }
+
+ @Override
+ public void closeOperation(boolean operationOK, boolean addToHistory, int mode) {
+ history.closeOperation(operationOK, addToHistory, mode);
+ }
+
+ @Override
+ public boolean canUndo(IUndoContext context) {
+ return history.canUndo(context);
+ }
+
+ @Override
+ public boolean canRedo(IUndoContext context) {
+ return history.canRedo(context);
+ }
+
+ @Override
+ public void addOperationHistoryListener(IOperationHistoryListener listener) {
+ history.addOperationHistoryListener(listener);
+ }
+
+ @Override
+ public void addOperationApprover(IOperationApprover approver) {
+ history.addOperationApprover(approver);
+ }
+
+ @Override
+ public void add(IUndoableOperation operation) {
+ history.add(operation);
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/EMFtoGMFCommandWrapper.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/EMFtoGMFCommandWrapper.java
new file mode 100644
index 00000000000..ca30d10d1cf
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/EMFtoGMFCommandWrapper.java
@@ -0,0 +1,204 @@
+/***************************************************************************
+ * Copyright (c) 2007, 2016 Conselleria de Infraestructuras y Transporte, Generalitat de la Comunitat Valenciana, CEA, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: Mario Cervera Ubeda (Prodevelop)
+ * Christian W. Damus (CEA) - bug 430701
+ * Christian W. Damus - bug 485220
+ *
+ ******************************************************************************/
+package org.eclipse.papyrus.infra.emf.gmf.command;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Function;
+
+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.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
+import org.eclipse.gmf.runtime.common.core.command.AbstractCommand;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+
+/**
+ * A GMF Command that wraps an EMF command. Each method is redirected to the EMF one.
+ */
+public class EMFtoGMFCommandWrapper extends AbstractCommand implements ICommandWrapper<Command> {
+
+ private static Function<Command, ICommand> wrapperFunction = EMFtoGMFCommandWrapper::new;
+ private static Function<Command, ICommand> ndWrapperFunction = NonDirtying::new;
+
+ /**
+ * The wrapped EMF Command. Package-level visibility so that the command stack wrapper can
+ * access the field.
+ */
+ protected Command emfCommand;
+
+ /**
+ * This variable is used to avoid reentrant call in canUndo/undo/redo
+ *
+ * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=389382
+ */
+ protected boolean isBusy;
+
+ /**
+ * Constructor.
+ *
+ * @param emfCommand
+ * the emf command
+ */
+ public EMFtoGMFCommandWrapper(Command emfCommand) {
+ super(emfCommand.getLabel());
+ this.emfCommand = emfCommand;
+ }
+
+ /**
+ * Wraps the given {@code command}, accounting for possible non-dirty state.
+ *
+ * @param command
+ * a command to wrap
+ * @return the best wrapper for the {@code command}
+ */
+ public static ICommand wrap(Command command) {
+ if (command instanceof org.eclipse.emf.common.command.AbstractCommand.NonDirtying) {
+ return ndWrapperFunction.apply(command);
+ }
+ return wrapperFunction.apply(command);
+ }
+
+ /**
+ * Returns the wrapped EMF command.
+ *
+ * @return the EMF command
+ */
+ public Command getEMFCommand() {
+ return emfCommand;
+ }
+
+ @Override
+ public Command getWrappedCommand() {
+ return getEMFCommand();
+ }
+
+ @Override
+ protected CommandResult doExecuteWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+
+ emfCommand.execute();
+
+ return CommandResult.newOKCommandResult();
+ }
+
+ @Override
+ protected CommandResult doRedoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+
+ if (!isBusy) {
+ isBusy = true;
+ emfCommand.redo();
+ isBusy = false;
+ }
+
+ return CommandResult.newOKCommandResult();
+ }
+
+ @Override
+ protected CommandResult doUndoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+
+ if (!isBusy) {
+ isBusy = true;
+ emfCommand.undo();
+ isBusy = false;
+ }
+
+ return CommandResult.newOKCommandResult();
+ }
+
+ @Override
+ public boolean canExecute() {
+ return emfCommand.canExecute();
+ }
+
+ @Override
+ public void dispose() {
+ emfCommand.dispose();
+ }
+
+ @Override
+ public boolean canUndo() {
+ if (!isBusy) {
+ isBusy = true;
+ boolean res = emfCommand.canUndo();
+ isBusy = false;
+ return res;
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public List getAffectedFiles() {
+ ArrayList affectedFiles = new ArrayList();
+ Collection<?> affectedObjects = emfCommand.getAffectedObjects();
+ if (affectedObjects != null) {
+ for (Object o : affectedObjects) {
+ if (o instanceof EObject) {
+ o = ((EObject) o).eResource();
+ }
+ if (o instanceof Resource) {
+ o = WorkspaceSynchronizer.getFile((Resource) o);
+ }
+ if (o instanceof IFile) {
+ affectedFiles.add(o);
+ }
+ }
+ }
+ return affectedFiles;
+ }
+
+ @Override
+ public CommandResult getCommandResult() {
+ Collection<?> res = emfCommand.getResult();
+ if (res != null && !res.isEmpty()) {
+ if (res.size() == 1) {
+ return CommandResult.newOKCommandResult(res.iterator().next());
+ }
+ return CommandResult.newOKCommandResult(res);
+ }
+ return CommandResult.newOKCommandResult();
+ }
+
+ protected static void setWrapperFunction(Function<Command, ICommand> wrapperFunction) {
+ EMFtoGMFCommandWrapper.wrapperFunction = wrapperFunction;
+ }
+
+ protected static void setNonDirtyingWrapperFunction(Function<Command, ICommand> wrapperFunction) {
+ EMFtoGMFCommandWrapper.ndWrapperFunction = wrapperFunction;
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A non-dirtying wrapper for non-dirtying commands.
+ */
+ public static class NonDirtying extends EMFtoGMFCommandWrapper implements INonDirtying {
+
+ public NonDirtying(org.eclipse.emf.common.command.Command command) {
+ super(command);
+
+ if (!(command instanceof org.eclipse.emf.common.command.AbstractCommand.NonDirtying)) {
+ throw new IllegalArgumentException("Wrapped command is not non-dirtying"); //$NON-NLS-1$
+ }
+ }
+
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/GMFtoEMFCommandWrapper.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/GMFtoEMFCommandWrapper.java
new file mode 100644
index 00000000000..3aa00f20abd
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/GMFtoEMFCommandWrapper.java
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * Copyright (c) 2007, 2016 Conselleria de Infraestructuras y Transporte, Generalitat de la Comunitat Valenciana, CEA, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors: Mario Cervera Ubeda (Prodevelop)
+ * Christian W. Damus (CEA) - bug 430701
+ * Christian W. Damus - bug 485220
+ *
+ ******************************************************************************/
+package org.eclipse.papyrus.infra.emf.gmf.command;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.function.Function;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+
+/**
+ * A EMF Command that wraps a GMF command. Each method is redirected to the GMF one.
+ */
+public class GMFtoEMFCommandWrapper extends AbstractCommand implements ICommandWrapper<ICommand> {
+
+ private static Function<ICommand, Command> wrapperFunction = GMFtoEMFCommandWrapper::new;
+ private static Function<ICommand, Command> ndWrapperFunction = NonDirtying::new;
+
+ /**
+ *
+ * Wraps the GMF command return value to be returned by this method.
+ *
+ * @return the possible return value from the GMF command
+ */
+ @Override
+ public Collection<?> getResult() {
+
+ Collection<Object> result = new ArrayList<Object>();
+ if (getGMFReturnValue() != null) {
+ result.add(getGMFReturnValue());
+ } // else return an empty collection
+
+ return result;
+ }
+
+ private Object getGMFReturnValue() {
+ if (getGMFCommand().getCommandResult() != null) {
+ return getGMFCommand().getCommandResult().getReturnValue();
+ }
+
+ return null;
+ }
+
+ /**
+ * The wrapped GMF Command. Package-level visibility so that the command stack wrapper can
+ * access the field.
+ */
+ private final ICommand gmfCommand;
+
+ /**
+ * Constructor.
+ *
+ * @param gmfCommand
+ * the gmf command
+ */
+ public GMFtoEMFCommandWrapper(ICommand gmfCommand) {
+ super(gmfCommand.getLabel());
+ this.gmfCommand = gmfCommand;
+ }
+
+ /**
+ * Wraps the given {@code command}, accounting for possible non-dirty state.
+ *
+ * @param command
+ * a command to wrap
+ * @return the best wrapper for the {@code command}
+ */
+ public static Command wrap(ICommand command) {
+ if (command instanceof INonDirtying) {
+ return ndWrapperFunction.apply(command);
+ }
+ return wrapperFunction.apply(command);
+ }
+
+ /**
+ * Returns the wrapped GMF command.
+ *
+ * @return the GMF command
+ */
+ public ICommand getGMFCommand() {
+ return gmfCommand;
+ }
+
+ @Override
+ public ICommand getWrappedCommand() {
+ return getGMFCommand();
+ }
+
+ @Override
+ public boolean canExecute() {
+ return gmfCommand.canExecute();
+ }
+
+ @Override
+ public void dispose() {
+ gmfCommand.dispose();
+ }
+
+ @Override
+ public boolean canUndo() {
+ return gmfCommand.canUndo();
+ }
+
+ @Override
+ public void execute() {
+ try {
+ gmfCommand.execute(new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+ }
+
+ }
+
+ @Override
+ public void redo() {
+ try {
+ gmfCommand.redo(new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+ }
+
+ }
+
+ @Override
+ public void undo() {
+ try {
+ gmfCommand.undo(new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+ }
+
+ }
+
+ @Override
+ public Collection<?> getAffectedObjects() {
+ return gmfCommand.getAffectedFiles();
+ }
+
+ @Override
+ public String getDescription() {
+ return gmfCommand.getLabel();
+ }
+
+ protected static void setWrapperFunction(Function<ICommand, Command> wrapperFunction) {
+ GMFtoEMFCommandWrapper.wrapperFunction = wrapperFunction;
+ }
+
+ protected static void setNonDirtyingWrapperFunction(Function<ICommand, Command> wrapperFunction) {
+ GMFtoEMFCommandWrapper.ndWrapperFunction = wrapperFunction;
+ }
+
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A non-dirtying wrapper for non-dirtying commands.
+ */
+ public static class NonDirtying extends GMFtoEMFCommandWrapper implements AbstractCommand.NonDirtying {
+
+ public NonDirtying(ICommand command) {
+ super(command);
+
+ if (!(command instanceof INonDirtying)) {
+ throw new IllegalArgumentException("Wrapped command is not non-dirtying"); //$NON-NLS-1$
+ }
+ }
+
+ }
+
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/ICommandWrapper.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/ICommandWrapper.java
new file mode 100644
index 00000000000..74737ff7b6c
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/ICommandWrapper.java
@@ -0,0 +1,184 @@
+/*****************************************************************************
+ * Copyright (c) 2016 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.gmf.command;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Function;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+
+/**
+ * A protocol for wrappers that adapt commands of one framework to another.
+ *
+ * @param <T>
+ * the wrapped command type
+ */
+public interface ICommandWrapper<T> {
+ Registry REGISTRY = new Registry();
+
+ /**
+ * Unwraps the wrapper to get the wrapped command of the other framework.
+ *
+ * @return the wrapped command (never {@code null})
+ */
+ T getWrappedCommand();
+
+ /**
+ * Wraps a {@code command} as another {@code type}. This also handles wrappers
+ * that are not {@link ICommandWrapper}s, such as those provided by GMF or
+ * other projects externally to Papyrus.
+ *
+ * @param command
+ * a command to wrap
+ * @param type
+ * the command type to obtain
+ *
+ * @return the wrapped command
+ *
+ * @throws IllegalArgumentException
+ * if no wrapper is available of the required {@code type}
+ */
+ static <F, T> T wrap(F command, Class<T> type) {
+ return REGISTRY.getWrapper(command, type).apply(command);
+ }
+
+ /**
+ * Queries whether a {@code command} is a wrapper of some other type of command.
+ * This also handles wrappers that are not {@link ICommandWrapper}s, such as
+ * those provided by GMF or other projects externally to Papyrus.
+ *
+ * @param command
+ * a command to wrapper
+ * @param type
+ * the command type that perhaps it wraps
+ *
+ * @return the wrapped command
+ *
+ * @throws IllegalArgumentException
+ * if no wrapper is available of the required {@code type}
+ */
+ static <F, T> boolean isWrapper(T command, Class<F> ofType) {
+ return REGISTRY.hasUnwrapper(command, ofType);
+ }
+
+ /**
+ * Unwraps a {@code command} as another {@code type}. This also handles wrappers
+ * that are not {@link ICommandWrapper}s, such as those provided by GMF or
+ * other projects externally to Papyrus.
+ *
+ * @param command
+ * a command to unwrap
+ * @param type
+ * the command type to obtain
+ *
+ * @return the wrapped command
+ *
+ * @throws IllegalArgumentException
+ * if no wrapper is available of the required {@code type}
+ */
+ static <F, T> F unwrap(T command, Class<F> type) {
+ return REGISTRY.getUnwrapper(command, type).apply(command);
+ }
+
+ //
+ // Nested types
+ //
+
+ class Registry {
+ private final ConcurrentMap<Class<?>, ConcurrentMap<Class<?>, Function<?, ?>>> wrappers = new ConcurrentHashMap<>();
+ private final ConcurrentMap<Class<?>, ConcurrentMap<Class<?>, Function<?, ?>>> unwrappers = new ConcurrentHashMap<>();
+
+ private Registry() {
+ super();
+
+ registerWrapper(Command.class, ICommand.class, EMFtoGMFCommandWrapper::wrap);
+ registerUnwrapper(EMFtoGMFCommandWrapper.class, Command.class, EMFtoGMFCommandWrapper::getWrappedCommand);
+ registerWrapper(ICommand.class, Command.class, GMFtoEMFCommandWrapper::wrap);
+ registerUnwrapper(GMFtoEMFCommandWrapper.class, ICommand.class, GMFtoEMFCommandWrapper::getWrappedCommand);
+ }
+
+ /**
+ * Registers a functions to wrap commands of a source type as a target type.
+ *
+ * @param fromType
+ * the source command type
+ * @param toType
+ * the target command type
+ * @param wrapper
+ * the wrapper function
+ *
+ * @throws IllegalStateException
+ * if this pair of {@code fromType} and {@code toType} already has a wrapper registered
+ */
+ public <F, T> void registerWrapper(Class<F> fromType, Class<T> toType, Function<? super F, ? extends T> wrapper) {
+ ConcurrentMap<Class<?>, Function<?, ?>> wrappers = this.wrappers.computeIfAbsent(fromType, key -> new ConcurrentHashMap<>());
+ if (wrappers.putIfAbsent(toType, wrapper) != null) {
+ throw new IllegalStateException(String.format("Wrapper already registered for %s -> %s", fromType.getSimpleName(), toType.getSimpleName()));
+ }
+ }
+
+ /**
+ * Registers a function to unwrap commands of a source type to obtain the original command type.
+ *
+ * @param fromType
+ * the source command type
+ * @param toType
+ * the target command type
+ * @param unwrapper
+ * the unwrapper function
+ *
+ * @throws IllegalStateException
+ * if this pair of {@code fromType} and {@code toType} already has an unwrapper registered
+ */
+ public <F, T> void registerUnwrapper(Class<F> fromType, Class<T> toType, Function<? super F, ? extends T> unwrapper) {
+ ConcurrentMap<Class<?>, Function<?, ?>> unwrappers = this.unwrappers.computeIfAbsent(fromType, key -> new ConcurrentHashMap<>());
+ if (unwrappers.putIfAbsent(toType, unwrapper) != null) {
+ throw new IllegalStateException(String.format("Unwrapper already registered for %s <- %s", toType.getSimpleName(), fromType.getSimpleName()));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ <F, T> Function<F, T> getWrapper(F command, Class<T> type) {
+ return (Function<F, T>) wrappers.entrySet().stream()
+ .filter(e -> e.getKey().isInstance(command))
+ .flatMap(e -> e.getValue().entrySet().stream())
+ .filter(e -> type.isAssignableFrom(e.getKey()))
+ .map(Map.Entry::getValue)
+ .findFirst()
+ .orElseThrow(IllegalArgumentException::new);
+ }
+
+ <F, T> Function<T, F> getUnwrapper(T command, Class<F> type) {
+ return maybeGetUnwrapper(command, type).orElseThrow(IllegalArgumentException::new);
+ }
+
+ boolean hasUnwrapper(Object command, Class<?> type) {
+ return maybeGetUnwrapper(command, type).isPresent();
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ <F, T> Optional<Function<T, F>> maybeGetUnwrapper(T command, Class<F> type) {
+ return (Optional) unwrappers.entrySet().stream()
+ .filter(e -> e.getKey().isInstance(command))
+ .flatMap(e -> e.getValue().entrySet().stream())
+ .filter(e -> type.isAssignableFrom(e.getKey()))
+ .map(Map.Entry::getValue)
+ .findFirst();
+ }
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/INonDirtying.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/INonDirtying.java
new file mode 100644
index 00000000000..d00aec01d7d
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/INonDirtying.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.emf.gmf.command;
+
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.Command;
+
+
+/**
+ * A marker interface for GMF and GEF commands that are non-dirtying. For EMF {@link Command}s, use the {@link AbstractCommand.NonDirtying} interface.
+ *
+ * @see AbstractCommand.NonDirtying
+ */
+public interface INonDirtying {
+ // Just a marker interface
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/NestingNotifyingWorkspaceCommandStack.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/NestingNotifyingWorkspaceCommandStack.java
new file mode 100644
index 00000000000..e2d94ddabed
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/NestingNotifyingWorkspaceCommandStack.java
@@ -0,0 +1,231 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and others.
+ *
+ * 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:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - adapted for self-nesting behaviour
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf.gmf.command;
+
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.transaction.RollbackException;
+
+
+public class NestingNotifyingWorkspaceCommandStack extends NotifyingWorkspaceCommandStack {
+
+ private NestingNotifyingWorkspaceCommandStack childCommandStack;
+
+ private final boolean nested;
+
+ private boolean executing;
+
+ protected IUndoContext defaultUndoContext;
+
+ public NestingNotifyingWorkspaceCommandStack(IOperationHistory history) {
+ this(false, history, null);
+ }
+
+ protected NestingNotifyingWorkspaceCommandStack(boolean nested, IOperationHistory history, IUndoContext defaultUndoContext) {
+ super(history);
+ this.nested = nested;
+ this.defaultUndoContext = defaultUndoContext;
+ }
+
+ protected NestingNotifyingWorkspaceCommandStack(boolean nested, IOperationHistory history) {
+ this(nested, history, computeNestedUndoContext());
+ }
+
+ private static IUndoContext computeNestedUndoContext() {
+ return new IUndoContext() {
+
+ public boolean matches(IUndoContext context) {
+ return context == this;
+ }
+
+ public String getLabel() {
+ return "Nested Undo Context";
+ }
+ };
+ }
+
+ @Override
+ public IUndoContext getDefaultUndoContext() {
+ if (defaultUndoContext == null) {
+ return super.getDefaultUndoContext();
+ }
+ return defaultUndoContext;
+ }
+
+ protected NestingNotifyingWorkspaceCommandStack getTopMostCommandStack() {
+ if (childCommandStack == null) {
+ return this;
+ }
+ return childCommandStack.getTopMostCommandStack();
+ }
+
+ protected void startNestedTransaction(Command command) {
+ if (childCommandStack != null) {
+ // Forwards to the current stack
+ childCommandStack.startNestedTransaction(command);
+ } else {
+ // Start a new nested transaction in a new nested Stack
+ childCommandStack = createNestedCommandStack(getOperationHistory());
+ childCommandStack.setEditingDomain(getDomain());
+
+ childCommandStack.execute(command);
+ }
+ }
+
+ protected NestingNotifyingWorkspaceCommandStack createNestedCommandStack(IOperationHistory history) {
+ return new NestingNotifyingWorkspaceCommandStack(true, history);
+ }
+
+ public void commit() {
+ if (childCommandStack != null) {
+ disposeLastCommandStack();
+ }
+ }
+
+ private boolean disposeLastCommandStack() {
+ if (childCommandStack == null) {
+ // I'm the last command stack
+ dispose();
+ return true;
+ }
+
+ // Propagates
+ if (childCommandStack.disposeLastCommandStack()) {
+ childCommandStack = null;
+ }
+
+ return false;
+ }
+
+ public void rollback() {
+ if (childCommandStack != null) {
+ while (canUndo()) {
+ undo();
+ }
+ disposeLastCommandStack();
+ }
+ }
+
+ @Override
+ public void execute(Command command) {
+ if (childCommandStack == null) {
+ if (!executing) {
+ executing = true;
+
+ try {
+ super.execute(command);
+ } finally {
+ executing = false;
+ }
+ } else {
+ // Re-entrant command execution goes on a nested stack
+ try {
+ startNestedTransaction(command);
+ commit();
+ } catch (OperationCanceledException e) {
+ rollback();
+ // Propagate
+ throw e;
+ }
+ }
+ } else {
+ childCommandStack.execute(command);
+ }
+ }
+
+ @Override
+ protected void handleError(Exception exception) {
+ if (nested && (exception instanceof RollbackException)) {
+ // A nested transaction rolled back
+ RollbackException rbe = (RollbackException) exception;
+ if (rbe.getStatus().getSeverity() == IStatus.CANCEL) {
+ // Propagate
+ throw new OperationCanceledException();
+ }
+ }
+
+ if (exception instanceof OperationCanceledException) {
+ rollback();
+ } else {
+ super.handleError(exception);
+ }
+ }
+
+ @Override
+ public Command getMostRecentCommand() {
+ if (childCommandStack == null) {
+ return super.getMostRecentCommand();
+ } else {
+ return childCommandStack.getMostRecentCommand();
+ }
+ }
+
+ @Override
+ public Command getRedoCommand() {
+ if (childCommandStack == null) {
+ return super.getRedoCommand();
+ } else {
+ return childCommandStack.getRedoCommand();
+ }
+ }
+
+ @Override
+ public Command getUndoCommand() {
+ if (childCommandStack == null) {
+ return super.getUndoCommand();
+ } else {
+ return childCommandStack.getUndoCommand();
+ }
+ }
+
+ @Override
+ public void undo() {
+ if (childCommandStack == null) {
+ super.undo();
+ } else {
+ childCommandStack.undo();
+ }
+ }
+
+ @Override
+ public boolean canUndo() {
+ if (childCommandStack == null) {
+ return super.canUndo();
+ } else {
+ return childCommandStack.canUndo();
+ }
+ }
+
+ @Override
+ public boolean canRedo() {
+ if (childCommandStack == null) {
+ return super.canRedo();
+ } else {
+ return childCommandStack.canRedo();
+ }
+ }
+
+ @Override
+ public void redo() {
+ if (childCommandStack == null) {
+ super.redo();
+ } else {
+ childCommandStack.redo();
+ }
+ }
+
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/NotifyingWorkspaceCommandStack.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/NotifyingWorkspaceCommandStack.java
new file mode 100644
index 00000000000..59dabfcca16
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/command/NotifyingWorkspaceCommandStack.java
@@ -0,0 +1,670 @@
+/*****************************************************************************
+ * Copyright (c) 2011, 2015 Atos, CEA, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathieu Velten (Atos) - Initial API and implementation
+ * Arthur Daussy (Atos) - 363826: [Model Explorer] Drag and drop and undo, incorrect behavior
+ * Christian W. Damus (CEA) - 404220: Add contexts for tracking objects changed by operations (CDO)
+ * Christian W. Damus (CEA) - bug 402525
+ * Christian W. Damus (CEA) - bug 430648
+ * Christian W. Damus (CEA) - bug 431023
+ * Christian W. Damus (CEA) - bug 384169
+ * Christian W. Damus - bug 459746
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf.gmf.command;
+
+import static org.eclipse.papyrus.infra.emf.gmf.util.OperationUtils.anyDirtying;
+import static org.eclipse.papyrus.infra.emf.gmf.util.OperationUtils.isDirty;
+
+import java.util.Collection;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IOperationHistoryListener;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.commands.operations.OperationHistoryEvent;
+import org.eclipse.core.commands.operations.UndoContext;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CommandStackListener;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.transaction.NotificationFilter;
+import org.eclipse.emf.transaction.ResourceSetChangeEvent;
+import org.eclipse.emf.transaction.ResourceSetListenerImpl;
+import org.eclipse.emf.transaction.RollbackException;
+import org.eclipse.emf.transaction.Transaction;
+import org.eclipse.emf.transaction.impl.AbstractTransactionalCommandStack;
+import org.eclipse.emf.transaction.impl.EMFCommandTransaction;
+import org.eclipse.emf.transaction.impl.InternalTransaction;
+import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
+import org.eclipse.emf.transaction.impl.TriggerCommandTransaction;
+import org.eclipse.emf.transaction.util.TriggerCommand;
+import org.eclipse.emf.workspace.EMFCommandOperation;
+import org.eclipse.emf.workspace.IResourceUndoContextPolicy;
+import org.eclipse.emf.workspace.IWorkspaceCommandStack;
+import org.eclipse.emf.workspace.ResourceUndoContext;
+import org.eclipse.emf.workspace.impl.EMFOperationTransaction;
+import org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl;
+import org.eclipse.emf.workspace.internal.EMFWorkspacePlugin;
+import org.eclipse.emf.workspace.internal.EMFWorkspaceStatusCodes;
+import org.eclipse.emf.workspace.internal.Tracing;
+import org.eclipse.emf.workspace.internal.l10n.Messages;
+import org.eclipse.gmf.runtime.emf.commands.core.command.EditingDomainUndoContext;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.emf.gmf.util.CommandUtils;
+
+/**
+ * Copied from WorkspaceCommandStackImpl but modify in order to change the
+ * IUndoContext. We want to make it point the the TransactionalEditingDomain. To
+ * see what really change in this class from original implementation look for
+ * "HAS CHANGE FROM ORIGINAL IMPLEMENTATION" in Java Doc.
+ *
+ */
+public class NotifyingWorkspaceCommandStack extends AbstractTransactionalCommandStack// AbstractTransactionalCommandStack
+ implements IWorkspaceCommandStack {
+
+ private final IOperationHistory history;
+
+ private DomainListener domainListener;
+
+ private IResourceUndoContextPolicy undoContextPolicy = IResourceUndoContextPolicy.DEFAULT;
+
+ private IUndoableOperation currentOperation;
+
+ private Set<Resource> historyAffectedResources;
+
+ /**
+ * HAS CHANGE FROM ORIGINAL IMPLEMENTATION TO USE {@link EditingDomainUndoContext}
+ */
+ private IUndoContext defaultContext = null;
+
+ private IUndoContext savedContext = null;
+
+ private IUndoableOperation mostRecentOperation;
+
+ /**
+ * Initializes me with the operation history to which I delegate command
+ * execution.
+ *
+ * @param history
+ * my operation history
+ */
+ public NotifyingWorkspaceCommandStack(IOperationHistory history) {
+ super();
+ this.history = history;
+ domainListener = new DomainListener();
+ defaultContext = new UndoContext() {
+
+ @Override
+ public String getLabel() {
+ return getDefaultUndoContextLabel();
+ }
+
+ @Override
+ public String toString() {
+ return getLabel();
+ }
+ };
+ }
+
+ /**
+ * map with registered listeners and the corresponding proxy registered to
+ * actual map
+ */
+ private Map<CommandStackListener, IOperationHistoryListener> proxyOperationListeners = new HashMap<CommandStackListener, IOperationHistoryListener>();
+
+ @Override
+ public void addCommandStackListener(final CommandStackListener listener) {
+ removeCommandStackListener(listener);
+ IOperationHistoryListener proxy = new IOperationHistoryListener() {
+
+ @Override
+ public void historyNotification(OperationHistoryEvent event) {
+ int type = event.getEventType();
+ // emf stack only needs to be notified when an operation is
+ // finished
+ if (OperationHistoryEvent.DONE == type || OperationHistoryEvent.REDONE == type || OperationHistoryEvent.UNDONE == type) {
+ listener.commandStackChanged(new EventObject(NotifyingWorkspaceCommandStack.this));
+ }
+ }
+ };
+ getOperationHistory().addOperationHistoryListener(proxy);
+ proxyOperationListeners.put(listener, proxy);
+ }
+
+ @Override
+ public void removeCommandStackListener(CommandStackListener listener) {
+ IOperationHistoryListener proxy = proxyOperationListeners.remove(listener);
+ if (proxy != null) {
+ getOperationHistory().removeOperationHistoryListener(proxy);
+ }
+ }
+
+ /**
+ * Extends the superclass implementation to add/remove listeners on the
+ * editing domain. HAS CHANGE FROM ORIGINAL IMPLEMENTATION TO USE {@link EditingDomainUndoContext}
+ */
+ @Override
+ public void setEditingDomain(InternalTransactionalEditingDomain domain) {
+ InternalTransactionalEditingDomain oldDomain = getDomain();
+ if (oldDomain != null) {
+ oldDomain.removeResourceSetListener(domainListener);
+ history.removeOperationHistoryListener(domainListener);
+ }
+ super.setEditingDomain(domain);
+ /*
+ * HAS CHANGE FROM ORIGINAL IMPLEMENTATION TO USE {@link
+ * EditingDomainUndoContext}
+ */
+ if (getDomain() != null) {
+ boolean domainHasChanged = oldDomain == null || !oldDomain.equals(getDomain());
+ if (domainHasChanged) {
+ defaultContext = new EditingDomainUndoContext(domain, getDefaultUndoContextLabel());
+ }
+ }
+ if (domain != null) {
+ history.addOperationHistoryListener(domainListener);
+ domain.addResourceSetListener(domainListener);
+ }
+ }
+
+ // Documentation copied from the method specification
+ @Override
+ public final IOperationHistory getOperationHistory() {
+ return history;
+ }
+
+ // Documentation copied from the method specification
+ @Override
+ public IUndoContext getDefaultUndoContext() {
+ return defaultContext;
+ }
+
+ /**
+ * Obtains the label to display for the default undo context that I apply to
+ * operations executed through me as {@link Command}s. Subclasses may
+ * override to customize the label.
+ *
+ * @return my default undo context label
+ *
+ * @since 1.2
+ */
+ protected String getDefaultUndoContextLabel() {
+ String domainID = (getDomain() == null) ? null : getDomain().getID();
+ if (domainID == null) {
+ domainID = String.valueOf(domainID); // guaranteed to be safe
+ }
+ return NLS.bind(Messages.cmdStkCtxLabel, domainID);
+ }
+
+ private final IUndoContext getSavedContext() {
+ if (savedContext == null) {
+ savedContext = new UndoContext() {
+
+ @Override
+ public String getLabel() {
+ return getSavepointUndoContextLabel();
+ }
+
+ @Override
+ public String toString() {
+ return getLabel();
+ }
+ };
+ }
+ return savedContext;
+ }
+
+ /**
+ * Obtains the label to display for the save-point undo context that I apply
+ * to the last operation in my {@linkplain #getDefaultUndoContext() default
+ * undo context} that was executed at the time save was performed (as
+ * indicated by invocation of the {@link #saveIsDone()} method). Subclasses
+ * may override to customize the label.
+ *
+ * @return my save-point undo context label
+ *
+ * @since 1.2
+ */
+ protected String getSavepointUndoContextLabel() {
+ String domainID = (getDomain() == null) ? null : getDomain().getID();
+ if (domainID == null) {
+ domainID = String.valueOf(domainID); // guaranteed to be safe
+ }
+ return NLS.bind(Messages.cmdStkSaveCtxLabel, domainID);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.1
+ */
+ @Override
+ protected void doExecute(Command command, Map<?, ?> options) throws InterruptedException, RollbackException {
+ IUndoableOperation oper = CommandUtils.wrap(getDomain(), command, options);
+ // add the appropriate context
+ oper.addContext(getDefaultUndoContext());
+ try {
+ IStatus status = history.execute(oper, new NullProgressMonitor(), null);
+ if (status.getSeverity() >= IStatus.ERROR) {
+ // the transaction must have rolled back if the status was
+ // error or worse
+ RollbackException exc = new RollbackException(status);
+ Tracing.throwing(WorkspaceCommandStackImpl.class, "execute", exc); //$NON-NLS-1$
+ throw exc;
+ }
+ notifyListeners();
+ } catch (ExecutionException e) {
+ Tracing.catching(WorkspaceCommandStackImpl.class, "execute", e); //$NON-NLS-1$
+ command.dispose();
+ if (e.getCause() instanceof RollbackException) {
+ // throw the rollback
+ RollbackException exc = (RollbackException) e.getCause();
+ Tracing.throwing(WorkspaceCommandStackImpl.class, "execute", exc); //$NON-NLS-1$
+ throw exc;
+ } else if (e.getCause() instanceof RuntimeException) {
+ // throw the programming error
+ RuntimeException exc = (RuntimeException) e.getCause();
+ Tracing.throwing(WorkspaceCommandStackImpl.class, "execute", exc); //$NON-NLS-1$
+ throw exc;
+ } else {
+ // log the problem. We can't rethrow whatever it was
+ handleError(e);
+ }
+ }
+ }
+
+ /**
+ * Queries whether we can undo my default undo context in my operation
+ * history.
+ */
+ @Override
+ public boolean canUndo() {
+ return getOperationHistory().canUndo(getDefaultUndoContext());
+ }
+
+ /**
+ * Undoes my default undo context in my operation history.
+ */
+ @Override
+ public void undo() {
+ try {
+ getOperationHistory().undo(getDefaultUndoContext(), new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+ Tracing.catching(WorkspaceCommandStackImpl.class, "undo", e); //$NON-NLS-1$
+ // can't throw anything from this method
+ handleError(e);
+ } finally {
+ // notify even if there was an error; clients should check to see
+ // that the command stack is flushed
+ notifyListeners();
+ }
+ }
+
+ /**
+ * Queries whether we can redo my default undo context in my operation
+ * history.
+ */
+ @Override
+ public boolean canRedo() {
+ return getOperationHistory().canRedo(getDefaultUndoContext());
+ }
+
+ /**
+ * Redoes my default undo context in my operation history.
+ */
+ @Override
+ public void redo() {
+ try {
+ getOperationHistory().redo(getDefaultUndoContext(), new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+ Tracing.catching(WorkspaceCommandStackImpl.class, "redo", e); //$NON-NLS-1$
+ // can't throw anything from this method
+ handleError(e);
+ } finally {
+ // notify even if there was an error; clients should check to see
+ // that the command stack is flushed
+ notifyListeners();
+ }
+ }
+
+ /**
+ * Disposes my default undo context in my operation history.
+ */
+ @Override
+ public void flush() {
+ getOperationHistory().dispose(getDefaultUndoContext(), true, true, true);
+ if (savedContext != null) {
+ getOperationHistory().dispose(getSavedContext(), true, true, true);
+ savedContext = null;
+ }
+ }
+
+ /**
+ * Gets the command from the most recently executed, done, or redone
+ * operation.
+ */
+ @Override
+ public Command getMostRecentCommand() {
+ Command result = null;
+ if (mostRecentOperation instanceof EMFCommandOperation) {
+ result = ((EMFCommandOperation) mostRecentOperation).getCommand();
+ }
+ return result;
+ }
+
+ /**
+ * Gets the command from the top of the undo history, if any.
+ */
+ @Override
+ public Command getUndoCommand() {
+ Command result = null;
+ IUndoableOperation topOperation = getOperationHistory().getUndoOperation(getDefaultUndoContext());
+ if (topOperation instanceof EMFCommandOperation) {
+ result = ((EMFCommandOperation) topOperation).getCommand();
+ }
+ return result;
+ }
+
+ /**
+ * Gets the command from the top of the redo history, if any.
+ */
+ @Override
+ public Command getRedoCommand() {
+ Command result = null;
+ IUndoableOperation topOperation = getOperationHistory().getRedoOperation(getDefaultUndoContext());
+ if (topOperation instanceof EMFCommandOperation) {
+ result = ((EMFCommandOperation) topOperation).getCommand();
+ }
+ return result;
+ }
+
+ // Documentation copied from the method specification
+ @Override
+ public EMFCommandTransaction createTransaction(Command command, Map<?, ?> options) throws InterruptedException {
+ EMFCommandTransaction result;
+ if (command instanceof TriggerCommand) {
+ result = new TriggerCommandTransaction((TriggerCommand) command, getDomain(), options);
+ } else {
+ result = new EMFOperationTransaction(command, getDomain(), options);
+ }
+ result.start();
+ return result;
+ }
+
+ // Documentation copied from the method specification
+ @Override
+ public void executeTriggers(Command command, List<Command> triggers, Map<?, ?> options) throws InterruptedException, RollbackException {
+ if (!triggers.isEmpty()) {
+ TriggerCommand trigger = (command == null) ? new TriggerCommand(triggers) : new TriggerCommand(command, triggers);
+ InternalTransaction tx = createTransaction(trigger, makeTriggerTransactionOptions(options));
+ try {
+ trigger.execute();
+ InternalTransaction parent = (InternalTransaction) tx.getParent();
+ // shouldn't be null if we're executing triggers!
+ if (parent != null) {
+ parent.addTriggers(trigger);
+ }
+ // commit the transaction now
+ tx.commit();
+ } catch (RuntimeException e) {
+ Tracing.catching(WorkspaceCommandStackImpl.class, "executeTriggers", e); //$NON-NLS-1$
+ IStatus status;
+ if (e instanceof OperationCanceledException) {
+ status = Status.CANCEL_STATUS;
+ } else {
+ status = new Status(IStatus.ERROR, EMFWorkspacePlugin.getPluginId(), EMFWorkspaceStatusCodes.PRECOMMIT_FAILED, Messages.precommitFailed, e);
+ }
+ RollbackException rbe = new RollbackException(status);
+ Tracing.throwing(WorkspaceCommandStackImpl.class, "executeTriggers", rbe); //$NON-NLS-1$
+ throw rbe;
+ } finally {
+ if ((tx != null) && (tx.isActive())) {
+ // roll back because an uncaught exception occurred
+ rollback(tx);
+ }
+ }
+ }
+ }
+
+ // Documentation copied from the method specification
+ @Override
+ public void dispose() {
+ setEditingDomain(null); // remove listeners
+ domainListener = null;
+ historyAffectedResources = null;
+ mostRecentOperation = null;
+
+ // remove listeners registered in opertationHistory
+ Collection<IOperationHistoryListener> values = proxyOperationListeners.values();
+ for (IOperationHistoryListener proxy : values) {
+ getOperationHistory().removeOperationHistoryListener(proxy);
+ }
+ proxyOperationListeners.clear();
+
+ // Flush default and savepoint undo contexts
+ flush();
+ }
+
+ /**
+ * Obtains my resource undo-context policy.
+ *
+ * @return my resource undo-context policy
+ *
+ * @since 1.3
+ */
+ public IResourceUndoContextPolicy getResourceUndoContextPolicy() {
+ return undoContextPolicy;
+ }
+
+ /**
+ * Sets my resource undo-context policy.
+ *
+ * @param policy
+ * my new policy, or <code>null</code> to restore the default
+ *
+ * @since 1.3
+ */
+ public void setResourceUndoContextPolicy(IResourceUndoContextPolicy policy) {
+ this.undoContextPolicy = policy;
+ }
+
+ /**
+ * A listener on the editing domain and operation history that tracks which
+ * resources are changed by an operation and attaches the appropriate {@link ResourceUndoContext} to it when it completes.
+ *
+ * @author Christian W. Damus (cdamus)
+ */
+ private class DomainListener extends ResourceSetListenerImpl implements IOperationHistoryListener {
+
+ @Override
+ public void historyNotification(OperationHistoryEvent event) {
+ final IUndoableOperation operation = event.getOperation();
+ switch (event.getEventType()) {
+ case OperationHistoryEvent.ABOUT_TO_EXECUTE:
+ // set up to remember affected resources in case we make EMF
+ // changes
+ currentOperation = operation;
+ historyAffectedResources = new java.util.HashSet<Resource>();
+ break;
+ case OperationHistoryEvent.DONE:
+ if ((historyAffectedResources != null) && !historyAffectedResources.isEmpty()) {
+ // add my undo context to the operation that has
+ // completed, but only if the operation actually changed
+ // any of my resources (in case this history is shared
+ // with other domains)
+ for (Resource next : historyAffectedResources) {
+ operation.addContext(new ResourceUndoContext(getDomain(), next));
+ }
+ }
+ currentOperation = null;
+ historyAffectedResources = null;
+ if (operation.hasContext(getDefaultUndoContext())) {
+ mostRecentOperation = operation;
+ }
+ break;
+ case OperationHistoryEvent.OPERATION_NOT_OK:
+ // just forget about the context because this operation
+ // failed
+ currentOperation = null;
+ historyAffectedResources = null;
+ break;
+ case OperationHistoryEvent.UNDONE:
+ case OperationHistoryEvent.REDONE:
+ if (operation.hasContext(getDefaultUndoContext())) {
+ mostRecentOperation = operation;
+ }
+ break;
+ case OperationHistoryEvent.OPERATION_REMOVED:
+ if (operation == mostRecentOperation) {
+ mostRecentOperation = null;
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void resourceSetChanged(ResourceSetChangeEvent event) {
+ IUndoableOperation operation = null;
+ Set<Resource> unloaded = getUnloadedResources(event.getNotifications());
+ if (unloaded != null) {
+ // dispose their undo contexts
+ for (Resource next : unloaded) {
+ getOperationHistory().dispose(new ResourceUndoContext(getDomain(), next), true, true, true);
+ }
+ }
+ Transaction tx = event.getTransaction();
+ if (tx != null) {
+ operation = (IUndoableOperation) tx.getOptions().get(EMFWorkspacePlugin.OPTION_OWNING_OPERATION);
+ }
+ if (operation == null) {
+ operation = currentOperation;
+ }
+ if (operation != null) {
+ Set<Resource> affectedResources = getResourceUndoContextPolicy().getContextResources(operation, event.getNotifications());
+ if (unloaded != null) {
+ // don't add these resources to the operation
+ affectedResources.removeAll(unloaded);
+ }
+ if (!affectedResources.isEmpty()) {
+ // add any resource undo contexts to this operation that are
+ // not already applied
+ for (Resource next : affectedResources) {
+ ResourceUndoContext ctx = new ResourceUndoContext(getDomain(), next);
+ if (!operation.hasContext(ctx)) {
+ operation.addContext(ctx);
+ }
+ }
+ }
+ if (historyAffectedResources != null) {
+ // there is an operation executing on our history that is
+ // affecting my editing domain. Remember the affected
+ // resources.
+ historyAffectedResources.addAll(affectedResources);
+ }
+
+ hookUndoContexts(operation, event);
+ }
+ }
+
+ /**
+ * Finds resources that have sent unload notifications.
+ *
+ * @param notifications
+ * notifications received from a transaction
+ * @return a set of resources that the notifications indicate have been
+ * unloaded, or <code>null</code> if none
+ */
+ private Set<Resource> getUnloadedResources(Collection<Notification> notifications) {
+ Set<Resource> result = null;
+ for (Notification next : notifications) {
+ if (NotificationFilter.RESOURCE_UNLOADED.matches(next)) {
+ if (result == null) {
+ result = new java.util.HashSet<Resource>();
+ }
+ result.add((Resource) next.getNotifier());
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isPostcommitOnly() {
+ // only interested in post-commit "resourceSetChanged" event
+ return true;
+ }
+ }
+
+ /**
+ * A hook for subclasses to attach additional undo-contexts to an {@code operation} based on changes
+ * in the resource set.
+ *
+ * @param operation
+ * an operation that has been executed (never {@code null})
+ * @param event
+ * the description of changes made by the {@code operation} in the resource set
+ */
+ protected void hookUndoContexts(IUndoableOperation operation, ResourceSetChangeEvent event) {
+ // pass
+ }
+
+
+ @Override
+ public boolean isSaveNeeded() {
+ // This class inherits from AbstractTransactionalCommandStack which in turn inherits from BasicCommandStack.
+
+ // The operation isSaveNeeded is defined in BasicCommandStack. In order to work, it requires an update of the
+ // variables "saveIndex" and "top" which is done in BasicCommandStack::execute. However, this operation is overridden
+ // in method AbstractTransactionalCommandStack::execute which never calls the superclass method BasicCommandStack::execute.
+ // Thus, we cannot rely on the super class method of isSaveNeeded (although it seems to work in some cases).
+ // => so we have to implement the isSaveNeeded method here.
+ IUndoableOperation nextUndoableOperation = history.getUndoOperation(getDefaultUndoContext());
+ if (nextUndoableOperation == null) {
+ // this is the last undoable operation. But the document might have been saved at some operation now on the redo stack
+ return savedContext != null;
+ }
+ return savedContext != null ? !nextUndoableOperation.hasContext(getSavedContext()) && isDirty(history.getUndoHistory(getDefaultUndoContext()), history.getRedoHistory(getDefaultUndoContext()), history.getUndoOperation(savedContext))
+ : anyDirtying(history.getUndoHistory(getDefaultUndoContext()));
+ }
+
+ @Override
+ public void saveIsDone() {
+ // See comment for isSaveNeeded
+ if (savedContext != null) {
+ // The save context is only stored on one operation. We must
+ // remove it from any other operation that may have contained it
+ // before.
+ IUndoableOperation[] undoableOperations = history.getUndoHistory(getSavedContext());
+ for (int i = 0; i < undoableOperations.length; i++) {
+ undoableOperations[i].removeContext(getSavedContext());
+ }
+ IUndoableOperation[] redoableOperations = history.getRedoHistory(getSavedContext());
+ for (int i = 0; i < redoableOperations.length; i++) {
+ redoableOperations[i].removeContext(getSavedContext());
+ }
+ }
+ IUndoableOperation nextUndoableOperation = history.getUndoOperation(getDefaultUndoContext());
+ if (nextUndoableOperation == null) {
+ // We no longer have any operation that was saved
+ savedContext = null;
+ return;
+ }
+ nextUndoableOperation.addContext(getSavedContext());
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/CommandTreeIterator.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/CommandTreeIterator.java
new file mode 100644
index 00000000000..6f58619012f
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/CommandTreeIterator.java
@@ -0,0 +1,175 @@
+/*****************************************************************************
+ * Copyright (c) 2015 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.gmf.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.papyrus.infra.emf.gmf.command.ICommandWrapper;
+
+/**
+ * An iterator over the tree structure of EMF, GEF, and GMF commands that returns leaf commands of one or all of these kinds,
+ * with accounting for the various kinds of wrappers employed to intermix them. This iterator does not support the
+ * optional {@link Iterator#remove()} operation.
+ */
+public class CommandTreeIterator<C> implements Iterator<C> {
+ private final Class<C> type;
+
+ private Iterator<?> current;
+ private List<Iterator<?>> iterators = new ArrayList<Iterator<?>>();
+
+ private C preparedNext;
+
+ private CommandTreeIterator(Object root, Class<C> type) {
+ super();
+
+ this.type = type;
+
+ root = unwrap(root);
+
+ if (isCompound(root)) {
+ pushIterator(root);
+ } else {
+ prepareNext(root);
+ }
+ }
+
+ public static CommandTreeIterator<Command> iterateEMF(Object command) {
+ return iterate(command, Command.class);
+ }
+
+ public static CommandTreeIterator<ICommand> iterateGMF(Object command) {
+ return iterate(command, ICommand.class);
+ }
+
+ public static CommandTreeIterator<?> iterate(Object command) {
+ return iterate(command, Object.class);
+ }
+
+ public static <C> CommandTreeIterator<C> iterate(Object command, Class<C> leafCommandType) {
+ return new CommandTreeIterator<C>(command, leafCommandType);
+ }
+
+ private boolean prepareNext(Object command) {
+ if (type.isInstance(command)) {
+ preparedNext = type.cast(command);
+ }
+
+ return preparedNext != null;
+ }
+
+ private Iterator<?> pushIterator(Object compoundCommand) {
+ if (current != null) {
+ iterators.add(current);
+ }
+ current = iterator(compoundCommand);
+ return current;
+ }
+
+ private Iterator<?> popIterator() {
+ if (iterators.isEmpty()) {
+ current = null;
+ } else {
+ current = iterators.remove(iterators.size() - 1);
+ }
+
+ return current;
+ }
+
+ private Object internalNext() {
+ Object result = null;
+
+ while ((result == null) && (current != null)) {
+ if (current.hasNext()) {
+ Object next = unwrap(current.next());
+ if (isCompound(next)) {
+ // Dive into it
+ pushIterator(next);
+ } else {
+ // We have the next leaf
+ result = next;
+ }
+ } else {
+ popIterator();
+ }
+ }
+
+ return result;
+ }
+
+ boolean isDone() {
+ return (current == null) && iterators.isEmpty();
+ }
+
+ @Override
+ public boolean hasNext() {
+ while (!isDone() && (preparedNext == null)) {
+ Object next = internalNext();
+ if (type.isInstance(next)) {
+ preparedNext = type.cast(next);
+ }
+ }
+
+ return preparedNext != null;
+ }
+
+ @Override
+ public C next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ C result = preparedNext;
+ preparedNext = null;
+ return result;
+ }
+
+ /**
+ * Remove is not supported.
+ */
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("remove"); //$NON-NLS-1$
+ }
+
+ private Object unwrap(Object command) {
+ Object result = command;
+
+ if (command instanceof ICommandWrapper<?>) {
+ return ((ICommandWrapper<?>) command).getWrappedCommand();
+ } else if (ICommandWrapper.isWrapper(command, Object.class)) {
+ // Try a registered foreign wrapper
+ return ICommandWrapper.unwrap(command, Object.class);
+ }
+
+ if (result != command) {
+ // Could be turtles all the way down
+ result = unwrap(result);
+ }
+
+ return result;
+ }
+
+ private boolean isCompound(Object command) {
+ return CommandUtils.isCompound(command);
+ }
+
+ private Iterator<?> iterator(Object compoundCommand) {
+ return CommandUtils.getChildren(compoundCommand).iterator();
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/CommandUtils.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/CommandUtils.java
new file mode 100644
index 00000000000..5048c89d699
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/CommandUtils.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2014, 2016 CEA, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ */
+package org.eclipse.papyrus.infra.emf.gmf.util;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.workspace.EMFCommandOperation;
+import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.common.core.command.ICompositeCommand;
+import org.eclipse.papyrus.infra.emf.gmf.command.INonDirtying;
+
+
+/**
+ * Utilities for working with potentially non-dirtying EMF, GEF, and GMF commands.
+ *
+ * @see INonDirtying
+ * @see AbstractCommand.NonDirtying
+ */
+public class CommandUtils {
+
+ public static final Registry REGISTRY = new Registry();
+
+ /**
+ * Not instantiable by clients.
+ */
+ private CommandUtils() {
+ super();
+ }
+
+ public static String getLabel(Object command) {
+ return REGISTRY.getLabeller(command).apply(command);
+ }
+
+ public static boolean isCompound(Object command) {
+ return REGISTRY.hasDecomposer(command);
+ }
+
+ public static <T, C extends T> Iterable<T> getChildren(C compoundCommand) {
+ return REGISTRY.<T, C> getDecomposer(compoundCommand).apply(compoundCommand);
+ }
+
+ public static <T> T chain(T command1, T command2) {
+ return REGISTRY.getComposer(command1).apply(command1, command2);
+ }
+
+ public static boolean isNonDirtying(Object command) {
+ return (command instanceof INonDirtying)
+ || (command instanceof AbstractCommand.NonDirtying);
+ }
+
+ public static IUndoableOperation wrap(TransactionalEditingDomain domain, Command command) {
+ if (command instanceof AbstractCommand.NonDirtying) {
+ return new NonDirtyingEMFCommandOperation(domain, command);
+ }
+ return new EMFCommandOperation(domain, command);
+ }
+
+ public static IUndoableOperation wrap(TransactionalEditingDomain domain, Command command, Map<?, ?> options) {
+ if (command instanceof AbstractCommand.NonDirtying) {
+ return new NonDirtyingEMFCommandOperation(domain, command, options);
+ }
+ return new EMFCommandOperation(domain, command, options);
+ }
+
+ public static CompoundCommand nonDirtyingEMFCompound() {
+ return new NonDirtyingEMFCompoundCommand();
+ }
+
+ public static Command chain(Command command1, Command command2) {
+ if ((command1 instanceof AbstractCommand.NonDirtying) && (command2 instanceof AbstractCommand.NonDirtying)) {
+ return new NonDirtyingEMFCompoundCommand().chain(command1).chain(command2);
+ }
+ return command1.chain(command2);
+ }
+
+ public static CompositeCommand nonDirtyingGMFComposite(String label) {
+ return new NonDirtyingGMFCompositeCommand(label);
+ }
+
+ public static ICommand compose(ICommand command1, ICommand command2) {
+ if ((command1 instanceof INonDirtying) && (command2 instanceof INonDirtying)) {
+ return new NonDirtyingGMFCompositeCommand(command1.getLabel()).compose(command1).compose(command2);
+ }
+ return command1.compose(command2);
+ }
+
+ //
+ // Nested types
+ //
+
+ private static class NonDirtyingEMFCommandOperation extends EMFCommandOperation implements INonDirtying {
+
+ NonDirtyingEMFCommandOperation(TransactionalEditingDomain domain, Command command, Map<?, ?> options) {
+ super(domain, checkCommand(command), options);
+ }
+
+ NonDirtyingEMFCommandOperation(TransactionalEditingDomain domain, Command command) {
+ super(domain, checkCommand(command));
+ }
+
+ static Command checkCommand(Command command) {
+ if (!(command instanceof AbstractCommand.NonDirtying)) {
+ throw new IllegalStateException("Attempt to wrap dirtying command in a non-dirtying operation."); //$NON-NLS-1$
+ }
+ return command;
+ }
+ }
+
+ private static class NonDirtyingEMFCompoundCommand extends CompoundCommand implements AbstractCommand.NonDirtying {
+
+ @Override
+ public void append(Command command) {
+ checkNonDirtying(command);
+ super.append(command);
+ }
+
+ @Override
+ public boolean appendAndExecute(Command command) {
+ checkNonDirtying(command);
+ return super.appendAndExecute(command);
+ }
+
+ @Override
+ public boolean appendIfCanExecute(Command command) {
+ checkNonDirtying(command);
+ return super.appendIfCanExecute(command);
+ }
+
+ @Override
+ public Command chain(Command command) {
+ append(command);
+ return this;
+ }
+
+ private void checkNonDirtying(Command command) {
+ if (!(command instanceof AbstractCommand.NonDirtying)) {
+ throw new IllegalArgumentException("Attempt to append a dirtying command to a non-dirtying compound."); //$NON-NLS-1$
+ }
+ }
+ }
+
+ private static class NonDirtyingGMFCompositeCommand extends CompositeCommand implements INonDirtying {
+
+ NonDirtyingGMFCompositeCommand(String label) {
+ super(label);
+ }
+
+ @Override
+ public void add(IUndoableOperation operation) {
+ checkNonDirtying(operation);
+ super.add(operation);
+ }
+
+ private void checkNonDirtying(IUndoableOperation operation) {
+ if (!(operation instanceof INonDirtying)) {
+ throw new IllegalArgumentException("Attempt to append a dirtying operation to a non-dirtying composite."); //$NON-NLS-1$
+ }
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ public static class Registry {
+ private final ConcurrentMap<Class<?>, BiFunction<?, ?, ?>> composers = new ConcurrentHashMap<>();
+ private final ConcurrentMap<Class<?>, Function<?, ? extends Iterable<?>>> decomposers = new ConcurrentHashMap<>();
+ private final ConcurrentMap<Class<?>, Function<?, String>> labellers = new ConcurrentHashMap<>();
+
+ @SuppressWarnings("unchecked")
+ private Registry() {
+ super();
+
+ registerComposer(Command.class, CommandUtils::chain);
+ registerDecomposer(CompoundCommand.class, CompoundCommand::getCommandList);
+ registerLabeller(Command.class, Command::getLabel);
+
+ registerComposer(ICommand.class, CommandUtils::compose);
+ this.<ICommand, ICompositeCommand> registerDecomposer(ICompositeCommand.class, c -> () -> c.iterator());
+ registerLabeller(IUndoableOperation.class, IUndoableOperation::getLabel);
+ }
+
+ /**
+ * Registers a function to compose two commands together into a compound of some sort.
+ *
+ * @param commandType
+ * the composable command type
+ * @param composer
+ * the composer function
+ *
+ * @throws IllegalStateException
+ * if this {@code commandType} already has a composer registered
+ */
+ public <T, C extends T> void registerComposer(Class<T> commandType, BiFunction<? super T, ? super T, ? extends C> composer) {
+ if (composers.putIfAbsent(commandType, composer) != null) {
+ throw new IllegalStateException(String.format("Composer already registered for %s", commandType.getSimpleName()));
+ }
+ }
+
+ /**
+ * Registers a function to decompose compounds commands of some type to obtain the composed commands.
+ *
+ * @param compoundType
+ * the compound command type
+ * @param decomposer
+ * the decomposer function
+ *
+ * @throws IllegalStateException
+ * if this {@code compoundType} already has ae decomposer registered
+ */
+ public <T, C extends T> void registerDecomposer(Class<C> compoundType, Function<? super C, ? extends Iterable<? extends T>> decomposer) {
+ if (decomposers.putIfAbsent(compoundType, decomposer) != null) {
+ throw new IllegalStateException(String.format("Decomposer already registered for %s", compoundType.getSimpleName()));
+ }
+ }
+
+ /**
+ * Registers a function to get the label of a command.
+ *
+ * @param commandType
+ * the labelled command type
+ * @param labeller
+ * the labeller function
+ *
+ * @throws IllegalStateException
+ * if this {@code commandType} already has a labeller registered
+ */
+ public <T> void registerLabeller(Class<T> commandType, Function<? super T, String> labeller) {
+ if (labellers.putIfAbsent(commandType, labeller) != null) {
+ throw new IllegalStateException(String.format("Labeller already registered for %s", commandType.getSimpleName()));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ <T, C extends T> BiFunction<T, T, C> getComposer(T command) {
+ return (BiFunction<T, T, C>) composers.entrySet().stream()
+ .filter(e -> e.getKey().isInstance(command))
+ .map(Map.Entry::getValue)
+ .findFirst()
+ .orElseThrow(IllegalArgumentException::new);
+ }
+
+ <T, C extends T> Function<? super C, ? extends Iterable<T>> getDecomposer(T command) {
+ return maybeGetDecomposer(command).orElseThrow(IllegalArgumentException::new);
+ }
+
+ boolean hasDecomposer(Object command) {
+ return maybeGetDecomposer(command).isPresent();
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ <T, C extends T> Optional<Function<? super C, ? extends Iterable<T>>> maybeGetDecomposer(C compound) {
+ return (Optional) decomposers.entrySet().stream()
+ .filter(e -> e.getKey().isInstance(compound))
+ .map(Map.Entry::getValue)
+ .findFirst();
+ }
+
+ @SuppressWarnings("unchecked")
+ <T> Function<T, String> getLabeller(T command) {
+ return (Function<T, String>) labellers.entrySet().stream()
+ .filter(e -> e.getKey().isInstance(command))
+ .map(Map.Entry::getValue)
+ .findFirst()
+ .orElse(Object::toString);
+ }
+ }
+
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/GMFUnsafe.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/GMFUnsafe.java
new file mode 100644
index 00000000000..dccad9b8d38
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/GMFUnsafe.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.emf.gmf.util;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.util.WrappedException;
+import org.eclipse.emf.transaction.RollbackException;
+import org.eclipse.emf.transaction.Transaction;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.papyrus.infra.emf.internal.gmf.Activator;
+
+
+/**
+ * Utilities for operations in the GMF context that we might consider as "unsafe" or exceptional cases.
+ */
+public class GMFUnsafe {
+
+ /**
+ * Not instantiable by clients.
+ */
+ private GMFUnsafe() {
+ super();
+ }
+
+ /**
+ * Performs an unsafe write to the model. The editing domain may or may not already have an active transaction, which may or may not be read-only;
+ * it does not matter. In any case, the changes performed will not be recorded for undo/redo or roll-back. Thus, this is appropriate only for use
+ * cases such as synchronization of canonical views, which are not considered logically as abstract model edits (though they be concrete changes).
+ *
+ * @param domain
+ * an editing domain that may or may not have a transaction in progress
+ * @param writeOperation
+ * an operation that will make unchecked/unsafe changes to the editing {@code domain}
+ *
+ * @throws RollbackException
+ * if the unprotected write transaction fails to commit. Note that this could occlude an uncaught exception thrown by the {@code writeOperation} runnable
+ * @throws InterruptedException
+ * if the current thread is interrupted while waiting for the unprotected write transaction to start
+ */
+ public static void write(TransactionalEditingDomain domain, Runnable writeOperation) throws InterruptedException, RollbackException {
+ runUnprotected(domain, writeOperation);
+ }
+
+ private static void runUnprotected(TransactionalEditingDomain domain, Runnable writeOperation) throws InterruptedException, RollbackException {
+ InternalTransactionalEditingDomain internalDomain = (InternalTransactionalEditingDomain) domain;
+ Transaction unprotected = internalDomain.startTransaction(false, Collections.singletonMap(Transaction.OPTION_UNPROTECTED, true));
+ try {
+ writeOperation.run();
+ } finally {
+ unprotected.commit();
+ }
+ }
+
+ /**
+ * Executes an unsafe command on the model. The editing domain may or may not already have an active transaction, which may or may not be
+ * read-only; it does not matter. In any case, the changes performed will not be recorded for undo/redo or roll-back. Thus, this is appropriate
+ * only for use cases such as synchronization of canonical views, which are not considered logically as abstract model edits (though they be
+ * concrete changes).
+ *
+ * @param domain
+ * an editing domain that may or may not have a transaction in progress
+ * @param command
+ * a command that will make unchecked/unsafe changes to the editing {@code domain}
+ *
+ * @throws RollbackException
+ * if the unprotected write transaction fails to commit. Note that this could occlude an uncaught exception thrown by the {@code writeOperation} runnable
+ * @throws InterruptedException
+ * if the current thread is interrupted while waiting for the unprotected write transaction to start
+ *
+ * @see #write(TransactionalEditingDomain, Runnable)
+ */
+ public static void write(TransactionalEditingDomain domain, Command command) throws InterruptedException, RollbackException {
+ write(domain, new CommandRunnable(command));
+ }
+
+ /**
+ * Executes an unsafe command on the model. The editing domain may or may not already have an active transaction, which may or may not be
+ * read-only; it does not matter. In any case, the changes performed will not be recorded for undo/redo or roll-back. Thus, this is appropriate
+ * only for use cases such as synchronization of canonical views, which are not considered logically as abstract model edits (though they be
+ * concrete changes).
+ *
+ * @param domain
+ * an editing domain that may or may not have a transaction in progress
+ * @param command
+ * a command that will make unchecked/unsafe changes to the editing {@code domain}
+ *
+ * @throws RollbackException
+ * if the unprotected write transaction fails to commit. Note that this could occlude an uncaught exception thrown by the {@code writeOperation} runnable
+ * @throws InterruptedException
+ * if the current thread is interrupted while waiting for the unprotected write transaction to start
+ * @throws ExecutionException
+ * if the {@code command} fails to execute
+ *
+ * @see #write(TransactionalEditingDomain, Runnable)
+ */
+ public static void write(TransactionalEditingDomain domain, ICommand command) throws InterruptedException, RollbackException, ExecutionException {
+ try {
+ write(domain, new GMFCommandRunnable(command));
+ } catch (WrappedException e) {
+ if (e.exception() instanceof ExecutionException) {
+ throw (ExecutionException) e.exception();
+ } else {
+ // It must have been an unchecked RuntimeException of some kind
+ throw (RuntimeException) e.exception();
+ }
+ }
+ }
+
+ /**
+ * Wraps a command for unprotected execution, undo, and redo on the command stack.
+ *
+ * @param domain
+ * a transactional editing domain on which the {@code command} operates
+ * @param command
+ * a command to wrap
+ * @return the wrapped command
+ */
+ public static Command wrap(TransactionalEditingDomain domain, Command command) {
+ return new UnsafeCommandWrapper(domain, command);
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A useful base class for commands that need to execute, undo, and redo in unprotected mode on the command stack.
+ */
+ public static abstract class UnsafeCommand extends AbstractCommand {
+
+ private final TransactionalEditingDomain domain;
+
+ protected UnsafeCommand(TransactionalEditingDomain domain) {
+ this.domain = domain;
+ }
+
+ protected UnsafeCommand(TransactionalEditingDomain domain, String label, String description) {
+ super(label, description);
+
+ this.domain = domain;
+ }
+
+ protected UnsafeCommand(TransactionalEditingDomain domain, String label) {
+ super(label);
+
+ this.domain = domain;
+ }
+
+ @Override
+ public final void execute() {
+ try {
+ runUnprotected(domain, new Runnable() {
+
+ @Override
+ public void run() {
+ doExecute();
+ }
+ });
+ } catch (Exception e) {
+ handleException(e);
+ }
+ }
+
+ protected abstract void doExecute();
+
+ @Override
+ public final void undo() {
+ try {
+ runUnprotected(domain, new Runnable() {
+
+ @Override
+ public void run() {
+ doUndo();
+ }
+ });
+ } catch (Exception e) {
+ handleException(e);
+ }
+ }
+
+ protected void doUndo() {
+ // Pass. Usually, unprotected changes are not undoable
+ }
+
+ @Override
+ public final void redo() {
+ try {
+ runUnprotected(domain, new Runnable() {
+
+ @Override
+ public void run() {
+ doRedo();
+ }
+ });
+ } catch (Exception e) {
+ handleException(e);
+ }
+ }
+
+ protected void doRedo() {
+ // Pass. Usually, unprotected changes are not undoable
+ }
+
+ void handleException(Exception e) {
+ Activator.log.error(e);
+ }
+ }
+
+ private static class UnsafeCommandWrapper extends UnsafeCommand {
+
+ private final Command command;
+
+ UnsafeCommandWrapper(TransactionalEditingDomain domain, Command command) {
+ super(domain, command.getLabel(), command.getDescription());
+
+ this.command = command;
+ }
+
+ @Override
+ public void dispose() {
+ command.dispose();
+ }
+
+ @Override
+ public boolean canExecute() {
+ return command.canExecute();
+ }
+
+ @Override
+ protected void doExecute() {
+ command.execute();
+ }
+
+ @Override
+ public boolean canUndo() {
+ return command.canUndo();
+ }
+
+ @Override
+ protected void doUndo() {
+ command.undo();
+ }
+
+ @Override
+ protected void doRedo() {
+ command.redo();
+ }
+
+ @Override
+ public Collection<?> getAffectedObjects() {
+ return command.getAffectedObjects();
+ }
+
+ @Override
+ public Collection<?> getResult() {
+ return command.getResult();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Unsafe(%s)", command.toString()); //$NON-NLS-1$
+ }
+ }
+
+ private static class CommandRunnable implements Runnable {
+
+ private final Command command;
+
+ CommandRunnable(Command command) {
+ this.command = command;
+ }
+
+ @Override
+ public void run() {
+ command.execute();
+ }
+ }
+
+ private static class GMFCommandRunnable implements Runnable {
+
+ private final ICommand command;
+
+ GMFCommandRunnable(ICommand command) {
+ this.command = command;
+ }
+
+ @Override
+ public void run() {
+ try {
+ command.execute(new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+ throw new WrappedException(e);
+ }
+ }
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/OperationHistoryDirtyState.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/OperationHistoryDirtyState.java
new file mode 100644
index 00000000000..1bbfd926c5a
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/OperationHistoryDirtyState.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.emf.gmf.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
+
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IOperationHistoryListener;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.commands.operations.OperationHistoryEvent;
+import org.eclipse.emf.common.command.BasicCommandStack;
+import org.eclipse.papyrus.infra.emf.gmf.command.INonDirtying;
+
+
+/**
+ * A utility class for tracking the dirty state of an operation history. It works in the
+ * same fashion as the EMF {@link BasicCommandStack}, accounting for operations that {@linkplain INonDirtying do not dirty} the editor.
+ */
+public class OperationHistoryDirtyState {
+
+ private static final Map<IUndoContext, OperationHistoryDirtyState> instances = new HashMap<IUndoContext, OperationHistoryDirtyState>();
+
+ private final AtomicInteger refCount = new AtomicInteger(0);
+
+ private final IUndoContext context;
+
+ private final IOperationHistory history;
+
+ private IOperationHistoryListener listener;
+
+ private IUndoableOperation savepoint;
+
+ private boolean forceDirty;
+
+ protected OperationHistoryDirtyState(IUndoContext context, IOperationHistory history) {
+ this.context = context;
+ this.history = history;
+
+ history.addOperationHistoryListener(createOperationHistoryListener());
+ }
+
+ /**
+ * Create a delegating dirty state, usually for legacy compatibility.
+ *
+ * @param delegate
+ * the real dirty state
+ */
+ OperationHistoryDirtyState(OperationHistoryDirtyState delegate) {
+ this.context = delegate.context;
+ this.history = delegate.history;
+ }
+
+ /**
+ * Obtains a new operation history dirty-state tracker. Every result of this call must eventually be {@linkplain #dispose() disposed},
+ * even if it is actually the same instance as returned by an earlier call, because instances are reference-counted.
+ */
+ public static OperationHistoryDirtyState newInstance(IUndoContext context, IOperationHistory history) {
+ return getInstance(context, history, OperationHistoryDirtyState::new);
+ }
+
+ protected static OperationHistoryDirtyState getInstance(IUndoContext context, IOperationHistory history, BiFunction<? super IUndoContext, ? super IOperationHistory, ? extends OperationHistoryDirtyState> factory) {
+ OperationHistoryDirtyState result;
+
+ synchronized (instances) {
+ result = instances.get(context);
+ if (result == null) {
+ result = factory.apply(context, history);
+ instances.put(context, result);
+ }
+ }
+
+ result.retain();
+ return result;
+ }
+
+ private IOperationHistoryListener createOperationHistoryListener() {
+ this.listener = new IOperationHistoryListener() {
+
+ @Override
+ public void historyNotification(OperationHistoryEvent event) {
+ switch (event.getEventType()) {
+ case OperationHistoryEvent.DONE:
+ case OperationHistoryEvent.UNDONE:
+ case OperationHistoryEvent.REDONE:
+ case OperationHistoryEvent.OPERATION_CHANGED:
+ // Check on our savepoint, if any
+ if ((savepoint != null) && !savepoint.hasContext(context)) {
+ // Our savepoint has been removed from the context (our undo/redo stack), so it
+ // is effectively lost
+ savepoint = null;
+ }
+ break;
+ case OperationHistoryEvent.OPERATION_REMOVED:
+ IUndoableOperation removed = event.getOperation();
+ if (removed != null) {
+ if (removed == savepoint) {
+ // the savepoint was removed, so now we can never return to it
+ savepoint = null;
+ } else if ((savepoint == null) && removed.hasContext(context) && !OperationUtils.isNonDirtying(removed)) {
+ // A dirtying operation has been lost from the history, so we will not now be able to return
+ // to a state equivalent to the savepoint
+ forceDirty = true;
+ }
+ }
+ break;
+ }
+ }
+ };
+
+ return this.listener;
+ }
+
+ private OperationHistoryDirtyState retain() {
+ refCount.incrementAndGet();
+ return this;
+ }
+
+ private boolean release() {
+ return refCount.decrementAndGet() == 0;
+ }
+
+ public void dispose() {
+ synchronized (instances) {
+ if (release()) {
+ instances.remove(context);
+
+ if (listener != null) {
+ history.removeOperationHistoryListener(listener);
+ listener = null;
+ }
+
+ savepoint = null;
+ }
+ }
+ }
+
+ public boolean isDirty() {
+ return forceDirty || OperationUtils.isDirty(history.getUndoHistory(context), history.getRedoHistory(context), savepoint);
+ }
+
+ public void saved() {
+ this.savepoint = history.getUndoOperation(context);
+ this.forceDirty = false;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof Delegator) ? equals(((Delegator) obj).delegate) : super.equals(obj);
+ }
+
+ //
+ // Nested types
+ //
+
+ public static class Delegator extends OperationHistoryDirtyState {
+ private final OperationHistoryDirtyState delegate;
+
+ protected Delegator(IUndoContext context, IOperationHistory history) {
+ this(newInstance(context, history));
+ }
+
+ protected Delegator(OperationHistoryDirtyState delegate) {
+ super(delegate);
+
+ this.delegate = delegate;
+
+ // And replace it
+ synchronized (instances) {
+ instances.put(delegate.context, this);
+ }
+ }
+
+ @Override
+ public boolean isDirty() {
+ return delegate.isDirty();
+ }
+
+ @Override
+ public void dispose() {
+ delegate.dispose();
+ }
+
+ @Override
+ public void saved() {
+ delegate.saved();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return delegate.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/OperationUtils.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/OperationUtils.java
new file mode 100644
index 00000000000..7878f6155ca
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/gmf/util/OperationUtils.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.emf.gmf.util;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.workspace.EMFCommandOperation;
+import org.eclipse.papyrus.infra.emf.gmf.command.EMFtoGMFCommandWrapper;
+import org.eclipse.papyrus.infra.emf.gmf.command.INonDirtying;
+
+
+/**
+ * Utilities for working with undoable operations.
+ */
+public class OperationUtils {
+
+ /**
+ * Not instantiable by clients.
+ */
+ private OperationUtils() {
+ super();
+ }
+
+ public static boolean anyDirtying(IUndoableOperation[] undoHistory) {
+ boolean result = false;
+
+ if ((undoHistory != null) && (undoHistory.length > 0)) {
+ for (int i = 0; i < undoHistory.length; i++) {
+ if (!isNonDirtying(undoHistory[i])) {
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries whether an operation is non-dirtying. The only known non-dirtying operations, currently, are those that wrap a {@link AbstractCommand.NonDirtying}.
+ *
+ * @param operation
+ * an undoable operation
+ *
+ * @return whether it is a non-dirtying operation
+ */
+ public static boolean isNonDirtying(IUndoableOperation operation) {
+ boolean result = operation instanceof INonDirtying;
+ if (!result) {
+ Command command = unwrap(operation);
+ result = command instanceof AbstractCommand.NonDirtying;
+ }
+ return result;
+ }
+
+ /**
+ * Obtains the singular EMF {@link Command} that is wrapped by an {@code operation}, if it is a command wrapper of some kind.
+ *
+ * @param operation
+ * an operation
+ *
+ * @return the {@link Command} that it wraps, or {@code null} if it does not wrap a singular EMF command
+ */
+ public static Command unwrap(IUndoableOperation operation) {
+ Command result = null;
+
+ if (operation instanceof EMFCommandOperation) {
+ result = ((EMFCommandOperation) operation).getCommand();
+ } else if (operation instanceof EMFtoGMFCommandWrapper) {
+ result = ((EMFtoGMFCommandWrapper) operation).getWrappedCommand();
+ }
+
+ return result;
+ }
+
+ public static boolean isDirty(IUndoableOperation[] undoHistory, IUndoableOperation[] redoHistory, IUndoableOperation savepoint) {
+ boolean result = false;
+
+ if (savepoint == null) {
+ result = anyDirtying(undoHistory);
+ } else {
+ List<IUndoableOperation> undos = ((undoHistory == null) || (undoHistory.length == 0)) ? Collections.<IUndoableOperation> emptyList() : Arrays.asList(undoHistory);
+ List<IUndoableOperation> redos = ((redoHistory == null) || (redoHistory.length == 0)) ? Collections.<IUndoableOperation> emptyList() : Arrays.asList(redoHistory);
+
+ if (undos.contains(savepoint)) {
+ // See whether there is any dirtying command after the savepoint in the undo stack
+ int i = 0;
+
+ for (; i < undoHistory.length; i++) {
+ if (undoHistory[i] == savepoint) {
+ i++; // Advance over the save point to start testing
+ break;
+ }
+ }
+
+ for (; i < undoHistory.length; i++) {
+ if (!isNonDirtying(undoHistory[i])) {
+ result = true;
+ break;
+ }
+ }
+ } else if (redos.contains(savepoint)) {
+ // See whether there is any dirtying command before the savepoint in the redo stack
+ for (int i = redoHistory.length - 1; i >= 0; i--) {
+ if (!isNonDirtying(redoHistory[i])) {
+ result = true;
+ break;
+ }
+ if (redoHistory[i] == savepoint) {
+ // Done scanning. Everything up to and including the savepoint is non-dirtying
+ break;
+ }
+ }
+ } else {
+ // If we have no history but we have a savepoint, then we cannot undo nor redo to that savepoint
+ // (the history has been flushed) so evidently some change was made that invalidated the history,
+ // therefore we are dirty
+ result = true;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/internal/gmf/Activator.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/internal/gmf/Activator.java
new file mode 100644
index 00000000000..cffec0820a5
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.gmf/src/org/eclipse/papyrus/infra/emf/internal/gmf/Activator.java
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf.internal.gmf;
+
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends Plugin {
+
+ /**
+ * The plug-in ID
+ */
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.infra.emf,gmf"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The plug-in's logger
+ */
+ public static LogHelper log;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ super();
+ }
+
+ @Override
+ public void start(final BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ log = new LogHelper(this);
+ }
+
+ @Override
+ public void stop(final 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/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF
index ea8d0941c57..09cd9998ca9 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF
@@ -1,23 +1,23 @@
-Manifest-Version: 1.0
-Export-Package: org.eclipse.papyrus.infra.emf.readonly,
- org.eclipse.papyrus.infra.emf.readonly.internal;x-friends:="org.eclipse.papyrus.infra.ui.emf",
- org.eclipse.papyrus.infra.emf.readonly.spi
-Require-Bundle: org.eclipse.papyrus.infra.onefile;bundle-version="1.2.0",
- org.eclipse.core.expressions;bundle-version="3.4.300",
- org.eclipse.emf.workspace;bundle-version="1.4.0",
- org.eclipse.gmf.runtime.common.core;bundle-version="1.4.1",
- org.eclipse.papyrus.infra.core.log;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.gmfdiag.commands;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.core;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.emf;bundle-version="1.2.0",
- com.google.guava;bundle-version="11.0.0",
- org.eclipse.papyrus.infra.tools;bundle-version="1.2.0"
-Bundle-Vendor: %providerName
-Bundle-ActivationPolicy: lazy
-Bundle-Version: 1.2.0.qualifier
-Bundle-Name: %pluginName
-Bundle-Localization: plugin
-Bundle-ManifestVersion: 2
-Bundle-Activator: org.eclipse.papyrus.infra.emf.readonly.Activator
-Bundle-SymbolicName: org.eclipse.papyrus.infra.emf.readonly;singleton:=true
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Manifest-Version: 1.0
+Export-Package: org.eclipse.papyrus.infra.emf.readonly,
+ org.eclipse.papyrus.infra.emf.readonly.internal;x-friends:="org.eclipse.papyrus.infra.ui.emf",
+ org.eclipse.papyrus.infra.emf.readonly.spi
+Require-Bundle: org.eclipse.papyrus.infra.onefile;bundle-version="1.2.0",
+ org.eclipse.core.expressions;bundle-version="3.4.300",
+ org.eclipse.emf.workspace;bundle-version="1.4.0",
+ org.eclipse.gmf.runtime.common.core;bundle-version="1.4.1",
+ org.eclipse.papyrus.infra.core.log;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.emf.gmf;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.core;bundle-version="1.2.0",
+ org.eclipse.papyrus.infra.emf;bundle-version="1.2.0",
+ com.google.guava;bundle-version="11.0.0",
+ org.eclipse.papyrus.infra.tools;bundle-version="1.2.0"
+Bundle-Vendor: %providerName
+Bundle-ActivationPolicy: lazy
+Bundle-Version: 1.2.0.qualifier
+Bundle-Name: %pluginName
+Bundle-Localization: plugin
+Bundle-ManifestVersion: 2
+Bundle-Activator: org.eclipse.papyrus.infra.emf.readonly.Activator
+Bundle-SymbolicName: org.eclipse.papyrus.infra.emf.readonly;singleton:=true
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml
index 9d985cdebac..30a5894ceec 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/plugin.xml
@@ -1,74 +1,74 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?eclipse version="3.4"?>
-<plugin>
- <extension-point id="readOnlyHandler" name="readOnlyHandler" schema="schema/readOnlyHandler.exsd"/>
- <extension
- point="org.eclipse.papyrus.infra.emf.readonly.readOnlyHandler">
- <readOnlyHandler
- class="org.eclipse.papyrus.infra.emf.readonly.EMFReadOnlyHandler"
- id="org.eclipse.papyrus.infra.emf.readonly.EMFReadOnlyHandler"
- priority="5">
- <affinity
- axis="permission">
- </affinity>
- </readOnlyHandler>
- <readOnlyHandler
- class="org.eclipse.papyrus.infra.emf.readonly.SashModelReadOnlyHandler"
- priority="20">
- <affinity
- axis="discretion">
- </affinity>
- </readOnlyHandler>
- </extension>
-<extension
- point="org.eclipse.papyrus.infra.core.transactionalEditingDomainProvider">
- <transactionalEditingDomainProvider
- class="org.eclipse.papyrus.infra.emf.readonly.PapyrusROTransactionalEditingDomainProvider"
- priority="10">
- </transactionalEditingDomainProvider>
-</extension>
-<extension
- point="org.eclipse.core.expressions.propertyTesters">
- <propertyTester
- class="org.eclipse.papyrus.infra.emf.readonly.ReadOnlyTester"
- id="org.eclipse.papyrus.infra.emf.readonly.tester"
- namespace="org.eclipse.papyrus.infra.emf.readonly.tester"
- properties="isReadOnly,canMakeWritable"
- type="org.eclipse.emf.ecore.EObject">
- </propertyTester>
-</extension>
-<extension
- point="org.eclipse.papyrus.infra.gmfdiag.commands.operationApprover">
- <operationApprover
- class="org.eclipse.papyrus.infra.emf.readonly.ReadOnlyOneFileApprover"
- priority="10">
- </operationApprover>
-</extension>
-<extension
- point="org.eclipse.core.runtime.adapters">
- <factory
- adaptableType="org.eclipse.emf.edit.domain.EditingDomain"
- class="org.eclipse.papyrus.infra.emf.readonly.ReadOnlyAdapterFactory">
- <adapter
- type="org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler">
- </adapter>
- <adapter
- type="org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2">
- </adapter>
- </factory>
-</extension>
-<!-- commented for Papyrus M4 build -->
-<!-- <extension
- point="org.eclipse.papyrus.editor.perspectiveconfiguration">
- <configuration
- perspectiveID="org.eclipse.papyrus.infra.core.perspective">
- <toolbar
- toolbarID="org.eclipse.papyrus.infra.emf.readonly.toolbar">
- </toolbar>
- <command
- commandID="org.eclipse.papyrus.infra.emf.readonly.EnableWriteCommand">
- </command>
- </configuration>
- </extension>
- -->
-</plugin>
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension-point id="readOnlyHandler" name="readOnlyHandler" schema="schema/readOnlyHandler.exsd"/>
+ <extension
+ point="org.eclipse.papyrus.infra.emf.readonly.readOnlyHandler">
+ <readOnlyHandler
+ class="org.eclipse.papyrus.infra.emf.readonly.EMFReadOnlyHandler"
+ id="org.eclipse.papyrus.infra.emf.readonly.EMFReadOnlyHandler"
+ priority="5">
+ <affinity
+ axis="permission">
+ </affinity>
+ </readOnlyHandler>
+ <readOnlyHandler
+ class="org.eclipse.papyrus.infra.emf.readonly.SashModelReadOnlyHandler"
+ priority="20">
+ <affinity
+ axis="discretion">
+ </affinity>
+ </readOnlyHandler>
+ </extension>
+<extension
+ point="org.eclipse.papyrus.infra.core.transactionalEditingDomainProvider">
+ <transactionalEditingDomainProvider
+ class="org.eclipse.papyrus.infra.emf.readonly.PapyrusROTransactionalEditingDomainProvider"
+ priority="10">
+ </transactionalEditingDomainProvider>
+</extension>
+<extension
+ point="org.eclipse.core.expressions.propertyTesters">
+ <propertyTester
+ class="org.eclipse.papyrus.infra.emf.readonly.ReadOnlyTester"
+ id="org.eclipse.papyrus.infra.emf.readonly.tester"
+ namespace="org.eclipse.papyrus.infra.emf.readonly.tester"
+ properties="isReadOnly,canMakeWritable"
+ type="org.eclipse.emf.ecore.EObject">
+ </propertyTester>
+</extension>
+<extension
+ point="org.eclipse.papyrus.infra.emf.gmf.operationApprovers">
+ <operationApprover
+ class="org.eclipse.papyrus.infra.emf.readonly.ReadOnlyOneFileApprover"
+ priority="10">
+ </operationApprover>
+</extension>
+<extension
+ point="org.eclipse.core.runtime.adapters">
+ <factory
+ adaptableType="org.eclipse.emf.edit.domain.EditingDomain"
+ class="org.eclipse.papyrus.infra.emf.readonly.ReadOnlyAdapterFactory">
+ <adapter
+ type="org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler">
+ </adapter>
+ <adapter
+ type="org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2">
+ </adapter>
+ </factory>
+</extension>
+<!-- commented for Papyrus M4 build -->
+<!-- <extension
+ point="org.eclipse.papyrus.editor.perspectiveconfiguration">
+ <configuration
+ perspectiveID="org.eclipse.papyrus.infra.core.perspective">
+ <toolbar
+ toolbarID="org.eclipse.papyrus.infra.emf.readonly.toolbar">
+ </toolbar>
+ <command
+ commandID="org.eclipse.papyrus.infra.emf.readonly.EnableWriteCommand">
+ </command>
+ </configuration>
+ </extension>
+ -->
+</plugin>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml
index 9ddcb10a820..ead630febec 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml
@@ -2,13 +2,11 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
- <artifactId>org.eclipse.papyrus.releng</artifactId>
+ <artifactId>org.eclipse.papyrus.infra-emf</artifactId>
<groupId>org.eclipse.papyrus</groupId>
- <version>1.2.0-SNAPSHOT</version>
- <relativePath>../../../../releng/main</relativePath>
+ <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.papyrus.infra.emf.readonly</artifactId>
- <groupId>org.eclipse.papyrus</groupId>
<version>1.2.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
-</project> \ No newline at end of file
+</project>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java
index 74cf0fee03c..e31c6bbf1f3 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomainProvider.java
@@ -1,46 +1,46 @@
-/*****************************************************************************
- * Copyright (c) 2011, 2014 Atos Origin, CEA, and others.
- *
- * 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:
- * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
- * Christian W. Damus (CEA) - bug 402525
- *
- *****************************************************************************/
-package org.eclipse.papyrus.infra.emf.readonly;
-
-import org.eclipse.emf.ecore.resource.ResourceSet;
-import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
-import org.eclipse.emf.transaction.TransactionalEditingDomain;
-import org.eclipse.emf.workspace.IResourceUndoContextPolicy;
-import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
-import org.eclipse.papyrus.commands.CheckedOperationHistory;
-import org.eclipse.papyrus.commands.NestingNotifyingWorkspaceCommandStack;
-import org.eclipse.papyrus.commands.NotifyingWorkspaceCommandStack;
-import org.eclipse.papyrus.infra.core.resource.ITransactionalEditingDomainProvider;
-
-/**
- * Editing Domain created using this provider will use handlers registered on readOnlyHandler extension
- * to determine if a resource is read only.
- *
- * @author mvelten
- *
- */
-public class PapyrusROTransactionalEditingDomainProvider implements ITransactionalEditingDomainProvider {
-
- public TransactionalEditingDomain createTransactionalEditingDomain(ResourceSet resourceSet) {
- NotifyingWorkspaceCommandStack stack = new NestingNotifyingWorkspaceCommandStack(CheckedOperationHistory.getInstance());
- stack.setResourceUndoContextPolicy(IResourceUndoContextPolicy.DEFAULT);
-
- TransactionalEditingDomain result = new PapyrusROTransactionalEditingDomain(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE), stack, resourceSet);
-
- WorkspaceEditingDomainFactory.INSTANCE.mapResourceSet(result);
-
- return result;
- }
-
-}
+/*****************************************************************************
+ * Copyright (c) 2011, 2014 Atos Origin, CEA, and others.
+ *
+ * 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:
+ * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 402525
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf.readonly;
+
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.workspace.IResourceUndoContextPolicy;
+import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
+import org.eclipse.papyrus.infra.core.resource.ITransactionalEditingDomainProvider;
+import org.eclipse.papyrus.infra.emf.gmf.command.CheckedOperationHistory;
+import org.eclipse.papyrus.infra.emf.gmf.command.NestingNotifyingWorkspaceCommandStack;
+import org.eclipse.papyrus.infra.emf.gmf.command.NotifyingWorkspaceCommandStack;
+
+/**
+ * Editing Domain created using this provider will use handlers registered on readOnlyHandler extension
+ * to determine if a resource is read only.
+ *
+ * @author mvelten
+ *
+ */
+public class PapyrusROTransactionalEditingDomainProvider implements ITransactionalEditingDomainProvider {
+
+ public TransactionalEditingDomain createTransactionalEditingDomain(ResourceSet resourceSet) {
+ NotifyingWorkspaceCommandStack stack = new NestingNotifyingWorkspaceCommandStack(CheckedOperationHistory.getInstance());
+ stack.setResourceUndoContextPolicy(IResourceUndoContextPolicy.DEFAULT);
+
+ TransactionalEditingDomain result = new PapyrusROTransactionalEditingDomain(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE), stack, resourceSet);
+
+ WorkspaceEditingDomainFactory.INSTANCE.mapResourceSet(result);
+
+ return result;
+ }
+
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java
index bc3162db449..80415983e91 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyOneFileApprover.java
@@ -1,200 +1,203 @@
-/*****************************************************************************
- * Copyright (c) 2011, 2014 Atos Origin, CEA, and others.
- *
- *
- * 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:
- * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
- * Christian W. Damus (CEA) - bug 323802
- * Christian W. Damus (CEA) - bug 429826
- *
- *****************************************************************************/
-package org.eclipse.papyrus.infra.emf.readonly;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.eclipse.core.commands.operations.IOperationApprover2;
-import org.eclipse.core.commands.operations.IOperationHistory;
-import org.eclipse.core.commands.operations.IUndoableOperation;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.emf.common.command.Command;
-import org.eclipse.emf.common.command.CompoundCommand;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.edit.domain.EditingDomain;
-import org.eclipse.emf.workspace.AbstractEMFOperation;
-import org.eclipse.emf.workspace.EMFCommandOperation;
-import org.eclipse.gmf.runtime.common.core.command.CommandResult;
-import org.eclipse.gmf.runtime.common.core.command.ICommand;
-import org.eclipse.gmf.runtime.common.core.command.ICompositeCommand;
-import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper;
-import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
-import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
-import org.eclipse.papyrus.infra.onefile.model.IPapyrusFile;
-import org.eclipse.papyrus.infra.onefile.model.PapyrusModelHelper;
-import org.eclipse.papyrus.infra.onefile.utils.OneFileUtils;
-
-import com.google.common.base.Optional;
-
-public class ReadOnlyOneFileApprover implements IOperationApprover2 {
-
- public IStatus proceedRedoing(IUndoableOperation operation, IOperationHistory history, IAdaptable info) {
- return proceedExecuting(operation, history, info);
- }
-
- public IStatus proceedUndoing(IUndoableOperation operation, IOperationHistory history, IAdaptable info) {
- return proceedExecuting(operation, history, info);
- }
-
- public IStatus proceedExecuting(IUndoableOperation operation, IOperationHistory history, IAdaptable info) {
- HashSet<URI> filesToCheckForLock = new HashSet<URI>();
-
- Set<IFile> affectedFiles = getAffectedFiles(operation);
-
- if (!affectedFiles.isEmpty()) {
- for (IFile affectedFile : affectedFiles) {
- if (affectedFile == null) {
- continue;
- }
-
- if (affectedFile.exists()) {
- // the file is in the workspace
- IPapyrusFile papFile = PapyrusModelHelper.getPapyrusModelFactory().createIPapyrusFile(affectedFile);
- for (IFile f : OneFileUtils.getAssociatedFiles(papFile)) {
- filesToCheckForLock.add(URI.createPlatformResourceURI(f.getFullPath().toString(), true));
- }
- } else {
- // the file is not in the workspace
- IPath path = affectedFile.getRawLocation();
- if (path == null) {
- // cancel if we can't find the file
- if (operation instanceof ICommand) {
- setCommandResult((ICommand) operation, Status.CANCEL_STATUS);
- }
- return Status.CANCEL_STATUS;
- }
- File file = path.toFile();
- if (file != null && file.exists() && !file.canWrite()) {
- // cancel if we find a read-only file outside the
- // workspace
- if (operation instanceof ICommand) {
- setCommandResult((ICommand) operation, Status.CANCEL_STATUS);
- }
- return Status.CANCEL_STATUS;
- }
- }
- }
- }
-
- EditingDomain editingDomain = getEditingDomain(operation);
-
- URI[] filesToCheckForLockArray = filesToCheckForLock.toArray(new URI[filesToCheckForLock.size()]);
- IReadOnlyHandler2 roHandler = ReadOnlyManager.getReadOnlyHandler(editingDomain);
- if (roHandler.anyReadOnly(ReadOnlyAxis.anyAxis(), filesToCheckForLockArray).get()) {
- Optional<Boolean> ok = roHandler.makeWritable(ReadOnlyAxis.anyAxis(), filesToCheckForLockArray);
- if (!ok.get()) {
- return Status.CANCEL_STATUS;
- }
- }
-
- return Status.OK_STATUS;
- }
-
- protected EditingDomain getEditingDomain(IUndoableOperation command) {
- EditingDomain editingDomain = null;
- if (command instanceof AbstractEMFOperation) {
- editingDomain = ((AbstractEMFOperation) command).getEditingDomain();
- }
-
- if (editingDomain == null && command instanceof ICompositeCommand) {
- Iterator<?> it = ((ICompositeCommand) command).iterator();
- while (editingDomain == null && it.hasNext()) {
- IUndoableOperation c = (IUndoableOperation) it.next();
- editingDomain = getEditingDomain(c);
- }
- }
- return editingDomain;
- }
-
- /**
- * Sets the command result of the specified command to a CommandResult
- * having the specified status.
- *
- * @param command
- * ICommand to set the CommandResult for
- * @param status
- * IStatus of the CommandResult that will be set on the
- * command
- */
- @SuppressWarnings("restriction")
- protected void setCommandResult(ICommand command, IStatus status) {
- if (command instanceof org.eclipse.gmf.runtime.common.core.internal.command.ICommandWithSettableResult) {
- ((org.eclipse.gmf.runtime.common.core.internal.command.ICommandWithSettableResult) command).internalSetResult(new CommandResult(status));
- }
- }
-
- protected Set<IFile> getAffectedFiles(IUndoableOperation operation) {
- Set<IFile> result = getAffectedFiles(operation, null);
- return (result == null) ? Collections.<IFile> emptySet() : result;
- }
-
- protected Set<IFile> getAffectedFiles(IUndoableOperation operation, Set<IFile> result) {
- if (operation instanceof ICommand) {
- @SuppressWarnings("unchecked")
- Collection<IFile> files = ((ICommand) operation).getAffectedFiles();
- result = appendFiles(result, files);
- } else if (operation instanceof GMFtoEMFCommandWrapper) {
- result = getAffectedFiles(((GMFtoEMFCommandWrapper) operation).getGMFCommand(), result);
- } else if (operation instanceof EMFCommandOperation) {
- result = getAffectedFiles(((EMFCommandOperation) operation).getCommand(), result);
- }
-
- return result;
- }
-
- private Set<IFile> appendFiles(Set<IFile> result, Collection<IFile> files) {
- if ((files != null) && !files.isEmpty()) {
- if (result == null) {
- result = new HashSet<IFile>(files);
- } else {
- result.addAll(files);
- }
- }
- return result;
- }
-
- /**
- * Dig into an EMF command to find wrapped GMF commands and get their affected files. As commands are generally provided by GMF edit-helpers, this
- * should turn up useful results.
- *
- * @param command
- * a command to mine for affected files
- * @param result
- * an accumulator of affected files
- * @return the {@code result} if it already exists, a non-empty set containing affected files, or {@code null}
- */
- protected Set<IFile> getAffectedFiles(Command command, Set<IFile> result) {
- if (command instanceof CompoundCommand) {
- for (Command next : ((CompoundCommand) command).getCommandList()) {
- // accumulate affected files
- result = getAffectedFiles(next, result);
- }
- } else if (command instanceof GMFtoEMFCommandWrapper) {
- result = getAffectedFiles(((GMFtoEMFCommandWrapper) command).getGMFCommand(), result);
- }
-
- return result;
- }
-}
+/*****************************************************************************
+ * Copyright (c) 2011, 2014 Atos Origin, CEA, and others.
+ *
+ *
+ * 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:
+ * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 323802
+ * Christian W. Damus (CEA) - bug 429826
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf.readonly;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.commands.operations.IOperationApprover2;
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.workspace.AbstractEMFOperation;
+import org.eclipse.emf.workspace.EMFCommandOperation;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.common.core.command.ICompositeCommand;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
+import org.eclipse.papyrus.infra.emf.gmf.command.GMFtoEMFCommandWrapper;
+import org.eclipse.papyrus.infra.onefile.model.IPapyrusFile;
+import org.eclipse.papyrus.infra.onefile.model.PapyrusModelHelper;
+import org.eclipse.papyrus.infra.onefile.utils.OneFileUtils;
+
+import com.google.common.base.Optional;
+
+public class ReadOnlyOneFileApprover implements IOperationApprover2 {
+
+ @Override
+ public IStatus proceedRedoing(IUndoableOperation operation, IOperationHistory history, IAdaptable info) {
+ return proceedExecuting(operation, history, info);
+ }
+
+ @Override
+ public IStatus proceedUndoing(IUndoableOperation operation, IOperationHistory history, IAdaptable info) {
+ return proceedExecuting(operation, history, info);
+ }
+
+ @Override
+ public IStatus proceedExecuting(IUndoableOperation operation, IOperationHistory history, IAdaptable info) {
+ HashSet<URI> filesToCheckForLock = new HashSet<URI>();
+
+ Set<IFile> affectedFiles = getAffectedFiles(operation);
+
+ if (!affectedFiles.isEmpty()) {
+ for (IFile affectedFile : affectedFiles) {
+ if (affectedFile == null) {
+ continue;
+ }
+
+ if (affectedFile.exists()) {
+ // the file is in the workspace
+ IPapyrusFile papFile = PapyrusModelHelper.getPapyrusModelFactory().createIPapyrusFile(affectedFile);
+ for (IFile f : OneFileUtils.getAssociatedFiles(papFile)) {
+ filesToCheckForLock.add(URI.createPlatformResourceURI(f.getFullPath().toString(), true));
+ }
+ } else {
+ // the file is not in the workspace
+ IPath path = affectedFile.getRawLocation();
+ if (path == null) {
+ // cancel if we can't find the file
+ if (operation instanceof ICommand) {
+ setCommandResult((ICommand) operation, Status.CANCEL_STATUS);
+ }
+ return Status.CANCEL_STATUS;
+ }
+ File file = path.toFile();
+ if (file != null && file.exists() && !file.canWrite()) {
+ // cancel if we find a read-only file outside the
+ // workspace
+ if (operation instanceof ICommand) {
+ setCommandResult((ICommand) operation, Status.CANCEL_STATUS);
+ }
+ return Status.CANCEL_STATUS;
+ }
+ }
+ }
+ }
+
+ EditingDomain editingDomain = getEditingDomain(operation);
+
+ URI[] filesToCheckForLockArray = filesToCheckForLock.toArray(new URI[filesToCheckForLock.size()]);
+ IReadOnlyHandler2 roHandler = ReadOnlyManager.getReadOnlyHandler(editingDomain);
+ if (roHandler.anyReadOnly(ReadOnlyAxis.anyAxis(), filesToCheckForLockArray).get()) {
+ Optional<Boolean> ok = roHandler.makeWritable(ReadOnlyAxis.anyAxis(), filesToCheckForLockArray);
+ if (!ok.get()) {
+ return Status.CANCEL_STATUS;
+ }
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ protected EditingDomain getEditingDomain(IUndoableOperation command) {
+ EditingDomain editingDomain = null;
+ if (command instanceof AbstractEMFOperation) {
+ editingDomain = ((AbstractEMFOperation) command).getEditingDomain();
+ }
+
+ if (editingDomain == null && command instanceof ICompositeCommand) {
+ Iterator<?> it = ((ICompositeCommand) command).iterator();
+ while (editingDomain == null && it.hasNext()) {
+ IUndoableOperation c = (IUndoableOperation) it.next();
+ editingDomain = getEditingDomain(c);
+ }
+ }
+ return editingDomain;
+ }
+
+ /**
+ * Sets the command result of the specified command to a CommandResult
+ * having the specified status.
+ *
+ * @param command
+ * ICommand to set the CommandResult for
+ * @param status
+ * IStatus of the CommandResult that will be set on the
+ * command
+ */
+ @SuppressWarnings("restriction")
+ protected void setCommandResult(ICommand command, IStatus status) {
+ if (command instanceof org.eclipse.gmf.runtime.common.core.internal.command.ICommandWithSettableResult) {
+ ((org.eclipse.gmf.runtime.common.core.internal.command.ICommandWithSettableResult) command).internalSetResult(new CommandResult(status));
+ }
+ }
+
+ protected Set<IFile> getAffectedFiles(IUndoableOperation operation) {
+ Set<IFile> result = getAffectedFiles(operation, null);
+ return (result == null) ? Collections.<IFile> emptySet() : result;
+ }
+
+ protected Set<IFile> getAffectedFiles(IUndoableOperation operation, Set<IFile> result) {
+ if (operation instanceof ICommand) {
+ @SuppressWarnings("unchecked")
+ Collection<IFile> files = ((ICommand) operation).getAffectedFiles();
+ result = appendFiles(result, files);
+ } else if (operation instanceof GMFtoEMFCommandWrapper) {
+ result = getAffectedFiles(((GMFtoEMFCommandWrapper) operation).getGMFCommand(), result);
+ } else if (operation instanceof EMFCommandOperation) {
+ result = getAffectedFiles(((EMFCommandOperation) operation).getCommand(), result);
+ }
+
+ return result;
+ }
+
+ private Set<IFile> appendFiles(Set<IFile> result, Collection<IFile> files) {
+ if ((files != null) && !files.isEmpty()) {
+ if (result == null) {
+ result = new HashSet<IFile>(files);
+ } else {
+ result.addAll(files);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Dig into an EMF command to find wrapped GMF commands and get their affected files. As commands are generally provided by GMF edit-helpers, this
+ * should turn up useful results.
+ *
+ * @param command
+ * a command to mine for affected files
+ * @param result
+ * an accumulator of affected files
+ * @return the {@code result} if it already exists, a non-empty set containing affected files, or {@code null}
+ */
+ protected Set<IFile> getAffectedFiles(Command command, Set<IFile> result) {
+ if (command instanceof CompoundCommand) {
+ for (Command next : ((CompoundCommand) command).getCommandList()) {
+ // accumulate affected files
+ result = getAffectedFiles(next, result);
+ }
+ } else if (command instanceof GMFtoEMFCommandWrapper) {
+ result = getAffectedFiles(((GMFtoEMFCommandWrapper) command).getGMFCommand(), result);
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/pom.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/pom.xml
index 63ffd3757a1..cc4360ddd2d 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/pom.xml
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/pom.xml
@@ -2,13 +2,11 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
- <artifactId>org.eclipse.papyrus.releng</artifactId>
+ <artifactId>org.eclipse.papyrus.infra-emf</artifactId>
<groupId>org.eclipse.papyrus</groupId>
- <version>1.2.0-SNAPSHOT</version>
- <relativePath>../../../../releng/main</relativePath>
+ <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.papyrus.infra.emf</artifactId>
- <groupId>org.eclipse.papyrus</groupId>
<version>1.2.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
-</project> \ No newline at end of file
+</project>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/Activator.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/Activator.java
index fe845446d23..a3c0e69cc06 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/Activator.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/Activator.java
@@ -1,130 +1,129 @@
-/*****************************************************************************
- * Copyright (c) 2013, 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 v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
- * Christian W. Damus - bug 485220
- *
- *****************************************************************************/
-package org.eclipse.papyrus.infra.emf;
-
-import java.util.ArrayList;
-
-import org.eclipse.core.runtime.Plugin;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EPackage;
-import org.eclipse.emf.ecore.resource.ResourceSet;
-import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
-import org.eclipse.papyrus.emf.facet.custom.core.ICustomizationManager;
-import org.eclipse.papyrus.emf.facet.custom.core.ICustomizationManagerFactory;
-import org.eclipse.papyrus.infra.core.log.LogHelper;
-import org.eclipse.papyrus.infra.emf.spi.resolver.EObjectResolverService;
-import org.eclipse.papyrus.infra.emf.spi.resolver.IEObjectResolver;
-import org.osgi.framework.BundleContext;
-
-/**
- * The activator class controls the plug-in life cycle
- */
-public class Activator extends Plugin {
-
- /**
- * The plug-in ID
- */
- public static final String PLUGIN_ID = "org.eclipse.papyrus.infra.emf"; //$NON-NLS-1$
-
- // The shared instance
- private static Activator plugin;
-
- /**
- * The plug-in's logger
- */
- public static LogHelper log;
-
- private ICustomizationManager fCustomizationManager;
- // temp resourceSet
- private ResourceSet facetRecsourceSet = new ResourceSetImpl();
-
- private EObjectResolverService resolverService;
-
- /**
- * The constructor
- */
- public Activator() {
- super();
- }
-
- @Override
- public void start(final BundleContext context) throws Exception {
- super.start(context);
- plugin = this;
- log = new LogHelper(this);
-
- resolverService = new EObjectResolverService(context);
- resolverService.open();
- }
-
- @Override
- public void stop(final BundleContext context) throws Exception {
- resolverService.close();
- resolverService = null;
-
- plugin = null;
- super.stop(context);
- }
-
- /**
- * Returns the shared instance
- *
- * @return the shared instance
- */
- public static Activator getDefault() {
- return plugin;
- }
-
- /**
- *
- * @return the customization manager in charge to adapt element in modisco
- */
- public ICustomizationManager getCustomizationManager() {
- if (this.fCustomizationManager == null) {
- this.fCustomizationManager = ICustomizationManagerFactory.DEFAULT.getOrCreateICustomizationManager(facetRecsourceSet);
- }
- return this.fCustomizationManager;
- }
-
- /** @return the qualified name of the given metaclass */
- public static String getMetaclassQualifiedName(final EClassifier eClass) {
- final ArrayList<String> qualifiedNameParts = new ArrayList<String>();
- final StringBuilder builder = new StringBuilder();
-
- EPackage ePackage = eClass.getEPackage();
- while (ePackage != null) {
- qualifiedNameParts.add(ePackage.getName());
- ePackage = ePackage.getESuperPackage();
- }
-
- for (int i = qualifiedNameParts.size() - 1; i >= 0; i--) {
- builder.append(qualifiedNameParts.get(i) + "."); //$NON-NLS-1$
- }
-
- builder.append(eClass.getName());
-
- return builder.toString();
- }
-
- /**
- * Obtain the instance of the {@link EObject} resolver service, if any.
- *
- * @return the object resolver service (never {@code null} while this bundle is active)
- */
- public IEObjectResolver getEObjectResolver() {
- return resolverService;
- }
-
-}
+/*****************************************************************************
+ * Copyright (c) 2013, 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.papyrus.emf.facet.custom.core.ICustomizationManager;
+import org.eclipse.papyrus.emf.facet.custom.core.ICustomizationManagerFactory;
+import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.eclipse.papyrus.infra.emf.spi.resolver.EObjectResolverService;
+import org.eclipse.papyrus.infra.emf.spi.resolver.IEObjectResolver;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends Plugin {
+
+ /**
+ * The plug-in ID
+ */
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.infra.emf"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The plug-in's logger
+ */
+ public static LogHelper log;
+
+ private ICustomizationManager fCustomizationManager;
+ // temp resourceSet
+ private ResourceSet facetRecsourceSet = new ResourceSetImpl();
+
+ private EObjectResolverService resolverService;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ super();
+ }
+
+ @Override
+ public void start(final BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ log = new LogHelper(this);
+
+ resolverService = new EObjectResolverService(context);
+ }
+
+ @Override
+ public void stop(final BundleContext context) throws Exception {
+ resolverService.dispose();
+ resolverService = null;
+
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ /**
+ *
+ * @return the customization manager in charge to adapt element in modisco
+ */
+ public ICustomizationManager getCustomizationManager() {
+ if (this.fCustomizationManager == null) {
+ this.fCustomizationManager = ICustomizationManagerFactory.DEFAULT.getOrCreateICustomizationManager(facetRecsourceSet);
+ }
+ return this.fCustomizationManager;
+ }
+
+ /** @return the qualified name of the given metaclass */
+ public static String getMetaclassQualifiedName(final EClassifier eClass) {
+ final ArrayList<String> qualifiedNameParts = new ArrayList<String>();
+ final StringBuilder builder = new StringBuilder();
+
+ EPackage ePackage = eClass.getEPackage();
+ while (ePackage != null) {
+ qualifiedNameParts.add(ePackage.getName());
+ ePackage = ePackage.getESuperPackage();
+ }
+
+ for (int i = qualifiedNameParts.size() - 1; i >= 0; i--) {
+ builder.append(qualifiedNameParts.get(i) + "."); //$NON-NLS-1$
+ }
+
+ builder.append(eClass.getName());
+
+ return builder.toString();
+ }
+
+ /**
+ * Obtain the instance of the {@link EObject} resolver service, if any.
+ *
+ * @return the object resolver service (never {@code null} while this bundle is active)
+ */
+ public IEObjectResolver getEObjectResolver() {
+ return resolverService;
+ }
+
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/spi/resolver/EObjectResolverService.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/spi/resolver/EObjectResolverService.java
index 9b2e0ecb239..dd9f1e67d95 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/spi/resolver/EObjectResolverService.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/spi/resolver/EObjectResolverService.java
@@ -13,20 +13,15 @@
package org.eclipse.papyrus.infra.emf.spi.resolver;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Stream;
-
+import org.eclipse.papyrus.infra.tools.util.CompositeServiceTracker;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
/**
* A resolver that delegates to registered OSGi services in a <em>Chain of Command</em>
* pattern to provide the first available service result.
*/
-public class EObjectResolverService extends ServiceTracker<IEObjectResolver, IEObjectResolver> implements IEObjectResolver {
- private final AtomicReference<IEObjectResolver> delegate = new AtomicReference<>(IEObjectResolver.identity());
+public class EObjectResolverService implements IEObjectResolver {
+ private final CompositeServiceTracker<IEObjectResolver> tracker;
/**
* Initializes me with the bundle context in which I track resolver services.
@@ -35,38 +30,21 @@ public class EObjectResolverService extends ServiceTracker<IEObjectResolver, IEO
* the bundle context
*/
public EObjectResolverService(BundleContext context) {
- super(context, IEObjectResolver.class, null);
- }
-
- @Override
- public Object resolve(Object object) {
- IEObjectResolver delegate = this.delegate.get();
- if (delegate == null) {
- // Recompute
- delegate = Stream.of(getServices(new IEObjectResolver[getTrackingCount()]))
- .filter(Objects::nonNull) // If the array has more slots than we have services
- .reduce(IEObjectResolver.identity(), IEObjectResolver::compose);
- this.delegate.set(delegate);
- }
+ super();
- return delegate.resolve(object);
+ tracker = new CompositeServiceTracker<>(context,
+ IEObjectResolver.class,
+ IEObjectResolver.identity(),
+ IEObjectResolver::compose);
+ tracker.open();
}
- @Override
- public IEObjectResolver addingService(ServiceReference<IEObjectResolver> reference) {
- IEObjectResolver result = super.addingService(reference);
-
- // We will have to recompute our delegates
- delegate.set(null);
-
- return result;
+ public void dispose() {
+ tracker.close();
}
@Override
- public void removedService(ServiceReference<IEObjectResolver> reference, IEObjectResolver service) {
- super.removedService(reference, service);
-
- // We will have to recompute our delegates
- delegate.set(null);
+ public Object resolve(Object object) {
+ return tracker.getService().resolve(object);
}
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/pom.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/pom.xml
index 8e34b9157d6..b5fbae85035 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/pom.xml
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/pom.xml
@@ -2,13 +2,11 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
- <artifactId>org.eclipse.papyrus.releng</artifactId>
+ <artifactId>org.eclipse.papyrus.infra-emf</artifactId>
<groupId>org.eclipse.papyrus</groupId>
- <version>1.2.0-SNAPSHOT</version>
- <relativePath>../../../../releng/main</relativePath>
+ <version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.papyrus.infra.ui.emf</artifactId>
- <groupId>org.eclipse.papyrus</groupId>
<version>1.2.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
-</project> \ No newline at end of file
+</project>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/utils/ProviderHelper.java b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/utils/ProviderHelper.java
index 77704b242af..5e6acf0d429 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/utils/ProviderHelper.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/utils/ProviderHelper.java
@@ -13,16 +13,25 @@
*****************************************************************************/
package org.eclipse.papyrus.infra.ui.emf.utils;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.papyrus.emf.facet.custom.core.ICustomizationManager;
+import org.eclipse.papyrus.infra.core.language.ILanguageService;
+import org.eclipse.papyrus.infra.core.resource.IModel;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.emf.utils.HistoryUtil;
import org.eclipse.papyrus.infra.ui.emf.providers.EMFGraphicalContentProvider;
import org.eclipse.papyrus.infra.ui.emf.providers.strategy.ContainmentBrowseStrategy;
+import org.eclipse.papyrus.infra.ui.emf.providers.strategy.SemanticEMFContentProvider;
import org.eclipse.papyrus.infra.ui.internal.emf.Activator;
+import org.eclipse.papyrus.infra.ui.providers.ISemanticContentProviderFactory;
import org.eclipse.papyrus.infra.widgets.strategy.ProviderBasedBrowseStrategy;
import org.eclipse.papyrus.infra.widgets.strategy.StrategyBasedContentProvider;
import org.eclipse.papyrus.infra.widgets.strategy.TreeBrowseStrategy;
@@ -70,4 +79,38 @@ public class ProviderHelper {
ResourceSet rs = editedEObject == null ? null : editedEObject.eResource() == null ? null : editedEObject.eResource().getResourceSet();
return encapsulateProvider(provider, rs, HistoryUtil.getHistoryID(editedEObject, feature));
}
+
+ /**
+ * Obtain the best available semantic content provider factory for a given resource set.
+ *
+ * @param resourceSet
+ * a resource set
+ * @return the best available semantic content provider factory (never {@code null})
+ *
+ * @see #getContentProvider(ResourceSet)
+ */
+ public static ISemanticContentProviderFactory getContentProviderFactory(ResourceSet resourceSet) {
+ Collection<? extends IModel> models = (resourceSet instanceof ModelSet)
+ ? ILanguageService.getLanguageModels((ModelSet) resourceSet)
+ : Collections.emptyList();
+ return models.stream()
+ .map(m -> m.getAdapter(ISemanticContentProviderFactory.class))
+ .filter(Objects::nonNull)
+ .reduce(ISemanticContentProviderFactory::compose)
+ .orElse(SemanticEMFContentProvider::new);
+ }
+
+ /**
+ * Obtain the best available semantic content provider for a given resource set.
+ *
+ * @param resourceSet
+ * a resource set
+ * @return the best available semantic content provider factory (never {@code null})
+ *
+ * @see #getContentProviderFactory(ResourceSet)
+ */
+ public static ITreeContentProvider getContentProvider(ResourceSet resourceSet) {
+ return getContentProviderFactory(resourceSet).createSemanticContentProvider(resourceSet);
+ }
+
}
diff --git a/plugins/infra/emf/pom.xml b/plugins/infra/emf/pom.xml
new file mode 100644
index 00000000000..b64c1d01e8b
--- /dev/null
+++ b/plugins/infra/emf/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>org.eclipse.papyrus.infra-emf</artifactId>
+ <packaging>pom</packaging>
+ <parent>
+ <groupId>org.eclipse.papyrus</groupId>
+ <artifactId>org.eclipse.papyrus.infra</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <name>Papyrus EMF Infrastructure</name>
+ <description>Various plug-ins providing extended modeling services on EMF.</description>
+
+ <modules>
+ <module>org.eclipse.papyrus.infra.emf</module>
+ <module>org.eclipse.papyrus.infra.emf.appearance</module>
+ <module>org.eclipse.papyrus.infra.emf.diagram.common</module>
+ <module>org.eclipse.papyrus.infra.emf.gmf</module>
+ <module>org.eclipse.papyrus.infra.emf.readonly</module>
+ <module>org.eclipse.papyrus.infra.ui.emf</module>
+ </modules>
+</project>

Back to the top