Bug 405710 - Re-enable redo after execution of a feature that has not
done any changes

*Store contexts of the operation in the redo stack before executing the
feature
*Re-add the stored contexts to the operation after executing a feature
when no changes were done

Change-Id: Ia24c15b34a580c7f91d968853ca86e9247569fdd
diff --git a/plugins/org.eclipse.graphiti.ui/src/org/eclipse/graphiti/ui/internal/editor/GFCommandStack.java b/plugins/org.eclipse.graphiti.ui/src/org/eclipse/graphiti/ui/internal/editor/GFCommandStack.java
index a59a456..b20f3f2 100644
--- a/plugins/org.eclipse.graphiti.ui/src/org/eclipse/graphiti/ui/internal/editor/GFCommandStack.java
+++ b/plugins/org.eclipse.graphiti.ui/src/org/eclipse/graphiti/ui/internal/editor/GFCommandStack.java
@@ -25,6 +25,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.core.commands.operations.IOperationHistory;
 import org.eclipse.core.commands.operations.IUndoContext;
 import org.eclipse.core.commands.operations.IUndoableOperation;
 import org.eclipse.core.runtime.IStatus;
@@ -32,7 +33,7 @@
 import org.eclipse.emf.transaction.RollbackException;
 import org.eclipse.emf.transaction.TransactionalCommandStack;
 import org.eclipse.emf.transaction.TransactionalEditingDomain;
-import org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl;
+import org.eclipse.emf.workspace.IWorkspaceCommandStack;
 import org.eclipse.gef.commands.Command;
 import org.eclipse.gef.commands.CommandStack;
 import org.eclipse.graphiti.features.IFeature;
@@ -119,6 +120,19 @@
 		Map<String, DefaultExecutionInfo> options = new HashMap<String, DefaultExecutionInfo>(2);
 		options.put(OPTION_EXECUTION_INFO, executionInfo);
 
+		// Store contexts of redo operations for restoring after a feature that
+		// has done no changes has been executed to re-enable redo. Executing a
+		// feature will remove the contexts from the operations - see Bug 405710
+		IUndoContext[][] contexts = new IUndoContext[0][];
+		if (emfCommandStack instanceof IWorkspaceCommandStack) {
+			IUndoableOperation[] originalRedoOperations = ((IWorkspaceCommandStack) emfCommandStack)
+					.getOperationHistory().getRedoHistory(IOperationHistory.GLOBAL_UNDO_CONTEXT);
+			contexts = new IUndoContext[originalRedoOperations.length][];
+			for (int i = 0; i < originalRedoOperations.length; i++) {
+				contexts[i] = originalRedoOperations[i].getContexts();
+			}
+		}
+
 		tbp.preExecute(executionInfo);
 		try {
 			getEmfCommandStack().execute(gfPreparableCommand, options);
@@ -174,15 +188,27 @@
 		}
 
 		// If no changes were done revert the undo stack entry
-		if (!changesDone) {
-			// Use the default context and retrieve the last operation
-			WorkspaceCommandStackImpl workspaceCommandStackImpl = (WorkspaceCommandStackImpl) getEmfCommandStack();
+		if (!changesDone && emfCommandStack instanceof IWorkspaceCommandStack) {
+			// Retrieve the last operation using the default context
+			IWorkspaceCommandStack workspaceCommandStackImpl = (IWorkspaceCommandStack) getEmfCommandStack();
 			IUndoContext context = workspaceCommandStackImpl.getDefaultUndoContext();
 			IUndoableOperation operation = workspaceCommandStackImpl.getOperationHistory().getUndoOperation(context);
 
 			// Replace the found operation with an empty set
 			workspaceCommandStackImpl.getOperationHistory().replaceOperation(operation, new IUndoableOperation[0]);
 
+			// Restore the original contexts of the redo operations to re-enable
+			// undo as there is no new entry on the undo stack - see Bug 405710
+			IUndoableOperation[] newRedoOperations = workspaceCommandStackImpl.getOperationHistory().getRedoHistory(
+					IOperationHistory.GLOBAL_UNDO_CONTEXT);
+			for (int i = 0; i < newRedoOperations.length; i++) {
+				for (int j = 0; j < contexts[i].length; j++) {
+					if (!newRedoOperations[i].hasContext(contexts[i][j])) {
+						newRedoOperations[i].addContext(contexts[i][j]);
+					}
+				}
+			}
+
 			// Update the editor actions bars, especially Edit --> Undo
 			notifyListeners(gefCommand, CommandStack.POST_MASK);
 		}