495066: Add ability for context store to change multiple handles 

Change-Id: I78f75974c889779921bede06cb74b1562bc1f191
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=495066
Signed-off-by: Brandon Dong <brandon.dong@tasktop.com>
diff --git a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ChangeActivityHandleOperation.java b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ChangeActivityHandleOperation.java
index fe36589..d4ca4e9 100644
--- a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ChangeActivityHandleOperation.java
+++ b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ChangeActivityHandleOperation.java
@@ -12,6 +12,9 @@
 package org.eclipse.mylyn.internal.context.tasks.ui;
 
 import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -23,30 +26,27 @@
 import org.eclipse.mylyn.monitor.core.InteractionEvent;
 
 /**
- * Changes handle from oldHandle to newHandle in Activity Meta Context
- * 
+ * Changes a set of old handles to a set of new handles in the Activity Meta Context.
+ *
  * @author Rob Elves
  */
 public class ChangeActivityHandleOperation extends TaskListModifyOperation {
 
-	private final String oldHandle;
-
-	private final String newHandle;
+	private final Map<String, String> handles;
 
 	public ChangeActivityHandleOperation(String oldHandle, String newHandle) {
-		this.oldHandle = oldHandle;
-		this.newHandle = newHandle;
+		this(Collections.singletonMap(oldHandle, newHandle));
+	}
+
+	public ChangeActivityHandleOperation(Map<String, String> handles) {
+		this.handles = handles;
 	}
 
 	@Override
-	protected void operations(IProgressMonitor monitor) throws CoreException, InvocationTargetException,
-			InterruptedException {
-		if (oldHandle == null || newHandle == null || oldHandle.equals(newHandle)) {
-			return;
-		}
+	protected void operations(IProgressMonitor monitor)
+			throws CoreException, InvocationTargetException, InterruptedException {
 		try {
-			monitor.beginTask(Messages.ChangeActivityHandleOperation_Activity_migration, IProgressMonitor.UNKNOWN);
-			refactorMetaContextHandles(oldHandle, newHandle);
+			refactorMetaContextHandles(handles, monitor);
 			TasksUiPlugin.getTaskActivityMonitor().reloadActivityTime();
 		} finally {
 			monitor.done();
@@ -54,20 +54,24 @@
 	}
 
 	@SuppressWarnings("restriction")
-	private void refactorMetaContextHandles(String oldHandle, String newHandle) {
+	private void refactorMetaContextHandles(Map<String, String> oldToNewHandles, IProgressMonitor monitor) {
 		ContextCorePlugin.getContextManager().saveActivityMetaContext();
 		InteractionContext metaContext = ContextCorePlugin.getContextManager().getActivityMetaContext();
 		ContextCorePlugin.getContextManager().resetActivityMetaContext();
 		InteractionContext newMetaContext = ContextCorePlugin.getContextManager().getActivityMetaContext();
-		for (InteractionEvent event : metaContext.getInteractionHistory()) {
+		List<InteractionEvent> interactionHistory = metaContext.getInteractionHistory();
+		monitor.beginTask(Messages.ChangeActivityHandleOperation_Activity_migration, interactionHistory.size());
+		for (InteractionEvent event : interactionHistory) {
 			if (event.getStructureHandle() != null) {
-				if (event.getStructureHandle().equals(oldHandle)) {
+				String newHandle = oldToNewHandles.get(event.getStructureHandle());
+				if (newHandle != null) {
 					event = new InteractionEvent(event.getKind(), event.getStructureKind(), newHandle,
 							event.getOriginId(), event.getNavigation(), event.getDelta(),
 							event.getInterestContribution(), event.getDate(), event.getEndDate());
 				}
 			}
 			newMetaContext.parseEvent(event);
+			monitor.worked(1);
 		}
 		ContextCorePlugin.getContextManager().saveActivityMetaContext();
 	}
diff --git a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStore.java b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStore.java
index 4db5744..d003eed 100644
--- a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStore.java
+++ b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStore.java
@@ -14,6 +14,8 @@
 import java.io.File;
 import java.lang.reflect.InvocationTargetException;
 import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
@@ -44,6 +46,8 @@
 import org.eclipse.mylyn.tasks.ui.TasksUi;
 import org.eclipse.osgi.util.NLS;
 
+import com.google.common.collect.ImmutableMap;
+
 /**
  * @author Steffen Pingel
  */
@@ -158,17 +162,41 @@
 		final IInteractionContext result = copyContextInternal(sourceTask, targetTask);
 
 		// move task activity
-		ChangeActivityHandleOperation operation = new ChangeActivityHandleOperation(sourceTask.getHandleIdentifier(),
-				targetTask.getHandleIdentifier());
+		moveTaskActivity(ImmutableMap.of(sourceTask.getHandleIdentifier(), targetTask.getHandleIdentifier()));
+
+		moveContextInStore(sourceTask, targetTask);
+
+		return asAdaptable(result);
+	}
+
+	@Override
+	public void refactorContext(Map<ITask, ITask> tasks) {
+		Map<String, String> handles = new HashMap<>();
+		for (ITask sourceTask : tasks.keySet()) {
+			handles.put(sourceTask.getHandleIdentifier(), tasks.get(sourceTask).getHandleIdentifier());
+			copyContextInternal(sourceTask, tasks.get(sourceTask));
+		}
+
+		moveTaskActivity(handles);
+
+		for (ITask sourceTask : tasks.keySet()) {
+			moveContextInStore(sourceTask, tasks.get(sourceTask));
+		}
+	}
+
+	private void moveTaskActivity(Map<String, String> handles) {
+		ChangeActivityHandleOperation operation = new ChangeActivityHandleOperation(handles);
 		try {
 			operation.run(new NullProgressMonitor());
 		} catch (InvocationTargetException e) {
-			StatusHandler.log(new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN,
-					"Failed to migrate activity to new task", e)); //$NON-NLS-1$
+			StatusHandler.log(
+					new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, "Failed to migrate activity to new task", e)); //$NON-NLS-1$
 		} catch (InterruptedException e) {
 			// ignore
 		}
+	}
 
+	private void moveContextInStore(ITask sourceTask, ITask targetTask) {
 		try {
 			getTaskStore().move(getPath(sourceTask), getPath(targetTask));
 		} catch (CoreException e) {
@@ -183,8 +211,6 @@
 				listener.taskContextChanged(event);
 			}
 		});
-
-		return asAdaptable(result);
 	}
 
 	@Override
@@ -322,14 +348,17 @@
 		}
 	}
 
-	private void refactorRepositoryLocation(TaskRepository repository, String oldRepositoryUrl, String newRepositoryUrl) {
-		IPath oldPath = new Path(repository.getConnectorKind() + "-" + CoreUtil.asFileName(oldRepositoryUrl)).append(FOLDER_DATA); //$NON-NLS-1$
-		IPath newPath = new Path(repository.getConnectorKind() + "-" + CoreUtil.asFileName(newRepositoryUrl)).append(FOLDER_DATA); //$NON-NLS-1$
+	private void refactorRepositoryLocation(TaskRepository repository, String oldRepositoryUrl,
+			String newRepositoryUrl) {
+		IPath oldPath = new Path(repository.getConnectorKind() + "-" + CoreUtil.asFileName(oldRepositoryUrl)) //$NON-NLS-1$
+				.append(FOLDER_DATA);
+		IPath newPath = new Path(repository.getConnectorKind() + "-" + CoreUtil.asFileName(newRepositoryUrl)) //$NON-NLS-1$
+				.append(FOLDER_DATA);
 		try {
 			getTaskStore().move(oldPath, newPath);
 		} catch (CoreException e) {
-			StatusHandler.log(new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, NLS.bind(
-					"Failed to migrate data store for repository {0}", newRepositoryUrl), e)); //$NON-NLS-1$
+			StatusHandler.log(new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN,
+					NLS.bind("Failed to migrate data store for repository {0}", newRepositoryUrl), e)); //$NON-NLS-1$
 		}
 	}