diff options
author | Steffen Pingel | 2012-02-24 19:41:00 +0000 |
---|---|---|
committer | Steffen Pingel | 2012-02-24 19:41:00 +0000 |
commit | 08523f38fde5a2b55a77a36dc204cea54d151ea4 (patch) | |
tree | e79647ab7a4b9d14d4ae46f6c6f6f229377b3e22 | |
parent | 9493ea22af7fb30525611bd8524a2bf66c1af25d (diff) | |
parent | 5cde6d896236d62efbd7fe6b73b4039a9ea6256d (diff) | |
download | org.eclipse.mylyn.context-e_4_1_m_3_x.tar.gz org.eclipse.mylyn.context-e_4_1_m_3_x.tar.xz org.eclipse.mylyn.context-e_4_1_m_3_x.zip |
Merge remote-tracking branch 'origin/master' into e_4_1_m_3_xe_4_1_m_3_x
31 files changed, 1961 insertions, 935 deletions
diff --git a/org.eclipse.mylyn.context.tasks.tests/build.properties b/org.eclipse.mylyn.context.tasks.tests/build.properties index d51c54b9d..c6e113fbf 100644 --- a/org.eclipse.mylyn.context.tasks.tests/build.properties +++ b/org.eclipse.mylyn.context.tasks.tests/build.properties @@ -7,7 +7,8 @@ ############################################################################### bin.includes = META-INF/,\ .,\ - about.html + about.html,\ + testdata/ src.includes = about.html source.. = src/ output.. = bin/ diff --git a/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/ContextMementoMigratorTest.java b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/ContextMementoMigratorTest.java new file mode 100644 index 000000000..b5a4177ad --- /dev/null +++ b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/ContextMementoMigratorTest.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2012 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.context.tasks.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.mylyn.commons.core.storage.ICommonStorable; +import org.eclipse.mylyn.context.core.ContextCore; +import org.eclipse.mylyn.internal.context.core.InteractionContext; +import org.eclipse.mylyn.internal.context.tasks.ui.ContextMementoMigrator; +import org.eclipse.mylyn.internal.context.tasks.ui.TaskContextStore; +import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; +import org.eclipse.mylyn.internal.context.ui.state.ContextState; +import org.eclipse.mylyn.internal.tasks.core.TaskTask; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.tasks.tests.TaskTestUtil; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IWorkbenchWindow; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Steffen Pingel + */ +public class ContextMementoMigratorTest { + + private static final String ID_RESOURCE_PERSPECTIVE = "org.eclipse.ui.resourcePerspective"; + + private static final String ID_PLANNING_PERSPECTIVE = "org.eclipse.mylyn.tasks.ui.perspectives.planning"; + + private TaskTask task; + + private ICommonStorable storable; + + @Before + public void setUp() throws Exception { + task = TaskTestUtil.createMockTask("1"); + TasksUiPlugin.getTaskList().addTask(task); + + storable = ((TaskContextStore) TasksUiPlugin.getContextStore()).getStorable(task); + // ensure that there is no stale data + storable.delete("context-state.xml"); + } + + @After + public void tearDown() { + if (storable != null) { + storable.release(); + } + } + + @Test + public void testMigratePreferencesDelete() throws Exception { + ContextUiPlugin.getDefault() + .getPreferenceStore() + .setValue(ContextMementoMigrator.PREFIX_TASK_TO_PERSPECTIVE + task.getHandleIdentifier(), + ID_PLANNING_PERSPECTIVE); + + ContextMementoMigrator migrator = new ContextMementoMigrator(ContextUiPlugin.getDefault().getStateManager()); + migrator.setDeleteOldDataEnabled(true); + IStatus status = migrator.migrateContextMementos(); + assertEquals(IStatus.OK, status.getSeverity()); + assertEquals( + "", + ContextUiPlugin.getDefault() + .getPreferenceStore() + .getString(ContextMementoMigrator.PREFIX_TASK_TO_PERSPECTIVE + task.getHandleIdentifier())); + } + + @Test + public void testMigratePreferences() throws Exception { + ContextUiPlugin.getDefault() + .getPreferenceStore() + .setValue(ContextMementoMigrator.PREFIX_TASK_TO_PERSPECTIVE + task.getHandleIdentifier(), + ID_PLANNING_PERSPECTIVE); + + IStatus status = new ContextMementoMigrator(ContextUiPlugin.getDefault().getStateManager()).migrateContextMementos(); + assertEquals(IStatus.OK, status.getSeverity()); + + InteractionContext context = new InteractionContext(task.getHandleIdentifier(), + ContextCore.getCommonContextScaling()); + ContextState state = ContextUiPlugin.getDefault() + .getStateManager() + .read(context, storable.read("context-state.xml", null)); + IMemento memento = state.getMemento("org.eclipse.mylyn.context.ui.perspectives"); + assertNotNull(memento); + assertEquals(ID_PLANNING_PERSPECTIVE, memento.getString("activeId")); + assertEquals( + ID_PLANNING_PERSPECTIVE, + ContextUiPlugin.getDefault() + .getPreferenceStore() + .getString(ContextMementoMigrator.PREFIX_TASK_TO_PERSPECTIVE + task.getHandleIdentifier())); + } + + private IWorkbenchWindow getWorkbenchWindow() { + IWorkbenchWindow window = ContextUiPlugin.getPerspectiveStateParticipant().getWorkbenchWindow(); + assertNotNull(window); + return window; + } + +} diff --git a/org.eclipse.mylyn.context.tests/src/org/eclipse/mylyn/context/tests/ContextEditorManagerTest.java b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/EditorRestoreTest.java index 034bf2885..dfa347d18 100644 --- a/org.eclipse.mylyn.context.tests/src/org/eclipse/mylyn/context/tests/ContextEditorManagerTest.java +++ b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/EditorRestoreTest.java @@ -9,7 +9,10 @@ * Tasktop Technologies - initial API and implementation *******************************************************************************/ -package org.eclipse.mylyn.context.tests; +package org.eclipse.mylyn.context.tasks.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.util.ArrayList; @@ -19,13 +22,19 @@ import java.util.Comparator; import java.util.List; import org.eclipse.core.resources.IFile; +import org.eclipse.mylyn.commons.sdk.util.ResourceTestUtil; +import org.eclipse.mylyn.commons.sdk.util.TestProject; import org.eclipse.mylyn.context.core.AbstractContextStructureBridge; import org.eclipse.mylyn.context.core.ContextCore; -import org.eclipse.mylyn.context.sdk.util.AbstractResourceContextTest; import org.eclipse.mylyn.context.ui.ContextAwareEditorInput; import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; import org.eclipse.mylyn.internal.context.ui.IContextUiPreferenceContstants; +import org.eclipse.mylyn.internal.tasks.core.LocalTask; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; import org.eclipse.mylyn.monitor.core.InteractionEvent; +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.ui.TasksUiUtil; +import org.eclipse.mylyn.tasks.ui.editors.TaskEditorInput; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorReference; @@ -33,11 +42,14 @@ import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.FileEditorInput; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * @author Steffen Pingel */ -public class ContextEditorManagerTest extends AbstractResourceContextTest { +public class EditorRestoreTest { private IEditorDescriptor editor; @@ -59,15 +71,36 @@ public class ContextEditorManagerTest extends AbstractResourceContextTest { } }; + private TestProject project; + + private LocalTask task; + + @Test public void testCloseAllOnDeactivate() throws Exception { IEditorInput[] inputs = new IEditorInput[] { new FileEditorInput(fileA) }; IEditorReference[] refs = openEditors(inputs); assertEquals(asInputList(refs), asInputList(page.getEditorReferences())); - ContextCore.getContextManager().deactivateContext(context.getHandleIdentifier()); + ContextCore.getContextManager().deactivateContext(task.getHandleIdentifier()); assertEquals(Collections.emptyList(), asList(page.getEditorReferences())); } + @Test + public void testActivationPreservesActiveTaskEditor() throws Exception { + ContextCore.getContextManager().deleteContext(task.getHandleIdentifier()); + // need to ensure that the context is empty otherwise the last element is opened in addition to the task + ContextCore.getContextManager().deactivateContext(task.getHandleIdentifier()); + TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository(task.getConnectorKind(), + task.getRepositoryUrl()); + TaskEditorInput input = new TaskEditorInput(repository, task); + + TasksUiUtil.openTask(task); + assertEquals(Arrays.asList(input), asInputList(page.getEditorReferences())); + ContextCore.getContextManager().activateContext(task.getHandleIdentifier()); + assertEquals(Arrays.asList(input), asInputList(page.getEditorReferences())); + } + + @Test public void testCloseAllRestore() throws Exception { IEditorInput[] inputs = new IEditorInput[] { new FileEditorInput(fileA), new FileEditorInput(fileB), new FileEditorInput(fileC) }; @@ -75,13 +108,14 @@ public class ContextEditorManagerTest extends AbstractResourceContextTest { assertEquals(asInputList(refs), asInputList(page.getEditorReferences())); //ContextCore.getContextManager().activateContext(context.getHandleIdentifier()); - ContextCore.getContextManager().deactivateContext(context.getHandleIdentifier()); + ContextCore.getContextManager().deactivateContext(task.getHandleIdentifier()); assertEquals(Collections.emptyList(), asList(page.getEditorReferences())); - ContextCore.getContextManager().activateContext(context.getHandleIdentifier()); + ContextCore.getContextManager().activateContext(task.getHandleIdentifier()); assertEquals(Arrays.asList(inputs), asInputList(page.getEditorReferences())); } + @Test public void testCloseAllRestoreContextAwareEditor() throws Exception { FileEditorInput input = new FileEditorInput(fileA); IEditorInput[] inputs = new IEditorInput[] { input, new FileEditorInput(fileB) { @@ -103,11 +137,11 @@ public class ContextEditorManagerTest extends AbstractResourceContextTest { assertEquals(asInputList(refs), asInputList(page.getEditorReferences())); //ContextCore.getContextManager().activateContext(context.getHandleIdentifier()); - ContextCore.getContextManager().deactivateContext(context.getHandleIdentifier()); + ContextCore.getContextManager().deactivateContext(task.getHandleIdentifier()); assertEquals(Collections.emptyList(), asList(page.getEditorReferences())); // fileB should not be restored in this case - ContextCore.getContextManager().activateContext(context.getHandleIdentifier()); + ContextCore.getContextManager().activateContext(task.getHandleIdentifier()); assertEquals(input, page.getEditorReferences()[0].getEditorInput()); } @@ -137,11 +171,14 @@ public class ContextEditorManagerTest extends AbstractResourceContextTest { return refs; } - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { + task = new LocalTask(getClass().getName(), getClass().getName()); + TasksUiPlugin.getTaskList().addTask(task); + + ContextCore.getContextManager().activateContext(task.getHandleIdentifier()); - ContextCore.getContextManager().activateContext(context.getHandleIdentifier()); + project = new TestProject(getClass().getName()); fileA = project.getProject().getFile("a.txt"); fileA.create(new ByteArrayInputStream("abc".getBytes()), false, null); @@ -164,17 +201,19 @@ public class ContextEditorManagerTest extends AbstractResourceContextTest { editor = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(fileA.getName()); page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + page.closeAllEditors(false); assertTrue(ContextUiPlugin.getDefault() .getPreferenceStore() .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_EDITORS)); - assertTrue(ContextUiPlugin.getEditorManager().isEnabled()); + assertTrue(ContextUiPlugin.getEditorStateParticipant().isEnabled()); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { + TasksUiPlugin.getTaskList().deleteTask(task); page.closeAllEditors(false); - super.tearDown(); + ResourceTestUtil.deleteProject(project.getProject()); } } diff --git a/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/ContextPerspectiveManagerTest.java b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/PerspectiveRestoreTest.java index 775e4083b..3461ba8eb 100644 --- a/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/ContextPerspectiveManagerTest.java +++ b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/PerspectiveRestoreTest.java @@ -11,22 +11,30 @@ package org.eclipse.mylyn.context.tasks.tests; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Collections; import org.eclipse.mylyn.context.sdk.util.ContextTestUtil; import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; import org.eclipse.mylyn.internal.context.ui.IContextUiPreferenceContstants; import org.eclipse.mylyn.internal.tasks.core.TaskTask; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.internal.tasks.ui.actions.DeleteAction; import org.eclipse.mylyn.tasks.tests.TaskTestUtil; import org.eclipse.mylyn.tasks.ui.TasksUi; import org.eclipse.mylyn.tests.util.TestFixture; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; /** * @author Steffen Pingel */ -public class ContextPerspectiveManagerTest extends TestCase { +public class PerspectiveRestoreTest { private static final String ID_RESOURCE_PERSPECTIVE = "org.eclipse.ui.resourcePerspective"; @@ -34,8 +42,8 @@ public class ContextPerspectiveManagerTest extends TestCase { private boolean previousSetting; - @Override - protected void setUp() throws Exception { + @Before + public void setUp() throws Exception { ContextTestUtil.triggerContextUiLazyStart(); TestFixture.resetTaskListAndRepositories(); @@ -47,18 +55,33 @@ public class ContextPerspectiveManagerTest extends TestCase { .setValue(IContextUiPreferenceContstants.AUTO_MANAGE_PERSPECTIVES, true); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { ContextUiPlugin.getDefault() .getPreferenceStore() .setValue(IContextUiPreferenceContstants.AUTO_MANAGE_PERSPECTIVES, previousSetting); TestFixture.resetTaskListAndRepositories(); } + @Test + public void testHasPlanningAndResourcePerspective() throws Exception { + PlatformUI.getWorkbench().showPerspective(ID_RESOURCE_PERSPECTIVE, getWorkbenchWindow()); + assertEquals(ID_RESOURCE_PERSPECTIVE, getActivePerspective()); + PlatformUI.getWorkbench().showPerspective(ID_PLANNING_PERSPECTIVE, getWorkbenchWindow()); + assertEquals(ID_PLANNING_PERSPECTIVE, getActivePerspective()); + } + + @Test + public void testHasActiveWorkbenchWindow() throws Exception { + assertNotNull("No active workbench window. Following tests are likely to fail.", PlatformUI.getWorkbench() + .getActiveWorkbenchWindow()); + } + + @Test public void testRestorePerspective() throws Exception { PlatformUI.getWorkbench().showPerspective(ID_RESOURCE_PERSPECTIVE, getWorkbenchWindow()); assertEquals(ID_RESOURCE_PERSPECTIVE, getActivePerspective()); - TaskTask task = TaskTestUtil.createMockTask("1"); + TaskTask task = TaskTestUtil.createMockTask("testRestorePerspective"); // check that perspective is not switched for new task TasksUi.getTaskActivityManager().activateTask(task); @@ -75,27 +98,29 @@ public class ContextPerspectiveManagerTest extends TestCase { assertEquals(ID_PLANNING_PERSPECTIVE, getActivePerspective()); } - // FIXME 3.5 re-enable test -// public void testRecreateTask() throws Exception { -// PlatformUI.getWorkbench().showPerspective(ID_RESOURCE_PERSPECTIVE, MonitorUi.getLaunchingWorkbenchWindow()); -// TaskTask task = TaskTestUtil.createMockTask("1"); -// -// // check that deleting task switches back to original perspective -// TasksUi.getTaskActivityManager().activateTask(task); -// PlatformUI.getWorkbench().showPerspective(ID_PLANNING_PERSPECTIVE, MonitorUi.getLaunchingWorkbenchWindow()); -// TasksUiPlugin.getTaskActivityManager().deactivateActiveTask(); -// TasksUiPlugin.getTaskList().deleteTask(task); -// assertEquals(ID_RESOURCE_PERSPECTIVE, getActivePerspective()); -// -// task = TaskTestUtil.createMockTask("1"); -// -// // check that activating new task with the same id does not switch the perspective -// TasksUi.getTaskActivityManager().activateTask(task); -// assertEquals(ID_RESOURCE_PERSPECTIVE, getActivePerspective()); -// } + @Test + public void testRecreateTask() throws Exception { + PlatformUI.getWorkbench().showPerspective(ID_RESOURCE_PERSPECTIVE, getWorkbenchWindow()); + TaskTask task = TaskTestUtil.createMockTask("1"); + TasksUiPlugin.getTaskList().addTask(task); + + // check that deleting task switches back to original perspective + TasksUi.getTaskActivityManager().activateTask(task); + PlatformUI.getWorkbench().showPerspective(ID_PLANNING_PERSPECTIVE, getWorkbenchWindow()); + TasksUiPlugin.getTaskActivityManager().deactivateActiveTask(); + // XXX ensure that InteractionContextManager is notified, TasksUiPlugin.getTaskList().deleteTask(task) does not do that + DeleteAction.performDeletion(Collections.singleton(task)); + assertEquals(ID_RESOURCE_PERSPECTIVE, getActivePerspective()); + + task = TaskTestUtil.createMockTask("1"); + + // check that activating new task with the same id does not switch the perspective + TasksUi.getTaskActivityManager().activateTask(task); + assertEquals(ID_RESOURCE_PERSPECTIVE, getActivePerspective()); + } private IWorkbenchWindow getWorkbenchWindow() { - IWorkbenchWindow window = ContextUiPlugin.getPerspectiveManager().getWorkbenchWindow(); + IWorkbenchWindow window = ContextUiPlugin.getPerspectiveStateParticipant().getWorkbenchWindow(); assertNotNull(window); return window; } diff --git a/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/RefactorRepositoryUrlOperationTest.java b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/RefactorRepositoryUrlOperationTest.java index c9eb545f8..c134215ae 100644 --- a/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/RefactorRepositoryUrlOperationTest.java +++ b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/RefactorRepositoryUrlOperationTest.java @@ -11,9 +11,10 @@ package org.eclipse.mylyn.context.tasks.tests; -import java.util.Calendar; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -import junit.framework.TestCase; +import java.util.Calendar; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.mylyn.internal.context.core.ContextCorePlugin; @@ -29,22 +30,24 @@ import org.eclipse.mylyn.tasks.core.IRepositoryQuery; import org.eclipse.mylyn.tasks.tests.TaskTestUtil; import org.eclipse.mylyn.tasks.tests.connector.MockRepositoryQuery; import org.eclipse.mylyn.tasks.tests.connector.MockTask; +import org.junit.Before; +import org.junit.Test; /** * @author Robert Elves * @author Steffen Pingel */ -public class RefactorRepositoryUrlOperationTest extends TestCase { +public class RefactorRepositoryUrlOperationTest { private TaskList taskList; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { taskList = TasksUiPlugin.getTaskList(); TaskTestUtil.resetTaskList(); } + @Test public void testMigrateQueryUrlHandles() throws Exception { RepositoryQuery query = new MockRepositoryQuery("mquery"); query.setRepositoryUrl("http://foo.bar"); @@ -58,6 +61,7 @@ public class RefactorRepositoryUrlOperationTest extends TestCase { assertEquals("http://bar.baz/b", changedQuery.getUrl()); } + @Test public void testRefactorMetaContextHandles() throws Exception { String firstUrl = "http://repository1.com/bugs"; String secondUrl = "http://repository2.com/bugs"; diff --git a/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/TaskContextStoreTest.java b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/TaskContextStoreTest.java new file mode 100644 index 000000000..3ce2b592f --- /dev/null +++ b/org.eclipse.mylyn.context.tasks.tests/src/org/eclipse/mylyn/context/tasks/tests/TaskContextStoreTest.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2012 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.context.tasks.tests; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.mylyn.internal.context.core.ContextCorePlugin; +import org.eclipse.mylyn.internal.context.tasks.ui.TaskContextStore; +import org.eclipse.mylyn.internal.monitor.ui.MonitorUiPlugin; +import org.eclipse.mylyn.internal.tasks.core.AbstractTask; +import org.eclipse.mylyn.internal.tasks.core.LocalTask; +import org.eclipse.mylyn.internal.tasks.core.TaskActivityManager; +import org.eclipse.mylyn.internal.tasks.core.TaskList; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.tasks.core.ITask; +import org.eclipse.mylyn.tasks.tests.TaskTestUtil; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Steffen Pingel + */ +public class TaskContextStoreTest { + + private TaskContextStore store; + + private TaskList taskList; + + private TaskActivityManager activityManager; + + @Before + public void setUp() throws Exception { + TaskTestUtil.resetTaskListAndRepositories(); + TasksUiPlugin.getTaskActivityManager().clear(); + ContextCorePlugin.getContextManager().resetActivityMetaContext(); + + store = (TaskContextStore) TasksUiPlugin.getContextStore(); + taskList = TasksUiPlugin.getTaskList(); + activityManager = TasksUiPlugin.getTaskActivityManager(); + } + + @After + public void tearDown() throws Exception { + TaskTestUtil.resetTaskListAndRepositories(); + TasksUiPlugin.getTaskActivityManager().clear(); + } + + @Test + public void testClearContextActivity() { + AbstractTask task = new LocalTask("clearContext", "clearContext"); + taskList.addTask(task); + assertEquals(0, activityManager.getElapsedTime(task)); + + addTime(task, 60 * 1000); + assertEquals(60 * 1000, activityManager.getElapsedTime(task)); + + store.clearContext(task); + assertEquals("Expected activity to remain", 60 * 1000, activityManager.getElapsedTime(task)); + } + + @Test + public void testCopyContextActivity() { + AbstractTask sourceTask = new LocalTask("sourceTask", "sourceTask"); + taskList.addTask(sourceTask); + AbstractTask targetTask = new LocalTask("targetTask", "targetTask"); + taskList.addTask(targetTask); + + addTime(sourceTask, 60 * 1000); + assertEquals(60 * 1000, activityManager.getElapsedTime(sourceTask)); + + store.copyContext(sourceTask, targetTask); + assertEquals("Expected activity to remain", 60 * 1000, activityManager.getElapsedTime(sourceTask)); + assertEquals("Expected activity not be copied", 0, activityManager.getElapsedTime(targetTask)); + } + + @Test + public void testDeleteContextActivity() { + AbstractTask task = new LocalTask("clearContext", "clearContext"); + taskList.addTask(task); + assertEquals(0, activityManager.getElapsedTime(task)); + + addTime(task, 60 * 1000); + assertEquals(60 * 1000, activityManager.getElapsedTime(task)); + + store.deleteContext(task); + // this has not been implemented, yet + //assertEquals("Expected activity to be cleared", 0, activityManager.getElapsedTime(task)); + assertEquals(60 * 1000, activityManager.getElapsedTime(task)); + } + + @Test + public void testMergeContextActivity() { + AbstractTask sourceTask = new LocalTask("sourceTask", "sourceTask"); + taskList.addTask(sourceTask); + AbstractTask targetTask = new LocalTask("targetTask", "targetTask"); + taskList.addTask(targetTask); + + addTime(sourceTask, 60 * 1000); + assertEquals(60 * 1000, activityManager.getElapsedTime(sourceTask)); + + store.mergeContext(sourceTask, targetTask); + assertEquals("Expected activity to remain", 60 * 1000, activityManager.getElapsedTime(sourceTask)); + assertEquals("Expected activity not be copied", 0, activityManager.getElapsedTime(targetTask)); + } + + @Test + public void testMoveContextActivity() { + AbstractTask sourceTask = new LocalTask("sourceTask", "sourceTask"); + taskList.addTask(sourceTask); + AbstractTask targetTask = new LocalTask("targetTask", "targetTask"); + taskList.addTask(targetTask); + + addTime(sourceTask, 60 * 1000); + assertEquals(60 * 1000, activityManager.getElapsedTime(sourceTask)); + + store.moveContext(sourceTask, targetTask); + assertEquals("Expected activity to be moved", 0, activityManager.getElapsedTime(sourceTask)); + assertEquals("Expected activity to be moved", 60 * 1000, activityManager.getElapsedTime(targetTask)); + } + + private void addTime(ITask task, long time) { + MonitorUiPlugin.getDefault() + .getActivityContextManager() + .addActivityTime(task.getHandleIdentifier(), 1, 1 + time); + } + +} diff --git a/org.eclipse.mylyn.context.tasks.tests/testdata/activityTests/.activity.xml.zip b/org.eclipse.mylyn.context.tasks.tests/testdata/activityTests/.activity.xml.zip Binary files differnew file mode 100644 index 000000000..676a3e64f --- /dev/null +++ b/org.eclipse.mylyn.context.tasks.tests/testdata/activityTests/.activity.xml.zip diff --git a/org.eclipse.mylyn.context.tasks.tests/testdata/activityTests/activity.xml.zip b/org.eclipse.mylyn.context.tasks.tests/testdata/activityTests/activity.xml.zip Binary files differnew file mode 100644 index 000000000..fd825ed31 --- /dev/null +++ b/org.eclipse.mylyn.context.tasks.tests/testdata/activityTests/activity.xml.zip diff --git a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextMementoMigrator.java b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextMementoMigrator.java new file mode 100644 index 000000000..a748e2d97 --- /dev/null +++ b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextMementoMigrator.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2012 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.context.tasks.ui; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringReader; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.mylyn.commons.core.storage.ICommonStorable; +import org.eclipse.mylyn.context.core.ContextCore; +import org.eclipse.mylyn.internal.context.core.InteractionContext; +import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; +import org.eclipse.mylyn.internal.context.ui.IContextUiPreferenceContstants; +import org.eclipse.mylyn.internal.context.ui.state.ContextState; +import org.eclipse.mylyn.internal.context.ui.state.ContextStateManager; +import org.eclipse.mylyn.internal.context.ui.state.EditorStateParticipant; +import org.eclipse.mylyn.internal.context.ui.state.PerspectiveStateParticipant; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.tasks.core.ITask; +import org.eclipse.mylyn.tasks.ui.TasksUi; +import org.eclipse.osgi.util.NLS; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.XMLMemento; +import org.eclipse.ui.preferences.ScopedPreferenceStore; +import org.osgi.service.prefs.BackingStoreException; + +/** + * @author Steffen Pingel + */ +public class ContextMementoMigrator { + + /** + * Only intended for tests and migration. + */ + @Deprecated + public static final String PREFIX_TASK_TO_PERSPECTIVE = "org.eclipse.mylyn.ui.perspectives.task."; //$NON-NLS-1$ + + /** + * Only intended for tests and migration. + */ + @Deprecated + public static final String EDITOR_MEMENTO_PREFS_PREFIX = "editors.task."; //$NON-NLS-1$ + + private final ContextStateManager stateManager; + + private boolean deleteOldDataEnabled; + + public ContextMementoMigrator(ContextStateManager stateManager) { + this.stateManager = stateManager; + + } + + public void setDeleteOldDataEnabled(boolean deleteOldDataEnabled) { + this.deleteOldDataEnabled = deleteOldDataEnabled; + } + + public boolean isDeleteOldDataEnabled() { + return deleteOldDataEnabled; + } + + /** + * Migrates editor mementos and perspective ids from the preferences to a memento based store in the file-system. + * <p> + * <b>Public for testing.</b> + * + * @since 3.4 + */ + public IStatus migrateContextMementos() { + MultiStatus status = new MultiStatus(ContextUiPlugin.ID_PLUGIN, 0, + "Errors migrating saved editors and perspective settings", null); //$NON-NLS-1$ + + ScopedPreferenceStore perspectivePreferenceStore = new ScopedPreferenceStore(new InstanceScope(), + "org.eclipse.mylyn.context.ui"); //$NON-NLS-1$ + ScopedPreferenceStore editorPreferenceStore = new ScopedPreferenceStore(new InstanceScope(), + "org.eclipse.mylyn.resources.ui"); //$NON-NLS-1$ + + // migrate editor mementos first + IEclipsePreferences[] perspectiveNodes = perspectivePreferenceStore.getPreferenceNodes(false); + IEclipsePreferences[] editorNodes = editorPreferenceStore.getPreferenceNodes(false); + if (editorNodes.length > 0) { + String[] keys; + try { + keys = editorNodes[0].keys(); + for (String key : keys) { + if (key.startsWith(EDITOR_MEMENTO_PREFS_PREFIX)) { + String contextHandle = key.substring(EDITOR_MEMENTO_PREFS_PREFIX.length()); + String mementoString = editorPreferenceStore.getString(key); + if (mementoString != null && !mementoString.trim().equals("")) { //$NON-NLS-1$ + try { + IMemento oldMemento = XMLMemento.createReadRoot(new StringReader(mementoString)); + InteractionContext context = new InteractionContext(contextHandle, + ContextCore.getCommonContextScaling()); + ContextState state = stateManager.createMemento(context, contextHandle); + + // migrate editors + IMemento newMemnto = state.createMemento(EditorStateParticipant.MEMENTO_EDITORS); + newMemnto.putMemento(oldMemento); + + // migrate perspective + String perspectiveId = perspectivePreferenceStore.getString(PREFIX_TASK_TO_PERSPECTIVE + + contextHandle); + if (perspectiveId != null && perspectiveId.length() > 0) { + IMemento perspectiveMemento = state.createMemento(PerspectiveStateParticipant.MEMENTO_PERSPECTIVE); + perspectiveMemento.putString(PerspectiveStateParticipant.KEY_ACTIVE_ID, + perspectiveId); + } + + ITask task = TasksUi.getRepositoryModel().getTask(contextHandle); + if (task != null) { + write(state, task); + } + } catch (Exception e) { + status.add(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, NLS.bind( + "Migration of editor memento failed for {0}", contextHandle), e)); //$NON-NLS-1$ + } + } + + if (isDeleteOldDataEnabled()) { + editorNodes[0].remove(key); + if (perspectiveNodes.length > 0) { + perspectiveNodes[0].remove(PREFIX_TASK_TO_PERSPECTIVE + contextHandle); + } + } + } + } + } catch (BackingStoreException e) { + status.add(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Reading of editor mementos failed", e)); //$NON-NLS-1$ + } + } + + // migrate remaining perspective mementos + if (perspectiveNodes.length > 0) { + try { + String[] keys = perspectiveNodes[0].keys(); + for (String key : keys) { + if (key.startsWith(PREFIX_TASK_TO_PERSPECTIVE) + && !key.equals(IContextUiPreferenceContstants.PERSPECTIVE_NO_ACTIVE_TASK)) { + String contextHandle = key.substring(PREFIX_TASK_TO_PERSPECTIVE.length()); + String perspectiveId = perspectivePreferenceStore.getString(key); + if (perspectiveId != null && perspectiveId.length() > 0) { + try { + InteractionContext context = new InteractionContext(contextHandle, + ContextCore.getCommonContextScaling()); + ContextState state = stateManager.createMemento(context, contextHandle); + + // migrate perspective + IMemento perspectiveMemento = state.createMemento(PerspectiveStateParticipant.MEMENTO_PERSPECTIVE); + perspectiveMemento.putString(PerspectiveStateParticipant.KEY_ACTIVE_ID, perspectiveId); + + ITask task = TasksUi.getRepositoryModel().getTask(contextHandle); + if (task != null) { + write(state, task); + } + } catch (Exception e) { + status.add(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, NLS.bind( + "Migration of editor memento failed for {0}", contextHandle), e)); //$NON-NLS-1$ + } + } + + if (isDeleteOldDataEnabled()) { + perspectiveNodes[0].remove(key); + } + } + } + } catch (BackingStoreException e) { + status.add(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, + "Reading of perspective mementos failed", e)); //$NON-NLS-1$ + } + } + + try { + editorPreferenceStore.save(); + } catch (IOException e) { + status.add(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Saving of preference store failed", e)); //$NON-NLS-1$ + } + try { + perspectivePreferenceStore.save(); + } catch (IOException e) { + status.add(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Saving of preference store failed", e)); //$NON-NLS-1$ + } + + return status; + } + + private void write(ContextState state, ITask task) throws IOException, CoreException { + ICommonStorable storable = ((TaskContextStore) TasksUiPlugin.getContextStore()).getStorable(task); + try { + if (!storable.exists("context-state.xml")) { + OutputStream out = storable.write("context-state.xml", null); + try { + stateManager.write(out, state); + } finally { + out.close(); + } + } + } finally { + storable.release(); + } + } + +} diff --git a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextStatePersistenceHandler.java b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextStatePersistenceHandler.java new file mode 100644 index 000000000..5f767f896 --- /dev/null +++ b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextStatePersistenceHandler.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2012 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.context.tasks.ui; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.commons.core.StatusHandler; +import org.eclipse.mylyn.commons.core.storage.ICommonStorable; +import org.eclipse.mylyn.context.core.ContextCore; +import org.eclipse.mylyn.context.core.IInteractionContext; +import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; +import org.eclipse.mylyn.internal.context.ui.state.ContextStateManager; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.tasks.core.ITask; +import org.eclipse.mylyn.tasks.ui.TasksUi; +import org.eclipse.osgi.util.NLS; + +/** + * Manages the persistence for {@link ContextStateManager}. + * + * @author Steffen Pingel + */ +public class ContextStatePersistenceHandler { + + public static final String FILE_NAME = "context-state.xml"; //$NON-NLS-1$ + + public ContextStatePersistenceHandler() { + } + + public void activated(IInteractionContext context) { + getStateManager().saveDefaultState(); + + ICommonStorable storable = getStorable(context.getHandleIdentifier()); + if (storable != null) { + try { + InputStream in = null; + if (storable.exists(FILE_NAME)) { + in = storable.read(FILE_NAME, null); + } + try { + getStateManager().restoreState(context, in); + } finally { + if (in != null) { + in.close(); + } + } + } catch (Exception e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, NLS.bind( + "Unexpected error restoring the context state for {0}", context.getHandleIdentifier()), e)); //$NON-NLS-1$ + } finally { + storable.release(); + } + } else { +// StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, NLS.bind( +// "Context restore failed: No corresponding task for {0} found.", context.getHandleIdentifier()))); //$NON-NLS-1$ + } + } + + public void clear(ITask task) { + ICommonStorable storable = getStorable(task); + try { + storable.delete(FILE_NAME); + } catch (Exception e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, NLS.bind( + "Unexpected error deleting the context state for {0}", task.getHandleIdentifier()), e)); //$NON-NLS-1$ + } finally { + storable.release(); + } + } + + public void clear(String contextHandle, boolean activeContext) { + // bug 255588: use the handle since the context is null when it is cleared + getStateManager().clearState(contextHandle, activeContext); + } + + public void copy(ITask sourceTask, ITask targetTask) { + copyState(sourceTask, targetTask, true); + } + + public void deactivated(IInteractionContext context) { + save(context); + getStateManager().restoreDefaultState(); + } + + public void merge(ITask sourceTask, ITask targetTask) { + copyState(sourceTask, targetTask, false); + } + + public void save(IInteractionContext context) { + ICommonStorable storable = getStorable(context.getHandleIdentifier()); + if (storable != null) { + try { + OutputStream out = storable.write(FILE_NAME, null); + try { + getStateManager().saveState(context, out); + } finally { + out.close(); + } + } catch (Exception e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, NLS.bind( + "Unexpected error saving the context state for {0}", context.getHandleIdentifier()), e)); //$NON-NLS-1$ + } finally { + storable.release(); + } + } else { +// StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, NLS.bind( +// "Context save failed: No corresponding task for {0} found.", context.getHandleIdentifier()))); //$NON-NLS-1$ + } + } + + public void saved(ITask task) { + IInteractionContext context = ContextCore.getContextManager().getActiveContext(); + if (context != null && task.getHandleIdentifier().equals(context.getHandleIdentifier())) { + save(context); + } + } + + private void copyState(ITask sourceTask, ITask targetTask, boolean overwrite) { + ICommonStorable targetStorable = getStorable(targetTask); + try { + if (overwrite || !targetStorable.exists(FILE_NAME)) { + ICommonStorable sourceStorable = getStorable(sourceTask); + try { + copyStateFile(sourceStorable, targetStorable, FILE_NAME); + } finally { + sourceStorable.release(); + } + } + } catch (Exception e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, NLS.bind( + "Unexpected error saving the context state for {0}", targetTask.getHandleIdentifier()), e)); //$NON-NLS-1$ + } finally { + targetStorable.release(); + } + } + + private void copyStateFile(ICommonStorable sourceStorable, ICommonStorable targetStorable, String handle) + throws CoreException, IOException { + BufferedInputStream in = new BufferedInputStream(sourceStorable.read(handle, null)); + try { + BufferedOutputStream out = new BufferedOutputStream(targetStorable.write(handle, null)); + try { + byte[] buffer = new byte[4096]; + while (true) { + int count = in.read(buffer); + if (count == -1) { + return; + } + out.write(buffer, 0, count); + } + } finally { + out.close(); + } + } finally { + in.close(); + } + } + + private ContextStateManager getStateManager() { + return ContextUiPlugin.getDefault().getStateManager(); + } + + private ICommonStorable getStorable(String contextHandle) { + ITask task = TasksUi.getRepositoryModel().getTask(contextHandle); + return (task != null) ? getStorable(task) : null; + } + + private ICommonStorable getStorable(ITask task) { + return ((TaskContextStore) TasksUiPlugin.getContextStore()).getStorable(task); + } + +} diff --git a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextTasksStartupHandler.java b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextTasksStartupHandler.java index c62fb426e..2bf5c3ced 100644 --- a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextTasksStartupHandler.java +++ b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextTasksStartupHandler.java @@ -13,9 +13,11 @@ package org.eclipse.mylyn.internal.context.tasks.ui; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.mylyn.commons.core.CoreUtil; +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; @@ -36,7 +38,6 @@ import org.eclipse.mylyn.tasks.core.ITaskActivationListener; import org.eclipse.mylyn.tasks.core.TaskActivationAdapter; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskData; -import org.eclipse.mylyn.tasks.ui.ITasksUiConstants; import org.eclipse.mylyn.tasks.ui.TasksUi; /** @@ -95,27 +96,42 @@ public class ContextTasksStartupHandler implements IContextUiStartup { private class ContextActivationListener extends AbstractContextListener { + private ContextStatePersistenceHandler stateHandler; + @Override public void contextChanged(ContextChangeEvent event) { switch (event.getEventKind()) { case PRE_ACTIVATED: ContextTasksStartupHandler.this.contextActivated(event); break; + case ACTIVATED: + getStateHandler().activated(event.getContext()); + break; + case DEACTIVATED: + getStateHandler().deactivated(event.getContext()); + break; + case CLEARED: + getStateHandler().clear(event.getContextHandle(), event.isActiveContext()); + break; } } + private ContextStatePersistenceHandler getStateHandler() { + return ((TaskContextStore) TasksUiPlugin.getContextStore()).getStateHandler(); + } + } private static final ITaskActivationListener TASK_ACTIVATION_LISTENER = new TaskActivationAdapter() { @Override public void preTaskDeactivated(ITask task) { - ContextUiPlugin.getEditorManager().setEnabled(!TaskMigrator.isActive()); + ContextUiPlugin.getEditorStateParticipant().setEnabled(!TaskMigrator.isActive()); } @Override public void preTaskActivated(ITask task) { - ContextUiPlugin.getEditorManager().setEnabled(!TaskMigrator.isActive()); + ContextUiPlugin.getEditorStateParticipant().setEnabled(!TaskMigrator.isActive()); } @SuppressWarnings("restriction") @@ -150,7 +166,12 @@ public class ContextTasksStartupHandler implements IContextUiStartup { externalizationManager.addParticipant(activeContextExternalizationParticipant); activeContextExternalizationParticipant.registerListeners(); - ContextUiPlugin.getPerspectiveManager().addManagedPerspective(ITasksUiConstants.ID_PERSPECTIVE_PLANNING); + ContextMementoMigrator migrator = new ContextMementoMigrator(ContextUiPlugin.getDefault().getStateManager()); + IStatus status = migrator.migrateContextMementos(); + if (!status.isOK()) { + StatusHandler.log(status); + } + TasksUi.getTaskActivityManager().addActivationListener(TASK_ACTIVATION_LISTENER); ContextUiPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() { @@ -168,7 +189,6 @@ public class ContextTasksStartupHandler implements IContextUiStartup { private void lazyStop() { ContextCore.getContextManager().removeListener(contextActivationListener); - ContextUiPlugin.getPerspectiveManager().removeManagedPerspective(ITasksUiConstants.ID_PERSPECTIVE_PLANNING); TasksUi.getTaskActivityManager().removeActivationListener(TASK_ACTIVATION_LISTENER); } diff --git a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextUiStartupHandler.java b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextUiStartupHandler.java deleted file mode 100644 index d20571828..000000000 --- a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/ContextUiStartupHandler.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Tasktop Technologies. - * 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.context.tasks.ui; - -import org.eclipse.mylyn.context.ui.IContextUiStartup; -import org.eclipse.mylyn.internal.tasks.core.externalization.ExternalizationManager; -import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; - -/** - * @author Steffen Pingel - */ -public class ContextUiStartupHandler implements IContextUiStartup { - - public ContextUiStartupHandler() { - // ignore - } - - public void lazyStartup() { - ExternalizationManager externalizationManager = TasksUiPlugin.getExternalizationManager(); - ActiveContextExternalizationParticipant activeContextExternalizationParticipant = new ActiveContextExternalizationParticipant( - externalizationManager); - externalizationManager.addParticipant(activeContextExternalizationParticipant); - activeContextExternalizationParticipant.registerListeners(); - } - -} 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 d8ab6b0bf..8b8a9cdcc 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 @@ -22,6 +22,8 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.commons.core.CommonListenerList; +import org.eclipse.mylyn.commons.core.CommonListenerList.Notifier; import org.eclipse.mylyn.commons.core.CoreUtil; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.commons.core.storage.CommonStore; @@ -31,6 +33,7 @@ import org.eclipse.mylyn.context.core.IInteractionContext; import org.eclipse.mylyn.internal.context.core.ContextCorePlugin; import org.eclipse.mylyn.internal.context.core.InteractionContext; import org.eclipse.mylyn.internal.context.core.InteractionContextManager; +import org.eclipse.mylyn.internal.context.tasks.ui.TaskContextStoreEvent.Kind; import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; import org.eclipse.mylyn.internal.tasks.core.RepositoryTaskHandleUtil; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; @@ -38,6 +41,8 @@ import org.eclipse.mylyn.monitor.core.InteractionEvent; import org.eclipse.mylyn.tasks.core.ITask; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.context.AbstractTaskContextStore; +import org.eclipse.mylyn.tasks.ui.TasksUi; +import org.eclipse.osgi.util.NLS; /** * @author Steffen Pingel @@ -46,31 +51,53 @@ public class TaskContextStore extends AbstractTaskContextStore { private static final String FOLDER_DATA = "data"; //$NON-NLS-1$ + private final CommonListenerList<TaskContextStoreListener> listeners; + private File directory; private CommonStore taskStore; - public ICommonStorable getStorable(ITask task) { - return getTaskStore().get(getPath(task)); - } + private final ContextStatePersistenceHandler stateHandler; - private IPath getPath(ITask task) { - IPath path = new Path(""); //$NON-NLS-1$ - path = path.append(task.getConnectorKind() + "-" + CoreUtil.asFileName(task.getRepositoryUrl())); //$NON-NLS-1$ - path = path.append(FOLDER_DATA); - path = path.append(CoreUtil.asFileName(task.getTaskId())); - return path; + public TaskContextStore() { + this.listeners = new CommonListenerList<TaskContextStoreListener>(TasksUiPlugin.ID_PLUGIN); + this.stateHandler = new ContextStatePersistenceHandler(); } - @Override - public IAdaptable copyContext(ITask sourceTask, ITask targetTask) { - IInteractionContext result = copyContextInternal(sourceTask, targetTask); - return asAdaptable(result); + public void addListener(TaskContextStoreListener listener) { + listeners.add(listener); } @Override public void clearContext(ITask task) { ContextCorePlugin.getContextManager().deleteContext(task.getHandleIdentifier()); + + stateHandler.clear(task); + + final TaskContextStoreEvent event = new TaskContextStoreEvent(Kind.CLEAR, task); + listeners.notify(new Notifier<TaskContextStoreListener>() { + @Override + public void run(TaskContextStoreListener listener) throws Exception { + listener.taskContextChanged(event); + } + }); + } + + @Override + public IAdaptable copyContext(ITask sourceTask, ITask targetTask) { + IInteractionContext result = copyContextInternal(sourceTask, targetTask); + + stateHandler.copy(sourceTask, targetTask); + + final TaskContextStoreEvent event = new TaskContextStoreEvent(Kind.COPY, sourceTask, targetTask); + listeners.notify(new Notifier<TaskContextStoreListener>() { + @Override + public void run(TaskContextStoreListener listener) throws Exception { + listener.taskContextChanged(event); + } + }); + + return asAdaptable(result); } @Override @@ -86,6 +113,15 @@ public class TaskContextStore extends AbstractTaskContextStore { } ContextCorePlugin.getContextManager().deleteContext(task.getHandleIdentifier()); + stateHandler.clear(task); + + final TaskContextStoreEvent event = new TaskContextStoreEvent(Kind.DELETE, task); + listeners.notify(new Notifier<TaskContextStoreListener>() { + @Override + public void run(TaskContextStoreListener listener) throws Exception { + listener.taskContextChanged(event); + } + }); } @Override @@ -93,6 +129,10 @@ public class TaskContextStore extends AbstractTaskContextStore { return ContextCorePlugin.getContextStore().getFileForContext(task.getHandleIdentifier()); } + public ICommonStorable getStorable(ITask task) { + return getTaskStore().get(getPath(task)); + } + @Override public boolean hasContext(ITask task) { return ContextCore.getContextStore().hasContext(task.getHandleIdentifier()); @@ -102,8 +142,15 @@ public class TaskContextStore extends AbstractTaskContextStore { public void mergeContext(ITask sourceTask, ITask targetTask) { ContextCorePlugin.getContextStore().merge(sourceTask.getHandleIdentifier(), targetTask.getHandleIdentifier()); - // FIXME migrate local state - taskStore.copy(getPath(sourceTask), getPath(targetTask), false); + stateHandler.merge(sourceTask, targetTask); + + final TaskContextStoreEvent event = new TaskContextStoreEvent(Kind.MERGE, sourceTask, targetTask); + listeners.notify(new Notifier<TaskContextStoreListener>() { + @Override + public void run(TaskContextStoreListener listener) throws Exception { + listener.taskContextChanged(event); + } + }); } @Override @@ -122,6 +169,21 @@ public class TaskContextStore extends AbstractTaskContextStore { // ignore } + try { + taskStore.move(getPath(sourceTask), getPath(targetTask)); + } catch (CoreException e) { + StatusHandler.log(new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, + "Failed to migrate context state to new task", e)); //$NON-NLS-1$ + } + + final TaskContextStoreEvent event = new TaskContextStoreEvent(Kind.MOVE, sourceTask, targetTask); + listeners.notify(new Notifier<TaskContextStoreListener>() { + @Override + public void run(TaskContextStoreListener listener) throws Exception { + listener.taskContextChanged(event); + } + }); + return asAdaptable(result); } @@ -134,22 +196,38 @@ public class TaskContextStore extends AbstractTaskContextStore { } } - private void refactorTasksStoreLocation(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$ - - File oldFile = new File(directory, oldPath.toOSString()); - if (oldFile.exists()) { - File newFile = new File(directory, newPath.toOSString()); - newFile.getParentFile().mkdirs(); - oldFile.renameTo(newFile); - } + public void removeListener(TaskContextStoreListener listener) { + listeners.remove(listener); } @Override public void saveActiveContext() { - // FIXME save local state ContextCorePlugin.getContextStore().saveActiveContext(); + + ITask task = TasksUi.getTaskActivityManager().getActiveTask(); + stateHandler.saved(task); + + final TaskContextStoreEvent event = new TaskContextStoreEvent(Kind.SAVE, task); + listeners.notify(new Notifier<TaskContextStoreListener>() { + @Override + public void run(TaskContextStoreListener listener) throws Exception { + listener.taskContextChanged(event); + } + }); + } + + @Override + public synchronized void setDirectory(File directory) { + this.directory = directory; + if (taskStore != null) { + taskStore.setLocation(directory); + } + + File contextDirectory = new File(directory.getParent(), ITasksCoreConstants.CONTEXTS_DIRECTORY); + if (!contextDirectory.exists()) { + contextDirectory.mkdirs(); + } + ContextCorePlugin.getContextStore().setContextDirectory(contextDirectory); } private IAdaptable asAdaptable(final IInteractionContext result) { @@ -167,11 +245,22 @@ public class TaskContextStore extends AbstractTaskContextStore { ContextCorePlugin.getContextStore().saveActiveContext(); final IInteractionContext result = ContextCore.getContextStore().cloneContext(sourceTask.getHandleIdentifier(), targetTask.getHandleIdentifier()); + return result; + } - // FIXME migrate local state - taskStore.copy(getPath(sourceTask), getPath(targetTask), true); + private IPath getPath(ITask task) { + IPath path = new Path(""); //$NON-NLS-1$ + path = path.append(task.getConnectorKind() + "-" + CoreUtil.asFileName(task.getRepositoryUrl())); //$NON-NLS-1$ + path = path.append(FOLDER_DATA); + path = path.append(CoreUtil.asFileName(task.getTaskId())); + return path; + } - return result; + private synchronized CommonStore getTaskStore() { + if (taskStore == null) { + taskStore = new CommonStore(directory); + } + return taskStore; } @SuppressWarnings("restriction") @@ -231,25 +320,19 @@ public class TaskContextStore extends AbstractTaskContextStore { } } - @Override - public synchronized void setDirectory(File directory) { - this.directory = directory; - if (taskStore != null) { - taskStore.setLocation(directory); - } - - File contextDirectory = new File(directory.getParent(), ITasksCoreConstants.CONTEXTS_DIRECTORY); - if (!contextDirectory.exists()) { - contextDirectory.mkdirs(); + private void refactorTasksStoreLocation(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$ + try { + taskStore.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$ } - ContextCorePlugin.getContextStore().setContextDirectory(contextDirectory); } - private synchronized CommonStore getTaskStore() { - if (taskStore == null) { - taskStore = new CommonStore(directory); - } - return taskStore; + public ContextStatePersistenceHandler getStateHandler() { + return stateHandler; } } diff --git a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStoreEvent.java b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStoreEvent.java new file mode 100644 index 000000000..ba64ec328 --- /dev/null +++ b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStoreEvent.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2012 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.context.tasks.ui; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.mylyn.tasks.core.ITask; + +/** + * @author Steffen Pingel + */ +public class TaskContextStoreEvent { + + public enum Kind { + CLEAR, COPY, DELETE, MERGE, MOVE, SAVE + } + + private final ITask sourceTask; + + private final ITask targetTask; + + private final Kind kind;; + + public TaskContextStoreEvent(Kind kind, ITask sourceTask, ITask targetTask) { + Assert.isNotNull(kind); + Assert.isNotNull(sourceTask); + this.kind = kind; + this.sourceTask = sourceTask; + this.targetTask = targetTask; + } + + public TaskContextStoreEvent(Kind kind, ITask sourceTask) { + this(kind, sourceTask, null); + } + + public Kind getKind() { + return kind; + } + + public ITask getSourceTask() { + return sourceTask; + } + + public ITask getTargetTask() { + return targetTask; + } + +} diff --git a/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStoreListener.java b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStoreListener.java new file mode 100644 index 000000000..d24dba861 --- /dev/null +++ b/org.eclipse.mylyn.context.tasks.ui/src/org/eclipse/mylyn/internal/context/tasks/ui/TaskContextStoreListener.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2012 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.context.tasks.ui; + +/** + * @author Steffen Pingel + */ +public abstract class TaskContextStoreListener { + + public abstract void taskContextChanged(TaskContextStoreEvent event); + +} diff --git a/org.eclipse.mylyn.context.tests/.settings/.api_filters b/org.eclipse.mylyn.context.tests/.settings/.api_filters deleted file mode 100644 index f1ae47ebe..000000000 --- a/org.eclipse.mylyn.context.tests/.settings/.api_filters +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<component id="org.eclipse.mylyn.context.tests" version="2"> - <resource path="src/org/eclipse/mylyn/context/tests/ContextEditorManagerTest.java" type="org.eclipse.mylyn.context.tests.ContextEditorManagerTest"> - <filter id="571519004"> - <message_arguments> - <message_argument value="org.eclipse.mylyn.context.tests.ContextEditorManagerTest.testCloseAllRestoreContextAwareEditor()"/> - <message_argument value="FileEditorInput"/> - </message_arguments> - </filter> - </resource> -</component> diff --git a/org.eclipse.mylyn.context.tests/src/org/eclipse/mylyn/context/tests/AllContextTests.java b/org.eclipse.mylyn.context.tests/src/org/eclipse/mylyn/context/tests/AllContextTests.java index fa0b69677..18b44e51b 100644 --- a/org.eclipse.mylyn.context.tests/src/org/eclipse/mylyn/context/tests/AllContextTests.java +++ b/org.eclipse.mylyn.context.tests/src/org/eclipse/mylyn/context/tests/AllContextTests.java @@ -33,7 +33,6 @@ public class AllContextTests { suite.addTestSuite(ContextTest.class); suite.addTestSuite(InteractionEventTest.class); suite.addTestSuite(ShadowsBridgeTest.class); - suite.addTestSuite(ContextEditorManagerTest.class); return suite; } diff --git a/org.eclipse.mylyn.context.ui/META-INF/MANIFEST.MF b/org.eclipse.mylyn.context.ui/META-INF/MANIFEST.MF index 8707b5acc..5fc7ce298 100644 --- a/org.eclipse.mylyn.context.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.mylyn.context.ui/META-INF/MANIFEST.MF @@ -26,6 +26,7 @@ Export-Package: org.eclipse.mylyn.context.ui, org.eclipse.mylyn.internal.context.ui.actions;x-internal:=true, org.eclipse.mylyn.internal.context.ui.commands;x-internal:=true, org.eclipse.mylyn.internal.context.ui.preferences;x-internal:=true, + org.eclipse.mylyn.internal.context.ui.state;x-internal:=true, org.eclipse.mylyn.internal.context.ui.views;x-internal:=true Bundle-RequiredExecutionEnvironment: J2SE-1.5 Import-Package: com.ibm.icu.text diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextEditorManager.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextEditorManager.java index c59edd20a..9931f0ab7 100644 --- a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextEditorManager.java +++ b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextEditorManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2009 Tasktop Technologies and others. + * Copyright (c) 2012 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 @@ -11,475 +11,71 @@ package org.eclipse.mylyn.internal.context.ui; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.ISafeRunnable; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.util.SafeRunnable; -import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.context.core.AbstractContextListener; import org.eclipse.mylyn.context.core.AbstractContextStructureBridge; 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.context.core.IInteractionContextManager; import org.eclipse.mylyn.context.core.IInteractionElement; import org.eclipse.mylyn.context.ui.AbstractContextUiBridge; -import org.eclipse.mylyn.context.ui.ContextAwareEditorInput; import org.eclipse.mylyn.context.ui.ContextUi; -import org.eclipse.mylyn.context.ui.IContextAwareEditor; -import org.eclipse.mylyn.monitor.ui.MonitorUi; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IEditorReference; -import org.eclipse.ui.IMemento; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.XMLMemento; -import org.eclipse.ui.internal.IPreferenceConstants; -import org.eclipse.ui.internal.IWorkbenchConstants; -import org.eclipse.ui.internal.Workbench; -import org.eclipse.ui.internal.WorkbenchPage; -import org.eclipse.ui.preferences.ScopedPreferenceStore; /** + * Closes editors based on interest. + * * @author Mik Kersten * @author Shawn Minto + * @author Steffen Pingel */ -public class ContextEditorManager extends AbstractContextListener { - - private static final String PREFS_PREFIX = "editors.task."; //$NON-NLS-1$ - - private static final String KEY_CONTEXT_EDITORS = "ContextOpenEditors"; //$NON-NLS-1$ - - private static final String KEY_MONITORED_WINDOW_OPEN_EDITORS = "MonitoredWindowOpenEditors"; //$NON-NLS-1$ - - private static final String ATTRIBUTE_CLASS = "class"; //$NON-NLS-1$ - - private static final String ATTRIBUTE_NUMER = "number"; //$NON-NLS-1$ - - private static final String ATTRIBUTE_IS_LAUNCHING = "isLaunching"; //$NON-NLS-1$ - - private static final String ATTRIBUTE_IS_ACTIVE = "isActive"; //$NON-NLS-1$ - - private boolean previousCloseEditorsSetting = Workbench.getInstance() - .getPreferenceStore() - .getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN); - - private final IPreferenceStore preferenceStore; - - private boolean enabled; - - public ContextEditorManager() { - preferenceStore = new ScopedPreferenceStore(new InstanceScope(), "org.eclipse.mylyn.resources.ui"); //$NON-NLS-1$ - setEnabled(true); - } - - @Override - public void contextChanged(ContextChangeEvent event) { - switch (event.getEventKind()) { - case ACTIVATED: - openEditorsFromMemento(event.getContext()); - break; - case DEACTIVATED: - closeEditorsAndSaveMemento(event.getContext()); - break; - case INTEREST_CHANGED: - for (IInteractionElement element : event.getElements()) { - closeEditor(element, false); - } - break; - case ELEMENTS_DELETED: - for (IInteractionElement element : event.getElements()) { - closeEditor(element, true); - } - break; - case CLEARED: - // use the handle since the context is null when it is cleared - // bug 255588 - clearEditorMemento(event.getContextHandle(), event.isActiveContext()); - break; - - } - } - - public void openEditorsFromMemento(IInteractionContext context) { - if (!Workbench.getInstance().isStarting() - && ContextUiPlugin.getDefault() - .getPreferenceStore() - .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_EDITORS) && isEnabled()) { - Workbench workbench = (Workbench) PlatformUI.getWorkbench(); - previousCloseEditorsSetting = workbench.getPreferenceStore().getBoolean( - IPreferenceConstants.REUSE_EDITORS_BOOLEAN); - workbench.getPreferenceStore().setValue(IPreferenceConstants.REUSE_EDITORS_BOOLEAN, false); - boolean wasPaused = ContextCore.getContextManager().isContextCapturePaused(); - try { - if (!wasPaused) { - ContextCore.getContextManager().setContextCapturePaused(true); - } - String mementoString = null; - // TODO change where memento is stored - IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - try { - mementoString = readEditorMemento(context.getHandleIdentifier()); - if (mementoString != null && !mementoString.trim().equals("")) { //$NON-NLS-1$ - IMemento memento = XMLMemento.createReadRoot(new StringReader(mementoString)); - IMemento[] children = memento.getChildren(KEY_MONITORED_WINDOW_OPEN_EDITORS); - if (children.length > 0) { - // This code supports restore from multiple windows - for (IMemento child : children) { - WorkbenchPage page = getWorkbenchPageForMemento(child, activeWindow); - if (child != null && page != null) { - restoreEditors(page, child, page.getWorkbenchWindow() == activeWindow); - } - } - } else { - // This code is for supporting the old editor management - only the active window - WorkbenchPage page = (WorkbenchPage) activeWindow.getActivePage(); - if (memento != null) { - restoreEditors(page, memento, true); - } - } - } - } catch (Exception e) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, - "Could not restore all editors, memento: \"" + mementoString + "\"", e)); //$NON-NLS-1$ //$NON-NLS-2$ +public class ContextEditorManager { + + private final AbstractContextListener contextListener = new AbstractContextListener() { + @Override + public void contextChanged(ContextChangeEvent event) { + switch (event.getEventKind()) { + case INTEREST_CHANGED: + for (IInteractionElement element : event.getElements()) { + closeEditor(element, false); } - activeWindow.setActivePage(activeWindow.getActivePage()); - IInteractionElement activeNode = context.getActiveNode(); - if (activeNode != null) { - ContextUi.getUiBridge(activeNode.getContentType()).open(activeNode); + break; + case ELEMENTS_DELETED: + for (IInteractionElement element : event.getElements()) { + closeEditor(element, true); } - } catch (Exception e) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, - "Failed to open editors on activation", e)); //$NON-NLS-1$ - } finally { - ContextCore.getContextManager().setContextCapturePaused(false); - } - } - } - - private WorkbenchPage getWorkbenchPageForMemento(IMemento memento, IWorkbenchWindow activeWindow) { - - String windowToRestoreClassName = memento.getString(ATTRIBUTE_CLASS); - if (windowToRestoreClassName == null) { - windowToRestoreClassName = ""; //$NON-NLS-1$ - } - Integer windowToRestorenumber = memento.getInteger(ATTRIBUTE_NUMER); - if (windowToRestorenumber == null) { - windowToRestorenumber = 0; - } - - // try to match the open windows to the one that we want to restore - Set<IWorkbenchWindow> monitoredWindows = MonitorUi.getMonitoredWindows(); - for (IWorkbenchWindow window : monitoredWindows) { - int windowNumber = 0; - // FIXME e4 find new API to identify window number -// if (window instanceof WorkbenchWindow) { -// windowNumber = ((WorkbenchWindow) window).getNumber(); -// } - if (window.getClass().getCanonicalName().equals(windowToRestoreClassName) - && windowNumber == windowToRestorenumber) { - return (WorkbenchPage) window.getActivePage(); - } - } - - // we don't have a good match here, try to make an educated guess - Boolean isActive = memento.getBoolean(ATTRIBUTE_IS_ACTIVE); - if (isActive == null) { - isActive = false; - } - - // both of these defaulting to true should ensure that all editors are opened even if their previous editor is not around - boolean shouldRestoreUnknownWindowToActive = true; // TODO could add a preference here - boolean shouldRestoreActiveWindowToActive = true; // TODO could add a preference here - - if (isActive && shouldRestoreActiveWindowToActive) { - // if the window that we are trying to restore was the active window, restore it to the active window - return (WorkbenchPage) activeWindow.getActivePage(); - } - - if (shouldRestoreUnknownWindowToActive) { - // we can't find a good window, so restore it to the active one - return (WorkbenchPage) activeWindow.getActivePage(); - } - - if (shouldRestoreActiveWindowToActive && shouldRestoreUnknownWindowToActive) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, - "Unable to find window to restore memento to.", new Exception())); //$NON-NLS-1$ - } - - // we dont have a window that will work, so don't restore the editors - // we shouldn't get here if both *WindowToActive booleans are true - return null; - } - - private String readEditorMemento(String handleIdentifier) { - return preferenceStore.getString(PREFS_PREFIX + handleIdentifier); - } - - public void closeEditorsAndSaveMemento(IInteractionContext context) { - if (!PlatformUI.getWorkbench().isClosing() - && ContextUiPlugin.getDefault() - .getPreferenceStore() - .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_EDITORS) && isEnabled()) { - closeContextAwareEditors(context.getHandleIdentifier()); - - XMLMemento rootMemento = XMLMemento.createWriteRoot(KEY_CONTEXT_EDITORS); - - IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - IWorkbenchWindow launchingWindow = MonitorUi.getLaunchingWorkbenchWindow(); - Set<IWorkbenchWindow> monitoredWindows = MonitorUi.getMonitoredWindows(); - - for (IWorkbenchWindow window : monitoredWindows) { - IMemento memento = rootMemento.createChild(KEY_MONITORED_WINDOW_OPEN_EDITORS); - - memento.putString(ATTRIBUTE_CLASS, window.getClass().getCanonicalName()); - int number = 0; - // FIXME e4 find new API to identify window number -// if (window instanceof WorkbenchWindow) { -// number = ((WorkbenchWindow) window).getNumber(); -// } - memento.putInteger(ATTRIBUTE_NUMER, number); - memento.putBoolean(ATTRIBUTE_IS_LAUNCHING, window == launchingWindow); - memento.putBoolean(ATTRIBUTE_IS_ACTIVE, window == activeWindow); - //((WorkbenchPage) window.getActivePage()).getEditorManager().saveState(memento); - } - // TODO: avoid storing with preferences due to bloat? - StringWriter writer = new StringWriter(); - try { - rootMemento.save(writer); - writeEditorMemento(context.getHandleIdentifier(), writer.getBuffer().toString()); - } catch (IOException e) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Could not store editor state", //$NON-NLS-1$ - e)); + break; } - - Workbench.getInstance() - .getPreferenceStore() - .setValue(IPreferenceConstants.REUSE_EDITORS_BOOLEAN, previousCloseEditorsSetting); - closeAllEditors(); - } - } - - public void writeEditorMemento(String contextHandle, String memento) { - preferenceStore.setValue(PREFS_PREFIX + contextHandle, memento); - } - - public void clearEditorMemento(String contextHandle, boolean closeEditors) { - - if (closeEditors) { - closeContextAwareEditors(contextHandle); } + }; - XMLMemento memento = XMLMemento.createWriteRoot(KEY_CONTEXT_EDITORS); - - // TODO: avoid storing with preferences due to bloat? - StringWriter writer = new StringWriter(); - try { - memento.save(writer); - writeEditorMemento(contextHandle, writer.getBuffer().toString()); - } catch (IOException e) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Could not store editor state", e)); //$NON-NLS-1$ - } - - Workbench.getInstance() - .getPreferenceStore() - .setValue(IPreferenceConstants.REUSE_EDITORS_BOOLEAN, previousCloseEditorsSetting); - if (closeEditors) { - closeAllEditors(); - } + public ContextEditorManager() { } - /** - * HACK: will fail to restore different parts with same name - */ - @SuppressWarnings("unchecked") - private void restoreEditors(WorkbenchPage page, IMemento memento, boolean isActiveWindow) { - //EditorManager editorManager = page.getEditorManager(); - final ArrayList visibleEditors = new ArrayList(5); - final IEditorReference activeEditor[] = new IEditorReference[1]; - final MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, "", null); //$NON-NLS-1$ - - try { - IMemento[] editorMementos = memento.getChildren(IWorkbenchConstants.TAG_EDITOR); - Set<IMemento> editorMementoSet = new HashSet<IMemento>(); - editorMementoSet.addAll(Arrays.asList(editorMementos)); - // HACK: same parts could have different editors - Set<String> restoredPartNames = new HashSet<String>(); -// List<IEditorReference> alreadyVisibleEditors = Arrays.asList(editorManager.getEditors()); -// for (IEditorReference editorReference : alreadyVisibleEditors) { -// restoredPartNames.add(editorReference.getPartName()); -// } - for (IMemento editorMemento : editorMementoSet) { - String partName = editorMemento.getString(IWorkbenchConstants.TAG_PART_NAME); - if (!restoredPartNames.contains(partName)) { - //editorManager.restoreEditorState(editorMemento, visibleEditors, activeEditor, result); - } else { - restoredPartNames.add(partName); - } - } - - for (int i = 0; i < visibleEditors.size(); i++) { - //editorManager.setVisibleEditor((IEditorReference) visibleEditors.get(i), false); - } - - if (activeEditor[0] != null && isActiveWindow) { - IWorkbenchPart editor = activeEditor[0].getPart(true); - if (editor != null) { - page.activate(editor); - } - } - } catch (Exception e) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Could not restore editors", e)); //$NON-NLS-1$ - } + public void start(IInteractionContextManager contextManager) { + contextManager.addListener(contextListener); } - public void closeContextAwareEditors(String contextHandle) { - try { - if (PlatformUI.getWorkbench().isClosing()) { - return; - } - for (IWorkbenchWindow window : MonitorUi.getMonitoredWindows()) { - IWorkbenchPage page = window.getActivePage(); - if (page != null) { - IEditorReference[] references = page.getEditorReferences(); - List<IEditorReference> toClose = new ArrayList<IEditorReference>(); - for (IEditorReference reference : references) { - if (canClose(reference)) { - try { - IEditorInput input = reference.getEditorInput(); - if (shouldForceClose(input, contextHandle)) { - toClose.add(reference); - } - } catch (PartInitException e) { - // ignore - } - } - } - page.closeEditors(toClose.toArray(new IEditorReference[toClose.size()]), true); - } - } - } catch (Throwable t) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Could not auto close editor", t)); //$NON-NLS-1$ - } + public void stop(IInteractionContextManager contextManager) { + contextManager.removeListener(contextListener); } - public void closeAllEditors() { - try { - if (PlatformUI.getWorkbench().isClosing()) { - return; - } - for (IWorkbenchWindow window : MonitorUi.getMonitoredWindows()) { - IWorkbenchPage page = window.getActivePage(); - if (page != null) { - IEditorReference[] references = page.getEditorReferences(); - List<IEditorReference> toClose = new ArrayList<IEditorReference>(); - for (IEditorReference reference : references) { - if (canClose(reference)) { - toClose.add(reference); - } - } - page.closeEditors(toClose.toArray(new IEditorReference[toClose.size()]), true); - } - } - } catch (Throwable t) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Could not auto close editor", t)); //$NON-NLS-1$ + private void closeEditor(IInteractionElement element, boolean force) { + if (!isEnabled()) { + return; } - } - - private boolean shouldForceClose(final IEditorInput input, final String contextHandle) { - final AtomicBoolean result = new AtomicBoolean(); - SafeRunnable.run(new ISafeRunnable() { - public void run() throws Exception { - ContextAwareEditorInput inputContext = (ContextAwareEditorInput) input.getAdapter(ContextAwareEditorInput.class); - result.set(inputContext != null && inputContext.forceClose(contextHandle)); - } - public void handleException(Throwable e) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, - "Failed to verify editor status", e)); //$NON-NLS-1$ + if (force || !element.getInterest().isInteresting()) { + AbstractContextStructureBridge bridge = ContextCore.getStructureBridge(element.getContentType()); + if (bridge.isDocument(element.getHandleIdentifier())) { + AbstractContextUiBridge uiBridge = ContextUi.getUiBridge(element.getContentType()); + uiBridge.close(element); } - }); - return result.get(); - } - - private boolean canClose(final IEditorReference editorReference) { - final IEditorPart editor = editorReference.getEditor(false); - if (editor != null) { - final boolean[] result = new boolean[1]; - result[0] = true; - SafeRunnable.run(new ISafeRunnable() { - public void run() throws Exception { - if (editor instanceof IContextAwareEditor) { - result[0] = ((IContextAwareEditor) editor).canClose(); - } else { - IContextAwareEditor contextAware = (IContextAwareEditor) editor.getAdapter(IContextAwareEditor.class); - if (contextAware != null) { - result[0] = contextAware.canClose(); - } - } - } - - public void handleException(Throwable e) { - StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, - "Failed to verify editor status", e)); //$NON-NLS-1$ - } - }); - return result[0]; } - return true; } - private void closeEditor(IInteractionElement element, boolean force) { - if (ContextUiPlugin.getDefault() + private boolean isEnabled() { + return ContextUiPlugin.getDefault() .getPreferenceStore() - .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_EDITORS)) { - if (force || !element.getInterest().isInteresting()) { - AbstractContextStructureBridge bridge = ContextCore.getStructureBridge(element.getContentType()); - if (bridge.isDocument(element.getHandleIdentifier())) { - AbstractContextUiBridge uiBridge = ContextUi.getUiBridge(element.getContentType()); - uiBridge.close(element); - } - } - } - } - - public void copyEditorMemento(String sourceHandle, String targetHandle) { - Assert.isNotNull(sourceHandle); - Assert.isNotNull(targetHandle); - String memento = readEditorMemento(sourceHandle); - if (memento != null) { - writeEditorMemento(targetHandle, memento); - } - } - - public boolean hasEditorMemento(String sourceHandle) { - Assert.isNotNull(sourceHandle); - return readEditorMemento(sourceHandle) != null; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean active) { - this.enabled = active; + .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_EDITORS); } } diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextPerspectiveManager.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextPerspectiveManager.java deleted file mode 100644 index edc84e548..000000000 --- a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextPerspectiveManager.java +++ /dev/null @@ -1,193 +0,0 @@ -/******************************************************************************* - * 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.context.ui; - -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.mylyn.context.core.AbstractContextListener; -import org.eclipse.mylyn.context.core.IInteractionContext; -import org.eclipse.ui.IPerspectiveDescriptor; -import org.eclipse.ui.IPerspectiveListener; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PerspectiveAdapter; -import org.eclipse.ui.PlatformUI; - -/** - * @author Mik Kersten - * @author Shawn Minto - */ -public class ContextPerspectiveManager { - - private final Set<String> actionSetsToSuppress; - - private final AbstractContextListener contextListener = new AbstractContextListener() { - @Override - public void contextChanged(org.eclipse.mylyn.context.core.ContextChangeEvent event) { - switch (event.getEventKind()) { - case ACTIVATED: - ContextPerspectiveManager.this.contextActivated(event.getContext()); - case DEACTIVATED: - ContextPerspectiveManager.this.contextDeactivated(event.getContext()); - } - }; - }; - - private final Set<String> managedPerspectiveIds; - - private final IPerspectiveListener perspectiveListener = new PerspectiveAdapter() { - - @Override - public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) { - cleanActionSets(page, perspective); - } - - @Override - public void perspectiveOpened(IWorkbenchPage page, IPerspectiveDescriptor perspective) { - cleanActionSets(page, perspective); - } - - }; - - private final IPreferenceStore preferenceStore; - - public ContextPerspectiveManager(IPreferenceStore preferenceStore) { - this.preferenceStore = preferenceStore; - this.managedPerspectiveIds = new HashSet<String>(); - this.actionSetsToSuppress = new HashSet<String>(); - actionSetsToSuppress.add("org.eclipse.ui.edit.text.actionSet.annotationNavigation"); //$NON-NLS-1$ - actionSetsToSuppress.add("org.eclipse.ui.edit.text.actionSet.convertLineDelimitersTo"); //$NON-NLS-1$ - actionSetsToSuppress.add("org.eclipse.ui.externaltools.ExternalToolsSet"); //$NON-NLS-1$ - } - - public void addManagedPerspective(String id) { - managedPerspectiveIds.add(id); - } - - public void contextActivated(IInteractionContext context) { - try { - IWorkbenchWindow launchingWindow = getWorkbenchWindow(); - if (launchingWindow != null) { - IPerspectiveDescriptor descriptor = launchingWindow.getActivePage().getPerspective(); - setPerspectiveIdFor(null, descriptor.getId()); - - String perspectiveId = getPerspectiveIdFor(context); - showPerspective(perspectiveId); - } - } catch (Exception e) { - // ignore, perspective may not have been saved, e.g. due to crash - } - } - - public void contextDeactivated(IInteractionContext context) { - try { - if (PlatformUI.isWorkbenchRunning() - && ContextUiPlugin.getDefault() - .getPreferenceStore() - .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_PERSPECTIVES)) { - IWorkbenchWindow launchingWindow = getWorkbenchWindow(); - if (launchingWindow != null) { - IPerspectiveDescriptor descriptor = launchingWindow.getActivePage().getPerspective(); - setPerspectiveIdFor(context, descriptor.getId()); - - String previousPerspectiveId = getPerspectiveIdFor(null); - showPerspective(previousPerspectiveId); - } - } - } catch (Exception e) { - // ignore, perspective may not have been saved, e.g. due to crash - } - } - - public AbstractContextListener getContextListener() { - return contextListener; - } - - public IPerspectiveListener getPerspectiveListener() { - return perspectiveListener; - } - - public IWorkbenchWindow getWorkbenchWindow() { - IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); - if (window == null) { - IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows(); - if (windows.length > 0) { - window = windows[0]; - } - } - return window; - } - - public void removeManagedPerspective(String id) { - managedPerspectiveIds.remove(id); - } - - private void cleanActionSets(IWorkbenchPage page, IPerspectiveDescriptor perspectiveDescriptor) { - if (managedPerspectiveIds.contains(perspectiveDescriptor.getId())) { - for (String actionSetId : actionSetsToSuppress) { - page.hideActionSet(actionSetId); - } - } - } - - /** - * @param context - * can be null to indicate no task - */ - private String getPerspectiveIdFor(IInteractionContext context) { - if (context != null) { - return preferenceStore.getString(IContextUiPreferenceContstants.PREFIX_TASK_TO_PERSPECTIVE - + context.getHandleIdentifier()); - } else { - return preferenceStore.getString(IContextUiPreferenceContstants.PERSPECTIVE_NO_ACTIVE_TASK); - } - } - - /** - * @param context - * can be null to indicate no task - */ - private void setPerspectiveIdFor(IInteractionContext context, String perspectiveId) { - if (context != null) { - preferenceStore.setValue( - IContextUiPreferenceContstants.PREFIX_TASK_TO_PERSPECTIVE + context.getHandleIdentifier(), - perspectiveId); - } else { - preferenceStore.setValue(IContextUiPreferenceContstants.PERSPECTIVE_NO_ACTIVE_TASK, perspectiveId); - } - } - - private void showPerspective(String perspectiveId) { - if (perspectiveId != null - && perspectiveId.length() > 0 - && ContextUiPlugin.getDefault() - .getPreferenceStore() - .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_PERSPECTIVES)) { - IWorkbenchWindow launchingWindow = getWorkbenchWindow(); - try { - if (launchingWindow != null) { - launchingWindow.getShell().setRedraw(false); - PlatformUI.getWorkbench().showPerspective(perspectiveId, launchingWindow); - } - } catch (Exception e) { - // perspective's preserved id not found, ignore - } finally { - if (launchingWindow != null) { - launchingWindow.getShell().setRedraw(true); - } - } - } - } - -} diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextUiPlugin.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextUiPlugin.java index d818a30f8..18a5a030d 100644 --- a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextUiPlugin.java +++ b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/ContextUiPlugin.java @@ -46,6 +46,9 @@ import org.eclipse.mylyn.context.core.IInteractionElement; import org.eclipse.mylyn.context.core.IInteractionRelation; import org.eclipse.mylyn.context.ui.AbstractContextUiBridge; import org.eclipse.mylyn.context.ui.IContextUiStartup; +import org.eclipse.mylyn.internal.context.ui.state.ContextStateManager; +import org.eclipse.mylyn.internal.context.ui.state.EditorStateParticipant; +import org.eclipse.mylyn.internal.context.ui.state.PerspectiveStateParticipant; import org.eclipse.mylyn.monitor.ui.MonitorUi; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; @@ -95,7 +98,7 @@ public class ContextUiPlugin extends AbstractUIPlugin { private FocusedViewerManager viewerManager; - private ContextPerspectiveManager perspectiveManager; + private PerspectiveStateParticipant perspectiveStateParticipant; private final ContentOutlineManager contentOutlineManager = new ContentOutlineManager(); @@ -181,6 +184,10 @@ public class ContextUiPlugin extends AbstractUIPlugin { private final AtomicBoolean lazyStarted = new AtomicBoolean(false); + private EditorStateParticipant editorStateParticipant; + + private ContextStateManager stateManager; + private ContextEditorManager editorManager; public ContextUiPlugin() { @@ -193,8 +200,15 @@ public class ContextUiPlugin extends AbstractUIPlugin { initDefaultPrefs(getPreferenceStore()); + stateManager = new ContextStateManager(); + viewerManager = new FocusedViewerManager(); - perspectiveManager = new ContextPerspectiveManager(getPreferenceStore()); + + perspectiveStateParticipant = new PerspectiveStateParticipant(getPreferenceStore()); + stateManager.addParticipant(perspectiveStateParticipant); + + editorStateParticipant = new EditorStateParticipant(); + stateManager.addParticipant(editorStateParticipant); editorManager = new ContextEditorManager(); @@ -227,9 +241,7 @@ public class ContextUiPlugin extends AbstractUIPlugin { try { ContextCore.getContextManager().addListener(viewerManager); MonitorUi.addWindowPartListener(contentOutlineManager); - MonitorUi.addWindowPerspectiveListener(perspectiveManager.getPerspectiveListener()); - ContextCore.getContextManager().addListener(perspectiveManager.getContextListener()); - ContextCore.getContextManager().addListener(editorManager); + editorManager.start(ContextCore.getContextManager()); } catch (Exception e) { StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Context UI initialization failed", //$NON-NLS-1$ e)); @@ -262,15 +274,16 @@ public class ContextUiPlugin extends AbstractUIPlugin { } private void lazyStop() { - if (editorManager != null) { - ContextCore.getContextManager().removeListener(editorManager); + editorManager.stop(ContextCore.getContextManager()); + if (editorStateParticipant != null) { + stateManager.removeParticipant(editorStateParticipant); + } + if (perspectiveStateParticipant != null) { + stateManager.removeParticipant(perspectiveStateParticipant); } ContextCore.getContextManager().removeListener(viewerManager); MonitorUi.removeWindowPartListener(contentOutlineManager); - - MonitorUi.removeWindowPerspectiveListener(perspectiveManager.getPerspectiveListener()); - ContextCore.getContextManager().removeListener(perspectiveManager.getContextListener()); } /** @@ -550,7 +563,6 @@ public class ContextUiPlugin extends AbstractUIPlugin { "Could not load startup extension", e)); //$NON-NLS-1$ } } - } private void setActiveSearchIcon(AbstractContextUiBridge bridge, ImageDescriptor descriptor) { @@ -607,12 +619,12 @@ public class ContextUiPlugin extends AbstractUIPlugin { } } - public static ContextEditorManager getEditorManager() { - return INSTANCE.editorManager; + public static EditorStateParticipant getEditorStateParticipant() { + return INSTANCE.editorStateParticipant; } - public static ContextPerspectiveManager getPerspectiveManager() { - return INSTANCE.perspectiveManager; + public static PerspectiveStateParticipant getPerspectiveStateParticipant() { + return INSTANCE.perspectiveStateParticipant; } public static void forceFlatLayoutOfJavaContent(CommonViewer commonViewer) { @@ -637,4 +649,8 @@ public class ContextUiPlugin extends AbstractUIPlugin { } } + public ContextStateManager getStateManager() { + return stateManager; + } + } diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/IContextUiPreferenceContstants.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/IContextUiPreferenceContstants.java index a2b7a7ffb..611326dfd 100644 --- a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/IContextUiPreferenceContstants.java +++ b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/IContextUiPreferenceContstants.java @@ -30,6 +30,4 @@ public interface IContextUiPreferenceContstants { public static final String PERSPECTIVE_NO_ACTIVE_TASK = "org.eclipse.mylyn.ui.perspectives.task.none"; //$NON-NLS-1$ - public static final String PREFIX_TASK_TO_PERSPECTIVE = "org.eclipse.mylyn.ui.perspectives.task."; //$NON-NLS-1$ - } diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextState.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextState.java new file mode 100644 index 000000000..abd640f1f --- /dev/null +++ b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextState.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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.context.ui.state; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.mylyn.context.core.IInteractionContext; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.XMLMemento; + +/** + * Stores workspace specific settings for a context. + * + * @author Steffen Pingel + */ +public class ContextState { + + private boolean dirty; + + private final IInteractionContext context; + + private String contextHandle; + + private final XMLMemento memento; + + public ContextState(IInteractionContext context, String contextHandle, XMLMemento memento) { + Assert.isNotNull(memento); + Assert.isNotNull(contextHandle); + this.context = context; + this.contextHandle = contextHandle; + this.memento = memento; + } + + void setContextHandle(String contextHandle) { + this.contextHandle = contextHandle; + } + + // XXX equals and hashcode should probably use the handle to determine equality + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ContextState)) { + return false; + } + return context.equals(((ContextState) obj).context); + } + + @Override + public int hashCode() { + return context.hashCode(); + } + + public String getContextHandle() { + return contextHandle; + } + + public IInteractionContext getContext() { + return context; + } + + XMLMemento getMemento() { + return memento; + } + + public IMemento getMemento(String type) { + return memento.getChild(type); + } + + public IMemento createMemento(String type) { + dirty = true; + return memento.createChild(type); + } + + public boolean isDirty() { + return dirty; + } + + public void removeMemento(String type) { + memento.createChild(type); + } + + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + +} diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextStateManager.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextStateManager.java new file mode 100644 index 000000000..3a0614594 --- /dev/null +++ b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextStateManager.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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.context.ui.state; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.commons.core.CommonListenerList; +import org.eclipse.mylyn.commons.core.CommonListenerList.Notifier; +import org.eclipse.mylyn.commons.core.StatusHandler; +import org.eclipse.mylyn.context.core.IInteractionContext; +import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; +import org.eclipse.ui.XMLMemento; + +/** + * @author Steffen Pingel + */ +public class ContextStateManager { + + private static final String TAG_CONTEXT_STATE = "ContextState"; //$NON-NLS-1$ + + private static final String CHARSET = "UTF-8"; //$NON-NLS-1$ + + private final CommonListenerList<ContextStateParticipant> participants; + + private final ContextState defaultState; + + public ContextStateManager() { + this.participants = new CommonListenerList<ContextStateParticipant>(ContextUiPlugin.ID_PLUGIN); + this.defaultState = createMemento(null, "default"); //$NON-NLS-1$ + } + + public void addParticipant(ContextStateParticipant participant) { + participants.add(participant); + } + + public void clearState(final String contextHandle, final boolean isActiveContext) { + participants.notify(new Notifier<ContextStateParticipant>() { + @Override + public void run(ContextStateParticipant participant) throws Exception { + participant.clearState(contextHandle, isActiveContext); + } + }); + } + + public ContextState createMemento(IInteractionContext context, String contextHandle) { + return new ContextState(context, contextHandle, XMLMemento.createWriteRoot(TAG_CONTEXT_STATE)); + } + + public ContextState read(IInteractionContext context, InputStream in) { + ContextState memento = null; + if (in != null) { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in, CHARSET)); + try { + XMLMemento xmlMemento = XMLMemento.createReadRoot(reader); + return new ContextState(context, context.getHandleIdentifier(), xmlMemento); + } finally { + reader.close(); + } + } catch (IOException e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, + "Failed to restore context state", e)); //$NON-NLS-1$ + } catch (CoreException e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, + "Failed to restore context state", e)); //$NON-NLS-1$ + } + } + + if (memento == null) { + memento = createMemento(context, context.getHandleIdentifier()); + } + return memento; + } + + public void removeParticipant(ContextStateParticipant participant) { + participants.remove(participant); + } + + public void restoreDefaultState() { + participants.notify(new Notifier<ContextStateParticipant>() { + @Override + public void run(ContextStateParticipant participant) throws Exception { + if (participant.isEnabled()) { + participant.restoreDefaultState(defaultState); + } + } + }); + } + + public void restoreState(IInteractionContext context, InputStream in) { + final ContextState memento = read(context, in); + participants.notify(new Notifier<ContextStateParticipant>() { + @Override + public void run(ContextStateParticipant participant) throws Exception { + if (participant.isEnabled()) { + participant.restoreState(memento); + } + } + }); + } + + public void saveDefaultState() { + participants.notify(new Notifier<ContextStateParticipant>() { + @Override + public void run(ContextStateParticipant participant) throws Exception { + if (participant.isEnabled()) { + participant.saveDefaultState(defaultState); + } + } + }); + } + + public void saveState(IInteractionContext context, OutputStream storable) { + final ContextState memento = createMemento(context, CHARSET); + participants.notify(new Notifier<ContextStateParticipant>() { + @Override + public void run(ContextStateParticipant participant) throws Exception { + if (participant.isEnabled()) { + participant.saveState(memento); + } + } + }); + + write(storable, memento); + } + + public void write(OutputStream out, ContextState memento) { + try { + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, CHARSET)); + try { + memento.getMemento().save(writer); + } finally { + writer.close(); + } + } catch (IOException e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Failed to save context state", e)); //$NON-NLS-1$ + } + } + +} diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextStateParticipant.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextStateParticipant.java new file mode 100644 index 000000000..2788f7962 --- /dev/null +++ b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/ContextStateParticipant.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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.context.ui.state; + +/** + * @author Steffen Pingel + */ +public abstract class ContextStateParticipant { + + public abstract void clearState(String contextHandle, boolean isActiveContext); + + public abstract boolean isEnabled(); + + public abstract void restoreDefaultState(ContextState memento); + + public abstract void restoreState(ContextState memento); + + public abstract void saveDefaultState(ContextState memento); + + public abstract void saveState(ContextState memento); + +} diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/EditorStateParticipant.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/EditorStateParticipant.java new file mode 100644 index 000000000..a9839c261 --- /dev/null +++ b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/EditorStateParticipant.java @@ -0,0 +1,437 @@ +/******************************************************************************* + * 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.context.ui.state; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.util.SafeRunnable; +import org.eclipse.mylyn.commons.core.StatusHandler; +import org.eclipse.mylyn.context.core.ContextCore; +import org.eclipse.mylyn.context.core.IInteractionElement; +import org.eclipse.mylyn.context.ui.ContextAwareEditorInput; +import org.eclipse.mylyn.context.ui.ContextUi; +import org.eclipse.mylyn.context.ui.IContextAwareEditor; +import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; +import org.eclipse.mylyn.internal.context.ui.IContextUiPreferenceContstants; +import org.eclipse.mylyn.monitor.ui.MonitorUi; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.internal.IPreferenceConstants; +import org.eclipse.ui.internal.IWorkbenchConstants; +import org.eclipse.ui.internal.Workbench; +import org.eclipse.ui.internal.WorkbenchPage; + +/** + * @author Mik Kersten + * @author Shawn Minto + */ +public class EditorStateParticipant extends ContextStateParticipant { + + public static final String MEMENTO_EDITORS = "org.eclipse.mylyn.context.ui.editors"; //$NON-NLS-1$ + + private static final String KEY_MONITORED_WINDOW_OPEN_EDITORS = "MonitoredWindowOpenEditors"; //$NON-NLS-1$ + + private static final String ATTRIBUTE_CLASS = "class"; //$NON-NLS-1$ + + private static final String ATTRIBUTE_NUMER = "number"; //$NON-NLS-1$ + + private static final String ATTRIBUTE_IS_LAUNCHING = "isLaunching"; //$NON-NLS-1$ + + private static final String ATTRIBUTE_IS_ACTIVE = "isActive"; //$NON-NLS-1$ + + private boolean previousCloseEditorsSetting = Workbench.getInstance() + .getPreferenceStore() + .getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN); + + private boolean enabled; + + public EditorStateParticipant() { + this.enabled = true; + } + + @Override + public void saveDefaultState(ContextState memento) { + // save platform preference setting + Workbench workbench = (Workbench) PlatformUI.getWorkbench(); + previousCloseEditorsSetting = workbench.getPreferenceStore().getBoolean( + IPreferenceConstants.REUSE_EDITORS_BOOLEAN); + workbench.getPreferenceStore().setValue(IPreferenceConstants.REUSE_EDITORS_BOOLEAN, false); + } + + @Override + public void restoreState(ContextState state) { + if (Workbench.getInstance().isStarting()) { + return; + } + + boolean wasPaused = ContextCore.getContextManager().isContextCapturePaused(); + try { + if (!wasPaused) { + ContextCore.getContextManager().setContextCapturePaused(true); + } + + // restore editors from memento + String mementoString = null; + IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + try { + IMemento memento = state.getMemento(MEMENTO_EDITORS); + if (memento != null) { + IMemento[] children = memento.getChildren(KEY_MONITORED_WINDOW_OPEN_EDITORS); + if (children.length > 0) { + // This code supports restore from multiple windows + for (IMemento child : children) { + WorkbenchPage page = getWorkbenchPageForMemento(child, activeWindow); + if (child != null && page != null) { + restoreEditors(page, child, page.getWorkbenchWindow() == activeWindow); + } + } + } else { + // This code is for supporting the old editor management - only the active window + WorkbenchPage page = (WorkbenchPage) activeWindow.getActivePage(); + if (memento != null) { + restoreEditors(page, memento, true); + } + } + } + } catch (Exception e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, + "Could not restore all editors, memento: \"" + mementoString + "\"", e)); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // refresh window + activeWindow.setActivePage(activeWindow.getActivePage()); + + // open last active context node, guarantees that something is opened even if no editor memento is available + IInteractionElement activeNode = state.getContext().getActiveNode(); + if (activeNode != null) { + ContextUi.getUiBridge(activeNode.getContentType()).open(activeNode); + } + } catch (Exception e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, + "Failed to open editors on activation", e)); //$NON-NLS-1$ + } finally { + ContextCore.getContextManager().setContextCapturePaused(false); + } + } + + private WorkbenchPage getWorkbenchPageForMemento(IMemento memento, IWorkbenchWindow activeWindow) { + String windowToRestoreClassName = memento.getString(ATTRIBUTE_CLASS); + if (windowToRestoreClassName == null) { + windowToRestoreClassName = ""; //$NON-NLS-1$ + } + Integer windowToRestorenumber = memento.getInteger(ATTRIBUTE_NUMER); + if (windowToRestorenumber == null) { + windowToRestorenumber = 0; + } + + // try to match the open windows to the one that we want to restore + Set<IWorkbenchWindow> monitoredWindows = MonitorUi.getMonitoredWindows(); + for (IWorkbenchWindow window : monitoredWindows) { + int windowNumber = getNumber(window); + if (window.getClass().getCanonicalName().equals(windowToRestoreClassName) + && windowNumber == windowToRestorenumber) { + return (WorkbenchPage) window.getActivePage(); + } + } + + // we don't have a good match here, try to make an educated guess + Boolean isActive = memento.getBoolean(ATTRIBUTE_IS_ACTIVE); + if (isActive == null) { + isActive = false; + } + + // both of these defaulting to true should ensure that all editors are opened even if their previous editor is not around + boolean shouldRestoreUnknownWindowToActive = true; // TODO could add a preference here + boolean shouldRestoreActiveWindowToActive = true; // TODO could add a preference here + + if (isActive && shouldRestoreActiveWindowToActive) { + // if the window that we are trying to restore was the active window, restore it to the active window + return (WorkbenchPage) activeWindow.getActivePage(); + } + + if (shouldRestoreUnknownWindowToActive) { + // we can't find a good window, so restore it to the active one + return (WorkbenchPage) activeWindow.getActivePage(); + } + + if (shouldRestoreActiveWindowToActive && shouldRestoreUnknownWindowToActive) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, + "Unable to find window to restore memento to.", new Exception())); //$NON-NLS-1$ + } + + // we dont have a window that will work, so don't restore the editors + // we shouldn't get here if both *WindowToActive booleans are true + return null; + } + + @Override + public void saveState(ContextState state) { + if (PlatformUI.getWorkbench().isClosing()) { + return; + } + + closeContextAwareEditors(state.getContextHandle()); + + IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + IWorkbenchWindow launchingWindow = MonitorUi.getLaunchingWorkbenchWindow(); + Set<IWorkbenchWindow> monitoredWindows = MonitorUi.getMonitoredWindows(); + + try { + IMemento rootMemento = state.createMemento(MEMENTO_EDITORS); + for (IWorkbenchWindow window : monitoredWindows) { + IMemento memento = rootMemento.createChild(KEY_MONITORED_WINDOW_OPEN_EDITORS); + + memento.putString(ATTRIBUTE_CLASS, window.getClass().getCanonicalName()); + int number = getNumber(window); + memento.putInteger(ATTRIBUTE_NUMER, number); + memento.putBoolean(ATTRIBUTE_IS_LAUNCHING, window == launchingWindow); + memento.putBoolean(ATTRIBUTE_IS_ACTIVE, window == activeWindow); + saveEditors_e_3_x((WorkbenchPage) window.getActivePage(), memento); + } + } catch (Exception e) { + // FIXME fall back to workbench API + } + } + + private void saveEditors_e_3_x(WorkbenchPage page, IMemento memento) throws Exception { + Method getEditorManagerMethod = WorkbenchPage.class.getDeclaredMethod("getEditorManager"); + Object editorManager = getEditorManagerMethod.invoke(page); + + Method getEditorsMethod = editorManager.getClass().getDeclaredMethod("saveState", IMemento.class); + getEditorsMethod.invoke(editorManager, memento); + } + + private int getNumber(IWorkbenchWindow window) { + IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows(); + for (int i = 0; i < windows.length; i++) { + if (windows[i] == window) { + return i; + } + } + return 0; + } + + @Override + public void restoreDefaultState(ContextState memento) { + Workbench.getInstance() + .getPreferenceStore() + .setValue(IPreferenceConstants.REUSE_EDITORS_BOOLEAN, previousCloseEditorsSetting); + closeAllEditors(); + } + + @Override + public void clearState(String contextHandle, boolean activeContext) { +// if (activeContext) { +// closeContextAwareEditors(contextHandle); +// } +// Workbench.getInstance() +// .getPreferenceStore() +// .setValue(IPreferenceConstants.REUSE_EDITORS_BOOLEAN, previousCloseEditorsSetting); +// if (activeContext) { +// closeAllEditors(); +// } + if (activeContext) { + closeAllEditors(); + } + } + + /** + * HACK: will fail to restore different parts with same name + */ + private void restoreEditors(WorkbenchPage page, IMemento memento, boolean isActiveWindow) { + final ArrayList<?> visibleEditors = new ArrayList<Object>(5); + final IEditorReference activeEditor[] = new IEditorReference[1]; + final MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, "", null); //$NON-NLS-1$ + + try { + IMemento[] editorMementos = memento.getChildren(IWorkbenchConstants.TAG_EDITOR); + Set<IMemento> editorMementoSet = new LinkedHashSet<IMemento>(); + editorMementoSet.addAll(Arrays.asList(editorMementos)); + // HACK: same parts could have different editors + + try { + restoreEditors_e_3_x(page, visibleEditors, activeEditor, result, editorMementoSet); + } catch (Exception e) { + // FIXME fall back to workbench API + } + + if (activeEditor[0] != null && isActiveWindow) { + IWorkbenchPart editor = activeEditor[0].getPart(true); + if (editor != null) { + page.activate(editor); + } + } + } catch (Exception e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Could not restore editors", e)); //$NON-NLS-1$ + } + } + + private void restoreEditors_e_3_x(WorkbenchPage page, final ArrayList<?> visibleEditors, + final IEditorReference[] activeEditor, final MultiStatus result, Set<IMemento> editorMementoSet) + throws Exception { + Method getEditorManagerMethod = WorkbenchPage.class.getDeclaredMethod("getEditorManager"); + Object editorManager = getEditorManagerMethod.invoke(page); + + Method getEditorsMethod = editorManager.getClass().getDeclaredMethod("getEditors"); + + List<IEditorReference> alreadyVisibleEditors = Arrays.asList((IEditorReference[]) getEditorsMethod.invoke(editorManager)); + Set<String> restoredPartNames = new HashSet<String>(); + for (IEditorReference editorReference : alreadyVisibleEditors) { + restoredPartNames.add(editorReference.getPartName()); + } + + Method restoreEditorStateMethod = editorManager.getClass().getDeclaredMethod("restoreEditorState", + IMemento.class, ArrayList.class, IEditorReference[].class, MultiStatus.class); + + for (IMemento editorMemento : editorMementoSet) { + String partName = editorMemento.getString(IWorkbenchConstants.TAG_PART_NAME); + if (!restoredPartNames.contains(partName)) { + restoreEditorStateMethod.invoke(editorManager, visibleEditors, activeEditor, result); + } else { + restoredPartNames.add(partName); + } + } + + Method setVisibleEditorMethod = editorManager.getClass().getDeclaredMethod("setVisibleEditor", + IEditorReference.class, boolean.class); + for (int i = 0; i < visibleEditors.size(); i++) { + setVisibleEditorMethod.invoke(editorManager, visibleEditors.get(i), false); + } + } + + public void closeContextAwareEditors(String contextHandle) { + try { + if (PlatformUI.getWorkbench().isClosing()) { + return; + } + for (IWorkbenchWindow window : MonitorUi.getMonitoredWindows()) { + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IEditorReference[] references = page.getEditorReferences(); + List<IEditorReference> toClose = new ArrayList<IEditorReference>(); + for (IEditorReference reference : references) { + if (canClose(reference)) { + try { + IEditorInput input = reference.getEditorInput(); + if (shouldForceClose(input, contextHandle)) { + toClose.add(reference); + } + } catch (PartInitException e) { + // ignore + } + } + } + page.closeEditors(toClose.toArray(new IEditorReference[toClose.size()]), true); + } + } + } catch (Throwable t) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Could not auto close editor", t)); //$NON-NLS-1$ + } + } + + public void closeAllEditors() { + try { + if (PlatformUI.getWorkbench().isClosing()) { + return; + } + for (IWorkbenchWindow window : MonitorUi.getMonitoredWindows()) { + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IEditorReference[] references = page.getEditorReferences(); + List<IEditorReference> toClose = new ArrayList<IEditorReference>(); + for (IEditorReference reference : references) { + if (canClose(reference)) { + toClose.add(reference); + } + } + page.closeEditors(toClose.toArray(new IEditorReference[toClose.size()]), true); + } + } + } catch (Throwable t) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, "Could not auto close editor", t)); //$NON-NLS-1$ + } + } + + private boolean shouldForceClose(final IEditorInput input, final String contextHandle) { + final AtomicBoolean result = new AtomicBoolean(); + SafeRunnable.run(new ISafeRunnable() { + public void run() throws Exception { + ContextAwareEditorInput inputContext = (ContextAwareEditorInput) input.getAdapter(ContextAwareEditorInput.class); + result.set(inputContext != null && inputContext.forceClose(contextHandle)); + } + + public void handleException(Throwable e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, + "Failed to verify editor status", e)); //$NON-NLS-1$ + } + }); + return result.get(); + } + + private boolean canClose(final IEditorReference editorReference) { + final IEditorPart editor = editorReference.getEditor(false); + if (editor != null) { + final boolean[] result = new boolean[1]; + result[0] = true; + SafeRunnable.run(new ISafeRunnable() { + public void run() throws Exception { + if (editor instanceof IContextAwareEditor) { + result[0] = ((IContextAwareEditor) editor).canClose(); + } else { + IContextAwareEditor contextAware = (IContextAwareEditor) editor.getAdapter(IContextAwareEditor.class); + if (contextAware != null) { + result[0] = contextAware.canClose(); + } + } + } + + public void handleException(Throwable e) { + StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, + "Failed to verify editor status", e)); //$NON-NLS-1$ + } + }); + return result[0]; + } + return true; + } + + @Override + public boolean isEnabled() { + return enabled + && ContextUiPlugin.getDefault() + .getPreferenceStore() + .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_EDITORS); + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + +} diff --git a/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/PerspectiveStateParticipant.java b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/PerspectiveStateParticipant.java new file mode 100644 index 000000000..6e14fa1c2 --- /dev/null +++ b/org.eclipse.mylyn.context.ui/src/org/eclipse/mylyn/internal/context/ui/state/PerspectiveStateParticipant.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * 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.context.ui.state; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; +import org.eclipse.mylyn.internal.context.ui.IContextUiPreferenceContstants; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.IPerspectiveDescriptor; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * Saves the active perspective on context deactivation and restores it on activation. + * + * @author Mik Kersten + * @author Shawn Minto + * @author Steffen Pingel + */ +public class PerspectiveStateParticipant extends ContextStateParticipant { + + public static final String KEY_ACTIVE_ID = "activeId"; //$NON-NLS-1$ + + public static final String MEMENTO_PERSPECTIVE = "org.eclipse.mylyn.context.ui.perspectives"; //$NON-NLS-1$ + + private final IPreferenceStore preferenceStore; + + public PerspectiveStateParticipant(IPreferenceStore preferenceStore) { + this.preferenceStore = preferenceStore; + } + + @Override + public void clearState(String contextHandle, boolean isActiveContext) { + // ignore + } + + public String getActivePerspectiveId() { + if (PlatformUI.isWorkbenchRunning()) { + IWorkbenchWindow launchingWindow = getWorkbenchWindow(); + if (launchingWindow != null) { + return getActivePerspectiveId(launchingWindow); + } + } + return null; + } + + public IWorkbenchWindow getWorkbenchWindow() { + if (PlatformUI.isWorkbenchRunning()) { + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window == null) { + IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows(); + if (windows.length > 0) { + window = windows[0]; + } + } + return window; + } + return null; + } + + @Override + public boolean isEnabled() { + return ContextUiPlugin.getDefault() + .getPreferenceStore() + .getBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_PERSPECTIVES); + } + + @Override + public void restoreDefaultState(ContextState memento) { + String previousPerspectiveId = getDefaultPerspectiveId(); + showPerspective(previousPerspectiveId); + } + + @Override + public void restoreState(ContextState state) { + IWorkbenchWindow launchingWindow = getWorkbenchWindow(); + if (launchingWindow != null) { + // restore perspective + IMemento memento = state.getMemento(MEMENTO_PERSPECTIVE); + if (memento != null) { + String perspectiveId = memento.getString(KEY_ACTIVE_ID); + showPerspective(perspectiveId); + } + } + } + + @Override + public void saveDefaultState(ContextState memento) { + String id = getActivePerspectiveId(); + if (id != null) { + setDefaultPerspectiveId(id); + } + } + + @Override + public void saveState(ContextState state) { + String id = getActivePerspectiveId(); + if (id != null) { + IMemento memento = state.createMemento(MEMENTO_PERSPECTIVE); + memento.putString(KEY_ACTIVE_ID, id); + } + } + + private String getActivePerspectiveId(IWorkbenchWindow window) { + Assert.isNotNull(window); + IPerspectiveDescriptor descriptor = window.getActivePage().getPerspective(); + return descriptor.getId(); + } + + private String getDefaultPerspectiveId() { + return preferenceStore.getString(IContextUiPreferenceContstants.PERSPECTIVE_NO_ACTIVE_TASK); + } + + private void setDefaultPerspectiveId(String perspectiveId) { + preferenceStore.setValue(IContextUiPreferenceContstants.PERSPECTIVE_NO_ACTIVE_TASK, perspectiveId); + } + + private void showPerspective(String perspectiveId) { + if (perspectiveId != null && perspectiveId.length() > 0) { + IWorkbenchWindow launchingWindow = getWorkbenchWindow(); + if (launchingWindow != null) { + try { + launchingWindow.getShell().setRedraw(false); + PlatformUI.getWorkbench().showPerspective(perspectiveId, launchingWindow); + } catch (Exception e) { + // perspective's preserved id not found, ignore + } finally { + launchingWindow.getShell().setRedraw(true); + } + } + } + } + +} diff --git a/org.eclipse.mylyn.java.tests/META-INF/MANIFEST.MF b/org.eclipse.mylyn.java.tests/META-INF/MANIFEST.MF index 243b4426c..885d01812 100644 --- a/org.eclipse.mylyn.java.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.mylyn.java.tests/META-INF/MANIFEST.MF @@ -24,6 +24,7 @@ Require-Bundle: org.junit, org.eclipse.mylyn.context.core, org.eclipse.mylyn.context.sdk.java, org.eclipse.mylyn.context.sdk.util, + org.eclipse.mylyn.tasks.ui, org.eclipse.mylyn.context.ui, org.eclipse.mylyn.ide.ui, org.eclipse.mylyn.java.ui, diff --git a/org.eclipse.mylyn.java.tests/src/org/eclipse/mylyn/java/tests/AllJavaTests.java b/org.eclipse.mylyn.java.tests/src/org/eclipse/mylyn/java/tests/AllJavaTests.java index 19ec40557..7e7745590 100644 --- a/org.eclipse.mylyn.java.tests/src/org/eclipse/mylyn/java/tests/AllJavaTests.java +++ b/org.eclipse.mylyn.java.tests/src/org/eclipse/mylyn/java/tests/AllJavaTests.java @@ -35,7 +35,6 @@ public class AllJavaTests { suite.addTestSuite(ContentSpecificContextTest.class); suite.addTestSuite(ResourceStructureMappingTest.class); suite.addTestSuite(InterestManipulationTest.class); - suite.addTestSuite(EditorManagerTest.class); suite.addTestSuite(RefactoringTest.class); suite.addTestSuite(ContentOutlineRefreshTest.class); suite.addTestSuite(TypeHistoryManagerTest.class); @@ -55,6 +54,7 @@ public class AllJavaTests { suite.addTestSuite(JavaEditingMonitorTest.class); suite.addTestSuite(JavaStackTraceContextComputationStrategyTest.class); suite.addTestSuite(JavaTaskTemplateVariableResolverTest.class); + suite.addTestSuite(JavaEditorManagerTest.class); return suite; } diff --git a/org.eclipse.mylyn.java.tests/src/org/eclipse/mylyn/java/tests/EditorManagerTest.java b/org.eclipse.mylyn.java.tests/src/org/eclipse/mylyn/java/tests/JavaEditorManagerTest.java index 70ffff7cf..084e4d329 100644 --- a/org.eclipse.mylyn.java.tests/src/org/eclipse/mylyn/java/tests/EditorManagerTest.java +++ b/org.eclipse.mylyn.java.tests/src/org/eclipse/mylyn/java/tests/JavaEditorManagerTest.java @@ -28,13 +28,13 @@ import org.eclipse.mylyn.context.core.IInteractionElement; import org.eclipse.mylyn.context.sdk.java.AbstractJavaContextTest; import org.eclipse.mylyn.context.ui.AbstractContextUiBridge; import org.eclipse.mylyn.context.ui.ContextUi; +import org.eclipse.mylyn.internal.context.core.ContextCorePlugin; import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; import org.eclipse.mylyn.internal.context.ui.IContextUiPreferenceContstants; +import org.eclipse.mylyn.internal.java.ui.ActiveFoldingEditorTracker; import org.eclipse.mylyn.internal.java.ui.JavaStructureBridge; -import org.eclipse.mylyn.internal.tasks.core.AbstractTask; -import org.eclipse.mylyn.internal.tasks.core.LocalTask; +import org.eclipse.mylyn.internal.java.ui.JavaUiBridgePlugin; import org.eclipse.mylyn.monitor.core.InteractionEvent; -import org.eclipse.mylyn.tasks.ui.TasksUiUtil; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; @@ -43,7 +43,7 @@ import org.eclipse.ui.ide.IDE; /** * @author Mik Kersten */ -public class EditorManagerTest extends AbstractJavaContextTest { +public class JavaEditorManagerTest extends AbstractJavaContextTest { private IWorkbenchPage page; @@ -64,13 +64,13 @@ public class EditorManagerTest extends AbstractJavaContextTest { .getPreferenceStore() .setValue(IContextUiPreferenceContstants.AUTO_MANAGE_EDITOR_CLOSE_WARNING, false); UiTestUtil.closeWelcomeView(); + UiTestUtil.closeAllEditors(); } @Override protected void tearDown() throws Exception { super.tearDown(); - ContextUiPlugin.getEditorManager().closeAllEditors(); - + UiTestUtil.closeAllEditors(); ContextUiPlugin.getDefault() .getPreferenceStore() .setValue( @@ -80,39 +80,6 @@ public class EditorManagerTest extends AbstractJavaContextTest { .getDefaultBoolean(IContextUiPreferenceContstants.AUTO_MANAGE_EDITOR_CLOSE_WARNING)); } - // XXX: Put back -// @SuppressWarnings("deprecation") -// public void testAutoOpen() throws JavaModelException, InvocationTargetException, InterruptedException, -// PartInitException { -// // need a task for mementos -// AbstractTask task = new LocalTask(contextId, contextId); -// TasksUiPlugin.getTaskList().addTask(task); -// manager.deleteContext(contextId); -// ResourcesUiBridgePlugin.getEditorManager().closeAllEditors(); -// assertEquals(0, page.getEditors().length); -// -// manager.activateContext(contextId); -// // assertEquals(0, page.getEditors().length); -// -// IType typeA = project.createType(p1, "TypeA.java", "public class TypeA{ }"); -// IType typeB = project.createType(p1, "TypeB.java", "public class TypeB{ }"); -// -// JavaUI.openInEditor(typeA); -// JavaUI.openInEditor(typeB); -// // monitor.selectionChanged(view, new StructuredSelection(typeA)); -// // monitor.selectionChanged(view, new StructuredSelection(typeB)); -// -// assertEquals(2, page.getEditors().length); -// -// manager.deactivateContext(contextId); -// assertEquals(0, page.getEditors().length); -// -// manager.activateContext(contextId); -// // TODO: verify number -// assertEquals(2, page.getEditors().length); -// TasksUiPlugin.getTaskList().deleteTask(task); -// } - public void testInterestCapturedForResourceOnFocus() throws CoreException, InvocationTargetException, InterruptedException { @@ -155,72 +122,32 @@ public class EditorManagerTest extends AbstractJavaContextTest { // MylarContextManager.getScalingFactors().getDecay().setValue(decayFactor); } - // XXX re-enable test -// public void testWaitingListenersDoNotLeakOnEditorActivation() throws JavaModelException { -// manager.deleteContext(contextId); -// ContextUiPlugin.getEditorManager().closeAllEditors(); -// -// int initialNumListeners = manager.getListeners().size(); -// manager.activateContext(contextId); -// assertEquals(initialNumListeners, manager.getListeners().size()); -// -// IType typeA = project.createType(p1, "TypeA.java", "public class TypeA{ }"); -// monitor.selectionChanged(view, new StructuredSelection(typeA)); -// manager.deactivateContext(contextId); -// assertEquals(initialNumListeners, manager.getListeners().size()); -// -// manager.activateContext(contextId); -// assertEquals(initialNumListeners + 1, manager.getListeners().size()); -// manager.deactivateContext(contextId); -// assertEquals(initialNumListeners, manager.getListeners().size()); -// -// manager.activateContext(contextId); -// manager.deactivateContext(contextId); -// assertEquals(initialNumListeners, manager.getListeners().size()); -// -// manager.activateContext(contextId); -// manager.deactivateContext(contextId); -// assertEquals(initialNumListeners, manager.getListeners().size()); -// } + public void testEditorTrackerListenerRegistration() throws JavaModelException { + ActiveFoldingEditorTracker tracker = JavaUiBridgePlugin.getDefault().getEditorTracker(); + assertTrue(tracker.getEditorListenerMap().isEmpty()); - // XXX re-enable test -// public void testEditorTrackerListenerRegistration() throws JavaModelException { -// ContextUiPlugin.getEditorManager().closeAllEditors(); -// -// ActiveFoldingEditorTracker tracker = JavaUiBridgePlugin.getDefault().getEditorTracker(); -// assertTrue(tracker.getEditorListenerMap().isEmpty()); -// -// AbstractContextUiBridge bridge = ContextUi.getUiBridge(JavaStructureBridge.CONTENT_TYPE); -// IMethod m1 = type1.createMethod("void m111() { }", null, true, null); -// monitor.selectionChanged(view, new StructuredSelection(m1)); -// -// int numListeners = ContextCorePlugin.getContextManager().getListeners().size(); -// IInteractionElement element = ContextCore.getContextManager().getElement(type1.getHandleIdentifier()); -// bridge.open(element); -// -// assertEquals(numListeners + 1, ContextCorePlugin.getContextManager().getListeners().size()); -// assertEquals(1, page.getEditorReferences().length); -// assertEquals(1, tracker.getEditorListenerMap().size()); -// ContextUiPlugin.getEditorManager().closeAllEditors(); -// -// assertEquals(numListeners, ContextCorePlugin.getContextManager().getListeners().size()); -// assertEquals(0, page.getEditorReferences().length); -// assertEquals(0, tracker.getEditorListenerMap().size()); -// } + AbstractContextUiBridge bridge = ContextUi.getUiBridge(JavaStructureBridge.CONTENT_TYPE); + IMethod m1 = type1.createMethod("void m111() { }", null, true, null); + monitor.selectionChanged(view, new StructuredSelection(m1)); - public void testActivationPreservesActiveTaskEditor() throws JavaModelException, InvocationTargetException, - InterruptedException { - assertEquals(0, page.getEditorReferences().length); - AbstractTask task = new LocalTask(contextId, contextId); - TasksUiUtil.openTask(task); - assertEquals(1, page.getEditorReferences().length); - manager.activateContext(contextId); + int numListeners = ContextCorePlugin.getContextManager().getListeners().size(); + IInteractionElement element = ContextCore.getContextManager().getElement(type1.getHandleIdentifier()); + bridge.open(element); + + assertEquals(numListeners + 1, ContextCorePlugin.getContextManager().getListeners().size()); assertEquals(1, page.getEditorReferences().length); + assertEquals(1, tracker.getEditorListenerMap().size()); + + UiTestUtil.closeAllEditors(); + + assertEquals(numListeners, ContextCorePlugin.getContextManager().getListeners().size()); + assertEquals(0, page.getEditorReferences().length); + assertEquals(0, tracker.getEditorListenerMap().size()); } @SuppressWarnings("deprecation") public void testAutoCloseWithDecay() throws JavaModelException, InvocationTargetException, InterruptedException { - ContextUiPlugin.getEditorManager().closeAllEditors(); + ContextUiPlugin.getEditorStateParticipant().closeAllEditors(); assertEquals(0, page.getEditors().length); AbstractContextUiBridge bridge = ContextUi.getUiBridge(JavaStructureBridge.CONTENT_TYPE); IMethod m1 = type1.createMethod("void m111() { }", null, true, null); @@ -247,44 +174,4 @@ public class EditorManagerTest extends AbstractJavaContextTest { assertEquals(1, page.getEditors().length); } - @SuppressWarnings("deprecation") - public void testAutoClose() throws JavaModelException, InvocationTargetException, InterruptedException { - ContextUiPlugin.getEditorManager().closeAllEditors(); - assertEquals(0, page.getEditors().length); - AbstractContextUiBridge bridge = ContextUi.getUiBridge(JavaStructureBridge.CONTENT_TYPE); - IMethod m1 = type1.createMethod("void m111() { }", null, true, null); - monitor.selectionChanged(view, new StructuredSelection(m1)); - IInteractionElement element = ContextCore.getContextManager().getElement(type1.getHandleIdentifier()); - bridge.open(element); - - assertEquals(1, page.getEditors().length); - manager.deactivateContext(contextId); - assertEquals(0, page.getEditors().length); - } - - public void testCloseOnUninteresting() { - // fail(); - } - - // private int getNumActiveEditors() { - // return ; - // for (int i = 0; i < page.getEditors().length; i++) { - // IEditorPart editor = page.getEditors()[i]; - - // if (editor instanceof AbstractDecoratedTextEditor) { - // manager.contextDeactivated(contextId, contextId); - // assertEquals(0, page.getEditors().length); - // } - // } - // } - - // assertEquals(1, page.getEditors().length); - // WorkspaceModifyOperation op = new WorkspaceModifyOperation() { - // protected void execute(IProgressMonitor monitor) throws CoreException { - - // } - // }; - // IProgressService service = - // PlatformUI.getWorkbench().getProgressService(); - // service.run(true, true, op); } @@ -73,6 +73,7 @@ <module>org.eclipse.mylyn.context.sdk-feature</module> <module>org.eclipse.mylyn.context.sdk.java</module> <module>org.eclipse.mylyn.context.sdk.util</module> + <module>org.eclipse.mylyn.context.tasks.tests</module> <module>org.eclipse.mylyn.context.tasks.ui</module> <module>org.eclipse.mylyn.context.tests</module> <module>org.eclipse.mylyn.context.ui</module> |