diff options
author | spingel | 2008-05-02 06:47:32 +0000 |
---|---|---|
committer | spingel | 2008-05-02 06:47:32 +0000 |
commit | 7f86af1782ec463946d18ec52bbdc8a79f72af61 (patch) | |
tree | db1a8a480829a1e1a7173f9357c607c0d555c287 | |
parent | 5ae2b037869f2e1aee6691084a6baec0baf76ad0 (diff) | |
download | org.eclipse.mylyn.tasks-7f86af1782ec463946d18ec52bbdc8a79f72af61.tar.gz org.eclipse.mylyn.tasks-7f86af1782ec463946d18ec52bbdc8a79f72af61.tar.xz org.eclipse.mylyn.tasks-7f86af1782ec463946d18ec52bbdc8a79f72af61.zip |
NEW - bug 211641: [api] supporting attaching of files for remote tasks
https://bugs.eclipse.org/bugs/show_bug.cgi?id=211641
28 files changed, 1076 insertions, 716 deletions
diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/ITaskJobFactory.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/ITaskJobFactory.java index e5a472de2..cb69d1d05 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/ITaskJobFactory.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/ITaskJobFactory.java @@ -14,6 +14,7 @@ import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; import org.eclipse.mylyn.tasks.core.AbstractRepositoryQuery; import org.eclipse.mylyn.tasks.core.AbstractTask; import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskData; import org.eclipse.mylyn.tasks.core.sync.SubmitJob; @@ -33,10 +34,14 @@ public interface ITaskJobFactory { public abstract SynchronizationJob createSynchronizeRepositoriesJob(Set<TaskRepository> repositories); - public abstract SubmitJob createSubmitJob(AbstractRepositoryConnector connector, TaskRepository taskRepository, + public abstract SubmitJob createSubmitTaskJob(AbstractRepositoryConnector connector, TaskRepository taskRepository, AbstractTask task, TaskData taskData, Set<TaskAttribute> changedAttributes); - public abstract TaskJob createUpdateRepositoryConfigurationJob(final AbstractRepositoryConnector connector, - final TaskRepository taskRepository); + public abstract TaskJob createUpdateRepositoryConfigurationJob(AbstractRepositoryConnector connector, + TaskRepository taskRepository); + + public abstract SubmitJob createSubmitTaskAttachmentJob(AbstractRepositoryConnector connector, + TaskRepository taskRepository, AbstractTask task, AbstractTaskAttachmentSource source, String comment, + TaskAttribute attachmentAttribute); } diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/data/FileTaskAttachmentSource.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/data/FileTaskAttachmentSource.java new file mode 100644 index 000000000..a6c9dab1b --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/data/FileTaskAttachmentSource.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Mylyn project committers 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 + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.core.data; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +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.mylyn.internal.tasks.core.ITasksCoreConstants; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; + +/** + * @author Steffen Pingel + */ +public class FileTaskAttachmentSource extends AbstractTaskAttachmentSource { + + private static final String CONTENT_TYPE_BINARY = "application/octet-stream"; + + private String contentType = CONTENT_TYPE_BINARY; + + private String description; + + private final File file; + + private String name; + + public FileTaskAttachmentSource(File file) { + this.file = file; + this.name = file.getName(); + } + + @Override + public InputStream createInputStream(IProgressMonitor monitor) throws CoreException { + try { + return new FileInputStream(file); + } catch (FileNotFoundException e) { + throw new CoreException(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, e.getMessage(), e)); + } + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public long getLength() { + return file.length(); + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isLocal() { + return true; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setName(String name) { + this.name = name; + } + +}
\ No newline at end of file diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/data/TextTaskAttachmentSource.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/data/TextTaskAttachmentSource.java new file mode 100644 index 000000000..d6ced41e4 --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/data/TextTaskAttachmentSource.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Mylyn project committers 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 + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.core.data; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; + +public class TextTaskAttachmentSource extends AbstractTaskAttachmentSource { + + private final String contents; + + public TextTaskAttachmentSource(String contents) { + this.contents = contents; + } + + @Override + public InputStream createInputStream(IProgressMonitor monitor) throws CoreException { + return new ByteArrayInputStream(contents.getBytes()); + } + + @Override + public String getContentType() { + return "text/plain"; + } + + @Override + public String getDescription() { + return ""; + } + + @Override + public long getLength() { + return contents.getBytes().length; + } + + @Override + public String getName() { + return "clipboard.txt"; + } + + @Override + public boolean isLocal() { + return true; + } + +}
\ No newline at end of file diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskAttachmentJob.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskAttachmentJob.java new file mode 100644 index 000000000..a1b695ebc --- /dev/null +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskAttachmentJob.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Mylyn project committers 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 + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.core.sync; + +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.mylyn.commons.net.Policy; +import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants; +import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; +import org.eclipse.mylyn.tasks.core.AbstractTask; +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentHandler; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; +import org.eclipse.mylyn.tasks.core.data.ITaskDataManager; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.core.data.TaskData; +import org.eclipse.mylyn.tasks.core.sync.SubmitJob; + +/** + * @author Steffen Pingel + */ +public class SubmitTaskAttachmentJob extends SubmitJob { + + private final TaskAttribute attachmentAttribute; + + private final String comment; + + private final AbstractRepositoryConnector connector; + + private IStatus error; + + private final AbstractTaskAttachmentSource source; + + private final AbstractTask task; + + private final TaskRepository taskRepository; + + private final ITaskDataManager taskDataManager; + + public SubmitTaskAttachmentJob(ITaskDataManager taskDataManager, AbstractRepositoryConnector connector, + TaskRepository taskRepository, AbstractTask task, AbstractTaskAttachmentSource source, String comment, + TaskAttribute attachmentAttribute) { + super("Submitting Attachment"); + this.taskDataManager = taskDataManager; + this.connector = connector; + this.taskRepository = taskRepository; + this.task = task; + this.source = source; + this.comment = comment; + this.attachmentAttribute = attachmentAttribute; + } + + @Override + public IStatus getError() { + return error; + } + + @Override + public AbstractTask getTask() { + return task; + } + + @Override + public IStatus run(IProgressMonitor monitor) { + final AbstractTaskAttachmentHandler attachmentHandler = connector.getTaskAttachmentHandler(); + if (attachmentHandler == null) { + error = new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, + "The task repository does not support attachments."); + return Status.OK_STATUS; + } + try { + monitor.beginTask("Submitting attachment", 2 * (1 + getSubmitJobListeners().length) * 100); + monitor.subTask("Sending data"); + attachmentHandler.postContent(taskRepository, task, source, comment, attachmentAttribute, + Policy.subMonitorFor(monitor, 100)); + fireTaskSubmitted(monitor); + monitor.subTask("Updating task"); + TaskData taskData = connector.getTaskData2(taskRepository, task.getTaskId(), Policy.subMonitorFor(monitor, + 100)); + taskDataManager.putUpdatedTaskData(task, taskData, true); + fireTaskSynchronized(monitor); + } catch (CoreException e) { + error = e.getStatus(); + } catch (OperationCanceledException e) { + return Status.CANCEL_STATUS; + } finally { + monitor.done(); + } + fireDone(); + return Status.OK_STATUS; + } + +} diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskJob.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskJob.java index 33f0384a3..54b6dbe8b 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskJob.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/sync/SubmitTaskJob.java @@ -32,8 +32,6 @@ import org.eclipse.mylyn.tasks.core.sync.SubmitJob; */ public class SubmitTaskJob extends SubmitJob { - private static final String LABEL_JOB_SUBMIT = "Submitting to repository"; - private final TaskRepository taskRepository; private final TaskData taskData; @@ -52,7 +50,7 @@ public class SubmitTaskJob extends SubmitJob { public SubmitTaskJob(ITaskDataManager taskDataManager, AbstractRepositoryConnector connector, TaskRepository taskRepository, AbstractTask task, TaskData taskData, Set<TaskAttribute> changedAttributes) { - super(LABEL_JOB_SUBMIT); + super("Submitting Task"); this.taskDataManager = taskDataManager; this.connector = connector; this.taskRepository = taskRepository; @@ -76,7 +74,7 @@ public class SubmitTaskJob extends SubmitJob { RepositoryStatus.ERROR_INTERNAL, "Task could not be created. No additional information was provided by the connector.")); } - fireTaskDataPosted(monitor); + fireTaskSubmitted(monitor); // update task in task list String taskId = response.getTaskId(); @@ -111,6 +109,7 @@ public class SubmitTaskJob extends SubmitJob { return errorStatus; } + @Override public AbstractTask getTask() { return task; } diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttachment.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttachment.java index f44d377e1..781941c49 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttachment.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttachment.java @@ -151,7 +151,7 @@ public class TaskAttachment implements ITaskAttachment2 { TaskData taskData = taskAttribute.getTaskData(); TaskAttributeMapper mapper = taskAttribute.getTaskData().getAttributeMapper(); String attachmentId = mapper.getValue(taskAttribute); - TaskAttachment attachment = new TaskAttachment(taskData.getRepositoryUrl(), taskData.getConnectorKind(), + TaskAttachment attachment = new TaskAttachment(taskData.getConnectorKind(), taskData.getRepositoryUrl(), taskData.getTaskId(), attachmentId); TaskAttribute child = taskAttribute.getMappedAttribute(TaskAttribute.ATTACHMENT_AUTHOR); if (child != null) { diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttachmentModel.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttachmentModel.java index 644db9780..19460cd14 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttachmentModel.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/data/TaskAttachmentModel.java @@ -17,13 +17,19 @@ import org.eclipse.mylyn.tasks.core.TaskRepository; */ public class TaskAttachmentModel { + private boolean attachContext; + private final TaskAttribute attribute; + private String comment; + private AbstractTaskAttachmentSource source; + private final AbstractTask task; + private final TaskRepository taskRepository; - private final AbstractTask task; + private String contentType; public TaskAttachmentModel(TaskRepository taskRepository, AbstractTask task, TaskAttribute attribute) { this.taskRepository = taskRepository; @@ -31,16 +37,20 @@ public class TaskAttachmentModel { this.attribute = attribute; } + public boolean getAttachContext() { + return attachContext; + } + public TaskAttribute getAttribute() { return attribute; } - public AbstractTaskAttachmentSource getSource() { - return source; + public String getComment() { + return comment; } - public void setSource(AbstractTaskAttachmentSource source) { - this.source = source; + public AbstractTaskAttachmentSource getSource() { + return source; } public AbstractTask getTask() { @@ -50,4 +60,28 @@ public class TaskAttachmentModel { public TaskRepository getTaskRepository() { return taskRepository; } + + public void setAttachContext(boolean attachContext) { + this.attachContext = attachContext; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public void setSource(AbstractTaskAttachmentSource source) { + this.source = source; + } + + public String getContentType() { + if (contentType == null) { + return getSource().getContentType(); + } + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + }
\ No newline at end of file diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/sync/SubmitJob.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/sync/SubmitJob.java index 460cad421..f63948e5d 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/sync/SubmitJob.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/sync/SubmitJob.java @@ -9,6 +9,7 @@ package org.eclipse.mylyn.tasks.core.sync; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.eclipse.core.runtime.CoreException; @@ -28,7 +29,7 @@ import org.eclipse.mylyn.tasks.core.AbstractTask; */ public abstract class SubmitJob extends TaskJob { - private final List<SubmitJobListener> submitJobListeners = new ArrayList<SubmitJobListener>(); + private final List<SubmitJobListener> submitJobListeners = Collections.synchronizedList(new ArrayList<SubmitJobListener>()); public SubmitJob(String name) { super(name); @@ -46,30 +47,22 @@ public abstract class SubmitJob extends TaskJob { return submitJobListeners.toArray(new SubmitJobListener[0]); } - protected void fireTaskDataPosted(final IProgressMonitor monitor) throws CoreException { + protected void fireTaskSubmitted(final IProgressMonitor monitor) throws CoreException { SubmitJobListener[] listeners = submitJobListeners.toArray(new SubmitJobListener[0]); if (listeners.length > 0) { final SubmitJobEvent event = new SubmitJobEvent(this); for (final SubmitJobListener listener : listeners) { - listener.taskDataPosted(event, Policy.subMonitorFor(monitor, 100)); + listener.taskSubmitted(event, Policy.subMonitorFor(monitor, 100)); } } } - protected void fireTaskSynchronized(final IProgressMonitor monitor) { + protected void fireTaskSynchronized(final IProgressMonitor monitor) throws CoreException { SubmitJobListener[] listeners = submitJobListeners.toArray(new SubmitJobListener[0]); if (listeners.length > 0) { final SubmitJobEvent event = new SubmitJobEvent(this); for (final SubmitJobListener listener : listeners) { - SafeRunner.run(new ISafeRunnable() { - public void handleException(Throwable e) { - StatusHandler.log(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, "Listener failed", e)); - } - - public void run() throws Exception { - listener.taskSynchronized(event, Policy.subMonitorFor(monitor, 100)); - } - }); + listener.taskSynchronized(event, Policy.subMonitorFor(monitor, 100)); } } } diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/sync/SubmitJobListener.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/sync/SubmitJobListener.java index 33c5ea669..c9d14b4c1 100644 --- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/sync/SubmitJobListener.java +++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/sync/SubmitJobListener.java @@ -17,9 +17,9 @@ import org.eclipse.core.runtime.IProgressMonitor; */ public abstract class SubmitJobListener { - public abstract void taskDataPosted(SubmitJobEvent event, IProgressMonitor monitor) throws CoreException; + public abstract void taskSubmitted(SubmitJobEvent event, IProgressMonitor monitor) throws CoreException; - public abstract void taskSynchronized(SubmitJobEvent event, IProgressMonitor monitor); + public abstract void taskSynchronized(SubmitJobEvent event, IProgressMonitor monitor) throws CoreException; public abstract void done(SubmitJobEvent event); diff --git a/org.eclipse.mylyn.tasks.ui/plugin.xml b/org.eclipse.mylyn.tasks.ui/plugin.xml index 60600cc95..146c50f32 100644 --- a/org.eclipse.mylyn.tasks.ui/plugin.xml +++ b/org.eclipse.mylyn.tasks.ui/plugin.xml @@ -1218,6 +1218,11 @@ id="org.eclipse.mylyn.tasks.ui.category.editor" name="Task Editor"> </category> + <command + categoryId="org.eclipse.mylyn.tasks.ui.category.editor" + id="org.eclipse.mylyn.tasks.ui.command.attachment.openInDefaultEditor" + name="Open Attachment in Default Editor"> + </command> </extension> <extension point="org.eclipse.ui.bindings"> @@ -1346,6 +1351,10 @@ class="org.eclipse.mylyn.internal.tasks.ui.commands.OpenTaskAttachmentInBrowserHandler" commandId="org.eclipse.mylyn.tasks.ui.command.attachment.openInBrowser"> </handler> + <handler + class="org.eclipse.mylyn.internal.tasks.ui.commands.OpenTaskAttachmentInDefaultEditorHandler" + commandId="org.eclipse.mylyn.tasks.ui.command.attachment.openInDefaultEditor"> + </handler> </extension> <extension point="org.eclipse.ui.menus"> @@ -1365,15 +1374,15 @@ name="group.open" visible="false"> </separator> + <command + commandId="org.eclipse.mylyn.tasks.ui.command.attachment.openInBrowser" + label="Open With Browser" + style="push"> + </command> <menu label="Open With"> <command - commandId="org.eclipse.mylyn.tasks.ui.command.attachment.openInBrowser" - label="Browser" - style="push"> - </command> - <command - commandId="org.eclipse.mylyn.tasks.ui.command3" + commandId="org.eclipse.mylyn.tasks.ui.command.attachment.openInDefaultEditor" label="Default Editor" style="push"> </command> diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/AttachmentUtil.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/AttachmentUtil.java index 60888044f..65a428111 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/AttachmentUtil.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/AttachmentUtil.java @@ -12,6 +12,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.HashSet; import java.util.Set; @@ -23,7 +24,9 @@ import org.eclipse.core.runtime.Status; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.context.core.ContextCore; import org.eclipse.mylyn.internal.tasks.core.TaskDataStorageManager; +import org.eclipse.mylyn.internal.tasks.core.data.FileTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.AbstractAttachmentHandler; +import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; import org.eclipse.mylyn.tasks.core.AbstractTask; import org.eclipse.mylyn.tasks.core.FileAttachment; import org.eclipse.mylyn.tasks.core.RepositoryAttachment; @@ -31,11 +34,12 @@ import org.eclipse.mylyn.tasks.core.RepositoryStatus; import org.eclipse.mylyn.tasks.core.RepositoryTaskData; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.AbstractTask.SynchronizationState; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentHandler; import org.eclipse.mylyn.tasks.core.data.ITaskAttachment2; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; /** * @author Steffen Pingel - * @since 3.0 */ public class AttachmentUtil { @@ -45,6 +49,8 @@ public class AttachmentUtil { private static final String CONTEXT_FILENAME = "mylyn-context.zip"; + private static final int BUFFER_SIZE = 1024; + /** * Attaches the associated context to <code>task</code>. * @@ -79,6 +85,21 @@ public class AttachmentUtil { return true; } + public static boolean postContext(AbstractRepositoryConnector connector, TaskRepository repository, + AbstractTask task, String comment, IProgressMonitor monitor) throws CoreException { + AbstractTaskAttachmentHandler attachmentHandler = connector.getTaskAttachmentHandler(); + ContextCore.getContextManager().saveContext(task.getHandleIdentifier()); + File file = ContextCore.getContextManager().getFileForContext(task.getHandleIdentifier()); + if (file != null && file.exists()) { + FileTaskAttachmentSource attachment = new FileTaskAttachmentSource(file); + attachment.setDescription(CONTEXT_DESCRIPTION); + attachment.setName(CONTEXT_FILENAME); + attachmentHandler.postContent(repository, task, attachment, comment, null, monitor); + return true; + } + return false; + } + /** * Implementors of this repositoryOperations must perform it locally without going to the server since it is used * for frequent repositoryOperations such as decoration. @@ -112,6 +133,7 @@ public class AttachmentUtil { } } + @Deprecated public static boolean isContext(RepositoryAttachment attachment) { return CONTEXT_DESCRIPTION.equals(attachment.getDescription()) || CONTEXT_DESCRIPTION_LEGACY.equals(attachment.getDescription()); @@ -127,6 +149,7 @@ public class AttachmentUtil { * * @return false, if operation is not supported by repository */ + @Deprecated public static boolean retrieveContext(AbstractAttachmentHandler attachmentHandler, TaskRepository repository, AbstractTask task, RepositoryAttachment attachment, String destinationPath, IProgressMonitor monitor) throws CoreException { @@ -159,4 +182,31 @@ public class AttachmentUtil { return true; } + public static boolean getContext(AbstractRepositoryConnector connector, TaskRepository repository, + AbstractTask task, TaskAttribute attribute, IProgressMonitor monitor) throws CoreException { + AbstractTaskAttachmentHandler attachmentHandler = connector.getTaskAttachmentHandler(); + File file = ContextCore.getContextManager().getFileForContext(task.getHandleIdentifier()); + try { + FileOutputStream out = new FileOutputStream(file); + try { + InputStream in = attachmentHandler.getContent(repository, task, attribute, monitor); + try { + int len; + byte[] buffer = new byte[BUFFER_SIZE]; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + } + } finally { + in.close(); + } + } finally { + out.close(); + } + } catch (IOException e) { + throw new CoreException(new RepositoryStatus(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, + RepositoryStatus.ERROR_INTERNAL, "Could not create context file", e)); + } + return true; + } + } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/RepositoryAwareStatusHandler.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/RepositoryAwareStatusHandler.java index b2df5b22e..a7f6ee4b8 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/RepositoryAwareStatusHandler.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/RepositoryAwareStatusHandler.java @@ -18,6 +18,7 @@ import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.tasks.ui.util.WebBrowserDialog; import org.eclipse.mylyn.tasks.core.RepositoryStatus; import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; /** @@ -52,51 +53,44 @@ public class RepositoryAwareStatusHandler implements IStatusHandler { return new MessageDialog(shell, title, null, message, type, new String[] { IDialogConstants.OK_LABEL }, 0); } - public void displayStatus(final String title, final IStatus status) { - + public void displayStatus(Shell shell, final String title, final IStatus status) { if (status.getCode() == RepositoryStatus.ERROR_INTERNAL) { StatusHandler.log(status); fail(status, true); - return; + } else { + if (status instanceof RepositoryStatus && ((RepositoryStatus) status).isHtmlMessage()) { + WebBrowserDialog.openAcceptAgreement(shell, title, status.getMessage(), + ((RepositoryStatus) status).getHtmlMessage()); + } else { + switch (status.getSeverity()) { + case IStatus.CANCEL: + case IStatus.INFO: + createDialog(shell, title, status.getMessage(), MessageDialog.INFORMATION).open(); + break; + case IStatus.WARNING: + createDialog(shell, title, status.getMessage(), MessageDialog.WARNING).open(); + break; + case IStatus.ERROR: + default: + createDialog(shell, title, status.getMessage(), MessageDialog.ERROR).open(); + break; + } + } } + } - if (Platform.isRunning()) { - try { - PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { - public void run() { - Shell shell = null; - if (PlatformUI.getWorkbench() != null - && PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) { - shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); - } - - if (status instanceof RepositoryStatus && ((RepositoryStatus) status).isHtmlMessage()) { - WebBrowserDialog.openAcceptAgreement(shell, title, status.getMessage(), - ((RepositoryStatus) status).getHtmlMessage()); - return; - } - - switch (status.getSeverity()) { - case IStatus.CANCEL: - case IStatus.INFO: - createDialog(shell, title, status.getMessage(), MessageDialog.INFORMATION).open(); - break; - case IStatus.WARNING: - createDialog(shell, title, status.getMessage(), MessageDialog.WARNING).open(); - break; - case IStatus.ERROR: - default: - createDialog(shell, title, status.getMessage(), MessageDialog.ERROR).open(); - break; - } - } - }); - } catch (Throwable t) { - status.getException().printStackTrace(); - } + public void displayStatus(final String title, final IStatus status) { + IWorkbench workbench = PlatformUI.getWorkbench(); + if (workbench != null && !workbench.getDisplay().isDisposed() + && workbench.getDisplay().getActiveShell() != null) { + Shell shell = workbench.getDisplay().getActiveShell(); + displayStatus(shell, title, status); + } else { + StatusHandler.log(status); } } + @Deprecated public void fail(final IStatus status, boolean informUser) { if (informUser && Platform.isRunning()) { try { diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/SubmitTaskAttachmentJob.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/SubmitTaskAttachmentJob.java deleted file mode 100644 index b4a4b335d..000000000 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/SubmitTaskAttachmentJob.java +++ /dev/null @@ -1,109 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2007 Mylyn project committers 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 - *******************************************************************************/ - -package org.eclipse.mylyn.internal.tasks.ui; - -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; -import org.eclipse.mylyn.tasks.core.AbstractTask; -import org.eclipse.mylyn.tasks.core.TaskRepository; -import org.eclipse.mylyn.tasks.core.data.ITaskAttachment2; - -/** - * @author Steffen Pingel - */ -public class SubmitTaskAttachmentJob extends Job { - - private static final String LABEL_JOB_SUBMIT = "Submitting to repository"; - - private final ITaskAttachment2 taskAttachment; - - private final AbstractRepositoryConnector connector; - - private final TaskRepository taskRepository; - - private AbstractTask task; - - public SubmitTaskAttachmentJob(AbstractRepositoryConnector connector, TaskRepository taskRepository, - ITaskAttachment2 taskAttachment) { - super(LABEL_JOB_SUBMIT); - this.connector = connector; - this.taskRepository = taskRepository; - this.taskAttachment = taskAttachment; - } - - @Override - public IStatus run(IProgressMonitor monitor) { - return null; -// try { -// if (monitor == null) { -// monitor = new NullProgressMonitor(); -// } -// monitor.beginTask("Attaching file...", 2); -// task.setSubmitting(true); -// task.setSynchronizationState(SynchronizationState.OUTGOING); -// -// if (screenshotMode || InputAttachmentSourcePage.SCREENSHOT_LABEL.equals(path)) { -// ((ImageAttachment) taskAttachment).ensureImageFileWasCreated(); -// } else if (InputAttachmentSourcePage.CLIPBOARD_LABEL.equals(path)) { -// String contents = inputPage.getClipboardContents(); -// if (contents == null) { -// throw new InvocationTargetException(new CoreException(new RepositoryStatus(IStatus.ERROR, -// TasksUiPlugin.ID_PLUGIN, RepositoryStatus.ERROR_INTERNAL, "Clipboard is empty", null))); -// } -// taskAttachment.setContent(contents.getBytes()); -// taskAttachment.setFilename(CLIPBOARD_FILENAME); -// } else { -// File file = new File(path); -// taskAttachment.setFile(file); -// taskAttachment.setFilename(file.getName()); -// } -// -// attachmentHandler.uploadAttachment(taskRepository, task, taskAttachment, taskAttachment.getComment(), -// new SubProgressMonitor(monitor, 1)); -// -// if (monitor.isCanceled()) { -// throw new OperationCanceledException(); -// } -// -// if (attachContext && connector.getAttachmentHandler() != null) { -// connector.getAttachmentHandler().attachContext(taskRepository, task, "", -// new SubProgressMonitor(monitor, 1)); -// } -// } catch (CoreException e) { -// return e.getStatus(); -// } finally { -// task.setSubmitting(false); -// task.setSynchronizationState(SynchronizationState.SYNCHRONIZED); -// -// monitor.done(); -// } - } - -// private void synchronizeTask() { -// TasksUiPlugin.getSynchronizationManager().synchronize(connector, task, false, new JobChangeAdapter() { -// @Override -// public void done(final IJobChangeEvent event) { -// PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { -// public void run() { -// if (event.getResult().getException() != null) { -// -// MessageDialog.openError(Display.getDefault().getActiveShell(), -// ITasksUiConstants.TITLE_DIALOG, event.getResult().getMessage()); -// -// } -// forceRefreshInplace(task); -// } -// }); -// } -// }); -// } - -} diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/TaskJobFactory.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/TaskJobFactory.java index 695cdfe2b..b875db0a1 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/TaskJobFactory.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/TaskJobFactory.java @@ -19,6 +19,7 @@ import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.tasks.core.ITaskJobFactory; import org.eclipse.mylyn.internal.tasks.core.ITaskListRunnable; import org.eclipse.mylyn.internal.tasks.core.TaskList; +import org.eclipse.mylyn.internal.tasks.core.sync.SubmitTaskAttachmentJob; import org.eclipse.mylyn.internal.tasks.core.sync.SubmitTaskJob; import org.eclipse.mylyn.internal.tasks.core.sync.SynchronizeAllTasksJob; import org.eclipse.mylyn.internal.tasks.core.sync.SynchronizeQueriesJob; @@ -29,6 +30,7 @@ import org.eclipse.mylyn.tasks.core.AbstractRepositoryQuery; import org.eclipse.mylyn.tasks.core.AbstractTask; import org.eclipse.mylyn.tasks.core.ITaskRepositoryManager; import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.data.ITaskDataManager; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskData; @@ -86,10 +88,9 @@ public class TaskJobFactory implements ITaskJobFactory { return job; } - public SubmitJob createSubmitJob(AbstractRepositoryConnector connector, TaskRepository taskRepository, + public SubmitJob createSubmitTaskJob(AbstractRepositoryConnector connector, TaskRepository taskRepository, final AbstractTask task, TaskData taskData, Set<TaskAttribute> changedAttributes) { - SubmitTaskJob job = new SubmitTaskJob(taskDataManager, connector, taskRepository, task, taskData, - changedAttributes); + SubmitJob job = new SubmitTaskJob(taskDataManager, connector, taskRepository, task, taskData, changedAttributes); job.setPriority(Job.INTERACTIVE); try { taskList.run(new ITaskListRunnable() { @@ -138,4 +139,23 @@ public class TaskJobFactory implements ITaskJobFactory { return updateJob; } + public SubmitJob createSubmitTaskAttachmentJob(AbstractRepositoryConnector connector, + TaskRepository taskRepository, final AbstractTask task, AbstractTaskAttachmentSource source, + String comment, TaskAttribute attachmentAttribute) { + SubmitJob job = new SubmitTaskAttachmentJob(taskDataManager, connector, taskRepository, task, source, comment, + attachmentAttribute); + job.setPriority(Job.INTERACTIVE); + try { + taskList.run(new ITaskListRunnable() { + public void execute(IProgressMonitor monitor) throws CoreException { + task.setSubmitting(true); + } + }); + } catch (CoreException e) { + StatusHandler.log(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Unexpected error", e)); + } + taskList.notifyTaskChanged(task, false); + job.setUser(true); + return job; + } } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInBrowserHandler.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInBrowserHandler.java index 093bdceee..3d607f6a6 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInBrowserHandler.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInBrowserHandler.java @@ -19,10 +19,12 @@ import org.eclipse.mylyn.tasks.core.data.ITaskAttachment2; import org.eclipse.mylyn.tasks.ui.TasksUiUtil; import org.eclipse.ui.handlers.HandlerUtil; +/** + * @author Steffen Pingel + */ public class OpenTaskAttachmentInBrowserHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { - //ISelection selection = HandlerUtil.getActiveMenuSelection(event); ISelection selection = HandlerUtil.getCurrentSelection(event); if (selection instanceof IStructuredSelection) { List<?> items = ((IStructuredSelection) selection).toList(); diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInDefaultEditorHandler.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInDefaultEditorHandler.java new file mode 100644 index 000000000..a9a3d628a --- /dev/null +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/commands/OpenTaskAttachmentInDefaultEditorHandler.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Mylyn project committers 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 + *******************************************************************************/ + +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.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.data.ITaskAttachment2; +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 { + + @Override + 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 ITaskAttachment2) { + if (page == null) { + IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event); + page = window.getActivePage(); + if (page == null) { + throw new ExecutionException("No active workbench page"); + } + } + openAttachment(page, (ITaskAttachment2) item); + } + } + } + return null; + } + + private void openAttachment(IWorkbenchPage page, ITaskAttachment2 attachment) throws ExecutionException { + TaskAttachmentEditorInput input = new TaskAttachmentEditorInput(attachment); + IEditorDescriptor description = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(input.getName()); + if (description == null) { + TasksUiInternal.displayStatus("Open Attachment Failed", new Status(IStatus.WARNING, + TasksUiPlugin.ID_PLUGIN, "No default editor for \"" + input.getName() + "\" found")); + } else { + try { + page.openEditor(input, description.getId()); + } catch (PartInitException e) { + throw new ExecutionException("Failed to open editor", e); + } + } + } + +} diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentEditorInput.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentEditorInput.java new file mode 100644 index 000000000..511f6c473 --- /dev/null +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskAttachmentEditorInput.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Mylyn project committers 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 + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui.editors; + +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.NullProgressMonitor; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; +import org.eclipse.mylyn.tasks.core.AbstractTask; +import org.eclipse.mylyn.tasks.core.TaskRepository; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentHandler; +import org.eclipse.mylyn.tasks.core.data.ITaskAttachment2; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.core.data.TaskData; +import org.eclipse.mylyn.tasks.ui.TasksUi; +import org.eclipse.ui.IPersistableElement; +import org.eclipse.ui.IStorageEditorInput; + +/** + * @author Jeff Pound + * @author Steffen Pingel + */ +public class TaskAttachmentEditorInput extends PlatformObject implements IStorageEditorInput { + + private static final String ATTACHMENT_DEFAULT_NAME = "attachment"; + + private static final String CTYPE_ZIP = "zip"; + + private static final String CTYPE_OCTET_STREAM = "octet-stream"; + + private static final String CTYPE_TEXT = "text"; + + private static final String CTYPE_HTML = "html"; + + private final ITaskAttachment2 attachment; + + private final String name; + + public TaskAttachmentEditorInput(ITaskAttachment2 attachment) { + this.attachment = attachment; + this.name = getName(attachment); + } + + private String getName(ITaskAttachment2 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)) { + String ctype = attachment.getContentType(); + if (ctype.endsWith(CTYPE_HTML)) { + name = ATTACHMENT_DEFAULT_NAME + ".html"; + } else if (ctype.startsWith(CTYPE_TEXT)) { + name = ATTACHMENT_DEFAULT_NAME + ".txt"; + } else if (ctype.endsWith(CTYPE_OCTET_STREAM)) { + name = ATTACHMENT_DEFAULT_NAME; + } else if (ctype.endsWith(CTYPE_ZIP)) { + name = ATTACHMENT_DEFAULT_NAME + "." + CTYPE_ZIP; + } else { + name = ATTACHMENT_DEFAULT_NAME + "." + ctype.substring(ctype.indexOf("/") + 1); + } + } + // treat .patch files as text files + if (name.endsWith(".patch")) { + name += ".txt"; + } + return name; + } + + public IStorage getStorage() throws CoreException { + TaskRepository taskRepository = TasksUi.getRepositoryManager().getRepository(attachment.getConnectorKind(), + attachment.getRepositoryUrl()); + AbstractTask task = TasksUi.getTaskListManager().getTaskList().getTask(attachment.getRepositoryUrl(), + attachment.getTaskId()); + TaskData taskData = TasksUi.getTaskDataManager().getTaskData(task, taskRepository.getConnectorKind()); + TaskAttribute[] attachments = taskData.getAttributeMapper().getAttributesByType(taskData, + TaskAttribute.TYPE_ATTACHMENT); + for (TaskAttribute taskAttribute : attachments) { + ITaskAttachment2 existingAttachment = taskData.getAttributeMapper().getTaskAttachment(taskAttribute); + if (existingAttachment.getAttachmentId().equals(attachment.getAttachmentId())) { + return new TaskAttachmentStorage(taskRepository, task, taskAttribute, name); + } + } + throw new CoreException(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Failed to find attachment: " + + attachment.getUrl())); + } + + 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: " + attachment.getAttachmentId() + " [" + attachment.getUrl() + "]"; + } + + private static class TaskAttachmentStorage extends PlatformObject implements IStorage { + + private final TaskRepository taskRepository; + + private final AbstractTask task; + + private final TaskAttribute attachmentAttribute; + + private final String name; + + public TaskAttachmentStorage(TaskRepository taskRepository, AbstractTask task, + TaskAttribute attachmentAttribute, String name) { + this.taskRepository = taskRepository; + this.task = task; + this.attachmentAttribute = attachmentAttribute; + this.name = 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; + } + + } +} diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorAttachmentPart.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorAttachmentPart.java index e8ad3c0e1..fe659f4d6 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorAttachmentPart.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorAttachmentPart.java @@ -8,11 +8,13 @@ package org.eclipse.mylyn.internal.tasks.ui.editors; +import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.OpenEvent; @@ -22,22 +24,35 @@ import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.jface.window.ToolTip; import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages; +import org.eclipse.mylyn.internal.tasks.core.data.FileTaskAttachmentSource; +import org.eclipse.mylyn.internal.tasks.core.data.TextTaskAttachmentSource; import org.eclipse.mylyn.internal.tasks.ui.actions.AttachAction; import org.eclipse.mylyn.internal.tasks.ui.actions.AttachScreenshotAction; import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; +import org.eclipse.mylyn.internal.tasks.ui.wizards.NewAttachmentWizardDialog; import org.eclipse.mylyn.internal.tasks.ui.wizards.TaskAttachmentWizard.Mode; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.data.ITaskAttachment2; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper; import org.eclipse.mylyn.tasks.ui.TasksUiUtil; import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart; import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.DropTargetListener; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; @@ -92,6 +107,8 @@ public class TaskEditorAttachmentPart extends AbstractTaskEditorPart { private MenuManager menuManager; + private TaskAttachmentDropListener dropListener; + public TaskEditorAttachmentPart() { setPartName("Attachments"); } @@ -161,8 +178,8 @@ public class TaskEditorAttachmentPart extends AbstractTaskEditorPart { attachmentsTable.setMenu(menu); } - private void createAttachmentTableMenu() { - // FIXME EDITOR +// private void createAttachmentTableMenu() { + // FIXME EDITOR // final Action openWithBrowserAction = new Action(LABEL_BROWSER) { // @Override // public void run() { @@ -320,7 +337,7 @@ public class TaskEditorAttachmentPart extends AbstractTaskEditorPart { // attachmentsTableViewer); // } // }); - } +// } private void createButtons(Composite attachmentsComposite, FormToolkit toolkit) { final Composite attachmentControlsComposite = toolkit.createComposite(attachmentsComposite); @@ -332,9 +349,10 @@ public class TaskEditorAttachmentPart extends AbstractTaskEditorPart { attachFileButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { - openNewAttachmentWizard(Mode.DEFAULT); + openNewAttachmentWizard(Mode.DEFAULT, null); } }); + registerDropListener(attachFileButton, dropListener); Button attachScreenshotButton = toolkit.createButton(attachmentControlsComposite, AttachScreenshotAction.LABEL, SWT.PUSH); @@ -342,9 +360,10 @@ public class TaskEditorAttachmentPart extends AbstractTaskEditorPart { attachScreenshotButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { - openNewAttachmentWizard(Mode.SCREENSHOT); + openNewAttachmentWizard(Mode.SCREENSHOT, null); } }); + registerDropListener(attachScreenshotButton, dropListener); } @Override @@ -358,6 +377,9 @@ public class TaskEditorAttachmentPart extends AbstractTaskEditorPart { attachmentsComposite.setLayout(new GridLayout(1, false)); attachmentsComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); + dropListener = new TaskAttachmentDropListener(); + registerDropListener(section, dropListener); + if (attachments.length > 0) { createAttachmentTable(toolkit, attachmentsComposite); } else { @@ -367,18 +389,19 @@ public class TaskEditorAttachmentPart extends AbstractTaskEditorPart { createButtons(attachmentsComposite, toolkit); - // TODO EDITOR fix drop listener -// registerDropListener(section); -// registerDropListener(attachmentsComposite); -// registerDropListener(attachFileButton); -// if (supportsAttachmentDelete()) { -// registerDropListener(deleteAttachmentButton); -// } - section.setClient(attachmentsComposite); setSection(toolkit, section); } + private void registerDropListener(Control control, TaskAttachmentDropListener dropListener) { + DropTarget target = new DropTarget(control, DND.DROP_COPY | DND.DROP_DEFAULT); + final TextTransfer textTransfer = TextTransfer.getInstance(); + final FileTransfer fileTransfer = FileTransfer.getInstance(); + Transfer[] types = new Transfer[] { textTransfer, fileTransfer }; + target.setTransfer(types); + target.addDropListener(dropListener); + } + @Override public void dispose() { if (menuManager != null) { @@ -392,11 +415,84 @@ public class TaskEditorAttachmentPart extends AbstractTaskEditorPart { TaskAttribute.TYPE_ATTACHMENT); } - private void openNewAttachmentWizard(Mode mode) { + private NewAttachmentWizardDialog openNewAttachmentWizard(Mode mode, AbstractTaskAttachmentSource source) { TaskAttributeMapper mapper = getModel().getTaskData().getAttributeMapper(); TaskAttribute attribute = mapper.createTaskAttachment(getModel().getTaskData()); - TasksUiInternal.openNewAttachmentWizard(getTaskEditorPage().getSite().getShell(), - getTaskEditorPage().getTaskRepository(), getTaskEditorPage().getTask(), attribute, mode); + return TasksUiInternal.openNewAttachmentWizard(getTaskEditorPage().getSite().getShell(), + getTaskEditorPage().getTaskRepository(), getTaskEditorPage().getTask(), attribute, mode, source); } + /** + * @author Mik Kersten + * @author Maarten Meijer + * @author Steffen Pingel + */ + public class TaskAttachmentDropListener implements DropTargetListener { + + public TaskAttachmentDropListener() { + } + + public void dragEnter(DropTargetEvent event) { + if (event.detail == DND.DROP_DEFAULT) { + if ((event.operations & DND.DROP_COPY) != 0) { + event.detail = DND.DROP_COPY; + } else { + event.detail = DND.DROP_NONE; + } + } + // will accept text but prefer to have files dropped + for (TransferData dataType : event.dataTypes) { + if (FileTransfer.getInstance().isSupportedType(dataType)) { + event.currentDataType = dataType; + // files should only be copied + if (event.detail != DND.DROP_COPY) { + event.detail = DND.DROP_NONE; + } + break; + } + } + } + + public void dragOver(DropTargetEvent event) { + event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL; + } + + public void dragOperationChanged(DropTargetEvent event) { + if ((event.detail == DND.DROP_DEFAULT) || (event.operations & DND.DROP_COPY) != 0) { + event.detail = DND.DROP_COPY; + } else { + event.detail = DND.DROP_NONE; + } + // allow text to be moved but files should only be copied + if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) { + if (event.detail != DND.DROP_COPY) { + event.detail = DND.DROP_NONE; + } + } + } + + public void dragLeave(DropTargetEvent event) { + } + + public void dropAccept(DropTargetEvent event) { + } + + public void drop(DropTargetEvent event) { + if (TextTransfer.getInstance().isSupportedType(event.currentDataType)) { + String text = (String) event.data; + openNewAttachmentWizard(null, new TextTaskAttachmentSource(text)); + } + if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) { + String[] files = (String[]) event.data; + if (files.length > 0) { + File file = new File(files[0]); + NewAttachmentWizardDialog dialog = openNewAttachmentWizard(null, new FileTaskAttachmentSource(file)); + if (files.length > 1) { + dialog.setMessage("Note that only the first file dragged will be attached.", + IMessageProvider.WARNING); + } + } + } + } + } } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/util/TasksUiInternal.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/util/TasksUiInternal.java index 9fcc47a42..5036c6ec0 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/util/TasksUiInternal.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/util/TasksUiInternal.java @@ -23,6 +23,8 @@ import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.mylyn.commons.core.CoreUtil; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.tasks.core.ITaskJobFactory; @@ -30,7 +32,6 @@ import org.eclipse.mylyn.internal.tasks.core.LocalTask; import org.eclipse.mylyn.internal.tasks.core.ScheduledTaskDelegate; import org.eclipse.mylyn.internal.tasks.core.TaskCategory; import org.eclipse.mylyn.internal.tasks.core.TaskList; -import org.eclipse.mylyn.internal.tasks.ui.RepositoryAwareStatusHandler; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; import org.eclipse.mylyn.internal.tasks.ui.editors.CategoryEditor; import org.eclipse.mylyn.internal.tasks.ui.editors.CategoryEditorInput; @@ -43,9 +44,11 @@ import org.eclipse.mylyn.tasks.core.AbstractRepositoryQuery; import org.eclipse.mylyn.tasks.core.AbstractTask; import org.eclipse.mylyn.tasks.core.AbstractTaskContainer; import org.eclipse.mylyn.tasks.core.ITaskList; +import org.eclipse.mylyn.tasks.core.RepositoryStatus; import org.eclipse.mylyn.tasks.core.RepositoryTaskData; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.TaskSelection; +import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.sync.SynchronizationJob; import org.eclipse.mylyn.tasks.core.sync.TaskJob; @@ -59,6 +62,7 @@ import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; @@ -147,7 +151,6 @@ public class TasksUiInternal { }); } - // API 3.0 move to internal class? public static void refreshAndOpenTaskListElement(AbstractTaskContainer element) { if (element instanceof AbstractTask || element instanceof ScheduledTaskDelegate) { final AbstractTask task; @@ -362,26 +365,56 @@ public class TasksUiInternal { return TasksUiPlugin.getTasksJobFactory(); } - /** - * Display error to user - * - * @param title - * dialog title - * @param status - * IStatus to reveal in dialog FIXME deprecated use - * <code>org.eclipse.ui.statushandlers.StatusMananger#getManager().handle()</code> instead. - */ - public static void displayStatus(String title, IStatus status) { - RepositoryAwareStatusHandler.getInstance().displayStatus(title, status); - } - - public static void openNewAttachmentWizard(Shell shell, TaskRepository taskRepository, AbstractTask task, - TaskAttribute taskAttribute, TaskAttachmentWizard.Mode mode) { + public static NewAttachmentWizardDialog openNewAttachmentWizard(Shell shell, TaskRepository taskRepository, + AbstractTask task, TaskAttribute taskAttribute, TaskAttachmentWizard.Mode mode, + AbstractTaskAttachmentSource source) { TaskAttachmentWizard attachmentWizard = new TaskAttachmentWizard(taskRepository, task, taskAttribute); + attachmentWizard.setSource(source); attachmentWizard.setMode(mode); NewAttachmentWizardDialog dialog = new NewAttachmentWizardDialog(shell, attachmentWizard, false); + dialog.setBlockOnOpen(false); dialog.create(); dialog.open(); + return dialog; + } + + private static MessageDialog createDialog(Shell shell, String title, String message, int type) { + return new MessageDialog(shell, title, null, message, type, new String[] { IDialogConstants.OK_LABEL }, 0); } + public static void displayStatus(Shell shell, final String title, final IStatus status) { + if (status.getCode() == RepositoryStatus.ERROR_INTERNAL) { + StatusHandler.fail(status); + } else { + if (status instanceof RepositoryStatus && ((RepositoryStatus) status).isHtmlMessage()) { + WebBrowserDialog.openAcceptAgreement(shell, title, status.getMessage(), + ((RepositoryStatus) status).getHtmlMessage()); + } else { + switch (status.getSeverity()) { + case IStatus.CANCEL: + case IStatus.INFO: + createDialog(shell, title, status.getMessage(), MessageDialog.INFORMATION).open(); + break; + case IStatus.WARNING: + createDialog(shell, title, status.getMessage(), MessageDialog.WARNING).open(); + break; + case IStatus.ERROR: + default: + createDialog(shell, title, status.getMessage(), MessageDialog.ERROR).open(); + break; + } + } + } + } + + public static void displayStatus(final String title, final IStatus status) { + IWorkbench workbench = PlatformUI.getWorkbench(); + if (workbench != null && !workbench.getDisplay().isDisposed() + && workbench.getDisplay().getActiveShell() != null) { + Shell shell = workbench.getDisplay().getActiveShell(); + displayStatus(shell, title, status); + } else { + StatusHandler.log(status); + } + } } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/InputAttachmentSourcePage.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/InputAttachmentSourcePage.java index 714734db0..c0c10d764 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/InputAttachmentSourcePage.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/InputAttachmentSourcePage.java @@ -35,6 +35,7 @@ import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.mylyn.internal.tasks.core.data.FileTaskAttachmentSource; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.data.ITaskAttachment2; @@ -687,16 +688,16 @@ public class InputAttachmentSourcePage extends WizardPage { public AbstractTaskAttachmentSource getSource() { switch (getInputMethod()) { case CLIPBOARD: - return new TaskAttachmentWizard.ClipboardSource(); + return new TaskAttachmentWizard.ClipboardTaskAttachmentSource(); case WORKSPACE: IResource[] resources = getResources(treeViewer.getSelection()); if (resources.length > 0) { - return new TaskAttachmentWizard.FileSource(resources[0].getLocation().toFile()); + return new FileTaskAttachmentSource(resources[0].getLocation().toFile()); } else { return null; } default: // FILE - return new TaskAttachmentWizard.FileSource(new File(getAttachmentFilePath())); + return new FileTaskAttachmentSource(new File(getAttachmentFilePath())); } } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/InputAttachmentSourcePage2.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/InputAttachmentSourcePage2.java index 75a981129..319d1f4b3 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/InputAttachmentSourcePage2.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/InputAttachmentSourcePage2.java @@ -35,8 +35,9 @@ import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.mylyn.internal.tasks.core.data.FileTaskAttachmentSource; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; -import org.eclipse.mylyn.internal.tasks.ui.wizards.TaskAttachmentWizard.ClipboardSource; +import org.eclipse.mylyn.internal.tasks.ui.wizards.TaskAttachmentWizard.ClipboardTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.data.TaskAttachmentModel; import org.eclipse.swt.SWT; @@ -125,7 +126,7 @@ public class InputAttachmentSourcePage2 extends WizardPage { super("InputAttachmentPage"); this.model = model; setTitle("Select attachment source"); - setDescription("Clipboard contents are for text attachments only."); + setDescription("Clipboard supports text and image attachments only."); // setMessage("Please select the source for the attachment"); } @@ -381,7 +382,7 @@ public class InputAttachmentSourcePage2 extends WizardPage { boolean attachmentFound = false; int inputMethod = getInputMethod(); if (inputMethod == CLIPBOARD) { - if (ClipboardSource.isSupportedType(getControl().getDisplay())) { + if (ClipboardTaskAttachmentSource.isSupportedType(getControl().getDisplay())) { attachmentFound = true; } else { error = "Clipboard contains an unsupported data"; @@ -631,16 +632,16 @@ public class InputAttachmentSourcePage2 extends WizardPage { public AbstractTaskAttachmentSource getSource() { switch (getInputMethod()) { case CLIPBOARD: - return new TaskAttachmentWizard.ClipboardSource(); + return new TaskAttachmentWizard.ClipboardTaskAttachmentSource(); case WORKSPACE: IResource[] resources = getResources(treeViewer.getSelection()); if (resources.length > 0) { - return new TaskAttachmentWizard.FileSource(resources[0].getLocation().toFile()); + return new FileTaskAttachmentSource(resources[0].getLocation().toFile()); } else { return null; } default: // FILE - return new TaskAttachmentWizard.FileSource(new File(getAttachmentFilePath())); + return new FileTaskAttachmentSource(new File(getAttachmentFilePath())); } } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/NewAttachmentWizardDialog.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/NewAttachmentWizardDialog.java index d8d40cea2..7ede8ef39 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/NewAttachmentWizardDialog.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/NewAttachmentWizardDialog.java @@ -44,4 +44,5 @@ public class NewAttachmentWizardDialog extends WizardDialog { } return section; } + } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/PreviewAttachmentPage2.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/PreviewAttachmentPage2.java index 92f4bb435..bd0f257cb 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/PreviewAttachmentPage2.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/PreviewAttachmentPage2.java @@ -40,8 +40,10 @@ import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.ScrollBar; @@ -67,10 +69,14 @@ public class PreviewAttachmentPage2 extends WizardPage { private final TaskAttachmentModel model; + private Button runInBackgroundButton; + private ScrolledComposite scrolledComposite; private final Set<String> textTypes; + private Composite contentComposite; + public PreviewAttachmentPage2(TaskAttachmentModel model) { super(PAGE_NAME); this.model = model; @@ -110,16 +116,34 @@ public class PreviewAttachmentPage2 extends WizardPage { composite.setLayout(new GridLayout()); setControl(composite); - if (isTextAttachment() || isImageAttachment()) { - Object content = getContent(composite); - if (content instanceof String) { - createTextPreview(composite, (String) content); - } else if (content instanceof Image) { - createImagePreview(composite, (Image) content); + contentComposite = new Composite(composite, SWT.NONE); + contentComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); + contentComposite.setLayout(new GridLayout()); + + runInBackgroundButton = new Button(composite, SWT.CHECK); + runInBackgroundButton.setText("Run in background"); + } + + @Override + public void setVisible(boolean visible) { + if (visible) { + Control[] children = contentComposite.getChildren(); + for (Control control : children) { + control.dispose(); } - } else { - createGenericPreview(composite); + if (isTextAttachment() || isImageAttachment()) { + Object content = getContent(contentComposite); + if (content instanceof String) { + createTextPreview(contentComposite, (String) content); + } else if (content instanceof Image) { + createImagePreview(contentComposite, (Image) content); + } + } else { + createGenericPreview(contentComposite); + } + contentComposite.layout(true, true); } + super.setVisible(visible); } private void createErrorPreview(Composite composite, String message) { @@ -132,7 +156,7 @@ public class PreviewAttachmentPage2 extends WizardPage { Label label = new Label(composite, SWT.NONE); label.setLayoutData(new GridData(GridData.FILL_BOTH)); label.setText("Attaching File '" + model.getSource().getName() + "'\nA preview the type '" - + model.getSource().getContentType() + "' is currently not available"); + + model.getContentType() + "' is currently not available"); } private void createImagePreview(Composite composite, final Image bufferedImage) { @@ -244,11 +268,15 @@ public class PreviewAttachmentPage2 extends WizardPage { } private boolean isImageAttachment() { - return imageTypes.contains(model.getSource().getContentType()); + return imageTypes.contains(model.getContentType()); } private boolean isTextAttachment() { - return textTypes.contains(model.getSource().getContentType()); + return textTypes.contains(model.getContentType()); + } + + public boolean runInBackground() { + return runInBackgroundButton.getSelection(); } } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentPage.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentPage.java deleted file mode 100644 index 5f3b99040..000000000 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentPage.java +++ /dev/null @@ -1,304 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2007 Mylyn project committers 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 - *******************************************************************************/ - -package org.eclipse.mylyn.internal.tasks.ui.wizards; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages; -import org.eclipse.mylyn.internal.tasks.ui.TasksUiImages; -import org.eclipse.mylyn.tasks.core.data.ITaskAttachment2; -import org.eclipse.mylyn.tasks.core.data.TaskAttachment; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -/** - * A wizard page to enter details of a new attachment. - * - * @author Jeff Pound - * @author Mik Kersten - */ -public class TaskAttachmentPage extends WizardPage { - - private final TaskAttachment attachment; - - private Text filePath; - - private Text attachmentDesc; - - private Text attachmentComment; - - private Button isPatchButton; - - private Button attachContextButton; - - private Combo contentTypeList; - - private boolean supportsDescription = true; - - private static List<String> contentTypes; - - private static Map<String, String> extensions2Types; - - static { - /* For UI */ - contentTypes = new LinkedList<String>(); - contentTypes.add("text/plain"); - contentTypes.add("text/html"); - contentTypes.add("application/xml"); - contentTypes.add("image/gif"); - contentTypes.add("image/jpeg"); - contentTypes.add("image/png"); - contentTypes.add("application/octet-stream"); - - /* For auto-detect */ - extensions2Types = new HashMap<String, String>(); - extensions2Types.put("txt", "text/plain"); - extensions2Types.put("html", "text/html"); - extensions2Types.put("htm", "text/html"); - extensions2Types.put("jpg", "image/jpeg"); - extensions2Types.put("jpeg", "image/jpeg"); - extensions2Types.put("gif", "image/gif"); - extensions2Types.put("png", "image/png"); - extensions2Types.put("xml", "application/xml"); - extensions2Types.put("zip", "application/octet-stream"); - extensions2Types.put("tar", "application/octet-stream"); - extensions2Types.put("gz", "application/octet-stream"); - } - - protected TaskAttachmentPage(TaskAttachment attachment) { - super("AttachmentDetails"); - setTitle("Attachment Details"); - setMessage("Enter a description and verify the content type of the attachment"); - this.attachment = attachment; - } - - public void createControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NONE); - GridLayout gridLayout = new GridLayout(); - gridLayout.numColumns = 3; - composite.setLayout(gridLayout); - setControl(composite); - - composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - composite.setLayout(new GridLayout(3, false)); - - final TaskAttachmentPage thisPage = this; - - new Label(composite, SWT.NONE).setText("File"); - filePath = new Text(composite, SWT.BORDER); - filePath.setEditable(false); - filePath.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); - - if (supportsDescription) { - new Label(composite, SWT.NONE).setText("Description"); - attachmentDesc = new Text(composite, SWT.BORDER); - attachmentDesc.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); - - attachmentDesc.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - if ("".equals(attachmentDesc.getText().trim())) { - thisPage.setErrorMessage("Description required"); - } else { - if (!"".equals(filePath.getText())) { - thisPage.setPageComplete(true); - thisPage.setErrorMessage(null); - } - } - } - - }); - } - - Label label = new Label(composite, SWT.NONE); - label.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false)); - label.setText("Comment"); - attachmentComment = new Text(composite, SWT.V_SCROLL | SWT.BORDER | SWT.WRAP); - attachmentComment.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); - - new Label(composite, SWT.NONE).setText("Content Type");// .setBackground(parent.getBackground()); - - contentTypeList = new Combo(composite, SWT.BORDER | SWT.DROP_DOWN | SWT.READ_ONLY); - contentTypeList.setLayoutData(new GridData(SWT.DEFAULT, SWT.DEFAULT, false, false, 2, 1)); - final HashMap<String, Integer> contentTypeIndices = new HashMap<String, Integer>(); - Iterator<String> iter = contentTypes.iterator(); - int i = 0; - while (iter.hasNext()) { - String next = iter.next(); - contentTypeList.add(next); - contentTypeIndices.put(next, new Integer(i)); - i++; - } - - /* Update attachment on select content type */ - contentTypeList.addSelectionListener(new SelectionListener() { - public void widgetDefaultSelected(SelectionEvent e) { - // ignore - } - - public void widgetSelected(SelectionEvent e) { - attachment.setContentType(contentTypeList.getItem(contentTypeList.getSelectionIndex())); - } - }); - contentTypeList.select(0); - attachment.setContentType(contentTypeList.getItem(0)); - - // TODO: is there a better way to pad? - new Label(composite, SWT.NONE); - - isPatchButton = new Button(composite, SWT.CHECK); - isPatchButton.setLayoutData(new GridData(SWT.DEFAULT, SWT.DEFAULT, false, false, 2, 1)); - isPatchButton.setText("Patch"); - - // TODO: is there a better way to pad? - new Label(composite, SWT.NONE); - - attachContextButton = new Button(composite, SWT.CHECK); - attachContextButton.setLayoutData(new GridData(SWT.DEFAULT, SWT.DEFAULT, false, false, 2, 1)); - attachContextButton.setText("Attach Context"); - attachContextButton.setImage(CommonImages.getImage(TasksUiImages.CONTEXT_ATTACH)); - attachContextButton.setEnabled((((NewAttachmentWizard) getWizard()).hasContext())); - - /* - * Attachment file name listener, update the local attachment - * accordingly - */ - filePath.addModifyListener(new ModifyListener() { - public void modifyText(ModifyEvent e) { - // Determine type by extension - int index = filePath.getText().lastIndexOf("."); - if (index > 0 && index < filePath.getText().length()) { - String ext = filePath.getText().substring(index + 1); - String type = extensions2Types.get(ext.toLowerCase(Locale.ENGLISH)); - if (type != null) { - contentTypeList.select(contentTypeIndices.get(type)); - attachment.setContentType(type); - } - } - - // check page completenes - if (attachmentDesc != null && "".equals(attachmentDesc.getText())) { - thisPage.setErrorMessage("Description required"); - } else { - if (!"".equals(filePath.getText())) { - thisPage.setPageComplete(true); - thisPage.setErrorMessage(null); - } - } - } - }); - - filePath.setText(attachment.getFileName() == null ? "" : attachment.getFileName()); //$NON-NLS-1$ - - /* Listener for isPatch */ - isPatchButton.addSelectionListener(new SelectionListener() { - private int lastSelected; - - public void widgetDefaultSelected(SelectionEvent e) { - // ignore - } - - public void widgetSelected(SelectionEvent e) { - attachment.setPatch(isPatchButton.getSelection()); - if (isPatchButton.getSelection()) { - lastSelected = contentTypeList.getSelectionIndex(); - contentTypeList.select(0); - contentTypeList.setEnabled(false); - if (attachContextButton.isEnabled()) { - attachContextButton.setSelection(true); - } - } else { - contentTypeList.setEnabled(true); - contentTypeList.select(lastSelected); - } - } - }); - - thisPage.setErrorMessage(null); - } - - @Override - public boolean isPageComplete() { - return !"".equals(filePath.getText().trim()) - && (attachmentDesc == null || !"".equals(attachmentDesc.getText().trim())); - } - - public void populateAttachment() { - if (attachmentDesc != null) { - attachment.setDescription(attachmentDesc.getText()); - } - attachment.setComment(attachmentComment.getText()); - } - - public ITaskAttachment2 getAttachment() { - return attachment; - } - - public void setFilePath(String path) { - filePath.setText(path); - if (path.endsWith(".patch")) { - isPatchButton.setSelection(true); - if (attachContextButton.isEnabled()) { - attachContextButton.setSelection(true); - } - } - } - - @Override - public IWizardPage getNextPage() { - populateAttachment(); - // TODO implement preview -// PreviewAttachmentPage page = new PreviewAttachmentPage(getAttachment()); -// page.setWizard(getWizard()); -// return page; - return null; - } - - public boolean getAttachContext() { - return attachContextButton.getSelection(); - } - - public void setContentType() { - String type = attachment.getContentType(); - String[] typeList = contentTypeList.getItems(); - for (int i = 0; i < typeList.length; i++) { - if (typeList[i].equals(type)) { - contentTypeList.select(i); - contentTypeList.setEnabled(false); - isPatchButton.setEnabled(false); - return; - } - } - } - - public boolean supportsDescription() { - return supportsDescription; - } - - public void setSupportsDescription(boolean supportsDescription) { - this.supportsDescription = supportsDescription; - } - -} diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentWizard.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentWizard.java index 0b900fbaa..d1e6de01b 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentWizard.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentWizard.java @@ -12,29 +12,41 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; +import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.Wizard; +import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages; import org.eclipse.mylyn.internal.provisional.commons.ui.ScreenshotCreationPage; +import org.eclipse.mylyn.internal.tasks.core.sync.SubmitTaskAttachmentJob; +import org.eclipse.mylyn.internal.tasks.ui.AttachmentUtil; import org.eclipse.mylyn.internal.tasks.ui.TasksUiImages; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; +import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; +import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; import org.eclipse.mylyn.tasks.core.AbstractTask; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.AbstractTaskAttachmentSource; import org.eclipse.mylyn.tasks.core.data.TaskAttachmentModel; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.core.sync.SubmitJob; +import org.eclipse.mylyn.tasks.core.sync.SubmitJobEvent; +import org.eclipse.mylyn.tasks.core.sync.SubmitJobListener; import org.eclipse.mylyn.tasks.ui.AbstractRepositoryConnectorUi; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.ImageTransfer; import org.eclipse.swt.dnd.TextTransfer; @@ -49,22 +61,37 @@ import org.eclipse.ui.PlatformUI; * A wizard to add a new attachment to a task report. * * @since 3.0 - * @author Jeff Pound * @author Steffen Pingel */ public class TaskAttachmentWizard extends Wizard { - static class ClipboardSource extends AbstractTaskAttachmentSource { + static class ClipboardTaskAttachmentSource extends AbstractTaskAttachmentSource { + + public static boolean isSupportedType(Display display) { + Clipboard clipboard = new Clipboard(display); + TransferData[] types = clipboard.getAvailableTypes(); + for (TransferData transferData : types) { + if (ImageTransfer.getInstance().isSupportedType(transferData) + || TextTransfer.getInstance().isSupportedType(transferData)) { + return true; + } + } + return false; + } private Object contents; - public ClipboardSource() { - Clipboard clipboard = new Clipboard(PlatformUI.getWorkbench().getDisplay()); - contents = clipboard.getContents(ImageTransfer.getInstance()); - if (contents == null) { - contents = clipboard.getContents(TextTransfer.getInstance()); - } - clipboard.dispose(); + public ClipboardTaskAttachmentSource() { + BusyIndicator.showWhile(PlatformUI.getWorkbench().getDisplay(), new Runnable() { + public void run() { + Clipboard clipboard = new Clipboard(PlatformUI.getWorkbench().getDisplay()); + contents = clipboard.getContents(ImageTransfer.getInstance()); + if (contents == null) { + contents = clipboard.getContents(TextTransfer.getInstance()); + } + clipboard.dispose(); + } + }); } @Override @@ -89,12 +116,12 @@ public class TaskAttachmentWizard extends Wizard { } else if (contents instanceof ImageData) { return "image/png"; } - return ""; + return "application/octet-stream"; } @Override public String getDescription() { - return "Clipboard"; + return null; } @Override @@ -120,64 +147,8 @@ public class TaskAttachmentWizard extends Wizard { return true; } - public static boolean isSupportedType(Display display) { - Clipboard clipboard = new Clipboard(display); - TransferData[] types = clipboard.getAvailableTypes(); - for (TransferData transferData : types) { - if (ImageTransfer.getInstance().isSupportedType(transferData) - || TextTransfer.getInstance().isSupportedType(transferData)) { - return true; - } - } - return false; - } - }; - static class FileSource extends AbstractTaskAttachmentSource { - - private final File file; - - public FileSource(File file) { - this.file = file; - } - - @Override - public InputStream createInputStream(IProgressMonitor monitor) throws CoreException { - try { - return new FileInputStream(file); - } catch (FileNotFoundException e) { - throw new CoreException(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, e.getMessage(), e)); - } - } - - @Override - public String getContentType() { - return null; - } - - @Override - public String getDescription() { - return getName(); - } - - @Override - public long getLength() { - return file.length(); - } - - @Override - public String getName() { - return file.getName(); - } - - @Override - public boolean isLocal() { - return true; - } - - } - static class ImageSource extends AbstractTaskAttachmentSource { private File file; @@ -249,16 +220,21 @@ public class TaskAttachmentWizard extends Wizard { private static final String DIALOG_SETTINGS_KEY = "AttachmentWizard"; + private final AbstractRepositoryConnector connector; + + private IWizardPage editPage; + private Mode mode = Mode.DEFAULT; private final TaskAttachmentModel model; - private IWizardPage editPage; + private PreviewAttachmentPage2 previewPage; public TaskAttachmentWizard(TaskRepository taskRepository, AbstractTask task, TaskAttribute taskAttachment) { Assert.isNotNull(taskRepository); Assert.isNotNull(taskAttachment); this.model = new TaskAttachmentModel(taskRepository, task, taskAttachment); + this.connector = TasksUiPlugin.getRepositoryManager().getRepositoryConnector(taskRepository.getConnectorKind()); setMode(Mode.DEFAULT); setNeedsProgressMonitor(true); setDialogSettings(TasksUiPlugin.getDefault().getDialogSettings().getSection(DIALOG_SETTINGS_KEY)); @@ -279,74 +255,98 @@ public class TaskAttachmentWizard extends Wizard { .getConnectorKind()); editPage = connectorUi.getAttachmentPage(model); addPage(editPage); - } - public TaskAttachmentModel getModel() { - return model; + previewPage = new PreviewAttachmentPage2(model); + addPage(previewPage); } public Mode getMode() { return mode; } - @Override - public IWizardPage getNextPage(IWizardPage page) { - if (page == editPage) { - PreviewAttachmentPage2 previewPage = new PreviewAttachmentPage2(model); - previewPage.setWizard(this); - return previewPage; - } - return super.getNextPage(page); + public TaskAttachmentModel getModel() { + return model; } public AbstractTaskAttachmentSource getSource() { return model.getSource(); } -// private void handleSubmitError(final CoreException exception) { -// if (exception.getStatus().getCode() == RepositoryStatus.ERROR_REPOSITORY_LOGIN) { -// if (TasksUiUtil.openEditRepositoryWizard(taskRepository) == Window.OK) { -// // performFinish(); -// } -// } else { -// TasksUiInternal.displayStatus("Attachment failed", exception.getStatus()); -// } -// } + private void handleDone(SubmitJob job) { + if (job.getError() != null) { + TasksUiInternal.displayStatus(getShell(), "Attachment Failed", job.getError()); + } + } @Override public boolean performFinish() { -// attachPage.populateAttachment(); -// final String path = inputPage.getAbsoluteAttachmentPath(); - // upload the attachment -// final AbstractRepositoryConnector connector = TasksUiPlugin.getRepositoryManager().getRepositoryConnector( -// taskRepository.getConnectorKind()); -// final AbstractAttachmentHandler attachmentHandler = connector.getAttachmentHandler(); -// if (attachmentHandler == null) { -// return false; -// } -// -//// final boolean attachContext = attachPage.getAttachContext(); -// -// final SubmitTaskAttachmentJob job = new SubmitTaskAttachmentJob(connector, taskRepository, taskAttachment); -// try { -// getContainer().run(true, true, new IRunnableWithProgress() { -// public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { -// job.run(monitor); -// } -// }); -// } catch (InvocationTargetException e) { -// if (e.getCause() instanceof CoreException) { -// handleSubmitError((CoreException) e.getCause()); -// } else { -// StatusHandler.fail(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Attachment failure", e)); -// } -// return false; -// } catch (InterruptedException e) { -// // cancelled -// return false; -// } - - return true; + SubmitJob job = TasksUiInternal.getJobFactory() + .createSubmitTaskAttachmentJob(connector, model.getTaskRepository(), model.getTask(), + model.getSource(), model.getComment(), model.getAttribute()); + final boolean attachContext = model.getAttachContext(); + job.addSubmitJobListener(new SubmitJobListener() { + @Override + public void done(SubmitJobEvent event) { + // ignore + } + + @Override + public void taskSubmitted(SubmitJobEvent event, IProgressMonitor monitor) throws CoreException { + if (attachContext) { + monitor.subTask("Attaching context"); + AttachmentUtil.postContext(connector, model.getTaskRepository(), model.getTask(), null, monitor); + } + } + + @Override + public void taskSynchronized(SubmitJobEvent event, IProgressMonitor monitor) throws CoreException { + // ignore + } + }); + if (previewPage.runInBackground()) { + runInBackground(job); + return false; + } else { + return runInWizard(job); + } + } + + private void runInBackground(final SubmitJob job) { + getContainer().getShell().setVisible(false); + job.addJobChangeListener(new JobChangeAdapter() { + @Override + public void done(IJobChangeEvent event) { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + if (job.getError() != null) { + getContainer().getShell().setVisible(true); + } + handleDone(job); + } + }); + } + }); + job.schedule(); + } + + private boolean runInWizard(final SubmitJob job) { + try { + getContainer().run(true, true, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + if (((SubmitTaskAttachmentJob) job).run(monitor) == Status.CANCEL_STATUS) { + throw new InterruptedException(); + } + } + }); + handleDone(job); + return job.getError() == null; + } catch (InvocationTargetException e) { + StatusHandler.fail(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Unexpected error", e)); + return false; + } catch (InterruptedException e) { + // canceled + return false; + } } public void setMode(Mode mode) { diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/AbstractRepositoryConnectorUi.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/AbstractRepositoryConnectorUi.java index 42bcdc056..a3a283939 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/AbstractRepositoryConnectorUi.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/AbstractRepositoryConnectorUi.java @@ -26,7 +26,6 @@ import org.eclipse.mylyn.internal.tasks.ui.OpenRepositoryTaskJob; import org.eclipse.mylyn.internal.tasks.ui.TasksUiImages; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; import org.eclipse.mylyn.internal.tasks.ui.wizards.CommonAddExistingTaskWizard; -import org.eclipse.mylyn.internal.tasks.ui.wizards.TaskAttachmentPage2; import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; import org.eclipse.mylyn.tasks.core.AbstractRepositoryQuery; import org.eclipse.mylyn.tasks.core.AbstractTask; @@ -40,6 +39,7 @@ import org.eclipse.mylyn.tasks.core.data.ITaskComment; import org.eclipse.mylyn.tasks.core.data.TaskAttachmentModel; import org.eclipse.mylyn.tasks.ui.editors.TaskEditor; import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage; +import org.eclipse.mylyn.tasks.ui.wizards.TaskAttachmentPage; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; @@ -293,6 +293,6 @@ public abstract class AbstractRepositoryConnectorUi { * @since 3.0 */ public IWizardPage getAttachmentPage(TaskAttachmentModel model) { - return new TaskAttachmentPage2(model); + return new TaskAttachmentPage(model); } } diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java index 7fdc9a110..33bfc2746 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java @@ -172,7 +172,7 @@ public abstract class AbstractTaskEditorPage extends FormPage implements ISelect } @Override - public void taskDataPosted(SubmitJobEvent event, IProgressMonitor monitor) throws CoreException { + public void taskSubmitted(SubmitJobEvent event, IProgressMonitor monitor) throws CoreException { // attach context if required if (attachContext && connector.getAttachmentHandler() != null) { AttachmentUtil.attachContext(connector.getAttachmentHandler(), taskRepository, task, "", monitor); @@ -534,7 +534,7 @@ public abstract class AbstractTaskEditorPage extends FormPage implements ISelect doSave(new NullProgressMonitor()); - SubmitJob submitJob = TasksUiInternal.getJobFactory().createSubmitJob(connector, taskRepository, task, + SubmitJob submitJob = TasksUiInternal.getJobFactory().createSubmitTaskJob(connector, taskRepository, task, getModel().getTaskData(), getModel().getChangedAttributes()); submitJob.addSubmitJobListener(new SubmitTaskJobListener(actionPart.getAttachContext())); submitJob.schedule(); diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentPage2.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/wizards/TaskAttachmentPage.java index 1aa79380e..3af30e956 100644 --- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskAttachmentPage2.java +++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/wizards/TaskAttachmentPage.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ -package org.eclipse.mylyn.internal.tasks.ui.wizards; +package org.eclipse.mylyn.tasks.ui.wizards; import java.util.HashMap; import java.util.Iterator; @@ -41,8 +41,9 @@ import org.eclipse.swt.widgets.Text; * @author Jeff Pound * @author Mik Kersten * @author Steffen Pingel + * @since 3.0 */ -public class TaskAttachmentPage2 extends WizardPage { +public class TaskAttachmentPage extends WizardPage { private static List<String> contentTypes; @@ -76,28 +77,30 @@ public class TaskAttachmentPage2 extends WizardPage { private Button attachContextButton; - private Text attachmentComment; + private Text commentText; - private Text attachmentDesc; + private Text descriptionText; private Combo contentTypeList; - private Text filePath; + private Text fileNameText; private Button isPatchButton; private final TaskAttachmentModel model; - private boolean supportsDescription = true; + private boolean needsDescription; private final TaskAttachment taskAttachment; - public TaskAttachmentPage2(TaskAttachmentModel model) { + private boolean first = true; + + public TaskAttachmentPage(TaskAttachmentModel model) { super("AttachmentDetails"); - setTitle("Attachment Details"); - setMessage("Enter a description and verify the content type of the attachment"); this.model = model; this.taskAttachment = TaskAttachment.createFrom(model.getAttribute()); + setTitle("Attachment Details"); + setNeedsDescription(true); } public void createControl(Composite parent) { @@ -111,20 +114,20 @@ public class TaskAttachmentPage2 extends WizardPage { composite.setLayout(new GridLayout(3, false)); new Label(composite, SWT.NONE).setText("File"); - filePath = new Text(composite, SWT.BORDER); - filePath.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); + fileNameText = new Text(composite, SWT.BORDER); + fileNameText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); - if (supportsDescription) { + if (needsDescription) { new Label(composite, SWT.NONE).setText("Description"); - attachmentDesc = new Text(composite, SWT.BORDER); - attachmentDesc.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); + descriptionText = new Text(composite, SWT.BORDER); + descriptionText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); - attachmentDesc.addModifyListener(new ModifyListener() { + descriptionText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { - if ("".equals(attachmentDesc.getText().trim())) { + if ("".equals(descriptionText.getText().trim())) { setErrorMessage("Description required"); } else { - if (!"".equals(filePath.getText())) { + if (!"".equals(fileNameText.getText())) { setPageComplete(true); setErrorMessage(null); } @@ -137,8 +140,8 @@ public class TaskAttachmentPage2 extends WizardPage { Label label = new Label(composite, SWT.NONE); label.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false)); label.setText("Comment"); - attachmentComment = new Text(composite, SWT.V_SCROLL | SWT.BORDER | SWT.WRAP); - attachmentComment.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); + commentText = new Text(composite, SWT.V_SCROLL | SWT.BORDER | SWT.WRAP); + commentText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); new Label(composite, SWT.NONE).setText("Content Type");// .setBackground(parent.getBackground()); @@ -188,12 +191,12 @@ public class TaskAttachmentPage2 extends WizardPage { * Attachment file name listener, update the local attachment * accordingly */ - filePath.addModifyListener(new ModifyListener() { + fileNameText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { // Determine type by extension - int index = filePath.getText().lastIndexOf("."); - if (index > 0 && index < filePath.getText().length()) { - String ext = filePath.getText().substring(index + 1); + int index = fileNameText.getText().lastIndexOf("."); + if (index > 0 && index < fileNameText.getText().length()) { + String ext = fileNameText.getText().substring(index + 1); String type = extensions2Types.get(ext.toLowerCase(Locale.ENGLISH)); if (type != null) { contentTypeList.select(contentTypeIndices.get(type)); @@ -202,10 +205,10 @@ public class TaskAttachmentPage2 extends WizardPage { } // check page completenes - if (attachmentDesc != null && "".equals(attachmentDesc.getText())) { + if (descriptionText != null && "".equals(descriptionText.getText())) { setErrorMessage("Description required"); } else { - if (!"".equals(filePath.getText())) { + if (!"".equals(fileNameText.getText())) { setPageComplete(true); setErrorMessage(null); } @@ -213,7 +216,7 @@ public class TaskAttachmentPage2 extends WizardPage { } }); - filePath.setText(taskAttachment.getFileName() == null ? "" : taskAttachment.getFileName()); //$NON-NLS-1$ + fileNameText.setText(taskAttachment.getFileName() == null ? "" : taskAttachment.getFileName()); //$NON-NLS-1$ /* Listener for isPatch */ isPatchButton.addSelectionListener(new SelectionListener() { @@ -240,10 +243,12 @@ public class TaskAttachmentPage2 extends WizardPage { }); setErrorMessage(null); - } - public boolean getAttachContext() { - return attachContextButton.getSelection(); + if (descriptionText != null) { + descriptionText.setFocus(); + } else { + commentText.setFocus(); + } } public TaskAttachmentModel getModel() { @@ -253,37 +258,30 @@ public class TaskAttachmentPage2 extends WizardPage { @Override public IWizardPage getNextPage() { taskAttachment.applyTo(model.getAttribute()); + model.setComment(commentText.getText()); + model.setAttachContext(attachContextButton.getSelection()); + model.setContentType(taskAttachment.getContentType()); return super.getNextPage(); } @Override public boolean isPageComplete() { - return !"".equals(filePath.getText().trim()) - && (attachmentDesc == null || !"".equals(attachmentDesc.getText().trim())); + return !"".equals(fileNameText.getText().trim()) + && (descriptionText == null || !"".equals(descriptionText.getText().trim())); } - public void populateAttachment() { - if (attachmentDesc != null) { - taskAttachment.setDescription(attachmentDesc.getText()); - } - taskAttachment.setComment(attachmentComment.getText()); - } - - public void setContentType() { - String type = taskAttachment.getContentType(); + private void setContentType(String contentType) { String[] typeList = contentTypeList.getItems(); for (int i = 0; i < typeList.length; i++) { - if (typeList[i].equals(type)) { + if (typeList[i].equals(contentType)) { contentTypeList.select(i); - contentTypeList.setEnabled(false); - isPatchButton.setEnabled(false); - return; + break; } } } - public void setFilePath(String path) { - filePath.setText(path); + private void setFilePath(String path) { + fileNameText.setText(path); if (path.endsWith(".patch")) { isPatchButton.setSelection(true); if (attachContextButton.isEnabled()) { @@ -292,12 +290,40 @@ public class TaskAttachmentPage2 extends WizardPage { } } - public void setSupportsDescription(boolean supportsDescription) { - this.supportsDescription = supportsDescription; + public void setNeedsDescription(boolean supportsDescription) { + this.needsDescription = supportsDescription; + if (supportsDescription) { + setMessage("Enter a description and verify the content type of the attachment"); + } else { + setMessage("Verify the content type of the attachment"); + } } public boolean supportsDescription() { - return supportsDescription; + return needsDescription; + } + + @Override + public void setVisible(boolean visible) { + if (visible) { + if (fileNameText.getText().length() == 0) { + setFilePath(getModel().getSource().getName()); + } + setContentType(getModel().getSource().getContentType()); + } + super.setVisible(visible); + if (first) { + if (descriptionText != null) { + descriptionText.setFocus(); + getShell().getDisplay().asyncExec(new Runnable() { + public void run() { + } + }); + } else { + commentText.setFocus(); + } + first = false; + } } } |