blob: 3aeb4fda5fc1d1517ca070b5d1ec21e96e5937c2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2015 Tasktop Technologies and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.context.tasks.ui;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.commons.workbench.WorkbenchUtil;
import org.eclipse.mylyn.context.core.AbstractContextListener;
import org.eclipse.mylyn.context.core.ContextChangeEvent;
import org.eclipse.mylyn.context.core.ContextCore;
import org.eclipse.mylyn.internal.context.core.ContextCorePlugin;
import org.eclipse.mylyn.internal.context.core.InteractionContextManager;
import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin;
import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants;
import org.eclipse.mylyn.internal.tasks.core.TaskActivityManager;
import org.eclipse.mylyn.internal.tasks.core.TaskList;
import org.eclipse.mylyn.internal.tasks.core.externalization.ExternalizationManager;
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
import org.eclipse.mylyn.monitor.core.InteractionEvent;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.ITaskActivationListener;
import org.eclipse.mylyn.tasks.core.ITaskActivityManager;
import org.eclipse.mylyn.tasks.core.TaskActivationAdapter;
import org.eclipse.mylyn.tasks.core.activity.AbstractTaskActivityMonitor;
import org.eclipse.mylyn.tasks.ui.editors.TaskEditor;
import org.eclipse.mylyn.tasks.ui.editors.TaskEditorInput;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
/**
* Monitors task activity and maintains task activation history
*
* @author Robert Elves
* @author Steffen Pingel
* @since 3.0
*/
@SuppressWarnings("restriction")
public class TaskActivityMonitor extends AbstractTaskActivityMonitor {
public static class ContextTaskActivationListener extends TaskActivationAdapter {
@Override
public boolean canDeactivateTask(ITask task) {
List<IEditorReference> dirtyRefs = findDirtyEditors();
if (dirtyRefs.size() == 1) {
IWorkbenchPart part = dirtyRefs.get(0).getPart(false);
if (part instanceof TaskEditor) {
// If the only dirty editor is the active task and the editor is active, do not display the dialog below
TaskEditor editor = ((TaskEditor) part);
TaskEditorInput input = editor.getTaskEditorInput();
if (input != null
&& task.equals(input.getTask())
&& editor.equals(PlatformUI.getWorkbench()
.getActiveWorkbenchWindow()
.getActivePage()
.getActiveEditor())) {
return true;
}
}
}
if (!dirtyRefs.isEmpty()) {
int returnCode = openTaskDeactivationDialog(dirtyRefs);
if (returnCode == 0) {
saveEditors(dirtyRefs);
} else if (returnCode == 2) {
activateEditors(dirtyRefs);
return false;
}
}
return true;
}
private void saveEditors(List<IEditorReference> refs) {
for (IEditorReference ref : refs) {
IEditorPart editor = ref.getEditor(false);
if (editor != null) {
editor.doSave(new NullProgressMonitor());
}
}
}
private void activateEditors(List<IEditorReference> refs) {
for (IEditorReference ref : refs) {
IWorkbenchPart part = ref.getPart(true);
if (part != null) {
ref.getPage().activate(part);
}
}
}
public int openTaskDeactivationDialog(List<IEditorReference> dirtyRefs) {
String editors = Joiner.on('\n').join(
Iterables.transform(dirtyRefs, new Function<IEditorReference, String>() {
@Override
public String apply(IEditorReference ref) {
return ref.getTitle();
}
}));
return new MessageDialog(WorkbenchUtil.getShell(), Messages.TaskActivityMonitor_Task_Deactivation, null,
NLS.bind(Messages.TaskActivityMonitor_Task_Deactivation_Message, editors), MessageDialog.QUESTION,
new String[] { Messages.TaskActivityMonitor_Deactivate_Task_and_Save_All,
Messages.TaskActivityMonitor_Deactivate_and_Save_Some, IDialogConstants.CANCEL_LABEL }, 1).open();
}
public List<IEditorReference> findDirtyEditors() {
List<IEditorReference> dirtyRefs = new ArrayList<IEditorReference>();
for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
for (IEditorReference ref : window.getActivePage().getEditorReferences()) {
if (ref.isDirty()) {
dirtyRefs.add(ref);
}
}
}
return dirtyRefs;
}
@Override
public void preTaskActivated(ITask task) {
// make sure that org.eclipse.mylyn.context.ui is active prior to the first task activation
ContextUiPlugin.getDefault();
}
@Override
public void taskActivated(final ITask task) {
ContextCore.getContextManager().activateContext(task.getHandleIdentifier());
}
@Override
public void taskDeactivated(final ITask task) {
ContextCore.getContextManager().deactivateContext(task.getHandleIdentifier());
}
}
private final AbstractContextListener CONTEXT_LISTENER = new AbstractContextListener() {
@Override
public void contextChanged(ContextChangeEvent event) {
switch (event.getEventKind()) {
case INTEREST_CHANGED:
List<InteractionEvent> events = contextManager.getActivityMetaContext().getInteractionHistory();
if (events.size() > 0) {
InteractionEvent interactionEvent = events.get(events.size() - 1);
parseInteractionEvent(interactionEvent, false);
}
break;
}
}
};
private static ITaskActivationListener CONTEXT_TASK_ACTIVATION_LISTENER = new ContextTaskActivationListener();
private final InteractionContextManager contextManager;
private TaskActivityManager taskActivityManager;
private final TaskList taskList;
private final List<ITask> activationHistory;
private ActivityExternalizationParticipant externalizationParticipant;
public TaskActivityMonitor() {
this.contextManager = ContextCorePlugin.getContextManager();
this.taskList = TasksUiPlugin.getTaskList();
this.activationHistory = new ArrayList<ITask>();
}
@Override
public void start(ITaskActivityManager taskActivityManager) {
this.taskActivityManager = (TaskActivityManager) taskActivityManager;
taskActivityManager.addActivationListener(CONTEXT_TASK_ACTIVATION_LISTENER);
contextManager.addActivityMetaContextListener(CONTEXT_LISTENER);
ExternalizationManager externalizationManager = TasksUiPlugin.getExternalizationManager();
ActivityExternalizationParticipant ACTIVITY_EXTERNALIZTAION_PARTICIPANT = new ActivityExternalizationParticipant(
externalizationManager);
externalizationManager.addParticipant(ACTIVITY_EXTERNALIZTAION_PARTICIPANT);
taskActivityManager.addActivityListener(ACTIVITY_EXTERNALIZTAION_PARTICIPANT);
setExternalizationParticipant(ACTIVITY_EXTERNALIZTAION_PARTICIPANT);
}
/** public for testing */
public boolean parseInteractionEvent(InteractionEvent event, boolean isReloading) {
try {
if (event.getKind().equals(InteractionEvent.Kind.COMMAND)) {
if ((event.getDelta().equals(InteractionContextManager.ACTIVITY_DELTA_ACTIVATED))) {
AbstractTask activatedTask = taskList.getTask(event.getStructureHandle());
if (activatedTask != null) {
activationHistory.add(activatedTask);
return true;
}
}
} else if (event.getKind().equals(InteractionEvent.Kind.ATTENTION)) {
if ((event.getDelta().equals("added") || event.getDelta().equals("add"))) { //$NON-NLS-1$ //$NON-NLS-2$
if (event.getDate().getTime() > 0 && event.getEndDate().getTime() > 0) {
if (event.getStructureKind()
.equals(InteractionContextManager.ACTIVITY_STRUCTUREKIND_WORKINGSET)) {
taskActivityManager.addWorkingSetElapsedTime(event.getStructureHandle(), event.getDate(),
event.getEndDate());
if (!isReloading) {
externalizationParticipant.setDirty(true);
// save not requested for working set time updates so...
externalizationParticipant.elapsedTimeUpdated(null, 0);
}
} else {
AbstractTask activatedTask = taskList.getTask(event.getStructureHandle());
if (activatedTask != null) {
taskActivityManager.addElapsedTime(activatedTask, event.getDate(), event.getEndDate());
}
}
}
} else if (event.getDelta().equals("removed")) { //$NON-NLS-1$
ITask task = taskList.getTask(event.getStructureHandle());
if (task != null) {
taskActivityManager.removeElapsedTime(task, event.getDate(), event.getEndDate());
}
}
}
} catch (Throwable t) {
StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN,
"Error parsing interaction event", t)); //$NON-NLS-1$
}
return false;
}
@Override
public void stop() {
contextManager.removeActivityMetaContextListener(CONTEXT_LISTENER);
}
@Override
public void reloadActivityTime() {
activationHistory.clear();
taskActivityManager.clearActivity();
List<InteractionEvent> events = contextManager.getActivityMetaContext().getInteractionHistory();
for (InteractionEvent event : events) {
parseInteractionEvent(event, true);
}
}
public void setExternalizationParticipant(ActivityExternalizationParticipant participant) {
this.externalizationParticipant = participant;
}
@Override
public List<ITask> getActivationHistory() {
return new ArrayList<ITask>(activationHistory);
}
@Override
public void loadActivityTime() {
ContextCorePlugin.getContextManager().loadActivityMetaContext();
reloadActivityTime();
}
@Override
public boolean isEnabled() {
return true;
}
}