Bug 507203 - Offer commands which allow progress reporting

* Paste commands which uses progress compound commands to pass a
progress monitor.
* commands which report progress and read from the event queue
* ReportSetHelpers allows to pass in an AdapterFactoryEditingDomain, so
that user may override createCommand and still use the current methods
in a convinient way

Change-Id: I2a38a18dbb5c9929a036d0bc24abbc3acb6f41e0
Signed-off-by: Johannes Faltermeier <jfaltermeier@eclipsesource.com>
diff --git a/bundles/org.eclipse.emf.ecp.edit.swt/META-INF/MANIFEST.MF b/bundles/org.eclipse.emf.ecp.edit.swt/META-INF/MANIFEST.MF
index 1f13dc3..1499ee9 100644
--- a/bundles/org.eclipse.emf.ecp.edit.swt/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.emf.ecp.edit.swt/META-INF/MANIFEST.MF
@@ -26,6 +26,7 @@
    org.eclipse.emf.ecp.view.treemasterdetail.ui.swt,
    org.eclipse.emf.ecp.view.core.swt",
  org.eclipse.emf.ecp.edit.spi.swt.actions;version="1.11.0",
+ org.eclipse.emf.ecp.edit.spi.swt.commands;version="1.11.0",
  org.eclipse.emf.ecp.edit.spi.swt.reference;version="1.11.0",
  org.eclipse.emf.ecp.edit.spi.swt.table;version="1.11.0",
  org.eclipse.emf.ecp.edit.spi.swt.util;version="1.11.0"
@@ -50,6 +51,7 @@
  org.eclipse.jface.dialogs;version="0.0.0",
  org.eclipse.jface.fieldassist;version="0.0.0",
  org.eclipse.jface.layout;version="0.0.0",
+ org.eclipse.jface.operation;version="0.0.0",
  org.eclipse.jface.resource;version="0.0.0",
  org.eclipse.jface.viewers;version="0.0.0",
  org.eclipse.jface.window;version="0.0.0",
diff --git a/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/IProgressMonitorConsumer.java b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/IProgressMonitorConsumer.java
new file mode 100644
index 0000000..8b64ce5
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/IProgressMonitorConsumer.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi.swt.commands;
+
+/**
+ * A Marker interface for classes which may consume an {@link IProgressMonitorProvider}.
+ *
+ * @author Johannes Faltermeier
+ * @since 1.11
+ *
+ */
+public interface IProgressMonitorConsumer {
+
+	/**
+	 * @param monitor the {@link IProgressMonitorProvider}
+	 */
+	void setIProgressMonitorAccessor(IProgressMonitorProvider monitor);
+
+}
diff --git a/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/IProgressMonitorProvider.java b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/IProgressMonitorProvider.java
new file mode 100644
index 0000000..cdee0c6
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/IProgressMonitorProvider.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi.swt.commands;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Interface which marks classes which provide an {@link IProgressMonitor}.
+ *
+ * @author Johannes Faltermeier
+ * @since 1.11
+ *
+ */
+public interface IProgressMonitorProvider {
+
+	/**
+	 * @return the {@link IProgressMonitor}
+	 */
+	IProgressMonitor getProgressMonitor();
+}
diff --git a/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressAddCommand.java b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressAddCommand.java
new file mode 100644
index 0000000..b30f186
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressAddCommand.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi.swt.commands;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.edit.command.AddCommand;
+import org.eclipse.emf.edit.command.CommandParameter;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * {@link AddCommand} which is able to report progress.
+ *
+ * @author Johannes Faltermeier
+ * @since 1.11
+ *
+ */
+public class ProgressAddCommand extends AddCommand implements IProgressMonitorConsumer {
+
+	private IProgressMonitorProvider monitor;
+
+	/**
+	 * Constructs a {@link ProgressAddCommand}.
+	 *
+	 * @param domain the {@link EditingDomain}
+	 * @param owner the parent
+	 * @param feature the feature
+	 * @param collection the children to add
+	 * @param index the start index
+	 */
+	public ProgressAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection<?> collection,
+		int index) {
+		super(domain, owner, feature, collection, index);
+	}
+
+	@Override
+	public void setIProgressMonitorAccessor(IProgressMonitorProvider monitor) {
+		this.monitor = monitor;
+	}
+
+	@Override
+	public void doExecute() {
+		// Simply add the collection to the list.
+		//
+		if (index == CommandParameter.NO_INDEX) {
+			for (final Object object : collection) {
+				ownerList.add(object);
+				worked();
+			}
+		} else {
+			int i = index;
+			for (final Object object : collection) {
+				ownerList.add(i++, object);
+				worked();
+			}
+		}
+
+		// Update the containing map, if necessary.
+		//
+		updateEMap(owner, feature);
+
+		// We'd like the collection of things added to be selected after this command completes.
+		//
+		affectedObjects = collection;
+	}
+
+	private void worked() {
+		final IProgressMonitor progressMonitor = monitor.getProgressMonitor();
+		if (progressMonitor == null) {
+			return;
+		}
+		progressMonitor.worked(1);
+		while (Display.getDefault().readAndDispatch()) {
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressCompoundCommand.java b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressCompoundCommand.java
new file mode 100644
index 0000000..3ad8c25
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressCompoundCommand.java
@@ -0,0 +1,552 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi.swt.commands;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.CommonPlugin;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.common.command.UnexecutableCommand;
+import org.eclipse.emf.common.util.WrappedException;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Extension of the {@link CompoundCommand} which reports progress.
+ *
+ * @author Johannes Faltermeier
+ * @since 1.11
+ *
+ */
+public class ProgressCompoundCommand extends CompoundCommand {
+
+	private final IProgressMonitorProvider monitor;
+
+	/**
+	 * Creates an empty instance with the given result index.
+	 *
+	 * @param resultIndex the {@link #resultIndex}.
+	 * @param monitor the progress monitor
+	 */
+	public ProgressCompoundCommand(int resultIndex, IProgressMonitorProvider monitor) {
+		super(resultIndex);
+		this.monitor = monitor;
+	}
+
+	// REUSED CLASS
+
+	/**
+	 * Returns whether there are commands in the list.
+	 *
+	 * @return whether there are commands in the list.
+	 */
+	@Override
+	public boolean isEmpty() {
+		return commandList.isEmpty();
+	}
+
+	/**
+	 * Returns an unmodifiable view of the commands in the list.
+	 *
+	 * @return an unmodifiable view of the commands in the list.
+	 */
+	@Override
+	public List<Command> getCommandList() {
+		return Collections.unmodifiableList(commandList);
+	}
+
+	/**
+	 * Returns the index of the command whose result and affected objects are forwarded.
+	 * Negative values have special meaning, as defined by the static constants.
+	 *
+	 * @return the index of the command whose result and affected objects are forwarded.
+	 * @see #LAST_COMMAND_ALL
+	 * @see #MERGE_COMMAND_ALL
+	 */
+	@Override
+	public int getResultIndex() {
+		return resultIndex;
+	}
+
+	/**
+	 * Returns whether all the commands can execute so that {@link #isExecutable} can be cached.
+	 * An empty command list causes <code>false</code> to be returned.
+	 *
+	 * @return whether all the commands can execute.
+	 */
+	@Override
+	protected boolean prepare() {
+		if (commandList.isEmpty()) {
+			return false;
+		}
+		for (final Command command : commandList) {
+			if (!command.canExecute()) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Calls {@link Command#execute} for each command in the list.
+	 */
+	@Override
+	public void execute() {
+		for (final ListIterator<Command> commands = commandList.listIterator(); commands.hasNext();) {
+			try {
+				final Command command = commands.next();
+				command.execute();
+				worked();
+			} catch (final RuntimeException exception) {
+				// Skip over the command that threw the exception.
+				//
+				commands.previous();
+
+				try {
+					// Iterate back over the executed commands to undo them.
+					//
+					while (commands.hasPrevious()) {
+						final Command command = commands.previous();
+						if (command.canUndo()) {
+							command.undo();
+							worked();
+						} else {
+							break;
+						}
+					}
+				} catch (final RuntimeException nestedException) {
+					CommonPlugin.INSTANCE
+						.log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
+							nestedException).fillInStackTrace());
+				}
+
+				throw exception;
+			}
+		}
+	}
+
+	/**
+	 * Returns <code>false</code> if any of the commands return <code>false</code> for {@link Command#canUndo}.
+	 *
+	 * @return <code>false</code> if any of the commands return <code>false</code> for <code>canUndo</code>.
+	 */
+	@Override
+	public boolean canUndo() {
+		for (final Command command : commandList) {
+			if (!command.canUndo()) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Calls {@link Command#undo} for each command in the list, in reverse order.
+	 */
+	@Override
+	public void undo() {
+		for (final ListIterator<Command> commands = commandList.listIterator(commandList.size()); commands
+			.hasPrevious();) {
+			try {
+				final Command command = commands.previous();
+				command.undo();
+				worked();
+			} catch (final RuntimeException exception) {
+				// Skip over the command that threw the exception.
+				//
+				commands.next();
+
+				try {
+					// Iterate forward over the undone commands to redo them.
+					//
+					while (commands.hasNext()) {
+						final Command command = commands.next();
+						command.redo();
+						worked();
+					}
+				} catch (final RuntimeException nestedException) {
+					CommonPlugin.INSTANCE
+						.log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
+							nestedException).fillInStackTrace());
+				}
+
+				throw exception;
+			}
+		}
+	}
+
+	/**
+	 * Calls {@link Command#redo} for each command in the list.
+	 */
+	@Override
+	public void redo() {
+		for (final ListIterator<Command> commands = commandList.listIterator(); commands.hasNext();) {
+			try {
+				final Command command = commands.next();
+				command.redo();
+				worked();
+			} catch (final RuntimeException exception) {
+				// Skip over the command that threw the exception.
+				//
+				commands.previous();
+
+				try {
+					// Iterate back over the executed commands to undo them.
+					//
+					while (commands.hasPrevious()) {
+						final Command command = commands.previous();
+						command.undo();
+						worked();
+					}
+				} catch (final RuntimeException nestedException) {
+					CommonPlugin.INSTANCE
+						.log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
+							nestedException).fillInStackTrace());
+				}
+
+				throw exception;
+			}
+		}
+	}
+
+	/**
+	 * Determines the result by composing the results of the commands in the list;
+	 * this is affected by the setting of {@link #resultIndex}.
+	 *
+	 * @return the result.
+	 */
+	@Override
+	public Collection<?> getResult() {
+		if (commandList.isEmpty()) {
+			return Collections.EMPTY_LIST;
+		} else if (resultIndex == LAST_COMMAND_ALL) {
+			return commandList.get(commandList.size() - 1).getResult();
+		} else if (resultIndex == MERGE_COMMAND_ALL) {
+			return getMergedResultCollection();
+		} else if (resultIndex < commandList.size()) {
+			return commandList.get(resultIndex).getResult();
+		} else {
+			return Collections.EMPTY_LIST;
+		}
+	}
+
+	/**
+	 * Returns the merged collection of all command results.
+	 *
+	 * @return the merged collection of all command results.
+	 */
+	@Override
+	protected Collection<?> getMergedResultCollection() {
+		final Collection<Object> result = new ArrayList<Object>();
+
+		for (final Command command : commandList) {
+			result.addAll(command.getResult());
+		}
+
+		return result;
+	}
+
+	/**
+	 * Determines the affected objects by composing the affected objects of the commands in the list;
+	 * this is affected by the setting of {@link #resultIndex}.
+	 *
+	 * @return the affected objects.
+	 */
+	@Override
+	public Collection<?> getAffectedObjects() {
+		if (commandList.isEmpty()) {
+			return Collections.EMPTY_LIST;
+		} else if (resultIndex == LAST_COMMAND_ALL) {
+			return commandList.get(commandList.size() - 1).getAffectedObjects();
+		} else if (resultIndex == MERGE_COMMAND_ALL) {
+			return getMergedAffectedObjectsCollection();
+		} else if (resultIndex < commandList.size()) {
+			return commandList.get(resultIndex).getAffectedObjects();
+		} else {
+			return Collections.EMPTY_LIST;
+		}
+	}
+
+	/**
+	 * Returns the merged collection of all command affected objects.
+	 *
+	 * @return the merged collection of all command affected objects.
+	 */
+	@Override
+	protected Collection<?> getMergedAffectedObjectsCollection() {
+		final Collection<Object> result = new ArrayList<Object>();
+
+		for (final Command command : commandList) {
+			result.addAll(command.getAffectedObjects());
+		}
+
+		return result;
+	}
+
+	/**
+	 * Determines the label by composing the labels of the commands in the list;
+	 * this is affected by the setting of {@link #resultIndex}.
+	 *
+	 * @return the label.
+	 */
+	@Override
+	public String getLabel() {
+		if (label != null) {
+			return label;
+		} else if (commandList.isEmpty()) {
+			return CommonPlugin.INSTANCE.getString("_UI_CompoundCommand_label"); //$NON-NLS-1$
+		} else if (resultIndex == LAST_COMMAND_ALL || resultIndex == MERGE_COMMAND_ALL) {
+			return commandList.get(commandList.size() - 1).getLabel();
+		} else if (resultIndex < commandList.size()) {
+			return commandList.get(resultIndex).getLabel();
+		} else {
+			return CommonPlugin.INSTANCE.getString("_UI_CompoundCommand_label"); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Determines the description by composing the descriptions of the commands in the list;
+	 * this is affected by the setting of {@link #resultIndex}.
+	 *
+	 * @return the description.
+	 */
+	@Override
+	public String getDescription() {
+		if (description != null) {
+			return description;
+		} else if (commandList.isEmpty()) {
+			return CommonPlugin.INSTANCE.getString("_UI_CompoundCommand_description"); //$NON-NLS-1$
+		} else if (resultIndex == LAST_COMMAND_ALL || resultIndex == MERGE_COMMAND_ALL) {
+			return commandList.get(commandList.size() - 1).getDescription();
+		} else if (resultIndex < commandList.size()) {
+			return commandList.get(resultIndex).getDescription();
+		} else {
+			return CommonPlugin.INSTANCE.getString("_UI_CompoundCommand_description"); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Adds a command to this compound command's list of commands.
+	 *
+	 * @param command the command to append.
+	 */
+	@Override
+	public void append(Command command) {
+		if (isPrepared) {
+			throw new IllegalStateException("The command is already prepared"); //$NON-NLS-1$
+		}
+
+		if (command != null) {
+			commandList.add(command);
+		}
+	}
+
+	/**
+	 * Checks if the command can execute;
+	 * if so, it is executed, appended to the list, and true is returned,
+	 * if not, it is just disposed and false is returned.
+	 * A typical use for this is to execute commands created during the execution of another command, e.g.,
+	 *
+	 * <pre>
+	 *   class MyCommand extends CommandBase
+	 *   {
+	 *     protected Command subcommand;
+	 *
+	 *     //...
+	 *
+	 *     public void execute()
+	 *     {
+	 *       // ...
+	 *       Compound subcommands = new CompoundCommand();
+	 *       subcommands.appendAndExecute(new AddCommand(...));
+	 *       if (condition) subcommands.appendAndExecute(new AddCommand(...));
+	 *       subcommand = subcommands.unwrap();
+	 *     }
+	 *
+	 *     public void undo()
+	 *     {
+	 *       // ...
+	 *       subcommand.undo();
+	 *     }
+	 *
+	 *     public void redo()
+	 *     {
+	 *       // ...
+	 *       subcommand.redo();
+	 *     }
+	 *
+	 *     public void dispose()
+	 *     {
+	 *       // ...
+	 *       if (subcommand != null)
+	 *      {
+	 *         subcommand.dispose();
+	 *       }
+	 *     }
+	 *   }
+	 * </pre>
+	 *
+	 * Another use is in an execute override of compound command itself:
+	 *
+	 * <pre>
+	 *   class MyCommand extends CompoundCommand
+	 *   {
+	 *     public void execute()
+	 *     {
+	 *       // ...
+	 *       appendAndExecute(new AddCommand(...));
+	 *       if (condition) appendAndExecute(new AddCommand(...));
+	 *     }
+	 *   }
+	 * </pre>
+	 *
+	 * Note that appending commands will modify what getResult and getAffectedObjects return,
+	 * so you may want to set the resultIndex flag.
+	 *
+	 * @param command the command.
+	 * @return whether the command was successfully executed and appended.
+	 */
+	@Override
+	public boolean appendAndExecute(Command command) {
+		if (command != null) {
+			if (!isPrepared) {
+				if (commandList.isEmpty()) {
+					isPrepared = true;
+					isExecutable = true;
+				} else {
+					isExecutable = prepare();
+					isPrepared = true;
+					if (isExecutable) {
+						execute();
+					}
+				}
+			}
+
+			if (command.canExecute()) {
+				try {
+					command.execute();
+					worked();
+					commandList.add(command);
+					return true;
+				} catch (final RuntimeException exception) {
+					CommonPlugin.INSTANCE
+						.log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
+							exception).fillInStackTrace());
+				}
+			}
+
+			command.dispose();
+		}
+
+		return false;
+	}
+
+	/**
+	 * Adds a command to this compound command's the list of commands and returns <code>true</code>,
+	 * if <code>command.{@link org.eclipse.emf.common.command.Command#canExecute() canExecute()}</code> returns true;
+	 * otherwise, it simply calls
+	 * <code>command.{@link org.eclipse.emf.common.command.Command#dispose() dispose()}</code>
+	 * and returns <code>false</code>.
+	 *
+	 * @param command the command.
+	 * @return whether the command was executed and appended.
+	 */
+	@Override
+	public boolean appendIfCanExecute(Command command) {
+		if (command == null) {
+			return false;
+		} else if (command.canExecute()) {
+			commandList.add(command);
+			return true;
+		} else {
+			command.dispose();
+			return false;
+		}
+	}
+
+	/**
+	 * Calls {@link Command#dispose} for each command in the list.
+	 */
+	@Override
+	public void dispose() {
+		for (final Command command : commandList) {
+			command.dispose();
+		}
+	}
+
+	/**
+	 * Returns one of three things:
+	 * {@link org.eclipse.emf.common.command.UnexecutableCommand#INSTANCE}, if there are no commands,
+	 * the one command, if there is exactly one command,
+	 * or <code>this</code>, if there are multiple commands;
+	 * this command is {@link #dispose}d in the first two cases.
+	 * You should only unwrap a compound command if you created it for that purpose, e.g.,
+	 *
+	 * <pre>
+	 * CompoundCommand subcommands = new CompoundCommand();
+	 * subcommands.append(x);
+	 * if (condition)
+	 * 	subcommands.append(y);
+	 * Command result = subcommands.unwrap();
+	 * </pre>
+	 *
+	 * is a good way to create an efficient accumulated result.
+	 *
+	 * @return the unwrapped command.
+	 */
+	@Override
+	public Command unwrap() {
+		switch (commandList.size()) {
+		case 0: {
+			dispose();
+			return UnexecutableCommand.INSTANCE;
+		}
+		case 1: {
+			final Command result = commandList.remove(0);
+			dispose();
+			return result;
+		}
+		default: {
+			return this;
+		}
+		}
+	}
+
+	@Override
+	public String toString() {
+		final StringBuffer result = new StringBuffer(super.toString());
+		result.append(" (commandList: #" + commandList.size() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+		result.append(" (resultIndex: " + resultIndex + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		return result.toString();
+	}
+
+	// END REUSED CLASS
+
+	private void worked() {
+		final IProgressMonitor progressMonitor = monitor.getProgressMonitor();
+		if (progressMonitor == null) {
+			return;
+		}
+		progressMonitor.worked(1);
+		while (Display.getDefault().readAndDispatch()) {
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressCopyCommandFactory.java b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressCopyCommandFactory.java
new file mode 100644
index 0000000..b689490
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressCopyCommandFactory.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi.swt.commands;
+
+import java.util.Collection;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.common.command.UnexecutableCommand;
+import org.eclipse.emf.edit.command.CommandParameter;
+import org.eclipse.emf.edit.command.CopyCommand;
+import org.eclipse.emf.edit.command.CopyCommand.Helper;
+import org.eclipse.emf.edit.domain.EditingDomain;
+
+/**
+ * Factory to create copy commands enabling progress reposrting.
+ *
+ * @since 1.11
+ */
+public final class ProgressCopyCommandFactory {
+
+	private ProgressCopyCommandFactory() {
+	}
+
+	/**
+	 * This creates a command that copies the given collection of objects. If the collection contains more than one
+	 * object,
+	 * then a compound command will be created containing individual copy commands for each object.
+	 *
+	 * @param domain {@link EditingDomain}
+	 * @param collection objects to copy
+	 * @param monitor the monitor.
+	 * @return the copy command.
+	 */
+	public static Command create(final EditingDomain domain, final Collection<?> collection,
+		IProgressMonitorProvider monitor) {
+		if (collection == null || collection.isEmpty()) {
+			return UnexecutableCommand.INSTANCE;
+		}
+
+		final Helper copyHelper = new Helper();
+		final CompoundCommand copyCommand = new ProgressCompoundCommand(CompoundCommand.MERGE_COMMAND_ALL, monitor);
+		for (final Object object : collection) {
+			copyCommand.append(domain.createCommand(CopyCommand.class, new CommandParameter(object, null, copyHelper)));
+		}
+
+		return copyCommand.unwrap();
+	}
+}
diff --git a/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressPasteFromClipboardCommand.java b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressPasteFromClipboardCommand.java
new file mode 100644
index 0000000..ed9d25c
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressPasteFromClipboardCommand.java
@@ -0,0 +1,272 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi.swt.commands;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CommandWrapper;
+import org.eclipse.emf.edit.command.AddCommand;
+import org.eclipse.emf.edit.command.PasteFromClipboardCommand;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Extension of the {@link PasteFromClipboardCommand} which enabled progress reporting.
+ *
+ * @author Johannes Faltermeier
+ * @since 1.11
+ *
+ */
+public class ProgressPasteFromClipboardCommand extends PasteFromClipboardCommand implements IProgressMonitorProvider {
+
+	private IProgressMonitor monitor;
+
+	/**
+	 * Constructs a new {@link ProgressPasteFromClipboardCommand}.
+	 *
+	 * @param domain the {@link EditingDomain}
+	 * @param owner the owner object
+	 * @param feature the feature
+	 * @param index the index
+	 */
+	public ProgressPasteFromClipboardCommand(EditingDomain domain, Object owner, Object feature, int index) {
+		super(domain, owner, feature, index);
+	}
+
+	/**
+	 * Constructs a new {@link ProgressPasteFromClipboardCommand}.
+	 *
+	 * @param domain the {@link EditingDomain}
+	 * @param owner the owner object
+	 * @param feature the feature
+	 * @param index the index
+	 * @param optimize whether to call the optimized can execute method
+	 */
+	public ProgressPasteFromClipboardCommand(EditingDomain domain, Object owner, Object feature, int index,
+		boolean optimize) {
+		super(domain, owner, feature, index, optimize);
+	}
+
+	@Override
+	protected boolean prepare() {
+		{
+			// Create a strict compound command to do a copy and then add the result
+			//
+			command = new ProgressStrictCompoundCommand(this);
+
+			// Create a command to copy the clipboard.
+			//
+			final Command copyCommand = ProgressCopyCommandFactory.create(domain, domain.getClipboard(), this);
+
+			// REUSED CLASS
+			command.append(copyCommand);
+
+			// Create a proxy that will create an add command.
+			//
+			command.append(new CommandWrapper() {
+				protected Collection<Object> original;
+				protected Collection<Object> copy;
+
+				@Override
+				protected Command createCommand() {
+					original = domain.getClipboard();
+					copy = new ArrayList<Object>(copyCommand.getResult());
+
+					// Use the original to do the add, but only if it's of the same type as the copy.
+					// This ensures that if there is conversion being done as part of the copy,
+					// as would be the case for a cross domain copy in the mapping framework,
+					// that we do actually use the converted instance.
+					//
+					if (original.size() == copy.size()) {
+						for (Iterator<Object> i = original.iterator(), j = copy.iterator(); i.hasNext();) {
+							final Object originalObject = i.next();
+							final Object copyObject = j.next();
+							if (originalObject.getClass() != copyObject.getClass()) {
+								original = null;
+								break;
+							}
+						}
+					}
+
+					final Command addCommand = AddCommand.create(domain, owner, feature,
+						original == null ? copy : original, index);
+					if (IProgressMonitorConsumer.class.isInstance(addCommand)) {
+						IProgressMonitorConsumer.class.cast(addCommand)
+							.setIProgressMonitorAccessor(ProgressPasteFromClipboardCommand.this);
+					}
+					return addCommand;
+				}
+
+				@Override
+				public void execute() {
+					if (original != null) {
+						domain.setClipboard(copy);
+					}
+					super.execute();
+				}
+
+				@Override
+				public void undo() {
+					super.undo();
+					if (original != null) {
+						domain.setClipboard(original);
+					}
+				}
+
+				@Override
+				public void redo() {
+					if (original != null) {
+						domain.setClipboard(copy);
+					}
+					super.redo();
+				}
+			});
+
+			boolean result;
+			if (optimize) {
+				// This will determine canExecute as efficiently as possible.
+				//
+				result = optimizedCanExecute();
+			} else {
+				// This will actually execute the copy command in order to check if the add can execute.
+				//
+				result = command.canExecute();
+			}
+
+			return result;
+		}
+	}
+	// END REUSED CLASS
+
+	@Override
+	public void doExecute() {
+		doExecuteWithProgress("Pasting elements..."); //$NON-NLS-1$
+	}
+
+	/**
+	 * Does the same as {@link #doExecute()} but also displays a progress dialog.
+	 *
+	 * @param task the name of the task
+	 */
+	protected void doExecuteWithProgress(final String task) {
+		try {
+			final ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(
+				Display.getDefault().getActiveShell());
+			progressMonitorDialog.run(
+				false, /* if we fork auto UI updates of EMF.edit.ui do not work, so stay on UI thread */
+				false,
+				new IRunnableWithProgress() {
+					@Override
+					public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+						ProgressPasteFromClipboardCommand.this.monitor = monitor;
+						monitor.beginTask(task, getTotalWorkExecute());
+						ProgressPasteFromClipboardCommand.super.doExecute();
+						ProgressPasteFromClipboardCommand.this.monitor = null;
+					}
+				});
+		} catch (final InvocationTargetException ex) {
+		} catch (final InterruptedException ex) {
+		}
+	}
+
+	/**
+	 * @return the total work required to execute the paste operation
+	 */
+	protected int getTotalWorkExecute() {
+		int work = domain.getClipboard().size();
+		final List<Command> commandList = command.getCommandList();
+		work += commandList.size();
+		for (final Command subCommand : commandList) {
+			if (!ProgressCompoundCommand.class.isInstance(subCommand)) {
+				continue;
+			}
+			work += ProgressCompoundCommand.class.cast(subCommand).getCommandList().size();
+		}
+		return work;
+	}
+
+	@Override
+	public void doUndo() {
+		doUndoWithProgress("Undoing paste operation"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Does the same as {@link #doUndo()} but also displays a progress dialog.
+	 *
+	 * @param task the name of the task
+	 */
+	protected void doUndoWithProgress(final String task) {
+		try {
+			final ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(
+				Display.getDefault().getActiveShell());
+			progressMonitorDialog.run(
+				false, /* if we fork auto UI updates of EMF.edit.ui do not work, so stay on UI thread */
+				false,
+				new IRunnableWithProgress() {
+					@Override
+					public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+						ProgressPasteFromClipboardCommand.this.monitor = monitor;
+						monitor.beginTask(task, 1);
+						ProgressPasteFromClipboardCommand.super.doUndo();
+						ProgressPasteFromClipboardCommand.this.monitor = null;
+					}
+				});
+		} catch (final InvocationTargetException ex) {
+		} catch (final InterruptedException ex) {
+		}
+	}
+
+	@Override
+	public void doRedo() {
+		doRedoWithProgress("Redoing paste operation."); //$NON-NLS-1$
+	}
+
+	/**
+	 * Does the same as {@link #doRedo()} but also displays a progress dialog.
+	 *
+	 * @param task the name of the task
+	 */
+	protected void doRedoWithProgress(final String task) {
+		try {
+			final ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(
+				Display.getDefault().getActiveShell());
+			progressMonitorDialog.run(
+				false, /* if we fork auto UI updates of EMF.edit.ui do not work, so stay on UI thread */
+				false,
+				new IRunnableWithProgress() {
+					@Override
+					public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+						ProgressPasteFromClipboardCommand.this.monitor = monitor;
+						monitor.beginTask(task, 1);
+						ProgressPasteFromClipboardCommand.super.doRedo();
+						ProgressPasteFromClipboardCommand.this.monitor = null;
+					}
+				});
+		} catch (final InvocationTargetException ex) {
+		} catch (final InterruptedException ex) {
+		}
+	}
+
+	@Override
+	public IProgressMonitor getProgressMonitor() {
+		return monitor;
+	}
+
+}
diff --git a/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressStrictCompoundCommand.java b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressStrictCompoundCommand.java
new file mode 100644
index 0000000..3fe6cde
--- /dev/null
+++ b/bundles/org.eclipse.emf.ecp.edit.swt/src/org/eclipse/emf/ecp/edit/spi/swt/commands/ProgressStrictCompoundCommand.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.ecp.edit.spi.swt.commands;
+
+import java.util.ListIterator;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.CommonPlugin;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.StrictCompoundCommand;
+import org.eclipse.emf.common.util.WrappedException;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Extension of the {@link StrictCompoundCommand} which reports the progress.
+ *
+ * @author Johannes Faltermeier
+ * @since 1.11
+ *
+ */
+public class ProgressStrictCompoundCommand extends StrictCompoundCommand {
+
+	private final IProgressMonitorProvider monitor;
+
+	/**
+	 * Creates an empty instance.
+	 *
+	 * @param monitor the monitor
+	 */
+	public ProgressStrictCompoundCommand(IProgressMonitorProvider monitor) {
+		super();
+		this.monitor = monitor;
+	}
+
+	// REUSED CLASS
+
+	@Override
+	protected boolean prepare() {
+		// Go through the commands of the list.
+		//
+		final ListIterator<Command> commands = commandList.listIterator();
+
+		// If there are some...
+		//
+		if (commands.hasNext()) {
+			boolean result = true;
+
+			// The termination guard is in the body.
+			//
+			for (;;) {
+				final Command command = commands.next();
+				if (command.canExecute()) {
+					if (commands.hasNext()) {
+						if (command.canUndo()) {
+							try {
+								if (commands.previousIndex() <= rightMostExecutedCommandIndex) {
+									command.redo();
+									worked();
+								} else {
+									++rightMostExecutedCommandIndex;
+									command.execute();
+									worked();
+								}
+							} catch (final RuntimeException exception) {
+								CommonPlugin.INSTANCE.log(new WrappedException(
+									CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), exception) //$NON-NLS-1$
+										.fillInStackTrace());
+
+								result = false;
+								break;
+							}
+						} else {
+							// We can't undo it, so we'd better give up.
+							//
+							result = false;
+							break;
+						}
+					} else {
+						// Now is the best time to record isUndoable because later we would have to do all the executes
+						// again!
+						// This makes canUndo very simple!
+						//
+						isUndoable = command.canUndo();
+						break;
+					}
+				} else {
+					// If we can't execute this one, we just can't do it at all.
+					//
+					result = false;
+					break;
+				}
+			}
+
+			// If we are pessimistic, then we need to undo all the commands that we have executed so far.
+			//
+			if (isPessimistic) {
+				// The most recently processed command will never have been executed.
+				//
+				commands.previous();
+
+				// We want to unroll all the effects of the previous commands.
+				//
+				while (commands.hasPrevious()) {
+					final Command command = commands.previous();
+					command.undo();
+					worked();
+				}
+			}
+
+			return result;
+		}
+		isUndoable = false;
+		return false;
+	}
+
+	@Override
+	public void execute() {
+		if (isPessimistic) {
+			for (final ListIterator<Command> commands = commandList.listIterator(); commands.hasNext();) {
+				try {
+					// Either execute or redo the command, as appropriate.
+					//
+					final Command command = commands.next();
+					if (commands.previousIndex() <= rightMostExecutedCommandIndex) {
+						command.redo();
+						worked();
+					} else {
+						command.execute();
+						worked();
+					}
+				} catch (final RuntimeException exception) {
+					// Skip over the command that threw the exception.
+					//
+					commands.previous();
+
+					// Iterate back over the executed commands to undo them.
+					//
+					while (commands.hasPrevious()) {
+						commands.previous();
+						final Command command = commands.previous();
+						if (command.canUndo()) {
+							command.undo();
+							worked();
+						} else {
+							break;
+						}
+					}
+
+					throw exception;
+				}
+			}
+		} else if (!commandList.isEmpty()) {
+			final Command command = commandList.get(commandList.size() - 1);
+			command.execute();
+			worked();
+		}
+	}
+
+	@Override
+	public void undo() {
+		if (isPessimistic) {
+			super.undo();
+		} else if (!commandList.isEmpty()) {
+			final Command command = commandList.get(commandList.size() - 1);
+			command.undo();
+			worked();
+		}
+	}
+
+	@Override
+	public void redo() {
+		if (isPessimistic) {
+			super.redo();
+		} else if (!commandList.isEmpty()) {
+			final Command command = commandList.get(commandList.size() - 1);
+			command.redo();
+			worked();
+		}
+	}
+
+	@Override
+	public boolean appendAndExecute(Command command) {
+		if (command != null) {
+			if (!isPrepared) {
+				if (commandList.isEmpty()) {
+					isPrepared = true;
+					isExecutable = true;
+				} else {
+					isExecutable = prepare();
+					isPrepared = true;
+					isPessimistic = true;
+					if (isExecutable) {
+						execute();
+					}
+				}
+			}
+
+			if (command.canExecute()) {
+				try {
+					command.execute();
+					worked();
+					commandList.add(command);
+					++rightMostExecutedCommandIndex;
+					isUndoable = command.canUndo();
+					return true;
+				} catch (final RuntimeException exception) {
+					CommonPlugin.INSTANCE
+						.log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
+							exception).fillInStackTrace());
+				}
+			}
+
+			command.dispose();
+		}
+
+		return false;
+	}
+
+	@Override
+	public String toString() {
+		final StringBuffer result = new StringBuffer(super.toString());
+		result.append(" (isUndoable: " + isUndoable + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+		result.append(" (isPessimistic: " + isPessimistic + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+		result.append(" (rightMostExecutedCommandIndex: " + rightMostExecutedCommandIndex + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		return result.toString();
+	}
+
+	// END REUSED CLASS
+
+	private void worked() {
+		final IProgressMonitor progressMonitor = monitor.getProgressMonitor();
+		if (progressMonitor == null) {
+			return;
+		}
+		progressMonitor.worked(1);
+		while (Display.getDefault().readAndDispatch()) {
+		}
+	}
+}
diff --git a/bundles/org.eclipse.emfforms.editor/src/org/eclipse/emfforms/spi/editor/helpers/ResourceSetHelpers.java b/bundles/org.eclipse.emfforms.editor/src/org/eclipse/emfforms/spi/editor/helpers/ResourceSetHelpers.java
index dec5e78..c13fc71 100644
--- a/bundles/org.eclipse.emfforms.editor/src/org/eclipse/emfforms/spi/editor/helpers/ResourceSetHelpers.java
+++ b/bundles/org.eclipse.emfforms.editor/src/org/eclipse/emfforms/spi/editor/helpers/ResourceSetHelpers.java
@@ -109,6 +109,17 @@
 					new ComposedAdapterFactory(
 						ComposedAdapterFactory.Descriptor.Registry.INSTANCE) }),
 			commandStack);
+		return createResourceSet(domain);
+	}
+
+	/**
+	 * Creates a ResourceSet with the given EditingDomain.
+	 *
+	 * @param domain the editing domain
+	 * @return the resource set
+	 * @since 1.11
+	 */
+	public static ResourceSet createResourceSet(final AdapterFactoryEditingDomain domain) {
 		final ResourceSet resourceSet = domain.getResourceSet();
 		resourceSet.eAdapters().add(
 			new AdapterFactoryEditingDomain.EditingDomainProvider(domain));