### Eclipse Workspace Patch 1.0 #P org.eclipse.mylyn.tasks.ui Index: src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorAttachmentPart.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorAttachmentPart.java,v retrieving revision 1.41 diff -u -r1.41 TaskEditorAttachmentPart.java --- src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorAttachmentPart.java 24 Jul 2009 12:05:45 -0000 1.41 +++ src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorAttachmentPart.java 5 Sep 2009 19:56:02 -0000 @@ -34,11 +34,11 @@ import org.eclipse.jface.window.ToolTip; import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages; import org.eclipse.mylyn.internal.tasks.core.TaskAttachment; +import org.eclipse.mylyn.internal.tasks.ui.commands.OpenTaskAttachmentHandler; import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiMenus; import org.eclipse.mylyn.internal.tasks.ui.wizards.TaskAttachmentWizard.Mode; import org.eclipse.mylyn.tasks.core.ITaskAttachment; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; -import org.eclipse.mylyn.tasks.ui.TasksUiUtil; import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; @@ -51,6 +51,7 @@ import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.forms.events.ExpansionAdapter; import org.eclipse.ui.forms.events.ExpansionEvent; import org.eclipse.ui.forms.widgets.FormToolkit; @@ -136,11 +137,7 @@ getTaskEditorPage().getAttributeEditorToolkit())); attachmentsViewer.addOpenListener(new IOpenListener() { public void open(OpenEvent event) { - if (!event.getSelection().isEmpty()) { - StructuredSelection selection = (StructuredSelection) event.getSelection(); - ITaskAttachment attachment = (ITaskAttachment) selection.getFirstElement(); - TasksUiUtil.openUrl(attachment.getUrl()); - } + openAttachments(event); } }); attachmentsViewer.addSelectionChangedListener(getTaskEditorPage()); @@ -260,4 +257,24 @@ toolBarManager.add(attachFileAction); } + protected void openAttachments(OpenEvent event) { + List 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: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentStorage.java,v retrieving revision 1.4 diff -u -r1.4 TaskAttachmentStorage.java --- src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentStorage.java 5 Dec 2008 23:25:50 -0000 1.4 +++ src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentStorage.java 5 Sep 2009 19:56:02 -0000 @@ -23,6 +23,7 @@ import org.eclipse.core.runtime.PlatformObject; import org.eclipse.core.runtime.Status; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; import org.eclipse.mylyn.tasks.core.ITask; import org.eclipse.mylyn.tasks.core.ITaskAttachment; @@ -36,17 +37,6 @@ * @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; @@ -75,23 +65,8 @@ } 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$ - } - } + String name = AttachmentUtil.getAttachmentFilename(attachment); + // treat .patch files as text files if (name.endsWith(".patch")) { //$NON-NLS-1$ name += ".txt"; //$NON-NLS-1$ 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 5 Sep 2009 19:56: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 5 Sep 2009 19:56: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/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 5 Sep 2009 19:56: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: plugin.xml =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/plugin.xml,v retrieving revision 1.365 diff -u -r1.365 plugin.xml --- plugin.xml 27 Aug 2009 00:32:33 -0000 1.365 +++ plugin.xml 5 Sep 2009 19:56:02 -0000 @@ -1286,6 +1286,11 @@ + + @@ -1539,6 +1544,10 @@ commandId="org.eclipse.mylyn.tasks.ui.command.attachment.openInBrowser"> + + @@ -1643,20 +1652,27 @@ - - + + + + + + + + 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("Failed to open viewer", ex.getStatus()); + } + } + } + } + + @Override + public boolean isDynamic() { + // depends on selected attachments + return true; + } +} 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,133 @@ +/******************************************************************************* + * 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.io.OutputStream; +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.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +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 { + file = File.createTempFile("attach-", "-" + attachmentFilename); + } catch (IOException e) { + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Failed to download attachment", e); + } + file.deleteOnExit(); + + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file); + AttachmentUtil.downloadAttachment(attachment, fos, monitor); + fos.close(); + fos = null; + } catch (IOException e) { + closeAndDelete(fos, file); + fos = null; + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Failed to download attachment", e); + } catch (CoreException e) { + closeAndDelete(fos, file); + fos = null; + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Failed to download attachment", e); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + // ignore ... something bad is happening here + } + } + } + + Display disp = page.getWorkbenchWindow().getWorkbench().getDisplay(); + if (disp.isDisposed()) { + return new Status(IStatus.WARNING, TasksUiPlugin.ID_PLUGIN, "Display is disposed"); + } + + if (disp.getThread() == Thread.currentThread()) { + try { + page.openEditor(new FileEditorInput(file, attachmentFilename, attachment.getUrl()), editorID); + } catch (PartInitException e) { + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Cannot open editor", e); + } + + return new Status(IStatus.OK, TasksUiPlugin.ID_PLUGIN, "OK"); + } else { + final AtomicReference status = new AtomicReference(); + final File tmpFile = file; + + disp.syncExec(new Runnable() { + public void run() { + try { + page.openEditor(new FileEditorInput(tmpFile, attachmentFilename, attachment.getUrl()), editorID); + status.set(new Status(IStatus.OK, TasksUiPlugin.ID_PLUGIN, "OK")); + } catch (PartInitException e) { + status.set(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Cannot open editor", e)); + } + }; + }); + + if (status.get() == null) { + return new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Cannot open editor"); + } + + return status.get(); + } + } + + void closeAndDelete(OutputStream os, File file) { + if (os != null) { + try { + os.close(); + } catch (IOException ex) { + // ignore ... we are going to delete the file anyway + } + } + + if (file == null) { + return; + } + + file.delete(); + } +} 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,68 @@ +/******************************************************************************* + * 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; + +public 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); + } + +} Index: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerDefaultEditor.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerDefaultEditor.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerDefaultEditor.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerDefaultEditor.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,41 @@ +package org.eclipse.mylyn.internal.tasks.ui; + +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.util.AttachmentUtil; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PlatformUI; + +public class TaskAttachmentViewerDefaultEditor implements ITaskAttachmentViewer { + public String getID() { + return "defaultEditor"; + } + + public String getLabel() { + return "Default Editor"; + } + + public boolean isAvailable(ITaskAttachment attachment) { + String name = AttachmentUtil.getAttachmentFilename(attachment); + IEditorDescriptor d = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(name); + + return d != null; + } + + public void openAttachment(IWorkbenchPage page, ITaskAttachment attachment) throws CoreException { + String name = AttachmentUtil.getAttachmentFilename(attachment); + IEditorDescriptor description = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(name); + + if (description == null) { + throw new CoreException(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + "Cannot find default editor for attachment")); + } + + DownloadAndOpenTaskAttachmentJob job = new DownloadAndOpenTaskAttachmentJob( + "Downloading and opening attachment in default editor", attachment, page, description.getId()); + job.schedule(); + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerSystemExternalEditor.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerSystemExternalEditor.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerSystemExternalEditor.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerSystemExternalEditor.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.ui.IEditorRegistry; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PlatformUI; + +public class TaskAttachmentViewerSystemExternalEditor implements ITaskAttachmentViewer { + public String getID() { + return "systemExternalEditor"; + } + + public String getLabel() { + // ignore + return "System Editor"; + } + + public boolean isAvailable(ITaskAttachment attachment) { + String name = AttachmentUtil.getAttachmentFilename(attachment); + return PlatformUI.getWorkbench().getEditorRegistry().isSystemExternalEditorAvailable(name); + } + + public void openAttachment(IWorkbenchPage page, ITaskAttachment attachment) throws CoreException { + String name = AttachmentUtil.getAttachmentFilename(attachment); + boolean avail = PlatformUI.getWorkbench().getEditorRegistry().isSystemExternalEditorAvailable(name); + + if (!avail) { + throw new CoreException(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + "Cannot find default editor for attachment")); + } + + DownloadAndOpenTaskAttachmentJob job = new DownloadAndOpenTaskAttachmentJob( + "Downloading and opening attachment in external editor", attachment, page, + IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID); + job.schedule(); + } +} 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,90 @@ +/******************************************************************************* + * 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.Collections; +import java.util.List; + +import org.eclipse.mylyn.tasks.core.ITaskAttachment; + +public class TaskAttachmentViewersManager { + private static final TaskAttachmentViewersManager instance = new TaskAttachmentViewersManager(); + + public static TaskAttachmentViewersManager getInstance() { + return instance; + } + + private final List viewers; + + private TaskAttachmentViewersManager() { + List vl = new ArrayList(); + + vl.add(new TaskAttachmentViewerBrowser()); + vl.add(new TaskAttachmentViewerDefaultEditor()); + vl.add(new TaskAttachmentViewerSystemInplaceEditor()); + vl.add(new TaskAttachmentViewerSystemExternalEditor()); + + viewers = Collections.unmodifiableList(vl); + } + + public List getTaskAttachmentViewers(ITaskAttachment attachment) { + List result = new ArrayList(); + + for (ITaskAttachmentViewer v : viewers) { + if (v.isAvailable(attachment)) { + result.add(v); + } + } + + return result; + } + + /** + * @param attachment + * @return list of attachment viewers, with preferred viewers in front + */ + public List getSortedTaskAttachmentViewers(ITaskAttachment attachment) { + List viewers = getTaskAttachmentViewers(attachment); + + String preferred = getPreferredViewerID(attachment); + if (preferred == null) { + return viewers; + } + + // put preferred handler to the beginning + int prefIndex = -1; + for (int i = 0; i < viewers.size(); i++) { + if (preferred.equals(viewers.get(i).getID())) { + prefIndex = i; + break; + } + } + + if (prefIndex >= 0) { + ITaskAttachmentViewer h = viewers.remove(prefIndex); + viewers.add(0, h); + } + + return viewers; + } + + public String getPreferredViewerID(ITaskAttachment attachment) { + return TasksUiPlugin.getDefault().getPreferenceStore().getString( + ITasksUiPreferenceConstants.PREFERRED_TASK_ATTACHMENT_VIEWER_ID); + } + + public void savePreferredViewerID(ITaskAttachment attachment, String handlerID) { + TasksUiPlugin.getDefault().getPreferenceStore().putValue( + ITasksUiPreferenceConstants.PREFERRED_TASK_ATTACHMENT_VIEWER_ID, handlerID); + } +} Index: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerSystemInplaceEditor.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerSystemInplaceEditor.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerSystemInplaceEditor.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/TaskAttachmentViewerSystemInplaceEditor.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.mylyn.internal.tasks.ui.util.AttachmentUtil; +import org.eclipse.mylyn.tasks.core.ITaskAttachment; +import org.eclipse.ui.IEditorRegistry; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PlatformUI; + +public class TaskAttachmentViewerSystemInplaceEditor implements ITaskAttachmentViewer { + public String getID() { + return "systemInplaceEditor"; + } + + public String getLabel() { + // ignore + return "In-Place Editor"; + } + + public boolean isAvailable(ITaskAttachment attachment) { + String name = AttachmentUtil.getAttachmentFilename(attachment); + return PlatformUI.getWorkbench().getEditorRegistry().isSystemExternalEditorAvailable(name); + } + + public void openAttachment(IWorkbenchPage page, ITaskAttachment attachment) throws CoreException { + String name = AttachmentUtil.getAttachmentFilename(attachment); + boolean avail = PlatformUI.getWorkbench().getEditorRegistry().isSystemExternalEditorAvailable(name); + + if (!avail) { + throw new CoreException(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + "Cannot find default in-place editor for attachment")); + } + + DownloadAndOpenTaskAttachmentJob job = new DownloadAndOpenTaskAttachmentJob( + "Downloading and opening attachment in in-place editor", attachment, page, + IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID); + job.schedule(); + } +} 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,39 @@ +/******************************************************************************* + * 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(); + + /** + * @param attachment + * @return whether viewer is available for this attachment + */ + public boolean isAvailable(ITaskAttachment attachment); + + 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,56 @@ +/******************************************************************************* + * 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; + +class FileStorage extends PlatformObject implements IStorage { + private final File file; + + private final String name; + + 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, "Unable to read file", 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,76 @@ +/******************************************************************************* + * 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 = TaskAttachmentViewersManager.getInstance(); + + for (ITaskAttachment a : attachments) { + List h = manager.getSortedTaskAttachmentViewers(a); + + if (h.isEmpty()) { + TasksUiInternal.logAndDisplayStatus("Failed to open editor", new Status(IStatus.WARNING, + TasksUiPlugin.ID_PLUGIN, "No suitable attachment viewer found")); + continue; + } + + ITaskAttachmentViewer dflt = h.get(0); + try { + dflt.openAttachment(page, a); + } catch (CoreException e) { + TasksUiInternal.logAndDisplayStatus("Failed to open editor", e.getStatus()); + } + } + } +}