### Eclipse Workspace Patch 1.0 #P org.eclipse.mylyn.tasks.ui Index: src/org/eclipse/mylyn/internal/tasks/ui/messages.properties =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/messages.properties,v retrieving revision 1.12 diff -u -r1.12 messages.properties --- src/org/eclipse/mylyn/internal/tasks/ui/messages.properties 19 Aug 2009 03:43:18 -0000 1.12 +++ src/org/eclipse/mylyn/internal/tasks/ui/messages.properties 12 Sep 2009 17:11:02 -0000 @@ -19,6 +19,9 @@ http://bugs.eclipse.org/bugs/enter_bug.cgi?product=Mylyn\n\ \n\ Or via the popup menu in the Error Log view (see Window -> Show View) +DownloadAndOpenTaskAttachmentJob_cannotOpenEditor=Cannot open editor +DownloadAndOpenTaskAttachmentJob_editorTooltip=Attachment from {0}, {1} +DownloadAndOpenTaskAttachmentJob_failedToDownloadAttachment=Failed to download attachment MoveToCategoryMenuContributor_Move_to=Move to @@ -37,6 +40,8 @@ ScheduleTaskMenuContributor_Not_Scheduled=Not Scheduled ScheduleTaskMenuContributor_Schedule_for=Schedule for +TaskAttachmentEditorViewer_openingAttachment=Opening attachment {0} +TaskAttachmentViewerBrowser_browser=Browser TaskHistoryDropDown_Activate_Task_=Activate Task... TaskHistoryDropDown_Deactivate_Task=Deactivate Task @@ -82,3 +87,4 @@ TaskHyperlink_Open_Task_X_in_X=Open Task {0} in {1} AbstractRetrieveTitleFromUrlJob_Retrieving_summary_from_URL=Retrieving summary from URL +FileStorage_unableToReadAttachmentFile=Unable to read attachment file Index: src/org/eclipse/mylyn/internal/tasks/ui/ITasksUiPreferenceConstants.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/ITasksUiPreferenceConstants.java,v retrieving revision 1.10 diff -u -r1.10 ITasksUiPreferenceConstants.java --- src/org/eclipse/mylyn/internal/tasks/ui/ITasksUiPreferenceConstants.java 24 Jul 2009 12:05:46 -0000 1.10 +++ src/org/eclipse/mylyn/internal/tasks/ui/ITasksUiPreferenceConstants.java 12 Sep 2009 17:11:02 -0000 @@ -83,4 +83,6 @@ public static final String PREF_DATA_DIR = "org.eclipse.mylyn.data.dir"; //$NON-NLS-1$ public static final String DEFAULT_ATTACHMENTS_DIRECTORY = "org.eclipse.mylyn.tasks.ui.attachments.defaultDirectory"; //$NON-NLS-1$ + + public static final String PREFERRED_TASK_ATTACHMENT_VIEWER_ID = "org.eclipse.mylyn.tasks.ui.attachments.preferredViewerID"; //$NON-NLS-1$ } Index: src/org/eclipse/mylyn/internal/tasks/ui/Messages.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/Messages.java,v retrieving revision 1.7 diff -u -r1.7 Messages.java --- src/org/eclipse/mylyn/internal/tasks/ui/Messages.java 24 Jul 2009 12:05:46 -0000 1.7 +++ src/org/eclipse/mylyn/internal/tasks/ui/Messages.java 12 Sep 2009 17:11:02 -0000 @@ -35,6 +35,12 @@ public static String DialogErrorReporter_Please_report_the_following_error_at; + public static String DownloadAndOpenTaskAttachmentJob_cannotOpenEditor; + + public static String DownloadAndOpenTaskAttachmentJob_editorTooltip; + + public static String DownloadAndOpenTaskAttachmentJob_failedToDownloadAttachment; + public static String MoveToCategoryMenuContributor_Move_to; public static String OpenRepositoryTaskJob_Could_not_find_repository_configuration_for_X; @@ -61,6 +67,10 @@ public static String ScheduleTaskMenuContributor_Schedule_for; + public static String TaskAttachmentEditorViewer_openingAttachment; + + public static String TaskAttachmentViewerBrowser_browser; + public static String TaskHistoryDropDown_Activate_Task_; public static String TaskHistoryDropDown_Deactivate_Task; @@ -127,4 +137,6 @@ public static String AbstractRetrieveTitleFromUrlJob_Retrieving_summary_from_URL; + public static String FileStorage_unableToReadAttachmentFile; + } Index: src/org/eclipse/mylyn/internal/tasks/ui/actions/SaveAttachmentsAction.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/actions/SaveAttachmentsAction.java,v retrieving revision 1.1 diff -u -r1.1 SaveAttachmentsAction.java --- src/org/eclipse/mylyn/internal/tasks/ui/actions/SaveAttachmentsAction.java 28 May 2009 09:13:39 -0000 1.1 +++ src/org/eclipse/mylyn/internal/tasks/ui/actions/SaveAttachmentsAction.java 12 Sep 2009 17:11:02 -0000 @@ -35,16 +35,6 @@ */ public class SaveAttachmentsAction extends Action { - private static final String ATTACHMENT_DEFAULT_NAME = "attachment"; //$NON-NLS-1$ - - private static final String CTYPE_ZIP = "zip"; //$NON-NLS-1$ - - private static final String CTYPE_OCTET_STREAM = "octet-stream"; //$NON-NLS-1$ - - private static final String CTYPE_TEXT = "text"; //$NON-NLS-1$ - - private static final String CTYPE_HTML = "html"; //$NON-NLS-1$ - public SaveAttachmentsAction(String text) { super(text); } @@ -66,7 +56,7 @@ */ private void saveSingleAttachment(ITaskAttachment attachment) { FileDialog fileChooser = new FileDialog(WorkbenchUtil.getShell(), SWT.SAVE); - fileChooser.setFileName(getAttachmentFilename(attachment)); + fileChooser.setFileName(AttachmentUtil.getAttachmentFilename(attachment)); File initDirectory = getInitialDirectory(); if (initDirectory != null) { @@ -123,7 +113,7 @@ } for (ITaskAttachment attachment : attachments) { - String filename = getAttachmentFilename(attachment); + String filename = AttachmentUtil.getAttachmentFilename(attachment); File file = getTargetFile(WorkbenchUtil.getShell(), directory, filename); if (file != null) { DownloadAttachmentJob job = new DownloadAttachmentJob(attachment, file); @@ -160,26 +150,6 @@ } } - private String getAttachmentFilename(ITaskAttachment attachment) { - String fname = attachment.getFileName(); - // default name if none is found - if (fname.equals("")) { //$NON-NLS-1$ - String ctype = attachment.getContentType(); - if (ctype.endsWith(CTYPE_HTML)) { - fname = ATTACHMENT_DEFAULT_NAME + ".html"; //$NON-NLS-1$ - } else if (ctype.startsWith(CTYPE_TEXT)) { - fname = ATTACHMENT_DEFAULT_NAME + ".txt"; //$NON-NLS-1$ - } else if (ctype.endsWith(CTYPE_OCTET_STREAM)) { - fname = ATTACHMENT_DEFAULT_NAME; - } else if (ctype.endsWith(CTYPE_ZIP)) { - fname = ATTACHMENT_DEFAULT_NAME + "." + CTYPE_ZIP; //$NON-NLS-1$ - } else { - fname = ATTACHMENT_DEFAULT_NAME + "." + ctype.substring(ctype.indexOf("/") + 1); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - return fname; - } - private File getInitialDirectory() { String dirName = TasksUiPlugin.getDefault().getPreferenceStore().getString( ITasksUiPreferenceConstants.DEFAULT_ATTACHMENTS_DIRECTORY); Index: src/org/eclipse/mylyn/internal/tasks/ui/util/AttachmentUtil.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/util/AttachmentUtil.java,v retrieving revision 1.14 diff -u -r1.14 AttachmentUtil.java --- src/org/eclipse/mylyn/internal/tasks/ui/util/AttachmentUtil.java 27 Aug 2009 00:32:33 -0000 1.14 +++ src/org/eclipse/mylyn/internal/tasks/ui/util/AttachmentUtil.java 12 Sep 2009 17:11:02 -0000 @@ -70,6 +70,16 @@ private static final String CONTEXT_CONTENT_TYPE = "application/octet-stream"; //$NON-NLS-1$ + private static final String ATTACHMENT_DEFAULT_NAME = "attachment"; //$NON-NLS-1$ + + private static final String CTYPE_ZIP = "zip"; //$NON-NLS-1$ + + private static final String CTYPE_OCTET_STREAM = "octet-stream"; //$NON-NLS-1$ + + private static final String CTYPE_TEXT = "text"; //$NON-NLS-1$ + + private static final String CTYPE_HTML = "html"; //$NON-NLS-1$ + public static boolean postContext(AbstractRepositoryConnector connector, TaskRepository repository, ITask task, String comment, TaskAttribute attribute, IProgressMonitor monitor) throws CoreException { AbstractTaskAttachmentHandler attachmentHandler = connector.getTaskAttachmentHandler(); @@ -307,4 +317,26 @@ } return Collections.emptyList(); } + + public static String getAttachmentFilename(ITaskAttachment attachment) { + String name = attachment.getFileName(); + // if no filename is set, make one up with the proper extension so + // we can support opening in that filetype's default editor + if (name == null || "".equals(name)) { //$NON-NLS-1$ + String ctype = attachment.getContentType(); + if (ctype.endsWith(CTYPE_HTML)) { + name = ATTACHMENT_DEFAULT_NAME + ".html"; //$NON-NLS-1$ + } else if (ctype.startsWith(CTYPE_TEXT)) { + name = ATTACHMENT_DEFAULT_NAME + ".txt"; //$NON-NLS-1$ + } else if (ctype.endsWith(CTYPE_OCTET_STREAM)) { + name = ATTACHMENT_DEFAULT_NAME; + } else if (ctype.endsWith(CTYPE_ZIP)) { + name = ATTACHMENT_DEFAULT_NAME + "." + CTYPE_ZIP; //$NON-NLS-1$ + } else { + name = ATTACHMENT_DEFAULT_NAME + "." + ctype.substring(ctype.indexOf("/") + 1); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + return name; + } } Index: src/org/eclipse/mylyn/internal/tasks/ui/commands/Messages.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/Messages.java,v retrieving revision 1.1 diff -u -r1.1 Messages.java --- src/org/eclipse/mylyn/internal/tasks/ui/commands/Messages.java 5 Dec 2008 01:12:49 -0000 1.1 +++ src/org/eclipse/mylyn/internal/tasks/ui/commands/Messages.java 12 Sep 2009 17:11:02 -0000 @@ -29,6 +29,10 @@ public static String NewLocalTaskHandler_Could_not_create_local_task; + public static String OpenTaskAttachmentHandler_failedToOpenViewer; + + public static String OpenTaskAttachmentHandler_noAttachmentViewerFound; + public static String OpenTaskAttachmentInDefaultEditorHandler_Failed_to_open_editor; public static String OpenTaskAttachmentInDefaultEditorHandler_No_default_editor_for_X_found; Index: src/org/eclipse/mylyn/internal/tasks/ui/commands/messages.properties =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/messages.properties,v retrieving revision 1.2 diff -u -r1.2 messages.properties --- src/org/eclipse/mylyn/internal/tasks/ui/commands/messages.properties 24 Jul 2009 12:05:46 -0000 1.2 +++ src/org/eclipse/mylyn/internal/tasks/ui/commands/messages.properties 12 Sep 2009 17:11:02 -0000 @@ -12,6 +12,8 @@ NewLocalTaskHandler_Could_not_create_local_task=Could not create local task +OpenTaskAttachmentHandler_failedToOpenViewer=Failed to open attachment viewer +OpenTaskAttachmentHandler_noAttachmentViewerFound=No suitable attachment viewer found OpenTaskAttachmentInDefaultEditorHandler_Failed_to_open_editor=Failed to open editor OpenTaskAttachmentInDefaultEditorHandler_No_default_editor_for_X_found=No default editor for "{0}" found OpenTaskAttachmentInDefaultEditorHandler_Open_Attachment_Failed=Open Attachment Failed Index: src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInDefaultEditorHandler.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInDefaultEditorHandler.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInDefaultEditorHandler.java --- src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInDefaultEditorHandler.java 5 Dec 2008 01:12:49 -0000 1.6 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,78 +0,0 @@ -/******************************************************************************* - * 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.tasks.ui.commands; - -import java.text.MessageFormat; -import java.util.List; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; -import org.eclipse.mylyn.internal.tasks.ui.editors.TaskAttachmentEditorInput; -import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; -import org.eclipse.mylyn.tasks.core.ITaskAttachment; -import org.eclipse.ui.IEditorDescriptor; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.handlers.HandlerUtil; - -/** - * @author Steffen Pingel - */ -public class OpenTaskAttachmentInDefaultEditorHandler extends AbstractHandler { - - public Object execute(ExecutionEvent event) throws ExecutionException { - IWorkbenchPage page = null; - ISelection selection = HandlerUtil.getCurrentSelection(event); - if (selection instanceof IStructuredSelection) { - List items = ((IStructuredSelection) selection).toList(); - for (Object item : items) { - if (item instanceof ITaskAttachment) { - if (page == null) { - IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event); - page = window.getActivePage(); - if (page == null) { - throw new ExecutionException("No active workbench page"); //$NON-NLS-1$ - } - } - openAttachment(page, (ITaskAttachment) item); - } - } - } - return null; - } - - private void openAttachment(IWorkbenchPage page, ITaskAttachment attachment) throws ExecutionException { - TaskAttachmentEditorInput input = new TaskAttachmentEditorInput(attachment); - IEditorDescriptor description = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(input.getName()); - if (description == null) { - TasksUiInternal.displayStatus(Messages.OpenTaskAttachmentInDefaultEditorHandler_Open_Attachment_Failed, - new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, MessageFormat.format( - Messages.OpenTaskAttachmentInDefaultEditorHandler_No_default_editor_for_X_found, - input.getName()))); - } else { - try { - page.openEditor(input, description.getId()); - } catch (PartInitException e) { - throw new ExecutionException(Messages.OpenTaskAttachmentInDefaultEditorHandler_Failed_to_open_editor, e); - } - } - } - -} Index: plugin.xml =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/plugin.xml,v retrieving revision 1.367 diff -u -r1.367 plugin.xml --- plugin.xml 11 Sep 2009 04:33:43 -0000 1.367 +++ plugin.xml 12 Sep 2009 17:11:02 -0000 @@ -1281,8 +1281,8 @@ + id="org.eclipse.mylyn.tasks.ui.command.attachment.open" + name="%command.attachment.open.name"> - - - - + class="org.eclipse.mylyn.internal.tasks.ui.commands.OpenTaskAttachmentHandler" + commandId="org.eclipse.mylyn.tasks.ui.command.attachment.open"> - - + + + + + + + + attachments = new ArrayList(); + + StructuredSelection selection = (StructuredSelection) event.getSelection(); + + List items = selection.toList(); + for (Object item : items) { + if (item instanceof ITaskAttachment) { + attachments.add((ITaskAttachment) item); + } + } + + if (attachments.isEmpty()) { + return; + } + + IWorkbenchPage page = getTaskEditorPage().getSite().getWorkbenchWindow().getActivePage(); + + OpenTaskAttachmentHandler.openAttachments(page, attachments); + } } Index: src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentStorage.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentStorage.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentStorage.java --- src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentStorage.java 5 Dec 2008 23:25:50 -0000 1.4 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,122 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2008 Jeff Pound 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: - * Jeff Pound - initial API and implementation - * Tasktop Technologies - improvements - *******************************************************************************/ - -package org.eclipse.mylyn.internal.tasks.ui.editors; - -import java.io.InputStream; - -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.PlatformObject; -import org.eclipse.core.runtime.Status; -import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; -import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; -import org.eclipse.mylyn.tasks.core.ITask; -import org.eclipse.mylyn.tasks.core.ITaskAttachment; -import org.eclipse.mylyn.tasks.core.TaskRepository; -import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentHandler; -import org.eclipse.mylyn.tasks.core.data.TaskAttribute; -import org.eclipse.mylyn.tasks.ui.TasksUi; - -/** - * @author Jeff Pound - * @author Steffen Pingel - */ -public class TaskAttachmentStorage extends PlatformObject implements IStorage { - - private static final String ATTACHMENT_DEFAULT_NAME = "attachment"; //$NON-NLS-1$ - - private static final String CTYPE_ZIP = "zip"; //$NON-NLS-1$ - - private static final String CTYPE_OCTET_STREAM = "octet-stream"; //$NON-NLS-1$ - - private static final String CTYPE_TEXT = "text"; //$NON-NLS-1$ - - private static final String CTYPE_HTML = "html"; //$NON-NLS-1$ - - private final TaskRepository taskRepository; - - private final ITask task; - - private final TaskAttribute attachmentAttribute; - - private final String name; - - public TaskAttachmentStorage(TaskRepository taskRepository, ITask task, TaskAttribute attachmentAttribute, - String name) { - this.taskRepository = taskRepository; - this.task = task; - this.attachmentAttribute = attachmentAttribute; - this.name = name; - } - - public static IStorage create(ITaskAttachment attachment) throws CoreException { - Assert.isNotNull(attachment); - TaskAttribute taskAttribute = attachment.getTaskAttribute(); - if (taskAttribute == null) { - throw new CoreException(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Failed to find attachment: " //$NON-NLS-1$ - + attachment.getUrl())); - } - return new TaskAttachmentStorage(attachment.getTaskRepository(), attachment.getTask(), taskAttribute, - getName(attachment)); - } - - private static String getName(ITaskAttachment attachment) { - String name = attachment.getFileName(); - // if no filename is set, make one up with the proper extension so - // we can support opening in that filetype's default editor - if (name == null || "".equals(name)) { //$NON-NLS-1$ - String ctype = attachment.getContentType(); - if (ctype.endsWith(CTYPE_HTML)) { - name = ATTACHMENT_DEFAULT_NAME + ".html"; //$NON-NLS-1$ - } else if (ctype.startsWith(CTYPE_TEXT)) { - name = ATTACHMENT_DEFAULT_NAME + ".txt"; //$NON-NLS-1$ - } else if (ctype.endsWith(CTYPE_OCTET_STREAM)) { - name = ATTACHMENT_DEFAULT_NAME; - } else if (ctype.endsWith(CTYPE_ZIP)) { - name = ATTACHMENT_DEFAULT_NAME + "." + CTYPE_ZIP; //$NON-NLS-1$ - } else { - name = ATTACHMENT_DEFAULT_NAME + "." + ctype.substring(ctype.indexOf("/") + 1); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - // treat .patch files as text files - if (name.endsWith(".patch")) { //$NON-NLS-1$ - name += ".txt"; //$NON-NLS-1$ - } - return name; - } - - public InputStream getContents() throws CoreException { - AbstractRepositoryConnector connector = TasksUi.getRepositoryManager().getRepositoryConnector( - taskRepository.getConnectorKind()); - AbstractTaskAttachmentHandler handler = connector.getTaskAttachmentHandler(); - return handler.getContent(taskRepository, task, attachmentAttribute, new NullProgressMonitor()); - } - - public IPath getFullPath() { - // ignore - return null; - } - - public String getName() { - return name; - } - - public boolean isReadOnly() { - return true; - } - -} \ No newline at end of file Index: src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentEditorInput.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentEditorInput.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentEditorInput.java --- src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentEditorInput.java 13 Sep 2008 03:28:17 -0000 1.7 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2008 Jeff Pound 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: - * Jeff Pound - initial API and implementation - * Tasktop Technologies - improvements - *******************************************************************************/ - -package org.eclipse.mylyn.internal.tasks.ui.editors; - -import org.eclipse.core.resources.IStorage; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.PlatformObject; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.mylyn.tasks.core.ITaskAttachment; -import org.eclipse.ui.IPersistableElement; -import org.eclipse.ui.IStorageEditorInput; - -/** - * @author Jeff Pound - * @author Steffen Pingel - */ -public class TaskAttachmentEditorInput extends PlatformObject implements IStorageEditorInput { - - private final ITaskAttachment attachment; - - public TaskAttachmentEditorInput(ITaskAttachment attachment) { - this.attachment = attachment; - } - - public boolean exists() { - return true; - } - - public ImageDescriptor getImageDescriptor() { - // ignore - return null; - } - - public String getName() { - return attachment.getFileName(); - } - - public IPersistableElement getPersistable() { - return null; - } - - public String getToolTipText() { - return attachment.getUrl(); - } - - public IStorage getStorage() throws CoreException { - return TaskAttachmentStorage.create(attachment); - } -} Index: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerBrowser.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerBrowser.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerBrowser.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerBrowser.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,19 @@ +package org.eclipse.mylyn.internal.tasks.ui; + +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.mylyn.tasks.ui.TasksUiUtil; +import org.eclipse.ui.IWorkbenchPage; + +public class TaskAttachmentViewerBrowser implements ITaskAttachmentViewer { + public String getID() { + return "inBrowserViewer"; //$NON-NLS-1$ + } + + public String getLabel() { + return Messages.TaskAttachmentViewerBrowser_browser; + } + + public void openAttachment(IWorkbenchPage page, ITaskAttachment attachment) { + TasksUiUtil.openUrl(attachment.getUrl()); + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentWithMenu.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentWithMenu.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentWithMenu.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentWithMenu.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2009 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui.commands; + +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.mylyn.internal.tasks.ui.ITaskAttachmentViewer; +import org.eclipse.mylyn.internal.tasks.ui.TaskAttachmentViewersManager; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +public class OpenTaskAttachmentWithMenu extends ContributionItem { + private final TaskAttachmentViewersManager manager = new TaskAttachmentViewersManager(); + + public OpenTaskAttachmentWithMenu() { + } + + public OpenTaskAttachmentWithMenu(String id) { + super(id); + } + + @Override + public void fill(Menu menu, int index) { + List attachments = AttachmentUtil.getSelectedAttachments(); + if (attachments.isEmpty() || attachments.size() > 1) { + return; + } + + // find all interesting editors, and add them into menu + ITaskAttachment at = attachments.get(0); + + String prefViewerID = manager.getPreferredViewerID(at); + + int i = 0; + + List viewers = manager.getTaskAttachmentViewers(at); + for (ITaskAttachmentViewer v : viewers) { + MenuItem it = new MenuItem(menu, SWT.RADIO, index + i); + + it.setText(v.getLabel()); + it.addSelectionListener(new RunAssociatedViewer(it, v)); + if (prefViewerID != null && prefViewerID.equals(v.getID())) { + it.setSelection(true); + } + + i++; + } + } + + private class RunAssociatedViewer extends SelectionAdapter { + private final MenuItem menuItem; + + private final ITaskAttachmentViewer viewer; + + RunAssociatedViewer(MenuItem item, ITaskAttachmentViewer handler) { + this.menuItem = item; + this.viewer = handler; + } + + @Override + public void widgetSelected(SelectionEvent e) { + // this event is fired also for item which gets unselected (i.e. previous 'preferred' viewer) + if (!menuItem.getSelection()) { + return; + } + + IWorkbench wb = PlatformUI.getWorkbench(); + + IWorkbenchWindow win = wb.getActiveWorkbenchWindow(); + if (win == null) { + return; + } + + IWorkbenchPage page = win.getActivePage(); + if (page == null) { + return; + } + + List attachments = AttachmentUtil.getSelectedAttachments(); + for (ITaskAttachment ta : attachments) { + manager.savePreferredViewerID(ta, viewer.getID()); + + try { + viewer.openAttachment(page, ta); + } catch (CoreException ex) { + TasksUiInternal.logAndDisplayStatus(Messages.OpenTaskAttachmentHandler_failedToOpenViewer, + ex.getStatus()); + } + } + } + } + + @Override + public boolean isDynamic() { + // menu depends on selected attachment(s) + return true; + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentEditorViewer.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentEditorViewer.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentEditorViewer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentEditorViewer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2009 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui; + +import java.text.MessageFormat; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IWorkbenchPage; + +public class TaskAttachmentEditorViewer implements ITaskAttachmentViewer { + private final IEditorDescriptor descriptor; + + TaskAttachmentEditorViewer(IEditorDescriptor descriptor) { + this.descriptor = descriptor; + } + + public String getID() { + return descriptor.getId(); + } + + public String getLabel() { + return descriptor.getLabel(); + } + + public void openAttachment(IWorkbenchPage page, ITaskAttachment attachment) throws CoreException { + DownloadAndOpenTaskAttachmentJob job = new DownloadAndOpenTaskAttachmentJob( + MessageFormat.format(Messages.TaskAttachmentEditorViewer_openingAttachment, + AttachmentUtil.getAttachmentFilename(attachment)), attachment, page, descriptor.getId()); + job.setUser(true); + job.schedule(); + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/DownloadAndOpenTaskAttachmentJob.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/DownloadAndOpenTaskAttachmentJob.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/DownloadAndOpenTaskAttachmentJob.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/DownloadAndOpenTaskAttachmentJob.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2009 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.tasks.core.ITask; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.ui.AbstractRepositoryConnectorUi; +import org.eclipse.mylyn.tasks.ui.TasksUi; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; + +class DownloadAndOpenTaskAttachmentJob extends Job { + private final ITaskAttachment attachment; + + private final IWorkbenchPage page; + + private final String editorID; + + DownloadAndOpenTaskAttachmentJob(String jobName, ITaskAttachment attachment, IWorkbenchPage page, String editorID) { + super(jobName); + + this.attachment = attachment; + this.page = page; + this.editorID = editorID; + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + final String attachmentFilename = AttachmentUtil.getAttachmentFilename(attachment); + + File file = null; + try { + // create temporary filename like 'attach-127562364-attachment-name.txt' + // This has correct extension based on attachment filename, resembles attachment name, but + // also indicates that it is temporary file + file = File.createTempFile("tmpattach-", "-" + attachmentFilename); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (IOException e) { + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + Messages.DownloadAndOpenTaskAttachmentJob_failedToDownloadAttachment, e); + } + file.deleteOnExit(); + + boolean ok = false; + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file); + AttachmentUtil.downloadAttachment(attachment, fos, monitor); + ok = true; + + } catch (IOException e) { + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + Messages.DownloadAndOpenTaskAttachmentJob_failedToDownloadAttachment, e); + } catch (CoreException e) { + int s = IStatus.ERROR; + if (e.getStatus() != null && e.getStatus().getCode() == IStatus.CANCEL) { + s = IStatus.CANCEL; + } + return new Status(s, TasksUiPlugin.ID_PLUGIN, + Messages.DownloadAndOpenTaskAttachmentJob_failedToDownloadAttachment, e); + } catch (OperationCanceledException e) { + return new Status(IStatus.CANCEL, TasksUiPlugin.ID_PLUGIN, + Messages.DownloadAndOpenTaskAttachmentJob_failedToDownloadAttachment, e); + } finally { + // (fos != null) only when there is some problem, in other cases we nulled fos already + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + if (ok) { + file.delete(); + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + Messages.DownloadAndOpenTaskAttachmentJob_failedToDownloadAttachment, e); + } + } + } + + if (!ok) { + file.delete(); + } + } + + // mark file read-only to warn user that he is working with local copy + file.setReadOnly(); + + Display disp = page.getWorkbenchWindow().getWorkbench().getDisplay(); + if (disp.isDisposed()) { + return new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, + Messages.DownloadAndOpenTaskAttachmentJob_cannotOpenEditor); + } + + if (disp.getThread() == Thread.currentThread()) { + return openEditor(file, attachmentFilename); + } else { + final AtomicReference status = new AtomicReference(); + final File tmpFile = file; + + disp.syncExec(new Runnable() { + public void run() { + status.set(openEditor(tmpFile, attachmentFilename)); + }; + }); + + if (status.get() == null) { + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + Messages.DownloadAndOpenTaskAttachmentJob_cannotOpenEditor); + } + + return status.get(); + } + } + + IStatus openEditor(File file, String attachmentName) { + try { + String taskLabel = getTaskLabel(attachment.getTask()); + String repoLabel = getRepositoryLabel(attachment.getTask()); + + String tooltip = MessageFormat.format(Messages.DownloadAndOpenTaskAttachmentJob_editorTooltip, taskLabel, repoLabel); + + page.openEditor(new FileEditorInput(file, attachmentName, tooltip), editorID); + return Status.OK_STATUS; + } catch (PartInitException e) { + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + Messages.DownloadAndOpenTaskAttachmentJob_cannotOpenEditor, e); + } + } + + private String getTaskLabel(ITask task) { + AbstractRepositoryConnectorUi connectorUi = TasksUiPlugin.getConnectorUi(task.getConnectorKind()); + StringBuilder taskLabel = new StringBuilder(); + if (connectorUi != null) { + taskLabel.append(connectorUi.getTaskKindLabel(task)); + } + + String key = task.getTaskKey(); + if (key != null) { + if (taskLabel.length() > 0) { + taskLabel.append(" "); //$NON-NLS-1$ + } + taskLabel.append(key); + } + return taskLabel.toString(); + } + + // copied from TaskListToolTip + private String getRepositoryLabel(ITask task) { + String repositoryKind = task.getConnectorKind(); + String repositoryUrl = task.getRepositoryUrl(); + + TaskRepository repository = TasksUi.getRepositoryManager().getRepository(repositoryKind, repositoryUrl); + if (repository != null) { + String label = repository.getRepositoryLabel(); + if (label.indexOf("//") != -1) { //$NON-NLS-1$ + return label.substring((repository.getRepositoryUrl().indexOf("//") + 2)); //$NON-NLS-1$ + } + return label; + } + return ""; //$NON-NLS-1$ + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/FileEditorInput.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/FileEditorInput.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/FileEditorInput.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/FileEditorInput.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2009 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui; + +import java.io.File; + +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IPathEditorInput; +import org.eclipse.ui.IPersistableElement; +import org.eclipse.ui.IStorageEditorInput; + +class FileEditorInput extends PlatformObject implements IPathEditorInput, IStorageEditorInput { + private final File file; + + private final String name; + + private final String tooltipText; + + FileEditorInput(File file, String name, String tooltipText) { + this.file = file; + this.name = name; + this.tooltipText = tooltipText; + } + + public IPath getPath() { + return Path.fromOSString(file.getAbsolutePath()); + } + + public boolean exists() { + return file.exists(); + } + + public ImageDescriptor getImageDescriptor() { + return null; + } + + public String getName() { + return name; + } + + public IPersistableElement getPersistable() { + // ignore + return null; + } + + public String getToolTipText() { + return tooltipText; + } + + public IStorage getStorage() throws CoreException { + return new FileStorage(file, name); + } + + @Override + public int hashCode() { + return file.hashCode() ^ name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof FileEditorInput)) { + return false; + } + + FileEditorInput other = (FileEditorInput) obj; + return name.equals(other.name) && file.equals(other.file); + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewersManager.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewersManager.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewersManager.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewersManager.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2009 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IEditorRegistry; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.editors.text.EditorsUI; + +public class TaskAttachmentViewersManager { + public List getTaskAttachmentViewers(ITaskAttachment attachment) { + IEditorRegistry er = PlatformUI.getWorkbench().getEditorRegistry(); + + List result = new ArrayList(); + IEditorDescriptor defaultEditor = er.getDefaultEditor(AttachmentUtil.getAttachmentFilename(attachment)); + if (defaultEditor != null) { + result.add(new TaskAttachmentEditorViewer(defaultEditor)); + } + + if (attachment.getUrl() != null && attachment.getUrl().trim().length() > 0) { + result.add(new TaskAttachmentViewerBrowser()); + } + + IEditorDescriptor defaultTextEditor = er.findEditor(EditorsUI.DEFAULT_TEXT_EDITOR_ID); // may be null + if (defaultTextEditor != null + && (defaultEditor == null || !defaultTextEditor.getId().equals(defaultEditor.getId()))) { + result.add(new TaskAttachmentEditorViewer(defaultTextEditor)); + } + + IEditorDescriptor[] descriptors = er.getEditors(AttachmentUtil.getAttachmentFilename(attachment)); + for (IEditorDescriptor ied : descriptors) { + if (defaultEditor == null || !ied.getId().equals(defaultEditor.getId())) { + result.add(new TaskAttachmentEditorViewer(ied)); + } + } + + // Don't check whether system external editor is available (IEditorRegistry.isSystemExternalEditorAvailable) ... + // At least Windows can handle even unknown files, and offers user to choose correct program to open file with + IEditorDescriptor extern = er.findEditor(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID); + result.add(new TaskAttachmentEditorViewer(extern)); + + if (er.isSystemInPlaceEditorAvailable(AttachmentUtil.getAttachmentFilename(attachment))) { + IEditorDescriptor inplace = er.findEditor(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID); + result.add(new TaskAttachmentEditorViewer(inplace)); + } + + return result; + } + + /** + * @param attachment + * @return preferred attachment viewers, or null if no suitable viewer can be found + */ + public ITaskAttachmentViewer getPreferredViewer(ITaskAttachment attachment) { + List viewers = getTaskAttachmentViewers(attachment); + + String preferred = getPreferredViewerID(attachment); + if (preferred != null) { + for (int i = 0; i < viewers.size(); i++) { + if (preferred.equals(viewers.get(i).getID())) { + return viewers.get(i); + } + } + } + + if (viewers.isEmpty()) { + return null; + } + + return viewers.get(0); + } + + public String getPreferredViewerID(ITaskAttachment attachment) { + String ext = getExtension(attachment); + if (ext == null) { + return null; + } + + return TasksUiPlugin.getDefault().getPreferenceStore().getString( + ITasksUiPreferenceConstants.PREFERRED_TASK_ATTACHMENT_VIEWER_ID + "_" + ext); //$NON-NLS-1$ + } + + public void savePreferredViewerID(ITaskAttachment attachment, String handlerID) { + String ext = getExtension(attachment); + if (ext == null) { + return; + } + + TasksUiPlugin.getDefault().getPreferenceStore().putValue( + ITasksUiPreferenceConstants.PREFERRED_TASK_ATTACHMENT_VIEWER_ID + "_" + ext, handlerID); //$NON-NLS-1$ + } + + private String getExtension(ITaskAttachment attachment) { + if (attachment == null) { + return null; + } + + String fname = AttachmentUtil.getAttachmentFilename(attachment); + int dot = fname.lastIndexOf('.'); + if (dot < 0) { + return null; + } + + return fname.substring(dot + 1); + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/ITaskAttachmentViewer.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/ITaskAttachmentViewer.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/ITaskAttachmentViewer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/ITaskAttachmentViewer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.ui.IWorkbenchPage; + +/** + * Simple interface for attachment 'viewers'. Most viewers are based on existing eclipse editors. + */ +public interface ITaskAttachmentViewer { + /** + * @return arbitrary string, used to remember preferred viewer + */ + public String getID(); + + /** + * @return name of the editor, displayed to user + */ + public String getLabel(); + + public void openAttachment(IWorkbenchPage page, ITaskAttachment attachment) throws CoreException; +} \ No newline at end of file Index: src/org/eclipse/mylyn/internal/tasks/ui/FileStorage.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/FileStorage.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/FileStorage.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/FileStorage.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2009 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Status; + +public class FileStorage extends PlatformObject implements IStorage { + private final File file; + + private final String name; + + public FileStorage(File file, String name) { + this.file = file; + this.name = name; + } + + public InputStream getContents() throws CoreException { + try { + return new FileInputStream(file); + } catch (FileNotFoundException e) { + throw new CoreException(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + Messages.FileStorage_unableToReadAttachmentFile, e)); + } + } + + public IPath getFullPath() { + // ignore + return null; + } + + public String getName() { + return name; + } + + public boolean isReadOnly() { + return true; + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentHandler.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentHandler.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentHandler.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentHandler.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2009 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui.commands; + +import java.util.List; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.internal.tasks.ui.ITaskAttachmentViewer; +import org.eclipse.mylyn.internal.tasks.ui.TaskAttachmentViewersManager; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +public class OpenTaskAttachmentHandler extends AbstractHandler implements IHandler { + + public Object execute(ExecutionEvent event) throws ExecutionException { + IWorkbench wb = PlatformUI.getWorkbench(); + + IWorkbenchWindow win = wb.getActiveWorkbenchWindow(); + if (win == null) { + return null; + } + + IWorkbenchPage page = win.getActivePage(); + if (page == null) { + return null; + } + + List attachments = AttachmentUtil.getSelectedAttachments(); + + openAttachments(page, attachments); + + return null; + } + + public static void openAttachments(IWorkbenchPage page, List attachments) { + TaskAttachmentViewersManager manager = new TaskAttachmentViewersManager(); + + for (ITaskAttachment a : attachments) { + ITaskAttachmentViewer v = manager.getPreferredViewer(a); + + if (v == null) { + TasksUiInternal.logAndDisplayStatus(Messages.OpenTaskAttachmentHandler_failedToOpenViewer, new Status( + IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, + Messages.OpenTaskAttachmentHandler_noAttachmentViewerFound)); + continue; + } + + try { + v.openAttachment(page, a); + } catch (CoreException e) { + TasksUiInternal.logAndDisplayStatus(Messages.OpenTaskAttachmentHandler_failedToOpenViewer, + e.getStatus()); + } + } + } +} #P org.eclipse.mylyn.team.ui Index: src/org/eclipse/mylyn/internal/team/ui/actions/Messages.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.team.ui/src/org/eclipse/mylyn/internal/team/ui/actions/Messages.java,v retrieving revision 1.1 diff -u -r1.1 Messages.java --- src/org/eclipse/mylyn/internal/team/ui/actions/Messages.java 3 Dec 2008 03:43:56 -0000 1.1 +++ src/org/eclipse/mylyn/internal/team/ui/actions/Messages.java 12 Sep 2009 17:11:07 -0000 @@ -30,7 +30,10 @@ public static String AddToTaskContextAction_No_resources_to_add; public static String ApplyPatchAction_Apply_Patch; + public static String ApplyPatchAction_cannotApplyPatch; + public static String ApplyPatchAction_downloadingPatch; public static String ApplyPatchAction_Error_Retrieving_Context; + public static String ApplyPatchAction_failedToDownloadPatch; public static String OpenCorrespondingTaskAction_Completed; public static String OpenCorrespondingTaskAction_Open_Corresponding_Task; Index: src/org/eclipse/mylyn/internal/team/ui/actions/ApplyPatchAction.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.team.ui/src/org/eclipse/mylyn/internal/team/ui/actions/ApplyPatchAction.java,v retrieving revision 1.26 diff -u -r1.26 ApplyPatchAction.java --- src/org/eclipse/mylyn/internal/team/ui/actions/ApplyPatchAction.java 3 Dec 2008 03:43:56 -0000 1.26 +++ src/org/eclipse/mylyn/internal/team/ui/actions/ApplyPatchAction.java 12 Sep 2009 17:11:07 -0000 @@ -11,20 +11,31 @@ package org.eclipse.mylyn.internal.team.ui.actions; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + import org.eclipse.compare.CompareConfiguration; import org.eclipse.compare.patch.ApplyPatchOperation; -import org.eclipse.core.resources.IStorage; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.mylyn.internal.tasks.ui.editors.TaskAttachmentStorage; -import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; +import org.eclipse.mylyn.internal.tasks.ui.FileStorage; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.internal.team.ui.FocusedTeamUiPlugin; import org.eclipse.mylyn.tasks.core.ITaskAttachment; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IViewActionDelegate; import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.BaseSelectionListenerAction; @@ -33,6 +44,7 @@ * @author Steffen Pingel */ public class ApplyPatchAction extends BaseSelectionListenerAction implements IViewActionDelegate { + private IViewPart viewPart; public ApplyPatchAction() { super(Messages.ApplyPatchAction_Apply_Patch); @@ -45,7 +57,7 @@ private ISelection currentSelection; public void init(IViewPart view) { - // ignore + this.viewPart = view; } public void run(IAction action) { @@ -53,18 +65,16 @@ Object object = ((StructuredSelection) currentSelection).getFirstElement(); if (object instanceof ITaskAttachment) { final ITaskAttachment attachment = (ITaskAttachment) object; - IStorage storage; - try { - storage = TaskAttachmentStorage.create(attachment); - } catch (CoreException e) { - TasksUiInternal.displayStatus(Messages.ApplyPatchAction_Error_Retrieving_Context, e.getStatus()); - return; + + IWorkbenchPart vp = viewPart; + if (vp == null) { + vp = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart(); } - ApplyPatchOperation op = new ApplyPatchOperation(PlatformUI.getWorkbench() - .getActiveWorkbenchWindow() - .getActivePage() - .getActivePart(), storage, null, new CompareConfiguration()); - BusyIndicator.showWhile(Display.getDefault(), op); + + DownloadAndApplyPatch job = new DownloadAndApplyPatch(Messages.ApplyPatchAction_downloadingPatch, + attachment, vp); + job.setUser(true); + job.schedule(); } } } @@ -72,4 +82,94 @@ public void selectionChanged(IAction action, ISelection selection) { this.currentSelection = selection; } + + private static class DownloadAndApplyPatch extends Job { + private final ITaskAttachment attachment; + + private final IWorkbenchPart wbPart; + + public DownloadAndApplyPatch(String jobName, ITaskAttachment attachment, IWorkbenchPart wbPart) { + super(jobName); + + this.attachment = attachment; + this.wbPart = wbPart; + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + String attachmentFilename = AttachmentUtil.getAttachmentFilename(attachment); + + File file = null; + try { + file = File.createTempFile("patch-", ".txt"); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (IOException e) { + return new Status(IStatus.ERROR, FocusedTeamUiPlugin.ID_PLUGIN, + Messages.ApplyPatchAction_failedToDownloadPatch, e); + } + file.deleteOnExit(); + + boolean ok = false; + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file); + AttachmentUtil.downloadAttachment(attachment, fos, monitor); + ok = true; + } catch (IOException e) { + return new Status(IStatus.ERROR, FocusedTeamUiPlugin.ID_PLUGIN, + Messages.ApplyPatchAction_failedToDownloadPatch, e); + } catch (CoreException e) { + int s = IStatus.ERROR; + if (e.getStatus() != null && e.getStatus().getCode() == IStatus.CANCEL) { + s = IStatus.CANCEL; + } + return new Status(s, FocusedTeamUiPlugin.ID_PLUGIN, Messages.ApplyPatchAction_failedToDownloadPatch, e); + } catch (OperationCanceledException e) { + return new Status(IStatus.CANCEL, FocusedTeamUiPlugin.ID_PLUGIN, + Messages.ApplyPatchAction_failedToDownloadPatch, e); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + if (ok) { + // report this exception if there was no other problem until now ... we will not work with file + // which cannot be closed properly, because this indicates some problem + file.delete(); + return new Status(IStatus.ERROR, FocusedTeamUiPlugin.ID_PLUGIN, + Messages.ApplyPatchAction_failedToDownloadPatch, e); + } + } + } + + if (!ok) { + file.delete(); + } + } + + IWorkbenchPartSite site = wbPart.getSite(); + if (site == null) { + return new Status(IStatus.WARNING, FocusedTeamUiPlugin.ID_PLUGIN, + Messages.ApplyPatchAction_cannotApplyPatch); + } + + final Display disp = site.getWorkbenchWindow().getWorkbench().getDisplay(); + if (disp.isDisposed()) { + return new Status(IStatus.WARNING, FocusedTeamUiPlugin.ID_PLUGIN, + Messages.ApplyPatchAction_cannotApplyPatch); + } + + final FileStorage fileStorage = new FileStorage(file, attachmentFilename); + + disp.asyncExec(new Runnable() { + public void run() { + ApplyPatchOperation op = new ApplyPatchOperation(wbPart, fileStorage, null, + new CompareConfiguration()); + + BusyIndicator.showWhile(disp, op); + } + }); + + return Status.OK_STATUS; + } + } } Index: src/org/eclipse/mylyn/internal/team/ui/actions/messages.properties =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.team.ui/src/org/eclipse/mylyn/internal/team/ui/actions/messages.properties,v retrieving revision 1.2 diff -u -r1.2 messages.properties --- src/org/eclipse/mylyn/internal/team/ui/actions/messages.properties 24 Jul 2009 12:04:39 -0000 1.2 +++ src/org/eclipse/mylyn/internal/team/ui/actions/messages.properties 12 Sep 2009 17:11:08 -0000 @@ -13,7 +13,10 @@ AddToTaskContextAction_No_resources_to_add=No resources to add. ApplyPatchAction_Apply_Patch=Apply Patch +ApplyPatchAction_cannotApplyPatch=Cannot apply patch +ApplyPatchAction_downloadingPatch=Downloading patch ApplyPatchAction_Error_Retrieving_Context=Error Retrieving Context +ApplyPatchAction_failedToDownloadPatch=Failed to download patch OpenCorrespondingTaskAction_Completed=Completed: OpenCorrespondingTaskAction_Open_Corresponding_Task=Open Corresponding Task