Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormkersten2006-08-24 04:17:54 +0000
committermkersten2006-08-24 04:17:54 +0000
commitc75c2f53ac8f9b431ff2fed49a528ff753cdf908 (patch)
tree7442daff377ea3f21276a9207931e6968b92e9e5
parent9edf3526df85040bae894a0e762073b21b14e5a3 (diff)
downloadorg.eclipse.mylyn.tasks-c75c2f53ac8f9b431ff2fed49a528ff753cdf908.tar.gz
org.eclipse.mylyn.tasks-c75c2f53ac8f9b431ff2fed49a528ff753cdf908.tar.xz
org.eclipse.mylyn.tasks-c75c2f53ac8f9b431ff2fed49a528ff753cdf908.zip
Progress on: 151899: Trac connector: migrate to using RepositoryTaskData
https://bugs.eclipse.org/bugs/show_bug.cgi?id=151899
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracAttributeFactory.java132
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracOfflineTaskHandler.java259
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java10
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/AbstractTracClient.java17
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/ITracClient.java4
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/Trac09Client.java6
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracUtils.java9
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracXmlRpcClient.java70
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracAttachment.java77
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracComment.java86
-rw-r--r--org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracTicket.java48
11 files changed, 713 insertions, 5 deletions
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracAttributeFactory.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracAttributeFactory.java
new file mode 100644
index 000000000..8423c0d98
--- /dev/null
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracAttributeFactory.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.trac;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mylar.internal.trac.model.TracTicket.Key;
+import org.eclipse.mylar.tasks.core.AbstractAttributeFactory;
+import org.eclipse.mylar.tasks.core.RepositoryTaskAttribute;
+
+/**
+ * Provides a mapping from Mylar task keys to Trac ticket keys.
+ *
+ * @author Steffen Pingel
+ */
+public class TracAttributeFactory extends AbstractAttributeFactory {
+
+ private static final long serialVersionUID = 5333211422546115138L;
+
+ private static Map<String, Attribute> attributeByTracKey = new HashMap<String, Attribute>();
+
+ private static Map<String, String> tracKeyByTaskKey = new HashMap<String, String>();
+
+ public enum Attribute {
+ CC(Key.CC, "CC:", RepositoryTaskAttribute.USER_CC),
+ CHANGE_TIME(Key.CHANGE_TIME, "Last Modification:", RepositoryTaskAttribute.DATE_MODIFIED, true, true),
+ COMPONENT(Key.COMPONENT, "Component:", null),
+ DESCRIPTION(Key.DESCRIPTION, "Description:", RepositoryTaskAttribute.DESCRIPTION, true, false),
+ ID(Key.ID, "<used by search engine>", null, true),
+ KEYWORDS(Key.KEYWORDS, "Keywords:", RepositoryTaskAttribute.KEYWORDS),
+ MILESTONE(Key.MILESTONE, "Milestone:", null),
+ OWNER(Key.OWNER, "Owner:", RepositoryTaskAttribute.USER_OWNER, false, true),
+ PRIORITY(Key.PRIORITY, "Priority:", null),
+ REPORTER(Key.REPORTER, "Reporter:", RepositoryTaskAttribute.USER_REPORTER, false, true),
+ RESOLUTION(Key.RESOLUTION, "Resolution:", RepositoryTaskAttribute.RESOLUTION, false, true),
+ SEVERITY(Key.SEVERITY, "Severity:", null),
+ STATUS(Key.STATUS, "Status:", RepositoryTaskAttribute.STATUS, false, true),
+ SUMMARY(Key.SUMMARY, "Summary:", RepositoryTaskAttribute.SUMMARY, true),
+ TIME(Key.TIME, "Created:", RepositoryTaskAttribute.DATE_CREATION, true, true),
+ TYPE(Key.TYPE, "Type:", null),
+ VERSION(Key.VERSION, "Version:", null);
+
+ private final boolean isHidden;
+
+ private final boolean isReadOnly;
+
+ private final String tracKey;
+
+ private final String prettyName;
+
+ private final String taskKey;
+
+ Attribute(Key key, String prettyName, String taskKey, boolean hidden, boolean readonly) {
+ this.tracKey = key.getKey();
+ this.taskKey = taskKey;
+ this.prettyName = prettyName;
+ this.isHidden = hidden;
+ this.isReadOnly = readonly;
+
+ attributeByTracKey.put(tracKey, this);
+ if (taskKey != null) {
+ tracKeyByTaskKey.put(taskKey, tracKey);
+ }
+ }
+
+ Attribute(Key key, String prettyName, String taskKey, boolean hidden) {
+ this(key, prettyName, taskKey, hidden, false);
+ }
+
+ Attribute(Key key, String prettyName, String taskKey) {
+ this(key, prettyName, taskKey, false, false);
+ }
+
+ public String getTaskKey() {
+ return taskKey;
+ }
+
+ public String getTracKey() {
+ return tracKey;
+ }
+
+ public boolean isHidden() {
+ return isHidden;
+ }
+
+ public boolean isReadOnly() {
+ return isReadOnly;
+ }
+
+ public String toString() {
+ return prettyName;
+ }
+ }
+
+
+ @Override
+ public boolean getIsHidden(String key) {
+ Attribute attribute = attributeByTracKey.get(key);
+ return (attribute != null) ? attribute.isHidden() : false;
+ }
+
+ @Override
+ public String getName(String key) {
+ Attribute attribute = attributeByTracKey.get(key);
+ // TODO if attribute == null it is probably a custom field: need
+ // to query custom field information from repoository
+ return (attribute != null) ? attribute.toString() : key;
+ }
+
+ @Override
+ public boolean isReadOnly(String key) {
+ Attribute attribute = attributeByTracKey.get(key);
+ return (attribute != null) ? attribute.isReadOnly() : false;
+ }
+
+ @Override
+ public String mapCommonAttributeKey(String key) {
+ String tracKey = tracKeyByTaskKey.get(key);
+ return (tracKey != null) ? tracKey : key;
+ }
+
+}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracOfflineTaskHandler.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracOfflineTaskHandler.java
new file mode 100644
index 000000000..1804c5bfe
--- /dev/null
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracOfflineTaskHandler.java
@@ -0,0 +1,259 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 University Of British Columbia and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * University Of British Columbia - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylar.internal.trac;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylar.internal.trac.TracAttributeFactory.Attribute;
+import org.eclipse.mylar.internal.trac.core.ITracClient;
+import org.eclipse.mylar.internal.trac.core.TracUtils;
+import org.eclipse.mylar.internal.trac.model.TracAttachment;
+import org.eclipse.mylar.internal.trac.model.TracComment;
+import org.eclipse.mylar.internal.trac.model.TracTicket;
+import org.eclipse.mylar.tasks.core.AbstractAttributeFactory;
+import org.eclipse.mylar.tasks.core.AbstractRepositoryTask;
+import org.eclipse.mylar.tasks.core.IOfflineTaskHandler;
+import org.eclipse.mylar.tasks.core.RepositoryAttachment;
+import org.eclipse.mylar.tasks.core.RepositoryOperation;
+import org.eclipse.mylar.tasks.core.RepositoryTaskAttribute;
+import org.eclipse.mylar.tasks.core.RepositoryTaskData;
+import org.eclipse.mylar.tasks.core.TaskComment;
+import org.eclipse.mylar.tasks.core.TaskRepository;
+import org.eclipse.mylar.tasks.ui.TasksUiPlugin;
+
+/**
+ * @author Steffen Pingel
+ */
+public class TracOfflineTaskHandler implements IOfflineTaskHandler {
+
+ private AbstractAttributeFactory attributeFactory = new TracAttributeFactory();
+
+ private TracRepositoryConnector connector;
+
+ public TracOfflineTaskHandler(TracRepositoryConnector connector) {
+ this.connector = connector;
+ }
+
+ public RepositoryTaskData downloadTaskData(final AbstractRepositoryTask task) throws CoreException {
+ if (!connector.hasRichEditor(task)) {
+ // offline mode is only supported for XML-RPC
+ return null;
+ }
+
+ TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository(TracUiPlugin.REPOSITORY_KIND,
+ task.getRepositoryUrl());
+ try {
+ int id = Integer.parseInt(AbstractRepositoryTask.getTaskId(task.getHandleIdentifier()));
+ RepositoryTaskData data = new RepositoryTaskData(attributeFactory, TracUiPlugin.REPOSITORY_KIND, repository
+ .getUrl(), id + "");
+ ITracClient client = connector.getClientManager().getRepository(repository);
+ client.updateAttributes(new NullProgressMonitor(), false);
+ TracTicket ticket = client.getTicket(id);
+ createDefaultAttributes(attributeFactory, data, client);
+ updateTaskData(repository, attributeFactory, data, ticket);
+ return data;
+ } catch (Exception e) {
+ throw new CoreException(new Status(IStatus.ERROR, TracUiPlugin.PLUGIN_ID, 0, "Ticket download from "
+ + task.getRepositoryUrl() + " failed, please see details.", e));
+ }
+ }
+
+ public AbstractAttributeFactory getAttributeFactory() {
+ return attributeFactory;
+ }
+
+ public Date getDateForAttributeType(String attributeKey, String dateString) {
+ if (dateString == null || dateString.length() == 0) {
+ return null;
+ }
+
+ try {
+ String mappedKey = attributeFactory.mapCommonAttributeKey(attributeKey);
+ if (mappedKey.equals(Attribute.TIME.getTracKey()) || mappedKey.equals(Attribute.CHANGE_TIME.getTracKey())) {
+ return TracUtils.parseDate(Integer.valueOf(dateString));
+ }
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ public static void updateTaskData(TaskRepository repository, AbstractAttributeFactory factory,
+ RepositoryTaskData data, TracTicket ticket) {
+ if (ticket.getCreated() != null) {
+ data.setAttributeValue(Attribute.TIME.getTracKey(), TracUtils.toTracTime(ticket.getCreated()) + "");
+ }
+ if (ticket.getLastChanged() != null) {
+ data.setAttributeValue(Attribute.CHANGE_TIME.getTracKey(), TracUtils.toTracTime(ticket.getLastChanged())
+ + "");
+ }
+ Map<String, String> valueByKey = ticket.getValues();
+ for (String key : valueByKey.keySet()) {
+ data.setAttributeValue(key, valueByKey.get(key));
+ }
+
+ TracComment[] comments = ticket.getComments();
+ if (comments != null) {
+ for (int i = 0; i < comments.length; i++) {
+ if (!"comment".equals(comments[i].getField())
+ || "".equals(comments[i].getNewValue())) {
+ continue;
+ }
+
+ TaskComment taskComment = new TaskComment(factory, data, data.getComments().size() + 1);
+ taskComment.setAttributeValue(RepositoryTaskAttribute.USER_OWNER, comments[i].getAuthor());
+ taskComment
+ .setAttributeValue(RepositoryTaskAttribute.COMMENT_DATE, comments[i].getCreated().toString());
+ taskComment.setAttributeValue(RepositoryTaskAttribute.COMMENT_TEXT, comments[i].getNewValue());
+ data.addComment(taskComment);
+ }
+ }
+
+ TracAttachment[] attachments = ticket.getAttachments();
+ if (attachments != null) {
+ for (int i = 0; i < attachments.length; i++) {
+ RepositoryAttachment taskAttachment = new RepositoryAttachment(factory);
+ taskAttachment.setCreator(attachments[i].getAuthor());
+ taskAttachment.setAttributeValue(Attribute.DESCRIPTION.getTracKey(), attachments[i].getDescription());
+ taskAttachment.setAttributeValue(RepositoryTaskAttribute.ATTACHMENT_FILENAME, attachments[i]
+ .getFilename());
+ taskAttachment.setAttributeValue(RepositoryTaskAttribute.USER_OWNER, attachments[i].getAuthor());
+ taskAttachment.setAttributeValue(RepositoryTaskAttribute.ATTACHMENT_DATE, attachments[i].getCreated()
+ .toString());
+ taskAttachment.setAttributeValue(RepositoryTaskAttribute.ATTACHMENT_URL, repository.getUrl()
+ + ITracClient.TICKET_ATTACHMENT_URL + ticket.getId() + "/" + attachments[i].getFilename());
+ taskAttachment.setAttributeValue(RepositoryTaskAttribute.ATTACHMENT_ID, i + "");
+ data.addAttachment(taskAttachment);
+ }
+ }
+
+ String[] actions = ticket.getActions();
+ for (String action : actions) {
+ addOperation(repository, data, ticket, action);
+ }
+ }
+
+ // TODO Reuse Labels from BugzillaServerFacade
+ private static void addOperation(TaskRepository repository, RepositoryTaskData data, TracTicket ticket, String action) {
+ RepositoryOperation operation = null;
+ if ("leave".equals(action)) {
+ operation = new RepositoryOperation(action, "Leave as " + data.getStatus() + " "
+ + data.getResolution());
+ operation.setChecked(true);
+ } else if ("accept".equals(action)) {
+ operation = new RepositoryOperation(action, "Accept");
+ } else if ("resolve".equals(action)) {
+ operation = new RepositoryOperation(action, "Resolve bug, changing resolution to");
+ operation.setUpOptions("resolution");
+ for (String resolution : ticket.getResolutions()) {
+ operation.addOption(resolution, resolution);
+ }
+ } else if ("reassign".equals(action)) {
+ String localUser = repository.getUserName();
+ operation = new RepositoryOperation(action, "Reassing bug to");
+ // FIXME owner?
+ operation.setInputName("assign_to");
+ operation.setInputValue(localUser);
+ } else if ("reopen".equals(action)) {
+ operation = new RepositoryOperation(action, "Reopen");
+ }
+
+ if (operation != null) {
+ data.addOperation(operation);
+ }
+ }
+
+ public static void createDefaultAttributes(AbstractAttributeFactory factory, RepositoryTaskData data,
+ ITracClient client) {
+ createAttribute(factory, data, Attribute.STATUS, client.getTicketStatus());
+ createAttribute(factory, data, Attribute.RESOLUTION, client.getTicketResolutions());
+
+ createAttribute(factory, data, Attribute.COMPONENT, client.getComponents());
+ createAttribute(factory, data, Attribute.VERSION, client.getVersions(), true);
+ createAttribute(factory, data, Attribute.PRIORITY, client.getPriorities());
+ createAttribute(factory, data, Attribute.SEVERITY, client.getSeverities());
+
+ createAttribute(factory, data, Attribute.TYPE, client.getTicketTypes());
+ createAttribute(factory, data, Attribute.OWNER);
+ createAttribute(factory, data, Attribute.MILESTONE, client.getMilestones(), true);
+ createAttribute(factory, data, Attribute.REPORTER);
+
+ createAttribute(factory, data, Attribute.CC);
+ createAttribute(factory, data, Attribute.KEYWORDS);
+ }
+
+ private static RepositoryTaskAttribute createAttribute(AbstractAttributeFactory factory, RepositoryTaskData data,
+ Attribute attribute, Object[] values, boolean allowEmtpy) {
+ RepositoryTaskAttribute attr = factory.createAttribute(attribute.getTracKey());
+ if (values != null && values.length > 0) {
+ if (allowEmtpy) {
+ attr.addOptionValue("", "");
+ }
+ for (int i = 0; i < values.length; i++) {
+ attr.addOptionValue(values[i].toString(), values[i].toString());
+ }
+ } else {
+ //attr.setHidden(true);
+ attr.setReadOnly(true);
+ }
+ data.addAttribute(attribute.getTracKey(), attr);
+ return attr;
+ }
+
+ private static RepositoryTaskAttribute createAttribute(AbstractAttributeFactory factory, RepositoryTaskData data,
+ Attribute attribute) {
+ RepositoryTaskAttribute attr = factory.createAttribute(attribute.getTracKey());
+ data.addAttribute(attribute.getTracKey(), attr);
+ return attr;
+ }
+
+ private static RepositoryTaskAttribute createAttribute(AbstractAttributeFactory factory, RepositoryTaskData data,
+ Attribute attribute, Object[] values) {
+ return createAttribute(factory, data, attribute, values, false);
+ }
+
+ public Set<AbstractRepositoryTask> getChangedSinceLastSync(TaskRepository repository,
+ Set<AbstractRepositoryTask> tasks) throws Exception {
+ if (repository.getSyncTimeStamp() == null) {
+ return tasks;
+ }
+
+ String dateString = repository.getSyncTimeStamp();
+ if (dateString == null) {
+ dateString = "0";
+ }
+ Date since = TracUtils.parseDate(Integer.parseInt(dateString));
+
+ ITracClient client = connector.getClientManager().getRepository(repository);
+ Set<Integer> ids = client.getChangedTickets(since);
+ if (ids == null) {
+ // the call is not supported, any task may have changed
+ return tasks;
+ }
+
+ Set<AbstractRepositoryTask> result = new HashSet<AbstractRepositoryTask>();
+ for (AbstractRepositoryTask task : tasks) {
+ Integer id = Integer.parseInt(AbstractRepositoryTask.getTaskId(task.getHandleIdentifier()));
+ if (ids.contains(id)) {
+ result.add(task);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java
index fa63b4276..5b6b9c366 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/TracRepositoryConnector.java
@@ -61,13 +61,15 @@ public class TracRepositoryConnector extends AbstractRepositoryConnector {
private List<String> supportedVersions;
private TracClientManager clientManager;
-
+
+ private TracOfflineTaskHandler offlineTaskHandler = new TracOfflineTaskHandler(this);
+
private TracAttachmentHandler attachmentHandler = new TracAttachmentHandler(this);
-
+
public TracRepositoryConnector() {
TracUiPlugin.getDefault().setConnector(this);
}
-
+
@Override
public boolean canCreateNewTask(TaskRepository repository) {
return true;
@@ -125,7 +127,7 @@ public class TracRepositoryConnector extends AbstractRepositoryConnector {
@Override
public IOfflineTaskHandler getOfflineTaskHandler() {
- return null;
+ return offlineTaskHandler;
}
@Override
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/AbstractTracClient.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/AbstractTracClient.java
index 528f2678c..914437ed8 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/AbstractTracClient.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/AbstractTracClient.java
@@ -101,4 +101,21 @@ public abstract class AbstractTracClient implements ITracClient {
this.data = data;
}
+ public String[] getDefaultTicketResolutions() {
+ return new String[] { "fixed", "invalid", "wontfix", "duplicat", "worksforme" };
+ }
+
+ public String[] getDefaultTicketActions(String status) {
+ if ("new".equals(status)) {
+ return new String[] { "leave", "resolve", "reassign", "accept" };
+ } else if ("assigned".equals(status)) {
+ return new String[] { "leave", "resolve", "reassign" };
+ } else if ("reopened".equals(status)) {
+ return new String[] { "leave", "resolve", "reassign" };
+ } else if ("closed".equals(status)) {
+ return new String[] { "leave", "reopen" };
+ }
+ return null;
+ }
+
}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/ITracClient.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/ITracClient.java
index 30effdab8..b7f7fdd89 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/ITracClient.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/ITracClient.java
@@ -11,7 +11,9 @@
package org.eclipse.mylar.internal.trac.core;
+import java.util.Date;
import java.util.List;
+import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.mylar.internal.trac.model.TracComponent;
@@ -146,5 +148,7 @@ public interface ITracClient {
* @param data cached repository attributes
*/
void setData(TracClientData data);
+
+ Set<Integer> getChangedTickets(Date since) throws TracException;
}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/Trac09Client.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/Trac09Client.java
index c1b571d97..beec213aa 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/Trac09Client.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/Trac09Client.java
@@ -18,9 +18,11 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.StringTokenizer;
import javax.security.auth.login.LoginException;
@@ -470,4 +472,8 @@ public class Trac09Client extends AbstractTracClient {
throw new TracException("Unsupported operation");
}
+ public Set<Integer> getChangedTickets(Date since) throws TracException {
+ throw new TracException("Unsupported operation");
+ }
+
}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracUtils.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracUtils.java
index 5c6c16669..e414bcfc1 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracUtils.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracUtils.java
@@ -19,11 +19,18 @@ import java.util.TimeZone;
*/
public class TracUtils {
- public static Date parseDate(int seconds) {
+ public static Date parseDate(long seconds) {
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone(ITracClient.TIME_ZONE));
c.setTimeInMillis(seconds * 1000l);
return c.getTime();
}
+ public static long toTracTime(Date date) {
+ Calendar c = Calendar.getInstance();
+ c.setTime(date);
+ c.setTimeZone(TimeZone.getTimeZone(ITracClient.TIME_ZONE));
+ return c.getTimeInMillis() / 1000l;
+ }
+
}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracXmlRpcClient.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracXmlRpcClient.java
index ad8f33027..ea618d6ef 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracXmlRpcClient.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/core/TracXmlRpcClient.java
@@ -4,9 +4,12 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
@@ -15,6 +18,8 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.mylar.context.core.MylarStatusHandler;
import org.eclipse.mylar.internal.trac.core.TracHttpClientTransportFactory.TracHttpException;
+import org.eclipse.mylar.internal.trac.model.TracAttachment;
+import org.eclipse.mylar.internal.trac.model.TracComment;
import org.eclipse.mylar.internal.trac.model.TracComponent;
import org.eclipse.mylar.internal.trac.model.TracMilestone;
import org.eclipse.mylar.internal.trac.model.TracPriority;
@@ -151,9 +156,50 @@ public class TracXmlRpcClient extends AbstractTracClient {
public TracTicket getTicket(int id) throws TracException {
Object[] result = (Object[]) call("ticket.get", id);
TracTicket ticket = parseTicket(result);
+
+ result = (Object[]) call("ticket.changeLog", id, 0);
+ for (Object item : result) {
+ ticket.addComment(parseChangeLogEntry((Object[]) item));
+ }
+
+ result = (Object[]) call("ticket.listAttachments", id);
+ for (Object item : result) {
+ ticket.addAttachment(parseAttachment((Object[]) item));
+ }
+
+ try {
+ String[] actions = getActions(id);
+ ticket.setActions(actions);
+ } catch (TracException e) {
+ // remove this if getActions() has been implemented in XmlRpcPlugin
+ String status = ticket.getValue(Key.STATUS);
+ ticket.setActions(getDefaultTicketActions(status));
+ }
+
+ ticket.setResolutions(getDefaultTicketResolutions());
+
return ticket;
}
+ private TracAttachment parseAttachment(Object[] entry) {
+ TracAttachment attachment = new TracAttachment((String) entry[0]);
+ attachment.setDescription((String) entry[1]);
+ attachment.setSize((Integer) entry[2]);
+ attachment.setCreated(TracUtils.parseDate((Integer) entry[3]));
+ attachment.setAuthor((String) entry[4]);
+ return attachment;
+ }
+
+ private TracComment parseChangeLogEntry(Object[] entry) {
+ TracComment comment = new TracComment();
+ comment.setCreated(TracUtils.parseDate((Integer) entry[0]));
+ comment.setAuthor((String) entry[1]);
+ comment.setField((String) entry[2]);
+ comment.setOldValue((String) entry[3]);
+ comment.setNewValue((String) entry[4]);
+ return comment;
+ }
+
/* public for testing */
@SuppressWarnings("unchecked")
public List<TracTicket> getTickets(int[] ids) throws TracException {
@@ -377,4 +423,28 @@ public class TracXmlRpcClient extends AbstractTracClient {
call("ticket.update", ticket.getId(), comment, attributes);
}
+ public Set<Integer> getChangedTickets(Date since) throws TracException {
+ Object[] ids;
+ try {
+ ids = (Object[]) call("ticket.getRecentChanges", since);
+ } catch (TracException e) {
+ // TODO remove this once getRecentChanges is supported by the XmlRpcPlugin
+ return null;
+ }
+ Set<Integer> result = new HashSet<Integer>();
+ for (Object id : ids) {
+ result.add((Integer) id);
+ }
+ return result;
+ }
+
+ public String[] getActions(int id) throws TracException {
+ Object[] actions = (Object[]) call("ticket.getAvailableActions", id);
+ String[] result = new String[actions.length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = (String) actions[i];
+ }
+ return result;
+ }
+
}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracAttachment.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracAttachment.java
new file mode 100644
index 000000000..338fae2c0
--- /dev/null
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracAttachment.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 Mylar 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.mylar.internal.trac.model;
+
+import java.util.Date;
+
+/**
+ * @author Steffen Pingel
+ */
+public class TracAttachment {
+
+ private String author;
+
+ private Date created;
+
+ private String description;
+
+ private String filename;
+
+ int size;
+
+ public TracAttachment(String filename) {
+ this.filename = filename;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ @Override
+ public String toString() {
+ return filename;
+ }
+
+}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracComment.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracComment.java
new file mode 100644
index 000000000..14b534393
--- /dev/null
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracComment.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2006 Mylar 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.mylar.internal.trac.model;
+
+import java.util.Date;
+
+/**
+ * @author Steffen Pingel
+ */
+public class TracComment {
+
+ private String author;
+
+ private Date created;
+
+ private String field;
+
+ private String newValue;
+
+ private String oldValue;
+
+ private boolean permanent;
+
+ public TracComment() {
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public String getField() {
+ return field;
+ }
+
+ public String getNewValue() {
+ return newValue;
+ }
+
+ public String getOldValue() {
+ return oldValue;
+ }
+
+ public boolean isPermanent() {
+ return permanent;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public void setField(String field) {
+ this.field = field;
+ }
+
+ public void setNewValue(String newValue) {
+ this.newValue = newValue;
+ }
+
+ public void setOldValue(String oldValue) {
+ this.oldValue = oldValue;
+ }
+
+ public void setPermanent(boolean permanent) {
+ this.permanent = permanent;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + field + "] " + author + ": " + oldValue + " -> " + newValue;
+ }
+
+}
diff --git a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracTicket.java b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracTicket.java
index c08851cad..9b4959963 100644
--- a/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracTicket.java
+++ b/org.eclipse.mylyn.trac.ui/src/org/eclipse/mylyn/internal/trac/model/TracTicket.java
@@ -11,8 +11,10 @@
package org.eclipse.mylar.internal.trac.model;
+import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.eclipse.mylar.internal.trac.core.InvalidTicketException;
@@ -78,6 +80,14 @@ public class TracTicket {
/** Trac's built-in ticket properties. */
private Map<Key, String> valueByKey = new HashMap<Key, String>();
+ private List<TracComment> comments;
+
+ private List<TracAttachment> attachments;
+
+ private String[] actions;
+
+ private String[] resolutions;
+
public TracTicket() {
}
@@ -174,4 +184,42 @@ public class TracTicket {
this.lastChanged = TracUtils.parseDate(lastChanged);
}
+ public void addComment(TracComment comment) {
+ if (comments == null) {
+ comments = new ArrayList<TracComment>();
+ }
+ comments.add(comment);
+ }
+
+ public void addAttachment(TracAttachment attachment) {
+ if (attachments == null) {
+ attachments = new ArrayList<TracAttachment>();
+ }
+ attachments.add(attachment);
+ }
+
+ public TracComment[] getComments() {
+ return (comments != null) ? comments.toArray(new TracComment[0]) : null;
+ }
+
+ public TracAttachment[] getAttachments() {
+ return (attachments != null) ? attachments.toArray(new TracAttachment[0]) : null;
+ }
+
+ public void setActions(String[] actions) {
+ this.actions = actions;
+ }
+
+ public String[] getActions() {
+ return actions;
+ }
+
+ public void setResolutions(String[] resolutions) {
+ this.resolutions = resolutions;
+ }
+
+ public String[] getResolutions() {
+ return resolutions;
+ }
+
}

Back to the top