### Eclipse Workspace Patch 1.0 #P org.eclipse.mylyn.tasks.core Index: src/org/eclipse/mylyn/internal/tasks/core/ITasksCoreConstants.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/ITasksCoreConstants.java,v retrieving revision 1.22 diff -u -r1.22 ITasksCoreConstants.java --- src/org/eclipse/mylyn/internal/tasks/core/ITasksCoreConstants.java 27 Aug 2009 21:04:32 -0000 1.22 +++ src/org/eclipse/mylyn/internal/tasks/core/ITasksCoreConstants.java 30 Sep 2009 20:36:25 -0000 @@ -49,6 +49,8 @@ public static final ISchedulingRule ACTIVITY_SCHEDULING_RULE = new MutexSchedulingRule(); + public static final ISchedulingRule ACTIVE_CONTEXT_SCHEDULING_RULE = new MutexSchedulingRule(); + public static final ISchedulingRule TASKLIST_SCHEDULING_RULE = new MutexSchedulingRule(); public static final ISchedulingRule ROOT_SCHEDULING_RULE = new RootSchedulingRule(); #P org.eclipse.mylyn.context.core Index: src/org/eclipse/mylyn/internal/context/core/LocalContextStore.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.context.core/src/org/eclipse/mylyn/internal/context/core/LocalContextStore.java,v retrieving revision 1.15 diff -u -r1.15 LocalContextStore.java --- src/org/eclipse/mylyn/internal/context/core/LocalContextStore.java 24 Jul 2009 12:06:53 -0000 1.15 +++ src/org/eclipse/mylyn/internal/context/core/LocalContextStore.java 30 Sep 2009 20:36:27 -0000 @@ -120,35 +120,39 @@ } public void saveContext(IInteractionContext context) { - // FIXME this should not reference the context manager - boolean wasPaused = ContextCore.getContextManager().isContextCapturePaused(); - try { - // TODO: make this asynchronous by creating a copy - if (!wasPaused) { - // FIXME this should not reference the context manager - ContextCore.getContextManager().setContextCapturePaused(true); - } - - if (context instanceof InteractionContext) { - ((InteractionContext) context).collapse(); - } - externalizer.writeContextToXml(context, getFileForContext(context.getHandleIdentifier())); - - if (context.getAllElements().size() == 0) { - removeFromCache(context); - } else { - addToCache(context); - } - } catch (Throwable t) { - StatusHandler.log(new Status(IStatus.ERROR, ContextCorePlugin.ID_PLUGIN, "could not save context", t)); //$NON-NLS-1$ - } finally { - if (!wasPaused) { - // FIXME this should not reference the context manager - ContextCore.getContextManager().setContextCapturePaused(false); + synchronized(context){ + // FIXME this should not reference the context manager + boolean wasPaused = ContextCore.getContextManager().isContextCapturePaused(); + try { + // TODO: make this asynchronous by creating a copy + if (!wasPaused) { + // FIXME this should not reference the context manager + ContextCore.getContextManager().setContextCapturePaused(true); + } + IInteractionContext contextToSave = context; + if (context instanceof InteractionContext) { + contextToSave = ((InteractionContext) context).createCollapsedWritableCopy(); + } + + externalizer.writeContextToXml(contextToSave, getFileForContext(contextToSave.getHandleIdentifier())); + + if (context.getAllElements().size() == 0) { + removeFromCache(context); + } else { + addToCache(context); + } + } catch (Throwable t) { + StatusHandler.log(new Status(IStatus.ERROR, ContextCorePlugin.ID_PLUGIN, "could not save context", t)); //$NON-NLS-1$ + } finally { + if (!wasPaused) { + // FIXME this should not reference the context manager + ContextCore.getContextManager().setContextCapturePaused(false); + } } } } + private boolean addToCache(IInteractionContext context) { initCache(); return contextFiles.add(getFileForContext(context.getHandleIdentifier())); Index: src/org/eclipse/mylyn/internal/context/core/InteractionContext.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.context.core/src/org/eclipse/mylyn/internal/context/core/InteractionContext.java,v retrieving revision 1.25 diff -u -r1.25 InteractionContext.java --- src/org/eclipse/mylyn/internal/context/core/InteractionContext.java 24 Jul 2009 12:06:53 -0000 1.25 +++ src/org/eclipse/mylyn/internal/context/core/InteractionContext.java 30 Sep 2009 20:36:26 -0000 @@ -249,6 +249,10 @@ } public synchronized void collapse() { + collapseHistory(interactionHistory); + } + + private synchronized void collapseHistory(List interactionHistoryToCollapseTo) { List collapsedHistory = new ArrayList(); for (InteractionContextElement node : elementMap.values()) { if (!node.equals(activeNode)) { @@ -259,8 +263,30 @@ collapseNode(collapsedHistory, activeNode); } - interactionHistory.clear(); - interactionHistory.addAll(collapsedHistory); + interactionHistoryToCollapseTo.clear(); + interactionHistoryToCollapseTo.addAll(collapsedHistory); + } + + /** + * This method is only used for asynchronous saving of task contexts + * + * @return a context with a copy of the collapsed interaction history. All other fields are not set. + */ + synchronized IInteractionContext createCollapsedWritableCopy() { + InteractionContext copiedContext = new InteractionContext(handleIdentifier, contextScaling); + copiedContext.contentLimitedTo = contentLimitedTo; + + collapseHistory(copiedContext.interactionHistory); + + // none of the following are used for writing contexts so we aren't going to try to copy them + //copiedContext.numUserEvents = numUserEvents; + // copiedContext.lastEdgeNode = lastEdgeNode; + // copiedContext.lastEdgeEvent = lastEdgeEvent; + // copiedContext.landmarkMap = landmarkMap; + // copiedContext.elementMap = elementMap; + // copiedContext.activeNode = activeNode; + + return copiedContext; } private void collapseNode(List collapsedHistory, InteractionContextElement node) { Index: src/org/eclipse/mylyn/internal/context/core/InteractionContextManager.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.context.core/src/org/eclipse/mylyn/internal/context/core/InteractionContextManager.java,v retrieving revision 1.80 diff -u -r1.80 InteractionContextManager.java --- src/org/eclipse/mylyn/internal/context/core/InteractionContextManager.java 10 Sep 2009 23:24:13 -0000 1.80 +++ src/org/eclipse/mylyn/internal/context/core/InteractionContextManager.java 30 Sep 2009 20:36:27 -0000 @@ -414,13 +414,19 @@ } } + public void saveContext(IInteractionContext context) { + if (context != null && contextStore != null) { + contextStore.saveContext(context); + } + } + public void deactivateContext(String handleIdentifier) { try { System.setProperty(InteractionContextManager.PROPERTY_CONTEXT_ACTIVE, Boolean.FALSE.toString()); final IInteractionContext context = activeContext.getContextMap().get(handleIdentifier); if (context != null) { - contextStore.saveContext(context); + saveContext(context); activeContext.getContextMap().remove(handleIdentifier); setContextCapturePaused(true); #P org.eclipse.mylyn.tasks.ui Index: src/org/eclipse/mylyn/internal/tasks/ui/messages.properties =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/messages.properties,v retrieving revision 1.14 diff -u -r1.14 messages.properties --- src/org/eclipse/mylyn/internal/tasks/ui/messages.properties 29 Sep 2009 17:28:24 -0000 1.14 +++ src/org/eclipse/mylyn/internal/tasks/ui/messages.properties 30 Sep 2009 20:36:29 -0000 @@ -8,6 +8,7 @@ # Contributors: # Tasktop Technologies - initial API and implementation ############################################################################### +ActiveContextExternalizationParticipant_Active_Task_Context=Active Task Context ActivityExternalizationParticipant_Activity_Context=Activity Context ChangeActivityHandleOperation_Activity_migration=Activity migration Index: src/org/eclipse/mylyn/internal/tasks/ui/Messages.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/Messages.java,v retrieving revision 1.9 diff -u -r1.9 Messages.java --- src/org/eclipse/mylyn/internal/tasks/ui/Messages.java 29 Sep 2009 17:28:24 -0000 1.9 +++ src/org/eclipse/mylyn/internal/tasks/ui/Messages.java 30 Sep 2009 20:36:29 -0000 @@ -25,6 +25,8 @@ NLS.initializeMessages(BUNDLE_NAME, Messages.class); } + public static String ActiveContextExternalizationParticipant_Active_Task_Context; + public static String ActivityExternalizationParticipant_Activity_Context; public static String ChangeActivityHandleOperation_Activity_migration; Index: src/org/eclipse/mylyn/internal/tasks/ui/TasksUiPlugin.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/TasksUiPlugin.java,v retrieving revision 1.121 diff -u -r1.121 TasksUiPlugin.java --- src/org/eclipse/mylyn/internal/tasks/ui/TasksUiPlugin.java 29 Aug 2009 06:55:36 -0000 1.121 +++ src/org/eclipse/mylyn/internal/tasks/ui/TasksUiPlugin.java 30 Sep 2009 20:36:29 -0000 @@ -350,6 +350,8 @@ private static TaskListExternalizationParticipant taskListExternalizationParticipant; + private ActiveContextExternalizationParticipant activeContextExternalizationParticipant; + private final Set listeners = new HashSet(); private static TaskList taskList; @@ -435,6 +437,10 @@ } finally { monitor.done(); } + activeContextExternalizationParticipant = new ActiveContextExternalizationParticipant( + externalizationManager); + externalizationManager.addParticipant(activeContextExternalizationParticipant); + activeContextExternalizationParticipant.registerListeners(); return new Status(IStatus.OK, TasksUiPlugin.ID_PLUGIN, IStatus.OK, "", null); //$NON-NLS-1$ } Index: src/org/eclipse/mylyn/internal/tasks/ui/ActiveContextExternalizationParticipant.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/ActiveContextExternalizationParticipant.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/ActiveContextExternalizationParticipant.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/ActiveContextExternalizationParticipant.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 Tasktop Technologies 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: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui; + +import java.io.File; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.mylyn.commons.core.StatusHandler; +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.context.core.IInteractionContext; +import org.eclipse.mylyn.internal.context.core.ContextCorePlugin; +import org.eclipse.mylyn.internal.monitor.ui.ActivityContextManager; +import org.eclipse.mylyn.internal.monitor.ui.MonitorUiPlugin; +import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; +import org.eclipse.mylyn.internal.tasks.core.externalization.AbstractExternalizationParticipant; +import org.eclipse.mylyn.internal.tasks.core.externalization.ExternalizationManager; +import org.eclipse.mylyn.internal.tasks.core.externalization.IExternalizationContext; +import org.eclipse.mylyn.monitor.ui.IUserAttentionListener; +import org.eclipse.mylyn.tasks.core.ITask; +import org.eclipse.mylyn.tasks.core.ITaskActivityListener; +import org.eclipse.mylyn.tasks.ui.TasksUi; + +/** + * @author Shawn Minto + */ +@SuppressWarnings("restriction") +public class ActiveContextExternalizationParticipant extends AbstractExternalizationParticipant implements + ITaskActivityListener, IUserAttentionListener { + private boolean isDirty = false; + + private final ExternalizationManager manager; + + private long lastUpdate; + + private IInteractionContext currentlyActiveContext; + + private final AbstractContextListener listener = new AbstractContextListener() { + @Override + public void contextChanged(ContextChangeEvent event) { + switch (event.getEventKind()) { + case ACTIVATED: + currentlyActiveContext = event.getContext(); + break; + case DEACTIVATED: + currentlyActiveContext = null; + setDirty(false); + break; + } + } + }; + + public ActiveContextExternalizationParticipant(ExternalizationManager manager) { + this.manager = manager; + } + + public void registerListeners() { + ContextCore.getContextManager().addListener(listener); + TasksUi.getTaskActivityManager().addActivityListener(this); + if (MonitorUiPlugin.getDefault() != null && MonitorUiPlugin.getDefault().getActivityContextManager() != null) { + ((ActivityContextManager) MonitorUiPlugin.getDefault().getActivityContextManager()).addListener(this); + } else { + StatusHandler.log(new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, + "Unable to register user activity listener.", new Exception())); //$NON-NLS-1$ + } + } + + // TODO: currently not called since no way to remove a participant + public void dispose() { + ContextCore.getContextManager().removeListener(listener); + TasksUi.getTaskActivityManager().removeActivityListener(this); + if (MonitorUiPlugin.getDefault() != null && MonitorUiPlugin.getDefault().getActivityContextManager() != null) { + ((ActivityContextManager) MonitorUiPlugin.getDefault().getActivityContextManager()).removeListener(this); + } + } + + @Override + public void execute(IExternalizationContext context, IProgressMonitor monitor) throws CoreException { + Assert.isNotNull(context); + switch (context.getKind()) { + case SAVE: + if (shouldWriteContext()) { + setDirty(false); + ContextCorePlugin.getContextManager().saveContext(currentlyActiveContext); + } + break; + case LOAD: + // ignore loads since we will do this synchronously with task activation + break; + case SNAPSHOT: + // ignore snapshots + break; + } + } + + @Override + public String getDescription() { + return Messages.ActiveContextExternalizationParticipant_Active_Task_Context; + } + + @Override + public ISchedulingRule getSchedulingRule() { + return ITasksCoreConstants.ACTIVE_CONTEXT_SCHEDULING_RULE; + } + + @Override + public boolean isDirty() { + synchronized (this) { + return isDirty; + } + } + + public void setDirty(boolean dirty) { + synchronized (this) { + isDirty = dirty; + } + } + + @Override + public String getFileName() { + // ignore + return null; + } + + @Override + public void load(File sourceFile, IProgressMonitor monitor) throws CoreException { + // ignore see execute method + } + + @Override + public void save(File targetFile, IProgressMonitor monitor) throws CoreException { + // ignore see execute method + } + + public void elapsedTimeUpdated(ITask task, long newElapsedTime) { + if (System.currentTimeMillis() - lastUpdate > 1000 * 60 * 3) { + // TODO TYR TO CHECK IF IT IS DIRTY AND IT EXISTS + setDirty(shouldWriteContext()); + if (isDirty()) { + manager.requestSave(); + } + lastUpdate = System.currentTimeMillis(); + } + } + + private boolean shouldWriteContext() { + if (ContextCorePlugin.getDefault() != null && ContextCorePlugin.getContextManager() != null + && currentlyActiveContext != null && currentlyActiveContext.getAllElements().size() > 0) { + // TODO check that there were changes? + + return true; + } + return false; + } + + public void activityReset() { + // ignore + } + + public void userAttentionGained() { + // ignore + } + + public void userAttentionLost() { + setDirty(shouldWriteContext()); + if (isDirty()) { + manager.requestSave(); + } + lastUpdate = System.currentTimeMillis(); + } + +}