Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrelves2006-06-08 03:34:12 +0000
committerrelves2006-06-08 03:34:12 +0000
commit1da2429e2fb0aff00ed898fc426c4ca0c40145c4 (patch)
tree1c0c1080179a1e959bad3856f00a19cdc4a5f7eb /org.eclipse.mylyn.tasks.ui
parent83907ba3f8781255a02b5003a0c1370b8effe0b1 (diff)
downloadorg.eclipse.mylyn.tasks-1da2429e2fb0aff00ed898fc426c4ca0c40145c4.tar.gz
org.eclipse.mylyn.tasks-1da2429e2fb0aff00ed898fc426c4ca0c40145c4.tar.xz
org.eclipse.mylyn.tasks-1da2429e2fb0aff00ed898fc426c4ca0c40145c4.zip
Progress on: 138043: create a common task editor
https://bugs.eclipse.org/bugs/show_bug.cgi?id=138043
Diffstat (limited to 'org.eclipse.mylyn.tasks.ui')
-rw-r--r--org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF4
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/OfflineTaskManager.java175
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/RepositoryTaskAttribute.java2
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskUiUtil.java64
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/AbstractBugEditorInput.java83
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/AbstractRepositoryTaskEditor.java2401
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/ExistingBugEditorInput.java195
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/IRepositoryTaskAttributeListener.java19
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/IRepositoryTaskSelection.java89
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/OutlineTools.java65
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskEditorCopyAction.java39
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlineComparer.java49
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlineNode.java356
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlinePage.java171
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskSelection.java171
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTextViewer.java125
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/SpellingDialog.java105
-rw-r--r--org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryConnector.java52
18 files changed, 4028 insertions, 137 deletions
diff --git a/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF b/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF
index 74e7e6536..f2084c474 100644
--- a/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF
@@ -11,7 +11,9 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.jface.text,
org.eclipse.mylar.core,
org.eclipse.update.core,
- org.eclipse.ui.browser
+ org.eclipse.ui.browser,
+ org.eclipse.ui.editors,
+ org.eclipse.ui.views
Eclipse-AutoStart: true
Bundle-Vendor: Eclipse.org
Bundle-ClassPath: mylar-tasklist.jar
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/OfflineTaskManager.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/OfflineTaskManager.java
index f03440cb9..60cdb961a 100644
--- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/OfflineTaskManager.java
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/OfflineTaskManager.java
@@ -23,7 +23,6 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryConnector;
import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
-import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask.RepositoryTaskSyncState;
/**
* Class to persist the data for the offline reports list
@@ -62,93 +61,115 @@ public class OfflineTaskManager {
/**
- * Add an offline report to the offline reports list
+ * Add a RepositoryTaskData to the offline reports file
*
* @param entry
* The bug to add
*/
- public RepositoryTaskSyncState add(final RepositoryTaskData entry, boolean forceSync) throws CoreException {
+ public void add(final RepositoryTaskData entry) throws CoreException {
+ int index = -1;
+ if ((index = find(entry.getRepositoryUrl(), entry.getId())) >= 0) {
- RepositoryTaskSyncState status = RepositoryTaskSyncState.SYNCHRONIZED;
-//
-// try {
-//
-// String handle = AbstractRepositoryTask.getHandle(entry.getRepositoryUrl(), entry.getId());
-// ITask task = MylarTaskListPlugin.getTaskListManager().getTaskList().getTask(handle);
-//
-// if (task != null && task instanceof AbstractRepositoryTask) {
-// AbstractRepositoryTask repositoryTask = (AbstractRepositoryTask) task;
-//
-// TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(
-// repositoryTask.getRepositoryKind(), repositoryTask.getRepositoryUrl());
-//
-// if (repository == null) {
-// throw new Exception("No repository associated with task. Unable to retrieve timezone information.");
-// }
-//
-// TimeZone repositoryTimeZone = DateUtil.getTimeZone(repository.getTimeZoneId());
+ list.remove(index);
- int index = -1;
- if ((index = find(entry.getRepositoryUrl(), entry.getId())) >= 0) {
- //RepositoryTaskData oldBug = list.get(index);
+ list.add(entry);
+ writeFile();
-// if (repositoryTask.getLastSynchronized() == null
-// || entry.getLastModified(repositoryTimeZone)
-// .compareTo(repositoryTask.getLastSynchronized()) > 0 || forceSync) {
+ } else {
+ list.add(entry);
+ writeFile();
+ }
+ }
+
+
+// /**
+// * Add an offline report to the offline reports list
+// *
+// * @param entry
+// * The bug to add
+// */
+// public RepositoryTaskSyncState add(final RepositoryTaskData entry, boolean forceSync) throws CoreException {
//
-// if (oldBug.hasChanges()) {
+// RepositoryTaskSyncState status = RepositoryTaskSyncState.SYNCHRONIZED;
+////
+//// try {
+////
+//// String handle = AbstractRepositoryTask.getHandle(entry.getRepositoryUrl(), entry.getId());
+//// ITask task = MylarTaskListPlugin.getTaskListManager().getTaskList().getTask(handle);
+////
+//// if (task != null && task instanceof AbstractRepositoryTask) {
+//// AbstractRepositoryTask repositoryTask = (AbstractRepositoryTask) task;
+////
+//// TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(
+//// repositoryTask.getRepositoryKind(), repositoryTask.getRepositoryUrl());
+////
+//// if (repository == null) {
+//// throw new Exception("No repository associated with task. Unable to retrieve timezone information.");
+//// }
+////
+//// TimeZone repositoryTimeZone = DateUtil.getTimeZone(repository.getTimeZoneId());
//
-// PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
-// public void run() {
-// updateLocalCopy = MessageDialog
-// .openQuestion(
-// null,
-// "Update Local Copy",
-// "Local copy of Report "
-// + entry.getId()
-// + " on "
-// + entry.getRepositoryUrl()
-// + " has changes.\nWould you like to override local changes? \n\nNote: if you select No, only the new comment will be saved with the updated bug, all other changes will be lost.");
-// }
-// });
+// int index = -1;
+// if ((index = find(entry.getRepositoryUrl(), entry.getId())) >= 0) {
+// //RepositoryTaskData oldBug = list.get(index);
//
-// if (!updateLocalCopy) {
-// ((RepositoryTaskData) entry).setNewComment(((RepositoryTaskData) oldBug).getNewComment());
-// ((RepositoryTaskData) entry).setHasChanged(true);
-// status = RepositoryTaskSyncState.CONFLICT;
-// } else {
-// ((RepositoryTaskData) entry).setHasChanged(false);
-// status = RepositoryTaskSyncState.SYNCHRONIZED;
-// }
-// } else {
-// if (forceSync) {
-// status = RepositoryTaskSyncState.SYNCHRONIZED;
-// } else {
-// status = RepositoryTaskSyncState.INCOMING;
-// }
-// }
- list.remove(index);
-// if (entry.hasChanges() && status != RepositoryTaskSyncState.CONFLICT) {
-// status = RepositoryTaskSyncState.OUTGOING;
-// }
- list.add(entry);
- writeFile();
-
- } else {
- // report doesn't exist in offline reports
- list.add(entry);
- writeFile();
- }
- //repositoryTask.setLastSynchronized(entry.getLastModified(repositoryTimeZone));
+//// if (repositoryTask.getLastSynchronized() == null
+//// || entry.getLastModified(repositoryTimeZone)
+//// .compareTo(repositoryTask.getLastSynchronized()) > 0 || forceSync) {
+////
+//// if (oldBug.hasChanges()) {
+////
+//// PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
+//// public void run() {
+//// updateLocalCopy = MessageDialog
+//// .openQuestion(
+//// null,
+//// "Update Local Copy",
+//// "Local copy of Report "
+//// + entry.getId()
+//// + " on "
+//// + entry.getRepositoryUrl()
+//// + " has changes.\nWould you like to override local changes? \n\nNote: if you select No, only the new comment will be saved with the updated bug, all other changes will be lost.");
+//// }
+//// });
+////
+//// if (!updateLocalCopy) {
+//// ((RepositoryTaskData) entry).setNewComment(((RepositoryTaskData) oldBug).getNewComment());
+//// ((RepositoryTaskData) entry).setHasChanged(true);
+//// status = RepositoryTaskSyncState.CONFLICT;
+//// } else {
+//// ((RepositoryTaskData) entry).setHasChanged(false);
+//// status = RepositoryTaskSyncState.SYNCHRONIZED;
+//// }
+//// } else {
+//// if (forceSync) {
+//// status = RepositoryTaskSyncState.SYNCHRONIZED;
+//// } else {
+//// status = RepositoryTaskSyncState.INCOMING;
+//// }
+//// }
+// list.remove(index);
+//// if (entry.hasChanges() && status != RepositoryTaskSyncState.CONFLICT) {
+//// status = RepositoryTaskSyncState.OUTGOING;
+//// }
+// list.add(entry);
+// writeFile();
+//
+// } else {
+// // report doesn't exist in offline reports
+// list.add(entry);
+// writeFile();
+// }
+// //repositoryTask.setLastSynchronized(entry.getLastModified(repositoryTimeZone));
+//// }
+//// } catch (Exception e) {
+//// e.printStackTrace();
+//// IStatus runtimestatus = new Status(IStatus.ERROR, MylarTaskListPlugin.PLUGIN_ID, IStatus.OK,
+//// "failed to add offline report", e);
+//// throw new CoreException(runtimestatus);
+//// }
+// return status;
// }
-// } catch (Exception e) {
-// e.printStackTrace();
-// IStatus runtimestatus = new Status(IStatus.ERROR, MylarTaskListPlugin.PLUGIN_ID, IStatus.OK,
-// "failed to add offline report", e);
-// throw new CoreException(runtimestatus);
-// }
- return status;
- }
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/RepositoryTaskAttribute.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/RepositoryTaskAttribute.java
index 8b5a16c0f..ce2359c69 100644
--- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/RepositoryTaskAttribute.java
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/RepositoryTaskAttribute.java
@@ -18,7 +18,7 @@ import java.util.List;
import java.util.Map;
/**
- * Class representing a report attribute may contain child attributes
+ * Class representing a report attribute
*
* @author Rob Elves
*/
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskUiUtil.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskUiUtil.java
index 66545bef9..ab5a92f11 100644
--- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskUiUtil.java
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/TaskUiUtil.java
@@ -16,6 +16,9 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.List;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
import org.eclipse.mylar.internal.tasklist.TaskListPreferenceConstants;
@@ -142,52 +145,37 @@ public class TaskUiUtil {
}
if (task instanceof AbstractRepositoryTask) {
- String repositoryKind = ((AbstractRepositoryTask) task).getRepositoryKind();
+ final AbstractRepositoryTask repositoryTask = (AbstractRepositoryTask) task;
+ String repositoryKind = repositoryTask.getRepositoryKind();
final AbstractRepositoryConnector connector = MylarTaskListPlugin.getRepositoryManager()
.getRepositoryConnector(repositoryKind);
- TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(repositoryKind, ((AbstractRepositoryTask) task).getRepositoryUrl());
+ TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(repositoryKind, repositoryTask.getRepositoryUrl());
if (!repository.hasCredentials()) {
MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
MylarTaskListPlugin.TITLE_DIALOG,
"Repository does not have credentials set, verify via " + TaskRepositoriesView.NAME + " view");
}
- if (connector != null) {
- TaskUiUtil.openEditor(task, false);
- connector.synchronize((AbstractRepositoryTask) task, false, null);
-
-
-// Job refreshJob = connector.synchronize((AbstractRepositoryTask) task, forceUpdate,
-// new IJobChangeListener() {
-//
-// public void done(IJobChangeEvent event) {
-// TaskUiUtil.openEditor(task, false);
-// }
-//
-// public void aboutToRun(IJobChangeEvent event) {
-// // ignore
-// }
-//
-// public void awake(IJobChangeEvent event) {
-// // ignore
-// }
-//
-// public void running(IJobChangeEvent event) {
-// // ignore
-// }
-//
-// public void scheduled(IJobChangeEvent event) {
-// // ignore
-// }
-//
-// public void sleeping(IJobChangeEvent event) {
-// // ignore
-// }
-// });
-// if (refreshJob == null) {
-// TaskUiUtil.openEditor(task, false);
-// }
- }
+ if (connector != null)
+ if (repositoryTask.getTaskData() != null) {
+ TaskUiUtil.openEditor(task, false);
+ // TODO: Eventually will need to check that this task
+ // isn't a new report awaiting submission if so
+ // don't synchronize
+ connector.synchronize((AbstractRepositoryTask) task, false, null);
+ } else {
+ Job refreshJob = connector.synchronize((AbstractRepositoryTask) task, true,
+ new JobChangeAdapter() {
+ public void done(IJobChangeEvent event) {
+ if (repositoryTask.getTaskData() != null) {
+ TaskUiUtil.openEditor(task, false);
+ }
+ }
+ });
+ if (refreshJob == null) {
+ TaskUiUtil.openEditor(task, false);
+ }
+ }
} else {
TaskUiUtil.openEditor(task, false);
}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/AbstractBugEditorInput.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/AbstractBugEditorInput.java
new file mode 100644
index 000000000..08a93404a
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/AbstractBugEditorInput.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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.tasklist.ui.editors;
+
+import java.net.Proxy;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IPersistableElement;
+
+/**
+ * Abstract base implementation of an <code>IEditorInput</code> for a subclass
+ * of <code>AbstractRepositoryTaskEditor</code>.
+ */
+public abstract class AbstractBugEditorInput implements IEditorInput {
+
+ protected String toolTipText = "";
+
+ protected Proxy proxySettings;
+
+ protected AbstractBugEditorInput() {
+ this.proxySettings = MylarTaskListPlugin.getDefault().getProxySettings();
+ }
+
+ /**
+ * Sets the tool tip text for this editor input.
+ *
+ * @param str
+ * The new tool tip text.
+ */
+ protected void setToolTipText(String str) {
+ // 03-20-03 Allows editor to store title (once it is known)
+ toolTipText = str;
+ }
+
+ public boolean exists() {
+ return true;
+ }
+
+ public abstract RepositoryTaskData getRepositoryTaskData();
+
+ public ImageDescriptor getImageDescriptor() {
+ return null;
+ }
+
+ public IPersistableElement getPersistable() {
+ return null;
+ }
+
+ public String getToolTipText() {
+ return toolTipText;
+ }
+
+ public Object getAdapter(Class adapter) {
+ return null;
+ }
+
+ /**
+ * @return <code>true</code> if the argument is an editor input on the
+ * same bug.
+ */
+ @Override
+ public abstract boolean equals(Object o);
+
+ public Proxy getProxySettings() {
+ return proxySettings;
+ }
+
+
+ public abstract TaskRepository getRepository();
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/AbstractRepositoryTaskEditor.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/AbstractRepositoryTaskEditor.java
new file mode 100644
index 000000000..21d0f1931
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/AbstractRepositoryTaskEditor.java
@@ -0,0 +1,2401 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 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.tasklist.ui.editors;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.TextViewer;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.internal.tasklist.Comment;
+import org.eclipse.mylar.internal.tasklist.LocalAttachment;
+import org.eclipse.mylar.internal.tasklist.RepositoryAttachment;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskAttribute;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+import org.eclipse.mylar.internal.tasklist.ui.TaskListImages;
+import org.eclipse.mylar.internal.tasklist.ui.TaskUiUtil;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryConnector;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask.RepositoryTaskSyncState;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+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.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.RetargetAction;
+import org.eclipse.ui.forms.events.ExpansionAdapter;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.events.HyperlinkAdapter;
+import org.eclipse.ui.forms.events.HyperlinkEvent;
+import org.eclipse.ui.forms.events.IExpansionListener;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+import org.eclipse.ui.forms.widgets.FormToolkit;
+import org.eclipse.ui.forms.widgets.ImageHyperlink;
+import org.eclipse.ui.forms.widgets.ScrolledForm;
+import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.part.EditorPart;
+import org.eclipse.ui.themes.IThemeManager;
+import org.eclipse.ui.views.contentoutline.ContentOutline;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+
+/**
+ * Abstract base implementation for an editor to view a bugzilla report.
+ *
+ * @author Mik Kersten (some hardening of prototype)
+ * @author Rob Elves (Conversion to Eclipse Forms)
+ */
+public abstract class AbstractRepositoryTaskEditor extends EditorPart {
+
+ protected static final String CONTEXT_MENU_ID = "#BugEditor";
+
+ public static final String REPOSITORY_TEXT_ID = "org.eclipse.mylar.tasklist.ui.fonts.task.editor.comment";
+
+ public static final String HYPERLINK_TYPE_TASK = "task";
+
+ public static final String HYPERLINK_TYPE_JAVA = "java";
+
+ private static final String LABEL_BUTTON_SUBMIT = "Submit to Repository";
+
+ private static final String LABEL_SECTION_ACTIONS = "Actions";
+
+ private static final String LABEL_SECTION_ATTRIBUTES = "Attributes";
+
+ private static final String LABEL_SECTION_ATTACHMENTS = "Attachments";
+
+ protected static final String LABEL_SECTION_DESCRIPTION = "Description";
+
+ protected static final String LABEL_SECTION_COMMENTS = "Comments";
+
+ protected static final String LABEL_SECTION_NEW_COMMENT = "New Comment";
+
+ private FormToolkit toolkit;
+
+ private ScrolledForm form;
+
+ protected TaskRepository repository;
+
+ public static final int WRAP_LENGTH = 90;
+
+ protected Display display;
+
+ public static final Font TITLE_FONT = JFaceResources.getBannerFont();
+
+ public static final Font TEXT_FONT = JFaceResources.getDefaultFont();
+
+ // public static final Font COMMENT_FONT =
+ // JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT);
+
+ public static final Font HEADER_FONT = JFaceResources.getDefaultFont();
+
+ public static final int DESCRIPTION_WIDTH = 79 * 8; // 500;
+
+ public static final int DESCRIPTION_HEIGHT = 10 * 14;
+
+ // protected Color background;
+ //
+ // protected Color foreground;
+
+ protected AbstractBugEditorInput editorInput;
+
+ private MylarTaskEditor parentEditor = null;
+
+ protected RepositoryTaskOutlineNode bugzillaOutlineModel = null;
+
+ // private static int MARGIN = 0;// 5
+
+ protected SimpleDateFormat simpleDateFormat = new SimpleDateFormat("E MMM dd, yyyy hh:mm aa");
+
+ // "yyyy-MM-dd HH:mm"
+
+ /**
+ * Style option for function <code>newLayout</code>. This will create a
+ * plain-styled, selectable text label.
+ */
+ protected final String VALUE = "VALUE";
+
+ /**
+ * Style option for function <code>newLayout</code>. This will create a
+ * bolded, selectable header. It will also have an arrow image before the
+ * text (simply for decoration).
+ */
+ protected final String HEADER = "HEADER";
+
+ /**
+ * Style option for function <code>newLayout</code>. This will create a
+ * bolded, unselectable label.
+ */
+ protected final String PROPERTY = "PROPERTY";
+
+ protected final int HORZ_INDENT = 0;
+
+ protected CCombo attributeCombo;
+
+ // protected CCombo versionCombo;
+ //
+ // protected CCombo platformCombo;
+ //
+ // protected CCombo priorityCombo;
+ //
+ // protected CCombo severityCombo;
+ //
+ // protected CCombo milestoneCombo;
+ //
+ // protected CCombo componentCombo;
+
+ protected Button addSelfToCCCheck;
+
+ // protected Text urlText;
+
+ protected Text summaryText;
+
+ protected Text addCommentsText;
+
+ // protected Text assignedTo;
+
+ protected Text attachmentDesc;
+
+ protected Text attachmentComment;
+
+ protected Button submitButton;
+
+ protected Table attachmentsTable;
+
+ protected TableViewer attachmentTableViewer;
+
+ protected String[] attachmentsColumns = { "Description", "Type", "Creator", "Created" };
+
+ protected int[] attachmentsColumnWidths = { 200, 100, 100, 200 };
+
+ protected int scrollIncrement;
+
+ protected int scrollVertPageIncrement;
+
+ protected int scrollHorzPageIncrement;
+
+ public boolean isDirty = false;
+
+ /** Manager controlling the context menu */
+ protected MenuManager contextMenuManager;
+
+ protected StyledText currentSelectedText;
+
+ protected static final String cutActionDefId = "org.eclipse.ui.edit.cut"; //$NON-NLS-1$
+
+ protected static final String copyActionDefId = "org.eclipse.ui.edit.copy"; //$NON-NLS-1$
+
+ protected static final String pasteActionDefId = "org.eclipse.ui.edit.paste"; //$NON-NLS-1$
+
+ protected RetargetAction cutAction;
+
+ protected RepositoryTaskEditorCopyAction copyAction;
+
+ // private Action revealAllAction;
+
+ protected RetargetAction pasteAction;
+
+ protected Composite editorComposite;
+
+ // protected CLabel titleLabel;
+
+ // protected ScrolledComposite scrolledComposite;
+
+ // protected Composite scrolledComposite;
+
+ // protected Composite infoArea;
+
+ // protected Hyperlink linkToBug;
+
+ // protected StyledText generalTitleText;
+
+ // private static List<String> contentTypes;
+
+ private static Map<String, String> extensions2Types;
+
+ static {
+ /* For possible 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");
+ 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");
+ }
+
+ private List<IRepositoryTaskAttributeListener> attributesListeners = new ArrayList<IRepositoryTaskAttributeListener>();
+
+ protected final ISelectionProvider selectionProvider = new ISelectionProvider() {
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ selectionChangedListeners.add(listener);
+ }
+
+ public ISelection getSelection() {
+ return null;
+ }
+
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ selectionChangedListeners.remove(listener);
+ }
+
+ public void setSelection(ISelection selection) {
+ // No implementation.
+ }
+ };
+
+ protected List<ISelectionChangedListener> selectionChangedListeners = new ArrayList<ISelectionChangedListener>();
+
+ protected HashMap<CCombo, RepositoryTaskAttribute> comboListenerMap = new HashMap<CCombo, RepositoryTaskAttribute>();
+
+ private IRepositoryTaskSelection lastSelected = null;
+
+ protected final ISelectionListener selectionListener = new ISelectionListener() {
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if ((part instanceof ContentOutline) && (selection instanceof StructuredSelection)) {
+ Object select = ((StructuredSelection) selection).getFirstElement();
+ if (select instanceof RepositoryTaskOutlineNode) {
+ RepositoryTaskOutlineNode n = (RepositoryTaskOutlineNode) select;
+
+ if (n != null && lastSelected != null
+ && OutlineTools.getHandle(n).equals(OutlineTools.getHandle(lastSelected))) {
+ // we don't need to set the selection if it is already
+ // set
+ return;
+ }
+ lastSelected = n;
+
+ Object data = n.getData();
+ boolean highlight = true;
+ if (n.getKey().toLowerCase().equals("comments")) {
+ highlight = false;
+ }
+ if (n.getKey().toLowerCase().equals("new comment")) {
+ selectNewComment();
+ } else if (n.getKey().toLowerCase().equals("new description")) {
+ selectNewDescription();
+ } else if (data != null) {
+ select(data, highlight);
+ }
+ }
+ }
+ }
+ };
+
+ private class ComboSelectionListener extends SelectionAdapter {
+
+ private CCombo combo;
+
+ public ComboSelectionListener(CCombo combo) {
+ this.combo = combo;
+ }
+
+ public void widgetDefaultSelected(SelectionEvent event) {
+ // ignore
+ }
+
+ public void widgetSelected(SelectionEvent event) {
+ if (comboListenerMap.containsKey(combo)) {
+ if (combo.getSelectionIndex() > -1) {
+ String sel = combo.getItem(combo.getSelectionIndex());
+ RepositoryTaskAttribute attribute = comboListenerMap.get(combo);
+ if (sel != null && !(sel.equals(attribute.getValue()))) {
+ attribute.setValue(sel);
+ for (IRepositoryTaskAttributeListener client : attributesListeners) {
+ client.attributeChanged(attribute.getName(), sel);
+ }
+ changeDirtyStatus(true);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a new <code>AbstractRepositoryTaskEditor</code>. Sets up the
+ * default fonts and cut/copy/paste actions.
+ */
+ public AbstractRepositoryTaskEditor() {
+ // set the scroll increments so the editor scrolls normally with the
+ // scroll wheel
+ FontData[] fd = TEXT_FONT.getFontData();
+ int cushion = 4;
+ scrollIncrement = fd[0].getHeight() + cushion;
+ scrollVertPageIncrement = 0;
+ scrollHorzPageIncrement = 0;
+
+ // set up actions for the context menu
+ cutAction = new RetargetAction(ActionFactory.CUT.getId(), WorkbenchMessages.Workbench_cut);
+ cutAction.setToolTipText(WorkbenchMessages.Workbench_cutToolTip);// WorkbenchMessages.getString("Workbench.cutToolTip"));
+ // //$NON-NLS-1$
+ cutAction.setImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
+ cutAction.setHoverImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
+ cutAction.setDisabledImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED));
+ cutAction.setAccelerator(SWT.CTRL | 'x');
+ cutAction.setActionDefinitionId(cutActionDefId);
+
+ pasteAction = new RetargetAction(ActionFactory.PASTE.getId(), WorkbenchMessages.Workbench_paste);
+ pasteAction.setToolTipText(WorkbenchMessages.Workbench_pasteToolTip);// WorkbenchMessages.getString("Workbench.pasteToolTip"));
+ // //$NON-NLS-1$
+ pasteAction.setImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
+ pasteAction.setHoverImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
+ pasteAction.setDisabledImageDescriptor(WorkbenchImages
+ .getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED));
+ pasteAction.setAccelerator(SWT.CTRL | 'v');
+ pasteAction.setActionDefinitionId(pasteActionDefId);
+
+ copyAction = new RepositoryTaskEditorCopyAction(this);
+ copyAction.setText(WorkbenchMessages.Workbench_copy);// WorkbenchMessages.getString("Workbench.copy"));
+ copyAction.setImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+ copyAction.setHoverImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+ copyAction.setDisabledImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
+ copyAction.setAccelerator(SWT.CTRL | 'c');
+
+ copyAction.setEnabled(false);
+
+ //
+ // revealAllAction = new ExpandCommentsAction(this);
+ // revealAllAction.setText("Reveal Comments");//
+ // WorkbenchMessages.getString("Workbench.copy"));
+ // revealAllAction.setImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+ // revealAllAction.setHoverImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+ // revealAllAction.setDisabledImageDescriptor(WorkbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
+ // revealAllAction.setAccelerator(SWT.CTRL | 'r');
+ //
+ // revealAllAction.setEnabled(true);
+
+ }
+
+ /**
+ * @return The task data this editor is displaying.
+ */
+ public abstract RepositoryTaskData getRepositoryTaskData();
+
+ public String getNewCommentText() {
+ return addCommentsTextBox.getText();
+ }
+
+ /**
+ * @return Any currently selected text.
+ */
+ protected StyledText getCurrentText() {
+ return currentSelectedText;
+ }
+
+ /**
+ * @return The action used to copy selected text from a bug editor to the
+ * clipboard.
+ */
+ protected RepositoryTaskEditorCopyAction getCopyAction() {
+ return copyAction;
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+
+ if (getRepositoryTaskData() == null) {
+
+ // MessageDialog.openError(Display.getDefault().getActiveShell(),
+ // "Bugzilla Client Errror",
+ // "Could not resolve the requested bug, check Bugzilla server and
+ // version.");
+
+ Composite composite = new Composite(parent, SWT.NULL);
+ composite.setLayout(new GridLayout());
+ Label noBugLabel = new Label(composite, SWT.NULL);
+ noBugLabel.setText("Could not resolve bug");
+ return;
+ }
+
+ toolkit = new FormToolkit(parent.getDisplay());
+ form = toolkit.createScrolledForm(parent);
+ // String truncatedSummary = getBug().getSummary();
+ // int maxLength = 50;
+ // if (truncatedSummary.length() > maxLength) {
+ // truncatedSummary = truncatedSummary.substring(0, maxLength) + "...";
+ // }
+ // form.setFont(COMMENT_FONT);
+ // form.setText("Bugzilla Bug: " + getBug().getSummary());
+
+ editorComposite = form.getBody();
+ editorComposite.setLayout(new GridLayout());
+ editorComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ // Header information
+
+ Composite summaryComposite = toolkit.createComposite(editorComposite);
+ summaryComposite.setLayout(new GridLayout(2, false));
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(summaryComposite);
+ addSummaryText(summaryComposite);
+ toolkit.paintBordersFor(summaryComposite);
+ Composite headerInfoComposite = toolkit.createComposite(editorComposite);
+ headerInfoComposite.setLayout(new GridLayout(6, false));
+ toolkit.createLabel(headerInfoComposite, "Task# ").setFont(TITLE_FONT);
+ toolkit.createText(headerInfoComposite, "" + getRepositoryTaskData().getId(), SWT.FLAT | SWT.READ_ONLY);
+
+ toolkit.createLabel(headerInfoComposite, " Opened: ").setFont(TITLE_FONT);
+ String openedDateString = "";
+ if (getRepositoryTaskData().getCreated() != null) {
+ openedDateString = simpleDateFormat.format(getRepositoryTaskData().getCreated());
+ }
+ toolkit.createText(headerInfoComposite, openedDateString, SWT.FLAT | SWT.READ_ONLY);
+
+ toolkit.createLabel(headerInfoComposite, " Modified: ").setFont(TITLE_FONT);
+ String lastModifiedDateString = "";
+ if (getRepositoryTaskData().getLastModified(null) != null) {
+ lastModifiedDateString = simpleDateFormat.format(getRepositoryTaskData().getLastModified(null));
+ }
+ toolkit.createText(headerInfoComposite, lastModifiedDateString, SWT.FLAT | SWT.READ_ONLY);
+
+ // openedText.setFont(TITLE_FONT);
+ // display = parent.getDisplay();
+ // background = JFaceColors.getBannerBackground(display);
+ // foreground = JFaceColors.getBannerForeground(display);
+
+ // createInfoArea(editorComposite);
+ createContextMenu();
+ createAttributeLayout();
+ createCustomAttributeLayout(toolkit, form);
+ createAttachmentLayout();
+ createCommentLayout(toolkit, form);
+ createButtonLayouts(toolkit, form.getBody());
+
+ // WorkbenchHelpSystem.getInstance().setHelp(parent,
+ // BugzillaUiPlugin.EDITOR_PAGE_CONTEXT);
+
+ editorComposite.setMenu(contextMenuManager.createContextMenu(editorComposite));
+ form.reflow(true);
+ getSite().getPage().addSelectionListener(selectionListener);
+ getSite().setSelectionProvider(selectionProvider);
+ }
+
+ public abstract void createCustomAttributeLayout();
+
+ /**
+ * Create a context menu for this editor.
+ */
+ protected void createContextMenu() {
+ contextMenuManager = new MenuManager(CONTEXT_MENU_ID);
+ contextMenuManager.setRemoveAllWhenShown(true);
+ contextMenuManager.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager manager) {
+ manager.add(cutAction);
+ manager.add(copyAction);
+ manager.add(pasteAction);
+ // manager.add(revealAllAction);
+ manager.add(new Separator());
+ manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
+ if (currentSelectedText == null || currentSelectedText.getSelectionText().length() == 0) {
+
+ copyAction.setEnabled(false);
+ } else {
+ copyAction.setEnabled(true);
+ }
+ }
+ });
+ getSite().registerContextMenu(CONTEXT_MENU_ID, contextMenuManager, getSite().getSelectionProvider());
+ }
+
+ // /**
+ // * Creates the attribute layout, which contains most of the basic
+ // attributes
+ // * of the bug (some of which are editable).
+ // */
+ // protected void createAttributeLayout() {
+ //
+ // String title = getTitleString();
+ // String keywords = "";
+ // String url = "";
+ //
+ // Section section = toolkit.createSection(form.getBody(),
+ // ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ // section.setText(LABEL_SECTION_ATTRIBUTES);
+ // section.setExpanded(true);
+ // section.setLayout(new GridLayout());
+ // section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ //
+ // section.addExpansionListener(new IExpansionListener() {
+ // public void expansionStateChanging(ExpansionEvent e) {
+ // form.reflow(true);
+ // }
+ //
+ // public void expansionStateChanged(ExpansionEvent e) {
+ // form.reflow(true);
+ // }
+ // });
+ //
+ // // Attributes Composite- this holds all the combo fiels and text fields
+ // Composite attributesComposite = toolkit.createComposite(section);
+ // GridLayout attributesLayout = new GridLayout();
+ // attributesLayout.numColumns = 4;
+ // attributesLayout.horizontalSpacing = 14;
+ // attributesLayout.verticalSpacing = 6;
+ // attributesComposite.setLayout(attributesLayout);
+ // GridData attributesData = new GridData(GridData.FILL_BOTH);
+ // attributesData.horizontalSpan = 1;
+ // attributesData.grabExcessVerticalSpace = false;
+ // attributesComposite.setLayoutData(attributesData);
+ // // attributesComposite.setBackground(background);
+ // // End Attributes Composite
+ //
+ // section.setClient(attributesComposite);
+ //
+ // // Attributes Title Area
+ // // Composite attributesTitleComposite = new
+ // // Composite(attributesComposite, SWT.NONE);
+ // // GridLayout attributesTitleLayout = new GridLayout();
+ // // attributesTitleLayout.horizontalSpacing = 0;
+ // // attributesTitleLayout.marginWidth = 0;
+ // // attributesTitleComposite.setLayout(attributesTitleLayout);
+ // // attributesTitleComposite.setBackground(background);
+ // // GridData attributesTitleData = new
+ // // GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ // // attributesTitleData.horizontalSpan = 4;
+ // // attributesTitleData.grabExcessVerticalSpace = false;
+ // // attributesTitleComposite.setLayoutData(attributesTitleData);
+ // // End Attributes Title
+ //
+ // // Set the Attributes Title
+ // // newAttributesLayout(attributesTitleComposite);
+ // // titleLabel.setText(title);
+ // bugzillaInput.setToolTipText(title);
+ // int currentCol = 1;
+ //
+ // // String ccValue = null;
+ //
+ // // Populate Attributes
+ // for (Iterator<RepositoryTaskAttribute> it =
+ // getReport().getAttributes().iterator(); it.hasNext();) {
+ // RepositoryTaskAttribute attribute = it.next();
+ // String key = attribute.getID();
+ // String name = attribute.getName();
+ // String value = checkText(attribute.getValue());
+ // System.err.println(">>> AbstractRepositoryTaskEditor>> name: "+name+"
+ // key: "+key+"
+ // value:"+value);
+ // Map<String, String> values = attribute.getOptionValues();
+ //
+ // // make sure we don't try to display a hidden field
+ // if (attribute.isHidden() || (key != null &&
+ // key.equals("status_whiteboard")))
+ // continue;
+ //
+ // if (values == null)
+ // values = new HashMap<String, String>();
+ //
+ // if (key == null)
+ // key = "";
+ //
+ // GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ // data.horizontalSpan = 1;
+ // data.horizontalIndent = HORZ_INDENT;
+ //
+ // if (key.equals(BugzillaReportElement.KEYWORDS.getKeyString())) {
+ // keywords = attribute.getValue();
+ // } else if (key.equals(BugzillaReportElement.CC.getKeyString())) {
+ // continue;
+ // } else if (key.equals(BugzillaReportElement.NEWCC.getKeyString())) {
+ // // force move to first column
+ // if (currentCol > 1) {
+ // while (currentCol <= attributesLayout.numColumns) {
+ // newLayout(attributesComposite, 1, "", PROPERTY);
+ // currentCol++;
+ // }
+ // }
+ // addCCList(toolkit, "", attributesComposite);
+ // } else if (key.equals(BugzillaReportElement.DEPENDSON.getKeyString())) {
+ // // Dependson and blocked are multi valued so need to explicitly
+ // // be parsed and shown in the AbstractRepositoryTaskEditor
+ // continue;
+ // } else if (key.equals(BugzillaReportElement.BLOCKED.getKeyString())) {
+ // // Dependson and blocked are multi valued so need to explicitly
+ // // be parsed and shown in the AbstractRepositoryTaskEditor
+ // continue;
+ // } else if (key.equals("bug_file_loc")) {
+ // url = value;
+ // } else if (key.equals("op_sys")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // // oSCombo = new Combo(attributesComposite, SWT.NO_BACKGROUND |
+ // // SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY);//SWT.NONE
+ // oSCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.READ_ONLY);
+ // // oSCombo = new Combo(attributesComposite, SWT.FLAT |
+ // // SWT.READ_ONLY);
+ // toolkit.adapt(oSCombo, true, true);
+ // oSCombo.setFont(TEXT_FONT);
+ // oSCombo.setLayoutData(data);
+ // // oSCombo.setBackground(background);
+ // Set<String> s = values.keySet();
+ // String[] a = s.toArray(new String[s.size()]);
+ // Arrays.sort(a);
+ // for (int i = 0; i < a.length; i++) {
+ // oSCombo.add(a[i]);
+ // }
+ // if (oSCombo.indexOf(value) != -1) {
+ // oSCombo.select(oSCombo.indexOf(value));
+ // } else {
+ // oSCombo.select(oSCombo.indexOf("All"));
+ // }
+ // // oSCombo.addListener(SWT.Modify, this);
+ // oSCombo.addSelectionListener(new ComboSelectionListener(oSCombo));
+ // comboListenerMap.put(oSCombo, attribute);
+ // oSCombo.addListener(SWT.FocusIn, new GenericListener());
+ // currentCol += 2;
+ // } else if (key.equals("version")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // versionCombo = new CCombo(attributesComposite, SWT.FLAT |
+ // SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ // | SWT.READ_ONLY);
+ // toolkit.adapt(versionCombo, true, true);
+ // versionCombo.setFont(TEXT_FONT);
+ // versionCombo.setLayoutData(data);
+ // // versionCombo.setBackground(background);
+ // Set<String> s = values.keySet();
+ // String[] a = s.toArray(new String[s.size()]);
+ // Arrays.sort(a);
+ // for (int i = 0; i < a.length; i++) {
+ // versionCombo.add(a[i]);
+ // }
+ // versionCombo.select(versionCombo.indexOf(value));
+ // // versionCombo.addListener(SWT.Modify, this);
+ // versionCombo.addSelectionListener(new
+ // ComboSelectionListener(versionCombo));
+ // versionCombo.addListener(SWT.FocusIn, new GenericListener());
+ // comboListenerMap.put(versionCombo, attribute);
+ // currentCol += 2;
+ // } else if (key.equals("priority")) {
+ // // newLayout(attributesComposite, 1, "Priority", PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // priorityCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.V_SCROLL |
+ // SWT.READ_ONLY);
+ // toolkit.adapt(priorityCombo, true, true);
+ // priorityCombo.setFont(TEXT_FONT);
+ // priorityCombo.setLayoutData(data);
+ // // priorityCombo.setBackground(background);
+ // Set<String> s = values.keySet();
+ // String[] a = s.toArray(new String[s.size()]);
+ // Arrays.sort(a);
+ // for (int i = 0; i < a.length; i++) {
+ // priorityCombo.add(a[i]);
+ // }
+ // priorityCombo.select(priorityCombo.indexOf(value));
+ // // priorityCombo.addListener(SWT.Modify, this);
+ // priorityCombo.addSelectionListener(new
+ // ComboSelectionListener(priorityCombo));
+ // priorityCombo.addListener(SWT.FocusIn, new GenericListener());
+ // comboListenerMap.put(priorityCombo, attribute);
+ // currentCol += 2;
+ // } else if (key.equals("bug_severity")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // severityCombo = new CCombo(attributesComposite, SWT.FLAT |
+ // SWT.READ_ONLY);
+ // toolkit.adapt(severityCombo, true, true);
+ // severityCombo.setFont(TEXT_FONT);
+ // severityCombo.setLayoutData(data);
+ // // severityCombo.setBackground(background);
+ // Set<String> s = values.keySet();
+ // String[] a = s.toArray(new String[s.size()]);
+ // Arrays.sort(a);
+ // for (int i = 0; i < a.length; i++) {
+ // severityCombo.add(a[i]);
+ // }
+ // severityCombo.select(severityCombo.indexOf(value));
+ // severityCombo.addSelectionListener(new
+ // ComboSelectionListener(severityCombo));
+ // // severityCombo.addListener(SWT.Modify, this);
+ // severityCombo.addListener(SWT.FocusIn, new GenericListener());
+ // comboListenerMap.put(severityCombo, attribute);
+ // currentCol += 2;
+ // } else if (key.equals("target_milestone")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // milestoneCombo = new CCombo(attributesComposite, SWT.FLAT |
+ // SWT.NO_BACKGROUND | SWT.MULTI
+ // | SWT.V_SCROLL | SWT.READ_ONLY);
+ // toolkit.adapt(milestoneCombo, true, true);
+ // milestoneCombo.setFont(TEXT_FONT);
+ // milestoneCombo.setLayoutData(data);
+ // // milestoneCombo.setBackground(background);
+ // Set<String> s = values.keySet();
+ // String[] a = s.toArray(new String[s.size()]);
+ // Arrays.sort(a);
+ // for (int i = 0; i < a.length; i++) {
+ // milestoneCombo.add(a[i]);
+ // }
+ // milestoneCombo.select(milestoneCombo.indexOf(value));
+ // // milestoneCombo.addListener(SWT.Modify, this);
+ // milestoneCombo.addSelectionListener(new
+ // ComboSelectionListener(milestoneCombo));
+ // milestoneCombo.addListener(SWT.FocusIn, new GenericListener());
+ // comboListenerMap.put(milestoneCombo, attribute);
+ // currentCol += 2;
+ // } else if (key.equals("rep_platform")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // platformCombo = new CCombo(attributesComposite, SWT.FLAT |
+ // SWT.NO_BACKGROUND | SWT.MULTI | SWT.V_SCROLL
+ // | SWT.READ_ONLY);
+ // toolkit.adapt(platformCombo, true, true);
+ // platformCombo.setFont(TEXT_FONT);
+ // platformCombo.setLayoutData(data);
+ // // platformCombo.setBackground(background);
+ // Set<String> s = values.keySet();
+ // String[] a = s.toArray(new String[s.size()]);
+ // Arrays.sort(a);
+ // for (int i = 0; i < a.length; i++) {
+ // platformCombo.add(a[i]);
+ // }
+ // platformCombo.select(platformCombo.indexOf(value));
+ // // platformCombo.addListener(SWT.Modify, this);
+ // platformCombo.addSelectionListener(new
+ // ComboSelectionListener(platformCombo));
+ // platformCombo.addListener(SWT.FocusIn, new GenericListener());
+ // comboListenerMap.put(platformCombo, attribute);
+ // currentCol += 2;
+ // } else if (key.equals("product")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // // toolkit.createLabel(attributesComposite, value);
+ // Composite uneditableComp = toolkit.createComposite(attributesComposite);
+ // GridLayout textLayout = new GridLayout();
+ // textLayout.marginWidth = 1;
+ // uneditableComp.setLayout(textLayout);
+ // toolkit.createText(uneditableComp, value, SWT.READ_ONLY);//
+ // Label(attributesComposite,
+ // // value);
+ // // newLayout(attributesComposite, 1, value,
+ // // VALUE).addListener(SWT.FocusIn, new GenericListener());
+ // currentCol += 2;
+ // } else if (key.equals("assigned_to")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // assignedTo = new Text(attributesComposite, SWT.SINGLE | SWT.WRAP);
+ // assignedTo.setFont(TEXT_FONT);
+ // assignedTo.setText(value);
+ // data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ // data.horizontalSpan = 1;
+ // assignedTo.setLayoutData(data);
+ //
+ // assignedTo.addListener(SWT.KeyUp, new Listener() {
+ // public void handleEvent(Event event) {
+ // String sel = assignedTo.getText();
+ // RepositoryTaskAttribute a = getReport().getAttribute(
+ // BugzillaReportElement.ASSIGNED_TO);
+ // if (!(a.getValue().equals(sel))) {
+ // a.setValue(sel);
+ // changeDirtyStatus(true);
+ // }
+ // }
+ // });
+ // assignedTo.addListener(SWT.FocusIn, new GenericListener());
+ //
+ // currentCol += 2;
+ // } else if (key.equals("component")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // componentCombo = new CCombo(attributesComposite, SWT.FLAT |
+ // SWT.NO_BACKGROUND | SWT.MULTI
+ // | SWT.V_SCROLL | SWT.READ_ONLY);
+ // toolkit.adapt(componentCombo, true, true);
+ // componentCombo.setFont(TEXT_FONT);
+ // componentCombo.setLayoutData(data);
+ // // componentCombo.setBackground(background);
+ // Set<String> s = values.keySet();
+ // String[] a = s.toArray(new String[s.size()]);
+ // Arrays.sort(a);
+ // for (int i = 0; i < a.length; i++) {
+ // componentCombo.add(a[i]);
+ // }
+ // componentCombo.select(componentCombo.indexOf(value));
+ // // componentCombo.addListener(SWT.Modify, this);
+ // componentCombo.addSelectionListener(new
+ // ComboSelectionListener(componentCombo));
+ // componentCombo.addListener(SWT.FocusIn, new GenericListener());
+ // comboListenerMap.put(componentCombo, attribute);
+ // currentCol += 2;
+ // } else if (name.equals("Summary")) {
+ // // Don't show the summary here.
+ // continue;
+ // } else if (name.equals("Last Modified")) {
+ // // Don't show last modified here.
+ // continue;
+ // } else if (name.equals("Bug#")) {
+ // // Don't show bug number here
+ // continue;
+ // } else if (key.equals("bug_status")) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // Composite uneditableComp = toolkit.createComposite(attributesComposite);
+ // GridLayout textLayout = new GridLayout();
+ // textLayout.marginWidth = 1;
+ // uneditableComp.setLayout(textLayout);
+ // toolkit.createText(uneditableComp, value, SWT.READ_ONLY);//
+ // Label(attributesComposite,
+ // // value);
+ // // newLayout(attributesComposite, 1, value,
+ // // VALUE).addListener(SWT.FocusIn, new GenericListener());
+ // currentCol += 2;
+ // } else if (values.isEmpty()) {
+ // // newLayout(attributesComposite, 1, name, PROPERTY);
+ // toolkit.createLabel(attributesComposite, name);
+ // Composite uneditableComp = toolkit.createComposite(attributesComposite);
+ // GridLayout textLayout = new GridLayout();
+ // textLayout.marginWidth = 1;
+ // uneditableComp.setLayout(textLayout);
+ // toolkit.createText(uneditableComp, value, SWT.READ_ONLY);//
+ // Label(attributesComposite,
+ // // value);
+ // // newLayout(attributesComposite, 1, value,
+ // // VALUE).addListener(SWT.FocusIn, new GenericListener());
+ // currentCol += 2;
+ // }
+ // if (currentCol > attributesLayout.numColumns) {
+ // currentCol -= attributesLayout.numColumns;
+ // }
+ // }
+ // // End Populate Attributes
+ //
+ // // make sure that we are in the first column
+ // if (currentCol > 1) {
+ // while (currentCol <= attributesLayout.numColumns) {
+ // newLayout(attributesComposite, 1, "", PROPERTY);
+ // currentCol++;
+ // }
+ // }
+ //
+ // // URL field
+ // addUrlText(url, attributesComposite);
+ //
+ // // keywords text field (not editable)
+ // addKeywordsList(toolkit, keywords, attributesComposite);
+ // // if (ccValue != null) {
+ // // addCCList(toolkit, ccValue, attributesComposite);
+ // // }
+ // addSummaryText(attributesComposite);
+ // // End URL, Keywords, Summary Text Fields
+ // toolkit.paintBordersFor(attributesComposite);
+ // }
+
+ /**
+ * Creates the attribute layout, which contains most of the basic attributes
+ * of the bug (some of which are editable).
+ */
+ protected void createAttributeLayout() {
+
+ String title = getTitleString();
+ Section section = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ section.setText(LABEL_SECTION_ATTRIBUTES);
+ section.setExpanded(true);
+ section.setLayout(new GridLayout());
+ section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ section.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ // Attributes Composite- this holds all the combo fields and text fields
+ Composite attributesComposite = toolkit.createComposite(section);
+ GridLayout attributesLayout = new GridLayout();
+ attributesLayout.numColumns = 4;
+ attributesLayout.horizontalSpacing = 14;
+ attributesLayout.verticalSpacing = 6;
+ attributesComposite.setLayout(attributesLayout);
+ GridData attributesData = new GridData(GridData.FILL_BOTH);
+ attributesData.horizontalSpan = 1;
+ attributesData.grabExcessVerticalSpace = false;
+ attributesComposite.setLayoutData(attributesData);
+ section.setClient(attributesComposite);
+ editorInput.setToolTipText(title);
+
+ int currentCol = 1;
+
+ for (RepositoryTaskAttribute attribute : getRepositoryTaskData().getAttributes()) {
+
+ // String key = attribute.getID();
+ String name = attribute.getName();
+ String value = "";
+ // try {
+ value = checkText(attribute.getValue());
+ // value =
+ // checkText(BugzillaRepositoryUtil.decodeStringFromCharset(attribute.getValue(),
+ // getReport().getCharset()));
+ // } catch (UnsupportedEncodingException e1) {
+ // // ignore
+ // }
+ // System.err.println(">>> AbstractRepositoryTaskEditor>> name:
+ // "+name+"
+ // key:"+key+" value:"+value+" is hidden"+attribute.isHidden());
+ if (attribute.isHidden())
+ continue;
+ Map<String, String> values = attribute.getOptionValues();
+ if (values == null)
+ values = new HashMap<String, String>();
+
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ data.horizontalSpan = 1;
+ data.horizontalIndent = HORZ_INDENT;
+
+ if (attribute.hasOptions() && !attribute.isReadOnly()) {
+ toolkit.createLabel(attributesComposite, name);
+ attributeCombo = new CCombo(attributesComposite, SWT.FLAT | SWT.READ_ONLY);
+ toolkit.adapt(attributeCombo, true, true);
+ attributeCombo.setFont(TEXT_FONT);
+ attributeCombo.setLayoutData(data);
+ Set<String> s = values.keySet();
+ String[] a = s.toArray(new String[s.size()]);
+ for (int i = 0; i < a.length; i++) {
+ attributeCombo.add(a[i]);
+ }
+ if (attributeCombo.indexOf(value) != -1) {
+ attributeCombo.select(attributeCombo.indexOf(value));
+ }
+ attributeCombo.addSelectionListener(new ComboSelectionListener(attributeCombo));
+ comboListenerMap.put(attributeCombo, attribute);
+ attributeCombo.addListener(SWT.FocusIn, new GenericListener());
+ currentCol += 2;
+ } else {
+ toolkit.createLabel(attributesComposite, name);
+ Composite textFieldComposite = toolkit.createComposite(attributesComposite);
+ GridLayout textLayout = new GridLayout();
+ textLayout.marginWidth = 1;
+ textFieldComposite.setLayout(textLayout);
+ GridData textData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ textData.horizontalSpan = 1;
+ textData.widthHint = 135;
+
+ if (attribute.isReadOnly()) {
+ final Text text = toolkit.createText(textFieldComposite, value, SWT.FLAT | SWT.READ_ONLY);
+ text.setLayoutData(textData);
+ } else {
+ final Text text = toolkit.createText(textFieldComposite, value, SWT.FLAT);
+ // text.setFont(COMMENT_FONT);
+ text.setLayoutData(textData);
+ toolkit.paintBordersFor(textFieldComposite);
+ text.setData(attribute);
+ text.addListener(SWT.KeyUp, new Listener() {
+ public void handleEvent(Event event) {
+ String sel = text.getText();
+ RepositoryTaskAttribute a = (RepositoryTaskAttribute) text.getData();
+ if (!(a.getValue().equals(sel))) {
+ a.setValue(sel);
+ changeDirtyStatus(true);
+ }
+ }
+ });
+ text.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ currentCol += 2;
+ }
+ if (currentCol > attributesLayout.numColumns) {
+ currentCol -= attributesLayout.numColumns;
+ }
+
+ }
+
+ // // make sure that we are in the first column
+ // if (currentCol > 1) {
+ // while (currentCol <= attributesLayout.numColumns) {
+ // toolkit.createLabel(attributesComposite, "");
+ // // newLayout(attributesComposite, 1, "", PROPERTY);
+ // currentCol++;
+ // }
+ // }
+
+ // // Perhaps these should be performed in subclass eventually
+ //
+ // addCCList(toolkit, "", attributesComposite);
+ //
+ // // URL field
+ // addUrlText(getReport().getAttributeValue(BugzillaReportElement.BUG_FILE_LOC.getKeyString()),
+ // attributesComposite);
+ //
+ // // keywords text field (not editable)
+ // try {
+ // addKeywordsList(toolkit,
+ // getReport().getAttributeValue(BugzillaReportElement.KEYWORDS.getKeyString()),
+ // attributesComposite);
+ // } catch (IOException e) {
+ // MessageDialog.openInformation(null,
+ // IBugzillaConstants.TITLE_MESSAGE_DIALOG,
+ // "Could not retrieve keyword list, ensure proper configuration in " +
+ // TaskRepositoriesView.NAME
+ // + "\n\nError reported: " + e.getMessage());
+ // }
+
+ // addSelfToCCCheck = toolkit.createButton(attributesComposite, "Add
+ // "+repository.getUserName()+" to CC", SWT.FLAT | SWT.CHECK);
+ // addSelfToCCCheck.setSelection(true);
+ // addSelfToCCCheck.addSelectionListener(new SelectionAdapter() {
+ //
+ // @Override
+ // public void widgetSelected(SelectionEvent e) {
+ // if(addSelfToCCCheck.getSelection()) {
+ // getReport().setAttributeValue(BugzillaReportElement.ADDSELFCC, "1");
+ // } else {
+ // getReport().setAttributeValue(BugzillaReportElement.ADDSELFCC, "0");
+ // }
+ // }});
+ //
+ // addSummaryText(attributesComposite);
+ // End URL, Keywords, Summary Text Fields
+ toolkit.paintBordersFor(attributesComposite);
+ }
+
+// protected abstract void addKeywordsList(FormToolkit toolkit, String keywords, Composite attributesComposite)
+// throws IOException;
+//
+// protected abstract void addCCList(FormToolkit toolkit, String value, Composite attributesComposite);
+
+ /**
+ * Adds a text field to display and edit the bug's summary.
+ *
+ * @param attributesComposite
+ * The composite to add the text field to.
+ */
+ protected void addSummaryText(Composite attributesComposite) {
+ // newLayout(attributesComposite, 1, "Summary:", PROPERTY);
+ toolkit.createLabel(attributesComposite, "Summary:").setFont(TITLE_FONT);
+ summaryText = toolkit.createText(attributesComposite, getRepositoryTaskData().getSummary(), SWT.FLAT);
+ IThemeManager themeManager = getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
+ Font summaryFont = themeManager.getCurrentTheme().getFontRegistry().get(REPOSITORY_TEXT_ID);
+ summaryText.setFont(summaryFont);
+ GridData summaryTextData = new GridData(GridData.FILL_HORIZONTAL);// HORIZONTAL_ALIGN_FILL
+ summaryTextData.horizontalSpan = 1;
+ // summaryTextData.widthHint = 200;
+
+ summaryText.setLayoutData(summaryTextData);
+ summaryText.addListener(SWT.KeyUp, new SummaryListener());
+ summaryText.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ protected void createAttachmentLayout() {
+ Section section = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ section.setText(LABEL_SECTION_ATTACHMENTS);
+ section.setExpanded(getRepositoryTaskData().getAttachments().size() > 0);
+ section.setLayout(new GridLayout());
+ section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ final Composite attachmentsComposite = toolkit.createComposite(section);
+ attachmentsComposite.setLayout(new GridLayout());
+ attachmentsComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+ section.setClient(attachmentsComposite);
+
+ if (getRepositoryTaskData().getAttachments().size() > 0) {
+
+ attachmentsTable = toolkit.createTable(attachmentsComposite, SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION);
+ attachmentsTable.setLinesVisible(true);
+ attachmentsTable.setHeaderVisible(true);
+ attachmentsTable.setLayout(new GridLayout());
+ GridData tableGridData = new GridData(GridData.FILL_BOTH);
+ // tableGridData.heightHint = 100;
+ tableGridData.widthHint = DESCRIPTION_WIDTH;
+ attachmentsTable.setLayoutData(tableGridData);
+
+ for (int i = 0; i < attachmentsColumns.length; i++) {
+ TableColumn column = new TableColumn(attachmentsTable, SWT.LEFT, i);
+ column.setText(attachmentsColumns[i]);
+ column.setWidth(attachmentsColumnWidths[i]);
+ }
+
+ TableViewer attachmentsTableViewer = new TableViewer(attachmentsTable);
+ attachmentsTableViewer.setUseHashlookup(true);
+ attachmentsTableViewer.setColumnProperties(attachmentsColumns);
+
+ attachmentsTableViewer.setSorter(new ViewerSorter() {
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ RepositoryAttachment attachment1 = (RepositoryAttachment) e1;
+ RepositoryAttachment attachment2 = (RepositoryAttachment) e2;
+ Date created1 = attachment1.getDateCreated();
+ Date created2 = attachment2.getDateCreated();
+ if (created1 != null && created2 != null) {
+ return attachment1.getDateCreated().compareTo(attachment2.getDateCreated());
+ } else {
+ return 0;
+ }
+ }
+ });
+
+ attachmentsTableViewer.setContentProvider(new IStructuredContentProvider() {
+ public Object[] getElements(Object inputElement) {
+ return getRepositoryTaskData().getAttachments().toArray();
+ }
+
+ public void dispose() {
+ // ignore
+
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // ignore
+
+ }
+ });
+
+ attachmentsTableViewer.setLabelProvider(new ITableLabelProvider() {
+
+ public Image getColumnImage(Object element, int columnIndex) {
+ // RepositoryAttachment attachment = (RepositoryAttachment)
+ // element;
+ return null;
+ }
+
+ public String getColumnText(Object element, int columnIndex) {
+ RepositoryAttachment attachment = (RepositoryAttachment) element;
+ switch (columnIndex) {
+ case 0:
+ return attachment.getDescription();
+ case 1:
+ return attachment.getContentType();
+ case 2:
+ return attachment.getCreator();
+ case 3:
+ return attachment.getDateCreated().toString();
+ }
+ return "unrecognized column";
+ }
+
+ public void addListener(ILabelProviderListener listener) {
+ // ignore
+
+ }
+
+ public void dispose() {
+ // ignore
+
+ }
+
+ public boolean isLabelProperty(Object element, String property) {
+ // ignore
+ return false;
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ // ignore
+
+ }
+
+ });
+
+ attachmentsTableViewer.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent event) {
+ String address = repository.getUrl() + "/attachment.cgi?id=";
+ if (!event.getSelection().isEmpty()) {
+ StructuredSelection selection = (StructuredSelection) event.getSelection();
+ RepositoryAttachment attachment = (RepositoryAttachment) selection.getFirstElement();
+ address += attachment.getId() + "&amp;action=view";
+ ;
+ TaskUiUtil.openUrl(address);
+ }
+ }
+ });
+
+ attachmentsTableViewer.setInput(getRepositoryTaskData());
+
+ } else {
+ toolkit.createLabel(attachmentsComposite, "No attachments");
+ }
+
+ /* Add a file chooser to add new attachments */
+ Composite addAttachmentComposite = toolkit.createComposite(attachmentsComposite);
+ addAttachmentComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ addAttachmentComposite.setLayout(new GridLayout(2, false));
+
+ Button addAttachmentButton = toolkit.createButton(addAttachmentComposite, "Add an Attachment...", SWT.PUSH);
+ final Text fname = new Text(addAttachmentComposite, SWT.LEFT);// toolkit.createText(addAttachmentComposite,
+ // "");
+ fname.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ final Composite addAttachmentInfo = toolkit.createComposite(addAttachmentComposite);
+ addAttachmentInfo.setSize(2, 1);
+ addAttachmentInfo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ addAttachmentInfo.setLayout(new GridLayout(3, false));
+
+ toolkit.createLabel(addAttachmentInfo, "Description: ");
+ attachmentDesc = toolkit.createText(addAttachmentInfo, "");
+ attachmentDesc.setEnabled(false);
+ attachmentDesc.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+ toolkit.createLabel(addAttachmentInfo, "Comment: ");
+ attachmentComment = toolkit.createText(addAttachmentInfo, "");
+ attachmentComment.setEnabled(false);
+ attachmentComment.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+ final Button isPatchButton = toolkit.createButton(addAttachmentInfo, "Patch", SWT.CHECK);
+
+ addAttachmentInfo.setVisible(false);
+
+ /* File Chooser listener */
+ addAttachmentButton.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // ignore
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ FileDialog fileChooser = new FileDialog(attachmentsComposite.getShell(), SWT.OPEN);
+ String file = fileChooser.open();
+
+ // Check if the dialog was canceled or an error occured
+ if (file == null) {
+ return;
+ }
+ // update UI
+ fname.setText(file);
+ }
+ });
+
+ /*
+ * Attachment file name listener, update the local attachment
+ * accordingly
+ */
+ fname.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ LocalAttachment att = getRepositoryTaskData().getNewAttachment();
+ if (att == null) {
+ att = new LocalAttachment();
+ att.setReport(getRepositoryTaskData());
+ }
+ if ("".equals(fname.getText())) {
+ attachmentDesc.setEnabled(false);
+ attachmentComment.setEnabled(false);
+ } else {
+ addAttachmentInfo.setVisible(true);
+ attachmentDesc.setEnabled(true);
+ attachmentComment.setEnabled(true);
+ }
+ att.setFilePath(fname.getText());
+ getRepositoryTaskData().setNewAttachment(att);
+
+ /* TODO jpound - UI for content type */
+ // Determine type by extension
+ int index = fname.getText().lastIndexOf(".");
+ if (index < 0) {
+ att.setContentType("text/plain");
+ } else {
+ String ext = fname.getText().substring(index + 1);
+ String type = extensions2Types.get(ext.toLowerCase());
+ if (type != null) {
+ att.setContentType(type);
+ } else {
+ att.setContentType("text/plain");
+ }
+ }
+ }
+ });
+
+ /* Listener for isPatch */
+ isPatchButton.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // ignore
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ LocalAttachment att = getRepositoryTaskData().getNewAttachment();
+ att.setPatch(isPatchButton.getSelection());
+ }
+ });
+
+ }
+
+ /**
+ * Creates the description layout, which displays and possibly edits the
+ * bug's description.
+ */
+ protected abstract void createCustomAttributeLayout(FormToolkit toolkit, final ScrolledForm form);
+
+ protected void createCommentLayout(FormToolkit toolkit, final ScrolledForm form) {
+
+ Section section = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ section.setText(LABEL_SECTION_COMMENTS);
+ section.setExpanded(true);
+ section.setLayout(new GridLayout());
+ section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ section.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ ImageHyperlink hyperlink = toolkit.createImageHyperlink(section, SWT.NONE);
+ hyperlink.setBackgroundMode(SWT.INHERIT_NONE);
+ hyperlink.setBackground(section.getTitleBarBackground());
+ hyperlink.setImage(TaskListImages.getImage(TaskListImages.EXPAND_ALL));
+ hyperlink.addHyperlinkListener(new HyperlinkAdapter() {
+ public void linkActivated(HyperlinkEvent e) {
+ revealAllComments();
+ }
+ });
+
+ section.setTextClient(hyperlink);
+
+ // Additional (read-only) Comments Area
+ Composite addCommentsComposite = toolkit.createComposite(section);
+ section.setClient(addCommentsComposite);
+ GridLayout addCommentsLayout = new GridLayout();
+ addCommentsLayout.numColumns = 1;
+ addCommentsComposite.setLayout(addCommentsLayout);
+ // addCommentsComposite.setBackground(background);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(addCommentsComposite);
+ // End Additional (read-only) Comments Area
+
+ StyledText styledText = null;
+ for (Iterator<Comment> it = getRepositoryTaskData().getComments().iterator(); it.hasNext();) {
+ final Comment comment = it.next();
+
+ // skip comment 0 as it is the description
+ if (comment.getNumber() == 0)
+ continue;
+
+ ExpandableComposite expandableComposite = toolkit.createExpandableComposite(addCommentsComposite,
+ ExpandableComposite.TREE_NODE);
+
+ if (!it.hasNext()) {
+ expandableComposite.setExpanded(true);
+ }
+
+ expandableComposite.setText(comment.getNumber() + ": " + comment.getAuthorName() + ", "
+ + simpleDateFormat.format(comment.getCreated()));
+
+ expandableComposite.addExpansionListener(new ExpansionAdapter() {
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ expandableComposite.setLayout(new GridLayout());
+ expandableComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ Composite ecComposite = toolkit.createComposite(expandableComposite);
+ GridLayout ecLayout = new GridLayout();
+ ecLayout.marginHeight = 0;
+ ecLayout.marginBottom = 10;
+ ecLayout.marginLeft = 10;
+ ecComposite.setLayout(ecLayout);
+ ecComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ expandableComposite.setClient(ecComposite);
+ // toolkit.paintBordersFor(expandableComposite);
+
+ // TODO: Attachments are no longer 'attached' to Comments
+
+ // if (comment.hasAttachment()) {
+ //
+ // Link attachmentLink = new Link(ecComposite, SWT.NONE);
+ //
+ // String attachmentHeader;
+ //
+ // if (!comment.isObsolete()) {
+ // attachmentHeader = " Attached: " +
+ // comment.getAttachmentDescription() + " [<a>view</a>]";
+ // } else {
+ // attachmentHeader = " Deprecated: " +
+ // comment.getAttachmentDescription();
+ // }
+ // // String result = MessageFormat.format(attachmentHeader, new
+ // // String[] { node
+ // // .getLabelText() });
+ //
+ // attachmentLink.addSelectionListener(new SelectionAdapter() {
+ // /*
+ // * (non-Javadoc)
+ // *
+ // * @see
+ // org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ // */
+ // public void widgetSelected(SelectionEvent e) {
+ // String address = repository.getUrl() + "/attachment.cgi?id=" +
+ // comment.getAttachmentId()
+ // + "&amp;action=view";
+ // TaskUiUtil.openUrl(address, address, address);
+ //
+ // }
+ // });
+ //
+ // attachmentLink.setText(attachmentHeader);
+ //
+ // }
+
+ TextViewer viewer = addRepositoryText(repository, ecComposite, comment.getText());
+ styledText = viewer.getTextWidget();
+ GridDataFactory.fillDefaults().hint(DESCRIPTION_WIDTH, SWT.DEFAULT).applyTo(styledText);
+
+
+ // code for outline
+ commentStyleText.add(styledText);
+ texts.add(textsindex, styledText);
+ textHash.put(comment, styledText);
+ textsindex++;
+ }
+
+ Section sectionAdditionalComments = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR
+ | Section.TWISTIE);
+ sectionAdditionalComments.setText(LABEL_SECTION_NEW_COMMENT);
+ sectionAdditionalComments.setExpanded(true);
+
+ sectionAdditionalComments.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ sectionAdditionalComments.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ Composite newCommentsComposite = toolkit.createComposite(sectionAdditionalComments);
+ newCommentsComposite.setLayout(new GridLayout());
+ newCommentsComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ addCommentsText = toolkit.createText(newCommentsComposite, getRepositoryTaskData().getNewComment(), SWT.MULTI | SWT.V_SCROLL
+ | SWT.WRAP);
+
+ IThemeManager themeManager = getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
+ Font newCommnetFont = themeManager.getCurrentTheme().getFontRegistry().get(REPOSITORY_TEXT_ID);
+ addCommentsText.setFont(newCommnetFont);
+ toolkit.paintBordersFor(newCommentsComposite);
+ GridData addCommentsTextData = new GridData(GridData.FILL_HORIZONTAL);
+ addCommentsTextData.widthHint = DESCRIPTION_WIDTH;
+ addCommentsTextData.heightHint = DESCRIPTION_HEIGHT;
+ addCommentsTextData.grabExcessHorizontalSpace = true;
+
+ addCommentsText.setLayoutData(addCommentsTextData);
+
+ addCommentsText.addListener(SWT.KeyUp, new Listener() {
+
+ public void handleEvent(Event event) {
+ String sel = addCommentsText.getText();
+ if (!(getRepositoryTaskData().getNewComment().equals(sel))) {
+ getRepositoryTaskData().setNewComment(sel);
+ changeDirtyStatus(true);
+ }
+ validateInput();
+ }
+ });
+ addCommentsText.addListener(SWT.FocusIn, new NewCommentListener());
+ addCommentsTextBox = addCommentsText;
+
+ sectionAdditionalComments.setClient(newCommentsComposite);
+
+// TODO: move into ExistingBugEditor commands section
+// // if they aren't already on the cc list create an add self check box
+//
+// RepositoryTaskAttribute owner = getReport().getAttribute(RepositoryTaskAttribute.USER_ASSIGNED);
+//
+// // Don't add addselfcc check box if the user is the bug owner
+// if (owner != null && owner.getValue().indexOf(repository.getUserName()) != -1) {
+// return;
+// }
+// // Don't add addselfcc if already there
+// RepositoryTaskAttribute ccAttribute = getReport().getAttribute(RepositoryTaskAttribute.USER_CC);
+// if (ccAttribute != null && ccAttribute.getValues().contains(repository.getUserName())) {
+// return;
+// }
+// RepositoryTaskAttribute addselfcc = getReport().getAttribute(BugzillaReportElement.ADDSELFCC.getKeyString());
+// if (addselfcc == null) {
+// // addselfcc =
+// // BugzillaRepositoryUtil.makeNewAttribute(BugzillaReportElement.ADDSELFCC);
+// getReport().setAttributeValue(BugzillaReportElement.ADDSELFCC.getKeyString(), "0");
+// } else {
+// addselfcc.setValue("0");
+// }
+//
+// final Button addSelfButton = toolkit.createButton(newCommentsComposite, "Add " + repository.getUserName()
+// + " to CC list", SWT.CHECK);
+//
+// addSelfButton.addSelectionListener(new SelectionAdapter() {
+//
+// @Override
+// public void widgetSelected(SelectionEvent e) {
+// if (addSelfButton.getSelection()) {
+// getReport().setAttributeValue(BugzillaReportElement.ADDSELFCC.getKeyString(), "1");
+// // connector.getAttributeFactory().setAttributeValue(getReport(),
+// // BugzillaReportElement.ADDSELFCC.getKeyString(), "1");
+// } else {
+// getReport().setAttributeValue(BugzillaReportElement.ADDSELFCC.getKeyString(), "0");
+// }
+// }
+// });
+ }
+
+ protected abstract void validateInput();
+
+
+ /**
+ * Creates the button layout. This displays options and buttons at the
+ * bottom of the editor to allow actions to be performed on the bug.
+ */
+ protected void createButtonLayouts(FormToolkit toolkit, Composite formComposite) {
+
+ Section section = toolkit.createSection(form.getBody(), ExpandableComposite.TITLE_BAR | Section.TWISTIE);
+ section.setText(LABEL_SECTION_ACTIONS);
+ section.setExpanded(true);
+ section.setLayout(new GridLayout());
+ section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ section.addExpansionListener(new IExpansionListener() {
+ public void expansionStateChanging(ExpansionEvent e) {
+ form.reflow(true);
+ }
+
+ public void expansionStateChanged(ExpansionEvent e) {
+ form.reflow(true);
+ }
+ });
+
+ Composite buttonComposite = toolkit.createComposite(section);
+ GridLayout buttonLayout = new GridLayout();
+ buttonLayout.numColumns = 4;
+ buttonComposite.setLayout(buttonLayout);
+ // buttonComposite.setBackground(background);
+ GridData buttonData = new GridData(GridData.FILL_BOTH);
+ buttonData.horizontalSpan = 1;
+ buttonData.grabExcessVerticalSpace = false;
+ buttonComposite.setLayoutData(buttonData);
+ section.setClient(buttonComposite);
+ addRadioButtons(buttonComposite);
+ addActionButtons(buttonComposite);
+ }
+
+ /**
+ * Adds radio buttons to this composite.
+ *
+ * @param buttonComposite
+ * Composite to add the radio buttons to.
+ */
+ abstract protected void addRadioButtons(Composite buttonComposite);
+
+ /**
+ * Adds buttons to this composite. Subclasses can override this method to
+ * provide different/additional buttons.
+ *
+ * @param buttonComposite
+ * Composite to add the buttons to.
+ */
+ protected void addActionButtons(Composite buttonComposite) {
+ submitButton = toolkit.createButton(buttonComposite, LABEL_BUTTON_SUBMIT, SWT.NONE);
+ // submitButton.setFont(TEXT_FONT);
+ GridData submitButtonData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ // submitButtonData.widthHint =
+ // AbstractRepositoryTaskEditor.WRAP_LENGTH;
+ // submitButtonData.heightHint = 20;
+
+ submitButton.setLayoutData(submitButtonData);
+ submitButton.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event e) {
+ submitBug();
+ }
+ });
+ submitButton.addListener(SWT.FocusIn, new GenericListener());
+
+ // This is not needed anymore since we have the save working properly
+ // with ctrl-s and file->save
+ // saveButton = new Button(buttonComposite, SWT.NONE);
+ // saveButton.setFont(TEXT_FONT);
+ // GridData saveButtonData = new
+ // GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ // saveButtonData.widthHint = 100;
+ // saveButtonData.heightHint = 20;
+ // saveButton.setText("Save Offline");
+ // saveButton.setLayoutData(saveButtonData);
+ // saveButton.addListener(SWT.Selection, new Listener() {
+ // public void handleEvent(Event e) {
+ // saveBug();
+ // updateEditor();
+ // }
+ // });
+ // saveButton.addListener(SWT.FocusIn, new GenericListener());
+ }
+
+ /**
+ * Make sure that a String that is <code>null</code> is changed to a null
+ * string
+ *
+ * @param text
+ * The text to check if it is null or not
+ * @return If the text is <code>null</code>, then return the null string (<code>""</code>).
+ * Otherwise, return the text.
+ */
+ public static String checkText(String text) {
+ if (text == null)
+ return "";
+ else
+ return text;
+ }
+
+ /**
+ * @return A string to use as a title for this editor.
+ */
+ protected abstract String getTitleString();
+
+ /**
+ * Creates an uneditable text field for displaying data.
+ */
+ protected StyledText newLayout(Composite composite, int colSpan, String text, String style) {
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ data.horizontalSpan = colSpan;
+
+ StyledText resultText;
+ if (style.equalsIgnoreCase(VALUE)) {
+ resultText = new StyledText(composite, SWT.READ_ONLY);
+ resultText.setText(checkText(text));
+ resultText.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ StyledText c = (StyledText) e.widget;
+ if (c != null && !c.getSelectionText().equals("")) {
+ if (currentSelectedText != null && !currentSelectedText.equals(c)) {
+ currentSelectedText.setSelectionRange(0, 0);
+ }
+ currentSelectedText = c;
+ }
+
+ }
+ });
+ resultText.setLayoutData(data);
+ } else if (style.equalsIgnoreCase(PROPERTY)) {
+ resultText = new StyledText(composite, SWT.READ_ONLY);
+ resultText.setText(checkText(text));
+ resultText.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ StyledText c = (StyledText) e.widget;
+ if (c != null && !c.getSelectionText().equals("")) {
+ if (currentSelectedText != null && !currentSelectedText.equals(c)) {
+ currentSelectedText.setSelectionRange(0, 0);
+ }
+ currentSelectedText = c;
+ }
+
+ }
+ });
+ resultText.setLayoutData(data);
+ } else {
+ resultText = new StyledText(composite, SWT.READ_ONLY);
+ resultText.setText(checkText(text));
+ resultText.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ StyledText c = (StyledText) e.widget;
+ if (c != null && !c.getSelectionText().equals("")) {
+ if (currentSelectedText != null && !currentSelectedText.equals(c)) {
+ currentSelectedText.setSelectionRange(0, 0);
+ }
+ currentSelectedText = c;
+ }
+
+ }
+ });
+ resultText.setLayoutData(data);
+ }
+
+ // composite.setMenu(contextMenuManager.createContextMenu(composite));
+ return resultText;
+ }
+
+ protected TextViewer addRepositoryText(TaskRepository repository, Composite composite, String text) {
+ RepositoryTextViewer commentViewer = new RepositoryTextViewer(repository, composite, SWT.MULTI | SWT.WRAP);
+
+ IThemeManager themeManager = getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
+
+ commentViewer.getTextWidget().setFont(themeManager.getCurrentTheme().getFontRegistry().get(REPOSITORY_TEXT_ID));
+
+ commentViewer.setEditable(false);
+ commentViewer.getTextWidget().addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ StyledText c = (StyledText) e.widget;
+ if (c != null && !c.getSelectionText().equals("")) {
+ if (currentSelectedText != null && !currentSelectedText.equals(c)) {
+ currentSelectedText.setSelectionRange(0, 0);
+ }
+ currentSelectedText = c;
+ }
+
+ }
+ });
+
+ commentViewer.getTextWidget().setMenu(contextMenuManager.createContextMenu(commentViewer.getTextWidget()));
+
+ // textViewer.getControl().setFont(COMMENT_FONT);
+ commentViewer.setDocument(new Document(text));
+ // commentViewer.activatePlugins();
+ // textViewer.refresh();
+ return commentViewer;
+ }
+
+ /**
+ * This refreshes the text in the title label of the info area (it contains
+ * elements which can change).
+ */
+ protected void setGeneralTitleText() {
+ // String text = "[Open in Internal Browser]";
+ // linkToBug.setText(text);
+ // linkToBug.setFont(TEXT_FONT);
+ // if (this instanceof ExistingBugEditor) {
+ // linkToBug.setUnderlined(true);
+ // linkToBug.setForeground(JFaceColors.getHyperlinkText(Display.getCurrent()));
+ // linkToBug.addMouseListener(new MouseListener() {
+ //
+ // public void mouseDoubleClick(MouseEvent e) {
+ // }
+ //
+ // public void mouseUp(MouseEvent e) {
+ // }
+ //
+ // public void mouseDown(MouseEvent e) {
+ // TaskListUiUtil.openUrl(getTitle(), getTitleToolTip(),
+ // BugzillaRepositoryUtil.getBugUrlWithoutLogin(
+ // bugzillaInput.getBug().getRepositoryUrl(),
+ // bugzillaInput.getBug().getId()));
+ // if (e.stateMask == SWT.MOD3) {
+ // // XXX come back to look at this ui
+ // close();
+ // }
+ //
+ // }
+ // });
+ // } else {
+ // linkToBug.setEnabled(false);
+ // }
+ // linkToBug.addListener(SWT.FocusIn, new GenericListener());
+ //
+ // // Resize the composite, in case the new summary is longer than the
+ // // previous one.
+ // // Then redraw it to show the changes.
+ // linkToBug.getParent().pack(true);
+ // linkToBug.redraw();
+
+ // String text = getTitleString();
+ // generalTitleText.setText(text);
+ // StyleRange sr = new StyleRange(generalTitleText.getOffsetAtLine(0),
+ // text.length(), foreground, background,
+ // SWT.BOLD);
+ // generalTitleText.setStyleRange(sr);
+ // generalTitleText.addListener(SWT.FocusIn, new GenericListener());
+ //
+ // // Resize the composite, in case the new summary is longer than the
+ // // previous one.
+ // // Then redraw it to show the changes.
+ // generalTitleText.getParent().pack(true);
+ // generalTitleText.redraw();
+ }
+
+ /**
+ * Creates some blank space underneath the supplied composite.
+ *
+ * @param parent
+ * The composite to add the blank space to.
+ */
+ protected void createSeparatorSpace(Composite parent) {
+ GridData separatorData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ separatorData.verticalSpan = 1;
+ separatorData.grabExcessVerticalSpace = false;
+
+ Composite separatorComposite = new Composite(parent, SWT.NONE);
+ GridLayout separatorLayout = new GridLayout();
+ separatorLayout.marginHeight = 0;
+ separatorLayout.verticalSpacing = 0;
+ separatorComposite.setLayout(separatorLayout);
+ // separatorComposite.setBackground(background);
+ separatorComposite.setLayoutData(separatorData);
+ newLayout(separatorComposite, 1, "", VALUE);
+ }
+
+ /**
+ * Submit the changes to the bug to the bugzilla server. (Public for testing
+ * purposes)
+ */
+ protected abstract void submitBug();
+
+ /**
+ * If there is no locally saved copy of the current bug, then it saved
+ * offline. Otherwise, any changes are updated in the file.
+ */
+ public void saveBug() {
+ try {
+ updateBug();
+
+ final AbstractRepositoryConnector bugzillaRepositoryClient = (AbstractRepositoryConnector) MylarTaskListPlugin
+ .getRepositoryManager().getRepositoryConnector(getRepositoryTaskData().getRepositoryKind());
+
+ IEditorInput input = this.getEditorInput();
+ if (input instanceof ExistingBugEditorInput) {
+ ExistingBugEditorInput existingInput = (ExistingBugEditorInput) input;
+ AbstractRepositoryTask repositoryTask = existingInput.getRepositoryTask();
+ // AbstractRepositoryTask repositoryTask = getRepositoryTask();
+ if (repositoryTask != null) {
+ if (getRepositoryTaskData().hasChanges()) {
+ repositoryTask.setSyncState(RepositoryTaskSyncState.OUTGOING);
+ } else {
+ repositoryTask.setSyncState(RepositoryTaskSyncState.SYNCHRONIZED);
+ }
+ MylarTaskListPlugin.getTaskListManager().getTaskList().notifyRepositoryInfoChanged(repositoryTask);
+ }
+ }
+
+ bugzillaRepositoryClient.saveOffline(getRepositoryTaskData());
+ changeDirtyStatus(false);
+ if (parentEditor != null) {
+ parentEditor.notifyTaskChanged();
+ }
+ } catch (Exception e) {
+ MylarStatusHandler.fail(e, "bug save offline failed", true);
+ }
+
+ }
+
+ /**
+ * Updates the <code>IBugzillaBug</code> object to contain the latest data
+ * entered in the data fields.
+ */
+ protected abstract void updateBug();
+
+// /**
+// * Resets the data fields to contain the data currently in the
+// * <code>IBugzillaBug</code> object.
+// */
+// protected abstract void restoreBug();
+
+ /**
+ * Refreshes any text labels in the editor that contain information that
+ * might change.
+ */
+ protected void updateEditor() {
+ // Reset all summary occurrences, since it might have
+ // been edited.
+ // String title = getTitleString();
+ // titleLabel.setText(title);
+ setGeneralTitleText();
+ }
+
+ @Override
+ public void setFocus() {
+ form.setFocus();
+ }
+
+ @Override
+ public boolean isDirty() {
+ return isDirty;
+ }
+
+ /**
+ * Updates the dirty status of this editor page. The dirty status is true if
+ * the bug report has been modified but not saved. The title of the editor
+ * is also updated to reflect the status.
+ *
+ * @param newDirtyStatus
+ * is true when the bug report has been modified but not saved
+ */
+ public void changeDirtyStatus(boolean newDirtyStatus) {
+ isDirty = newDirtyStatus;
+ if (parentEditor == null) {
+ firePropertyChange(PROP_DIRTY);
+ } else {
+ parentEditor.markDirty();
+ }
+
+ }
+
+ /**
+ * Updates the title of the editor to reflect dirty status. If the bug
+ * report has been modified but not saved, then an indicator will appear in
+ * the title.
+ */
+ protected void updateEditorTitle() {
+ setPartName(editorInput.getName());
+ }
+
+ @Override
+ public boolean isSaveAsAllowed() {
+ return false;
+ }
+
+ @Override
+ public void doSave(IProgressMonitor monitor) {
+ saveBug();
+ updateEditor();
+ }
+
+ @Override
+ public void doSaveAs() {
+ // we don't save, so no need to implement
+ }
+
+ /**
+ * @return The composite for the whole editor.
+ */
+ public Composite getEditorComposite() {
+ return editorComposite;
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ isDisposed = true;
+ getSite().getPage().removeSelectionListener(selectionListener);
+ }
+
+ // public void handleEvent(Event event) {
+ // if (event.widget instanceof CCombo) {
+ // CCombo combo = (CCombo) event.widget;
+ // if (comboListenerMap.containsKey(combo)) {
+ // if (combo.getSelectionIndex() > -1) {
+ // String sel = combo.getItem(combo.getSelectionIndex());
+ // Attribute attribute = getBug().getAttribute(comboListenerMap.get(combo));
+ // if (sel != null && !(sel.equals(attribute.getNewValue()))) {
+ // attribute.setNewValue(sel);
+ // for (IRepositoryTaskAttributeListener client : attributesListeners) {
+ // client.attributeChanged(attribute.getName(), sel);
+ // }
+ // changeDirtyStatus(true);
+ // }
+ // }
+ // }
+ // }
+ // }
+
+ /**
+ * Fires a <code>SelectionChangedEvent</code> to all listeners registered
+ * under <code>selectionChangedListeners</code>.
+ *
+ * @param event
+ * The selection event.
+ */
+ protected void fireSelectionChanged(final SelectionChangedEvent event) {
+ Object[] listeners = selectionChangedListeners.toArray();
+ for (int i = 0; i < listeners.length; i++) {
+ final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i];
+ SafeRunnable.run(new SafeRunnable() {
+ public void run() {
+ l.selectionChanged(event);
+ }
+ });
+ }
+ }
+
+ /**
+ * A generic listener for selection of unimportant items. The default
+ * selection item sent out is the entire bug object.
+ */
+ public class GenericListener implements Listener {
+ public void handleEvent(Event event) {
+ RepositoryTaskData bug = (RepositoryTaskData) getRepositoryTaskData();
+ fireSelectionChanged(new SelectionChangedEvent(selectionProvider, new StructuredSelection(
+ new RepositoryTaskSelection(bug.getId(), bug.getRepositoryUrl(), bug.getLabel(), false, bug
+ .getSummary()))));
+ }
+ }
+
+ /**
+ * A listener to check if the summary field was modified.
+ */
+ protected class SummaryListener implements Listener {
+ public void handleEvent(Event event) {
+ handleSummaryEvent();
+ }
+ }
+
+ /**
+ * Check if the summary field was modified, and update it if necessary.
+ */
+ public void handleSummaryEvent() {
+ String sel = summaryText.getText();
+ RepositoryTaskAttribute a = getRepositoryTaskData().getAttribute(RepositoryTaskAttribute.SUMMARY);
+ if (!(a.getValue().equals(sel))) {
+ a.setValue(sel);
+ changeDirtyStatus(true);
+ }
+ }
+
+ /*----------------------------------------------------------*
+ * CODE TO SCROLL TO A COMMENT OR OTHER PIECE OF TEXT
+ *----------------------------------------------------------*/
+
+ /** List of the StyledText's so that we can get the previous and the next */
+ protected ArrayList<StyledText> texts = new ArrayList<StyledText>();
+
+ protected HashMap<Object, StyledText> textHash = new HashMap<Object, StyledText>();
+
+ protected List<StyledText> commentStyleText = new ArrayList<StyledText>();
+
+ /** Index into the styled texts */
+ protected int textsindex = 0;
+
+ protected Text addCommentsTextBox = null;
+
+ protected Text descriptionTextBox = null;
+
+ // private FormText previousText = null;
+
+ /**
+ * Selects the given object in the editor.
+ *
+ * @param commentNumber
+ * The comment number to be selected
+ */
+ public void select(int commentNumber) {
+ if (commentNumber == -1)
+ return;
+
+ for (Object o : textHash.keySet()) {
+ if (o instanceof Comment) {
+ if (((Comment) o).getNumber() == commentNumber) {
+ select(o, true);
+ }
+ }
+ }
+ }
+
+ public void revealAllComments() {
+ for (StyledText text : commentStyleText) {
+ Composite comp = text.getParent();
+ while (comp != null) {
+ if (comp instanceof ExpandableComposite) {
+ ExpandableComposite ex = (ExpandableComposite) comp;
+ ex.setExpanded(true);
+ }
+ comp = comp.getParent();
+ }
+ }
+ }
+
+ /**
+ * Selects the given object in the editor.
+ *
+ * @param o
+ * The object to be selected.
+ * @param highlight
+ * Whether or not the object should be highlighted.
+ */
+ public void select(Object o, boolean highlight) {
+ if (textHash.containsKey(o)) {
+ StyledText t = textHash.get(o);
+ if (t != null) {
+ Composite comp = t.getParent();
+ while (comp != null) {
+ if (comp instanceof ExpandableComposite) {
+ ExpandableComposite ex = (ExpandableComposite) comp;
+ ex.setExpanded(true);
+ }
+ comp = comp.getParent();
+ }
+ focusOn(t, highlight);
+ }
+ } else if (o instanceof RepositoryTaskData) {
+ focusOn(null, highlight);
+ }
+ }
+
+ public void selectDescription() {
+ for (Object o : textHash.keySet()) {
+ if (o.equals(editorInput.getRepositoryTaskData().getDescription())) {
+ select(o, true);
+ }
+ }
+ }
+
+ public void selectNewComment() {
+ focusOn(addCommentsTextBox, false);
+ }
+
+ public void selectNewDescription() {
+ focusOn(descriptionTextBox, false);
+ }
+
+ /**
+ * Scroll to a specified piece of text
+ *
+ * @param selectionComposite
+ * The StyledText to scroll to
+ */
+ private void focusOn(Control selectionComposite, boolean highlight) {
+ int pos = 0;
+ // if (previousText != null && !previousText.isDisposed()) {
+ // previousText.setsetSelection(0);
+ // }
+
+ // if (selectionComposite instanceof FormText)
+ // previousText = (FormText) selectionComposite;
+
+ if (selectionComposite != null) {
+
+ // if (highlight && selectionComposite instanceof FormText &&
+ // !selectionComposite.isDisposed())
+ // ((FormText) selectionComposite).set.setSelection(0, ((FormText)
+ // selectionComposite).getText().length());
+
+ // get the position of the text in the composite
+ pos = 0;
+ Control s = selectionComposite;
+ if (s.isDisposed())
+ return;
+ s.setEnabled(true);
+ s.setFocus();
+ s.forceFocus();
+ while (s != null && s != getEditorComposite()) {
+ if (!s.isDisposed()) {
+ pos += s.getLocation().y;
+ s = s.getParent();
+ }
+ }
+
+ pos = pos - 60; // form.getOrigin().y;
+
+ }
+ if (!form.getBody().isDisposed())
+ form.setOrigin(0, pos);
+ }
+
+ private RepositoryTaskOutlinePage outlinePage = null;
+
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (IContentOutlinePage.class.equals(adapter)) {
+ if (outlinePage == null && editorInput != null) {
+ outlinePage = new RepositoryTaskOutlinePage(bugzillaOutlineModel);
+ }
+ return outlinePage;
+ }
+ return super.getAdapter(adapter);
+ }
+
+ public RepositoryTaskOutlineNode getOutlineModel() {
+ return bugzillaOutlineModel;
+ }
+
+ public RepositoryTaskOutlinePage getOutline() {
+ return outlinePage;
+ }
+
+ private boolean isDisposed = false;
+
+ public boolean isDisposed() {
+ return isDisposed;
+ }
+
+ public void close() {
+ Display activeDisplay = getSite().getShell().getDisplay();
+ activeDisplay.asyncExec(new Runnable() {
+ public void run() {
+ if (getSite() != null && getSite().getPage() != null && !AbstractRepositoryTaskEditor.this.isDisposed())
+ if (parentEditor != null) {
+ getSite().getPage().closeEditor(parentEditor, false);
+ } else {
+ getSite().getPage().closeEditor(AbstractRepositoryTaskEditor.this, false);
+ }
+ }
+ });
+ }
+
+ public void addAttributeListener(IRepositoryTaskAttributeListener listener) {
+ attributesListeners.add(listener);
+ }
+
+ public void removeAttributeListener(IRepositoryTaskAttributeListener listener) {
+ attributesListeners.remove(listener);
+ }
+
+ public void setParentEditor(MylarTaskEditor parentEditor) {
+ this.parentEditor = parentEditor;
+ }
+
+ public RepositoryTaskOutlineNode getBugzillaOutlineModel() {
+ return bugzillaOutlineModel;
+ }
+
+ public void setBugzillaOutlineModel(RepositoryTaskOutlineNode bugzillaOutlineModel) {
+ this.bugzillaOutlineModel = bugzillaOutlineModel;
+ }
+
+ /**
+ * A listener for selection of the textbox where a new comment is entered
+ * in.
+ */
+ protected class NewCommentListener implements Listener {
+ public void handleEvent(Event event) {
+ fireSelectionChanged(new SelectionChangedEvent(selectionProvider, new StructuredSelection(
+ new RepositoryTaskSelection(getRepositoryTaskData().getId(), getRepositoryTaskData().getRepositoryUrl(), "New Comment", false,
+ getRepositoryTaskData().getSummary()))));
+ }
+ }
+
+ // private void addHyperlinks(final StyledText styledText, Composite
+ // composite) {
+ //
+ // StringMatcher javaElementMatcher = new StringMatcher("*(*.java:*)", true,
+ // false);
+ // String[] lines = styledText.getText().split("\r\n|\n");
+ //
+ // int totalLength = 0;
+ // for (int x = 0; x < lines.length; x++) {
+ //
+ // String line = lines[x];
+ // Position position = javaElementMatcher.find(line, 0, line.length());
+ // if (position != null) {
+ // String linkText = line.substring(position.getStart() + 1,
+ // position.getEnd() - 1);
+ // // Link hyperlink = new Link(styledText, SWT.NONE);
+ // IRegion region = new Region(styledText.getText().indexOf(line) +
+ // position.getStart(), position.getEnd()
+ // - position.getStart());
+ // addControl(styledText, region, linkText, line, HYPERLINK_TYPE_JAVA);
+ // }
+ //
+ // IHyperlink[] bugHyperlinks = BugzillaUITools.findBugHyperlinks(0,
+ // line.length(), line, 0);
+ // if (bugHyperlinks != null) {
+ // for (IHyperlink hyperlink : bugHyperlinks) {
+ // String linkText = hyperlink.getHyperlinkText();
+ // int index = linkText.lastIndexOf('=');
+ // if (index >= 0) {
+ // String taskId = linkText.substring(index + 1);
+ // String href = repository.getUrl() + hyperlink.getHyperlinkText();
+ // addControl(styledText, hyperlink.getHyperlinkRegion(), "bug# " + taskId,
+ // href,
+ // HYPERLINK_TYPE_TASK);
+ // }
+ //
+ // }
+ // }
+ //
+ // totalLength = totalLength + line.length();
+ //
+ // } // bottom of for loop
+ //
+ // // reposition widgets on paint event
+ // styledText.addPaintObjectListener(new PaintObjectListener() {
+ // public void paintObject(PaintObjectEvent event) {
+ // StyleRange style = event.style;
+ // int start = style.start;
+ // Map<Integer, Control> controlMap = controls.get(styledText);
+ // Control control = controlMap.get(start);
+ // if (control != null) {
+ // Point pt = control.getSize();
+ // int x = event.x + MARGIN;
+ // int y = event.y + event.ascent - 2 * pt.y / 3;
+ // control.setLocation(x, y);
+ // }
+ // }
+ // });
+ // }
+
+ // private void addControl(final StyledText styledText, IRegion region,
+ // String linkText, String href,
+ // final String listenerType) {
+ // Hyperlink hyperlink = toolkit.createHyperlink(styledText, linkText,
+ // SWT.NONE);
+ // hyperlink.setText(linkText);
+ // hyperlink.setFont(COMMENT_FONT);
+ // hyperlink.setHref(href);
+ // IHyperlinkListener hyperlinkListener =
+ // MylarTaskListPlugin.getDefault().getTaskHyperlinkListeners().get(
+ // listenerType);
+ // if (hyperlinkListener != null) {
+ // hyperlink.addHyperlinkListener(hyperlinkListener);
+ // }
+ // Map<Integer, Control> controlMap = controls.get(styledText);
+ // if (controlMap == null) {
+ // controlMap = new HashMap<Integer, Control>();
+ // controls.put(styledText, controlMap);
+ // }
+ // controlMap.put(new Integer(region.getOffset()), hyperlink);
+ // StyleRange style = new StyleRange();
+ // style.start = region.getOffset();
+ // style.length = region.getLength();
+ // hyperlink.pack();
+ // Rectangle rect = hyperlink.getBounds();
+ // int ascent = 2 * rect.height / 3;
+ // int descent = rect.height - ascent;
+ // style.metrics = new GlyphMetrics(ascent + MARGIN, descent + MARGIN,
+ // rect.width + 2 * MARGIN);
+ // styledText.setStyleRange(style);
+ // }
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/ExistingBugEditorInput.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/ExistingBugEditorInput.java
new file mode 100644
index 000000000..3c4a57ca9
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/ExistingBugEditorInput.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 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.tasklist.ui.editors;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.security.GeneralSecurityException;
+
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.internal.tasklist.OfflineTaskManager;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+import org.eclipse.mylar.provisional.tasklist.AbstractRepositoryTask;
+import org.eclipse.mylar.provisional.tasklist.ITask;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+
+/**
+ * The <code>IEditorInput</code> implementation for
+ * <code>ExistingBugEditor</code>.
+ *
+ * @author Mik Kersten
+ * @author Rob Elves
+ */
+public class ExistingBugEditorInput extends AbstractBugEditorInput {
+
+ private TaskRepository repository;
+
+ protected int bugId;
+ protected AbstractRepositoryTask repositoryTask;
+ protected RepositoryTaskData repositoryTaskData;
+
+ // Called for new bug reports
+ public ExistingBugEditorInput(TaskRepository repository, RepositoryTaskData bug) {
+ this.repositoryTaskData = bug;
+ this.bugId = bug.getId();
+ this.repository = repository;
+ }
+
+
+// public ExistingBugEditorInput(TaskRepository repository, AbstractRepositoryTask task) throws IOException, GeneralSecurityException {
+// this.repositoryTask = task;
+// this.repository = repository;
+// this.repositoryTaskData = task.getTaskData();
+// //bug = BugzillaRepositoryUtil.getBug(repository.getUrl(), repository.getUserName(), repository.getPassword(), proxySettings, repository.getCharacterEncoding(), bugId);
+// }
+
+ public ExistingBugEditorInput(TaskRepository repository, int bugId) throws IOException, GeneralSecurityException {
+ this.bugId = bugId;
+ this.repository = repository;
+ this.repositoryTaskData = getOfflineTaskData(repository, proxySettings, bugId);
+
+
+ String handle = AbstractRepositoryTask.getHandle(repository.getUrl(), bugId);
+ ITask task = MylarTaskListPlugin.getTaskListManager().getTaskList().getTask(handle);
+ if(task != null && task instanceof AbstractRepositoryTask) {
+ this.repositoryTask = (AbstractRepositoryTask)task;
+ } else {
+ MylarStatusHandler.log("Could not locate repository task", this);
+ }
+
+
+
+ //bug = BugzillaRepositoryUtil.getBug(repository.getUrl(), repository.getUserName(), repository.getPassword(), proxySettings, repository.getCharacterEncoding(), bugId);
+ }
+
+ public AbstractRepositoryTask getRepositoryTask() {
+ return repositoryTask;
+ }
+
+ @Override
+ public RepositoryTaskData getRepositoryTaskData() {
+ return repositoryTaskData;
+ }
+// public ExistingBugEditorInput(TaskRepository repository, int bugId, boolean offline) throws IOException, GeneralSecurityException {
+// this.bugId = bugId;
+// this.repository = repository;
+// this.repositoryTaskData = getOfflineTaskData(repository, proxySettings, bugId);
+// // if (!offline) {
+// // try {
+// // bug = BugzillaRepositoryUtil.getBug(repository.getUrl(),
+// // repository.getUserName(), repository.getPassword(), proxySettings,
+// // repository.getCharacterEncoding(), bugId);
+// // } catch (IOException e) {
+// // bug = getCurrentBug(repository, proxySettings, bugId);
+// // // IWorkbench workbench = PlatformUI.getWorkbench();
+// // // workbench.getDisplay().asyncExec(new Runnable() {
+// // // public void run() {
+// // // MessageDialog.openInformation(
+// // // Display.getDefault().getActiveShell(),
+// // // "Mylar Bugzilla Client",
+// // // "Unable to download bug report, using offline copy.");
+// // //
+// // // }
+// // // });
+// // }
+// // } else {
+// // bug = getCurrentBug(repository, proxySettings, bugId);
+// // }
+// }
+
+ // TODO: move?
+ private RepositoryTaskData getOfflineTaskData(final TaskRepository repository, Proxy proxySettings, final int id)
+ throws IOException, GeneralSecurityException {
+ RepositoryTaskData result = null;
+ // Look among the offline reports for a bug with the given id.
+ OfflineTaskManager reportsFile = MylarTaskListPlugin.getDefault().getOfflineReportsFile();
+ if (reportsFile != null) {
+ int offlineId = reportsFile.find(repository.getUrl(), id);
+ // If an offline bug was found, return it if possible.
+ if (offlineId != -1) {
+ RepositoryTaskData bug = reportsFile.elements().get(offlineId);
+ if (bug instanceof RepositoryTaskData) {
+ result = (RepositoryTaskData) bug;
+ }
+ }
+ }
+
+ // If a suitable offline report was not found, get it from the server
+// if(result == null) {
+// try {
+// result = BugzillaRepositoryUtil.getBug(repository.getUrl(), repository.getUserName(), repository.getPassword(), proxySettings, repository.getCharacterEncoding(), id);
+// } catch (final LoginException e) {
+// PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+// public void run() {
+// MessageDialog.openError(Display.getDefault().getActiveShell(), "Report Download Failed",
+// "Ensure proper repository configuration of " + repository.getUrl() + " in "
+// + TaskRepositoriesView.NAME + ".");
+// }
+// });
+// } catch (final UnrecognizedBugzillaError e) {
+// PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+// public void run() {
+// WebBrowserDialog.openAcceptAgreement(null, "Report Download Failed", "Unrecognized response from "
+// + repository.getUrl(), e.getMessage());
+// }
+// });
+// } catch (final Exception e) {
+// if (PlatformUI.getWorkbench() != null && !PlatformUI.getWorkbench().isClosing()) {
+// PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+// public void run() {
+// if (e instanceof FileNotFoundException) {
+// MessageDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Report Download Failed",
+// "Resource not found: " + e.getMessage());
+//
+// } else {
+// MessageDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Report Download Failed",
+// "Report "+id+" did not download correctly from " + repository.getUrl());
+//
+// }
+// }
+// });
+// }
+// }
+// }
+ return result;
+ }
+
+ public String getName() {
+ return repositoryTaskData.getLabel();
+ }
+
+ /**
+ * @return The id of the bug for this editor input.
+ */
+ public int getBugId() {
+ return bugId;
+ }
+
+
+ /**
+ * @return <code>true</code> if the argument is a bug report editor input
+ * on the same bug id.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ExistingBugEditorInput) {
+ ExistingBugEditorInput input = (ExistingBugEditorInput) o;
+ return getBugId() == input.getBugId();
+ }
+ return false;
+ }
+
+ public TaskRepository getRepository() {
+ return repository;
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/IRepositoryTaskAttributeListener.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/IRepositoryTaskAttributeListener.java
new file mode 100644
index 000000000..199926120
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/IRepositoryTaskAttributeListener.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * 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.tasklist.ui.editors;
+
+/**
+ * @author Ken Sueda
+ */
+public interface IRepositoryTaskAttributeListener {
+ public abstract void attributeChanged(String attribute, String value);
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/IRepositoryTaskSelection.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/IRepositoryTaskSelection.java
new file mode 100644
index 000000000..09825e830
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/IRepositoryTaskSelection.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * 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.tasklist.ui.editors;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.mylar.internal.tasklist.Comment;
+
+/**
+ * Interface for a selection of a Bugzilla element in a view.
+ */
+public interface IRepositoryTaskSelection extends ISelection {
+
+ /**
+ * @return <code>true</code> if a comment was selected.
+ */
+ public boolean hasComment();
+
+ /**
+ * @return the <code>Comment</code> object for this selection, or
+ * <code>null</code> if a comment was not selected.
+ */
+ public Comment getComment();
+
+ /**
+ * Sets the <code>Comment</code> object for this selection. If a comment
+ * was not selected, then this should be <code>null</code>.
+ *
+ * @param comment
+ * The selection's comment, or <code>null</code> if not
+ * applicable.
+ */
+ public void setComment(Comment comment);
+
+ /**
+ * @return The contents of the selection. This can be <code>null</code>.
+ */
+ public String getContents();
+
+ /**
+ * Sets the contents of the selection.
+ *
+ * @param contents
+ * The selection.
+ */
+ public void setContents(String contents);
+
+ /**
+ * @return The id of the Bugzilla object that the selection was on.
+ */
+ public int getId();
+
+ /**
+ * Sets the id of the Bugzilla object that the selection was on.
+ *
+ * @param id
+ * The id of the bug.
+ */
+ public void setId(int id);
+
+ /**
+ * @return The server of the Bugzilla object that the selection was on, or
+ * <code>null</code> if no server is supplied.
+ */
+ public String getServer();
+
+ /**
+ * Sets the server of the Bugzilla object that the selection was on.
+ *
+ * @param server
+ * The server of the bug.
+ */
+ public void setServer(String server);
+
+ public boolean isCommentHeader();
+
+ public boolean isDescription();
+
+ public String getBugSummary();
+
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/OutlineTools.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/OutlineTools.java
new file mode 100644
index 000000000..55fdeb523
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/OutlineTools.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 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.tasklist.ui.editors;
+
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+
+public class OutlineTools {
+
+ /** The default string used for locally created bugs. */
+ public static final String OFFLINE_SERVER_DEFAULT = "[local]";
+
+ /**
+ * Returns a unique handle for the bugzilla selection. Contains the bug id,
+ * the bug server, and (if applicable) the comment number.
+ *
+ * @param bugSel
+ * The bugzilla selection.
+ * @return The handle for the bugzilla selection.
+ */
+ public static String getHandle(IRepositoryTaskSelection bugSel) {
+ String handle = bugSel.getServer() + ";" + bugSel.getId();
+ if (bugSel.hasComment()) {
+ int number = bugSel.getComment().getNumber() + 1;
+ handle += ";" + number;
+ } else if (bugSel.isCommentHeader()) {
+ handle += ";1";
+ } else if (bugSel.isDescription()) {
+ handle += ";0";
+ }
+ return handle;
+ }
+
+ public static String getName(IRepositoryTaskSelection bugSel) {
+ String name = bugSel.getServer() + ": Bug#: " + bugSel.getId() + ": " + bugSel.getBugSummary();
+ if (bugSel.hasComment()) {
+ name += " : Comment#: " + bugSel.getComment().getNumber();
+ } else if (bugSel.isCommentHeader()) {
+ name += " : Comment Header";
+ } else if (bugSel.isDescription()) {
+ name += ": Description";
+ }
+ return name;
+ }
+
+ public static String getHandle(RepositoryTaskData bug) {
+ return getHandle(bug.getRepositoryUrl(), bug.getId());
+ }
+
+ public static String getHandle(String server, int id) {
+ return server + ";" + id;
+ }
+
+ public static String getName(RepositoryTaskData bug) {
+ return bug.getRepositoryUrl() + ": Bug#: " + bug.getId() + ": " + bug.getSummary();
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskEditorCopyAction.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskEditorCopyAction.java
new file mode 100644
index 000000000..322ac2af4
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskEditorCopyAction.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.tasklist.ui.editors;
+
+import org.eclipse.jface.action.Action;
+
+/**
+ * Action used to copy selected text from a bug editor to the clipboard.
+ */
+public class RepositoryTaskEditorCopyAction extends Action {
+ /** The editor to copy text selections from. */
+ private AbstractRepositoryTaskEditor bugEditor;
+
+ /**
+ * Creates a new <code>RepositoryTaskEditorCopyAction</code>.
+ *
+ * @param editor
+ * The editor that this action is copying text selections from.
+ */
+ public RepositoryTaskEditorCopyAction(AbstractRepositoryTaskEditor editor) {
+ bugEditor = editor;
+ setText("AbstractRepositoryTaskEditor.copy.text");
+ }
+
+ @Override
+ public void run() {
+ bugEditor.getCurrentText().copy();
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlineComparer.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlineComparer.java
new file mode 100644
index 000000000..b9f6405e2
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlineComparer.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.tasklist.ui.editors;
+
+import org.eclipse.jface.viewers.IElementComparer;
+
+/**
+ * This class is used to compare two <code>IRepositoryTaskSelection</code>
+ * objects.
+ *
+ * @see IElementComparer
+ * @see IRepositoryTaskSelection
+ */
+public class RepositoryTaskOutlineComparer implements IElementComparer {
+
+ public boolean equals(Object a, Object b) {
+ if ((a instanceof IRepositoryTaskSelection) && (b instanceof IRepositoryTaskSelection)) {
+ IRepositoryTaskSelection s1 = (IRepositoryTaskSelection) a;
+ IRepositoryTaskSelection s2 = (IRepositoryTaskSelection) b;
+
+ // An IRepositoryTaskSelection is uniquely defined by its handle and
+ // its contents
+ return ((OutlineTools.getHandle(s1).equals(OutlineTools.getHandle(s2))) && ((s1.getContents() == null) ? (s2
+ .getContents() == null)
+ : s1.getContents().equals(s2.getContents())));
+ }
+ return a.equals(b);
+ }
+
+ public int hashCode(Object element) {
+ if (element instanceof IRepositoryTaskSelection) {
+ IRepositoryTaskSelection sel = (IRepositoryTaskSelection) element;
+
+ // An IRepositoryTaskSelection is uniquely defined by its handle and
+ // its contents
+ return (OutlineTools.getHandle(sel) + sel.getContents()).hashCode();
+ }
+ return element.hashCode();
+ }
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlineNode.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlineNode.java
new file mode 100644
index 000000000..562e4b923
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlineNode.java
@@ -0,0 +1,356 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 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.tasklist.ui.editors;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.mylar.internal.tasklist.Comment;
+import org.eclipse.mylar.internal.tasklist.RepositoryTaskData;
+import org.eclipse.mylar.internal.tasklist.ui.TaskListImages;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * A node for the tree in the <code>RepositoryTaskOutlinePage</code>.
+ *
+ * @author Mik Kersten (hardening of prototype)
+ */
+public class RepositoryTaskOutlineNode implements IRepositoryTaskSelection {
+
+ /** The id of the Bugzilla object that the selection was on. */
+ protected int id;
+
+ /** The server of the Bugzilla object that the selection was on. */
+ protected String server;
+
+ /** The label for this piece of data. */
+ private String key;
+
+ /** The children of this node. */
+ private ArrayList<RepositoryTaskOutlineNode> nodeChildren;
+
+ /** The parent of this node or null if it is the bug report */
+ private RepositoryTaskOutlineNode parent;
+
+ /** This node's image. */
+ private Image image;
+
+ private Object data = null;
+
+ private String bugSummary;
+
+ private boolean fromEditor = false;
+
+ private boolean isCommentHeader = false;
+
+ private boolean isDescription = false;
+
+ /**
+ * Creates a new <code>RepositoryTaskOutlineNode</code>.
+ *
+ * @param id
+ * The id of the bug this outline is for.
+ * @param server
+ * The server of the bug this outline is for.
+ * @param key
+ * The label for this node.
+ * @param image
+ * The image that will be displayed by this node in the tree.
+ * @param data
+ * The data, if necessary, this node represents.
+ * @param parent
+ * The parent of this node
+ */
+ public RepositoryTaskOutlineNode(int id, String server, String key, Image image, Object data, String summary) {
+ this.id = id;
+ this.server = server;
+ this.key = key;
+ this.nodeChildren = null;
+ this.image = image;
+ this.data = data;
+ this.parent = null;
+ this.bugSummary = summary;
+ }
+
+ public boolean isFromEditor() {
+ return fromEditor;
+ }
+
+ /**
+ * @return The children of this node, represented as an <code>Object</code>
+ * array.
+ */
+ public RepositoryTaskOutlineNode[] getChildren() {
+ return (nodeChildren == null) ? new RepositoryTaskOutlineNode[0] : nodeChildren
+ .toArray(new RepositoryTaskOutlineNode[nodeChildren.size()]);
+ }
+
+ /**
+ * Adds a node to this node's list of children.
+ *
+ * @param bugNode
+ * The new child.
+ */
+ public void addChild(RepositoryTaskOutlineNode bugNode) {
+ if (nodeChildren == null) {
+ nodeChildren = new ArrayList<RepositoryTaskOutlineNode>();
+ }
+ bugNode.setParent(this);
+ nodeChildren.add(bugNode);
+ }
+
+ /**
+ * @return The label of this node.
+ */
+ public String getKey() {
+ return key;
+ }
+
+ // /**
+ // * Set the label of this node.
+ // * @param key The new label.
+ // */
+ // public void setKey(String key) {
+ // this.key = key;
+ // }
+
+ /**
+ * TODO: remove, nodes don't need to know about image decorator
+ */
+ public Image getImage() {
+ return image;
+ }
+
+ /**
+ * Sets the decorator image for this node.
+ *
+ * @param newImage
+ * The new image.
+ */
+ public void setImage(Image newImage) {
+ this.image = newImage;
+ }
+
+ /**
+ * @return <code>true</code> if the given object is another node
+ * representing the same piece of data in the editor.
+ */
+ @Override
+ public boolean equals(Object arg0) {
+ if (arg0 instanceof RepositoryTaskOutlineNode) {
+ RepositoryTaskOutlineNode bugNode = (RepositoryTaskOutlineNode) arg0;
+ return getKey().equals(bugNode.getKey());
+ }
+ return super.equals(arg0);
+ }
+
+ @Override
+ public int hashCode() {
+ return getKey().hashCode();
+ }
+
+ /**
+ * @return The name of this node.
+ */
+ public String getName() {
+ return getKey();
+ }
+
+ /**
+ * @return The data (where applicable) this node represents.
+ */
+ public Object getData() {
+ return data;
+ }
+
+ /**
+ * Sets the data that this node represents.
+ *
+ * @param data
+ * The new piece of data.
+ */
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+ /**
+ * Parses the given <code>IBugzillaBug</code> into a tree of
+ * <code>RepositoryTaskOutlineNode</code>'s suitable for use in the
+ * <code>RepositoryTaskOutlinePage</code> view.
+ *
+ * @param bug
+ * The bug that needs parsing.
+ * @return The tree of <code>RepositoryTaskOutlineNode</code>'s.
+ */
+ public static RepositoryTaskOutlineNode parseBugReport(RepositoryTaskData bug) {
+ // Choose the appropriate parsing function based on
+ // the type of IBugzillaBug.
+// if (bug instanceof NewBugzillaReport) {
+// return parseNewBugReport((NewBugzillaReport) bug);
+// } else
+ if (bug instanceof RepositoryTaskData) {
+ return parseExistingBugReport((RepositoryTaskData) bug);
+ } else {
+ return null;
+ }
+ }
+
+// /**
+// * Parses the given <code>NewBugModel</code> into a tree of
+// * <code>RepositoryTaskOutlineNode</code>'s suitable for use in the
+// * <code>RepositoryTaskOutlinePage</code> view.
+// *
+// * @param bug
+// * The <code>NewBugModel</code> that needs parsing.
+// * @return The tree of <code>RepositoryTaskOutlineNode</code>'s.
+// */
+// protected static RepositoryTaskOutlineNode parseNewBugReport(NewBugzillaReport bug) {
+// int bugId = bug.getId();
+// String bugServer = bug.getRepositoryUrl();
+// Image bugImage = BugzillaImages.getImage(BugzillaImages.BUG);
+// Image defaultImage = BugzillaImages.getImage(BugzillaImages.BUG_COMMENT);
+// RepositoryTaskOutlineNode topNode = new RepositoryTaskOutlineNode(bugId, bugServer, bug.getLabel(), bugImage, bug, bug
+// .getSummary());
+//
+// topNode.addChild(new RepositoryTaskOutlineNode(bugId, bugServer, "New Description", defaultImage, null, bug
+// .getSummary()));
+//
+// RepositoryTaskOutlineNode titleNode = new RepositoryTaskOutlineNode(bugId, bugServer, "NewBugModel Object", defaultImage,
+// null, bug.getSummary());
+// titleNode.addChild(topNode);
+//
+// return titleNode;
+// }
+
+ /**
+ * Parses the given <code>BugReport</code> into a tree of
+ * <code>RepositoryTaskOutlineNode</code>'s suitable for use in the
+ * <code>RepositoryTaskOutlinePage</code> view.
+ *
+ * @param bug
+ * The <code>BugReport</code> that needs parsing.
+ * @return The tree of <code>RepositoryTaskOutlineNode</code>'s.
+ */
+ protected static RepositoryTaskOutlineNode parseExistingBugReport(RepositoryTaskData bug) {
+
+ int bugId = bug.getId();
+ String bugServer = bug.getRepositoryUrl();
+ Image bugImage = TaskListImages.getImage(TaskListImages.TASK_REMOTE);
+ //MylarTaskListPlugin.getDefault().BugzillaImages.getImage(BugzillaImages.BUG);
+ Image defaultImage = TaskListImages.getImage(TaskListImages.TASK_NOTES);
+ //BugzillaImages.getImage(BugzillaImages.BUG_COMMENT);
+ RepositoryTaskOutlineNode topNode = new RepositoryTaskOutlineNode(bugId, bugServer, bug.getLabel(), bugImage, bug, bug
+ .getSummary());
+
+ RepositoryTaskOutlineNode desc = new RepositoryTaskOutlineNode(bugId, bugServer, "Description", defaultImage, bug
+ .getDescription(), bug.getSummary());
+ desc.setIsDescription(true);
+
+ topNode.addChild(desc);
+
+ RepositoryTaskOutlineNode comments = null;
+ for (Iterator<Comment> iter = bug.getComments().iterator(); iter.hasNext();) {
+ Comment comment = iter.next();
+ // first comment is the bug description
+ if(comment.getNumber() == 0) continue;
+ if (comments == null) {
+ comments = new RepositoryTaskOutlineNode(bugId, bugServer, "Comments", defaultImage, comment, bug
+ .getSummary());
+ comments.setIsCommentHeader(true);
+ }
+ comments.addChild(new RepositoryTaskOutlineNode(bugId, bugServer, comment.getCreated().toString(), defaultImage,
+ comment, bug.getSummary()));
+ }
+ if (comments != null) {
+ topNode.addChild(comments);
+ }
+
+ topNode
+ .addChild(new RepositoryTaskOutlineNode(bugId, bugServer, "New Comment", defaultImage, null, bug.getSummary()));
+
+ RepositoryTaskOutlineNode titleNode = new RepositoryTaskOutlineNode(bugId, bugServer, "BugReport Object", defaultImage,
+ null, bug.getSummary());
+ titleNode.addChild(topNode);
+
+ return titleNode;
+ }
+
+ public boolean hasComment() {
+ // If the comment category was selected, then the comment object is
+ // not the intended selection (it is just used to help find the correct
+ // location in the editor).
+ return (data instanceof Comment) && !(key.toLowerCase().equals("comments"));
+ }
+
+ public Comment getComment() {
+ return (hasComment()) ? (Comment) data : null;
+ }
+
+ public void setComment(Comment comment) {
+ data = comment;
+ }
+
+ public String getContents() {
+ return key;
+ }
+
+ public void setContents(String contents) {
+ key = contents;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getServer() {
+ return server;
+ }
+
+ public void setServer(String server) {
+ this.server = server;
+ }
+
+ public boolean isEmpty() {
+ return (server == null) || ((getContents() == null) && (getComment() == null));
+ }
+
+ public RepositoryTaskOutlineNode getParent() {
+ return parent;
+ }
+
+ public void setParent(RepositoryTaskOutlineNode parent) {
+ this.parent = parent;
+ }
+
+ public boolean isCommentHeader() {
+ return isCommentHeader;
+ }
+
+ public boolean isDescription() {
+ return isDescription;
+ }
+
+ public void setIsCommentHeader(boolean isCommentHeader) {
+ this.isCommentHeader = isCommentHeader;
+ }
+
+ public void setIsDescription(boolean isDescription) {
+ this.isDescription = isDescription;
+ }
+
+ public String getBugSummary() {
+ return bugSummary;
+ }
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlinePage.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlinePage.java
new file mode 100644
index 000000000..351941349
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskOutlinePage.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2003 - 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.tasklist.ui.editors;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
+import org.eclipse.mylar.internal.tasklist.ui.TaskListImages;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
+
+/**
+ * An outline page for a <code>BugEditor</code>.
+ */
+public class RepositoryTaskOutlinePage extends ContentOutlinePage {
+
+ private RepositoryTaskOutlineNode topTreeNode;
+
+ protected final ISelectionListener selectionListener = new ISelectionListener() {
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if ((part instanceof AbstractRepositoryTaskEditor) && (selection instanceof IStructuredSelection)) {
+ if (((IStructuredSelection) selection).getFirstElement() instanceof IRepositoryTaskSelection) {
+ if (((IStructuredSelection) getSelection()).getFirstElement() instanceof IRepositoryTaskSelection) {
+ IRepositoryTaskSelection brs1 = (IRepositoryTaskSelection) ((IStructuredSelection) getSelection())
+ .getFirstElement();
+ IRepositoryTaskSelection brs2 = ((IRepositoryTaskSelection) ((IStructuredSelection) selection)
+ .getFirstElement());
+ if (OutlineTools.getHandle(brs1).compareTo(OutlineTools.getHandle(brs2)) == 0) {
+ // don't need to make a selection for the same
+ // element
+ return;
+ }
+ }
+ getTreeViewer().setSelection(selection, true);
+ }
+ }
+ }
+ };
+
+ private TreeViewer viewer;
+
+ /**
+ * Creates a new <code>RepositoryTaskOutlinePage</code>.
+ *
+ * @param topTreeNode
+ * The top data node of the tree for this view.
+ * @param editor
+ * The editor this outline page is for.
+ */
+ public RepositoryTaskOutlinePage(RepositoryTaskOutlineNode topTreeNode) {
+ super();
+ this.topTreeNode = topTreeNode;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ super.createControl(parent);
+ viewer = getTreeViewer();
+ viewer.setContentProvider(new BugTaskOutlineContentProvider());
+ viewer.setLabelProvider(new LabelProvider() {
+ @Override
+ public Image getImage(Object element) {
+ if (element instanceof RepositoryTaskOutlineNode) {
+ RepositoryTaskOutlineNode node = (RepositoryTaskOutlineNode) element;
+ if (node.getComment() != null) {
+ return node.getImage();
+ } else {
+ return TaskListImages.getImage(TaskListImages.TASK);
+ //BugzillaImages.getImage(BugzillaImages.BUG);
+ }
+ } else {
+ return super.getImage(element);
+ }
+ }
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof RepositoryTaskOutlineNode) {
+ RepositoryTaskOutlineNode node = (RepositoryTaskOutlineNode) element;
+ if (node.getComment() != null) {
+ return node.getComment().getAuthorName() + " (" + node.getName() + ")";
+ } else {
+ return node.getName();
+ }
+ }
+ return super.getText(element);
+ }
+ });
+ try {
+ viewer.setInput(topTreeNode);
+ viewer.setComparer(new RepositoryTaskOutlineComparer());
+ viewer.expandAll();
+ } catch (Exception e) {
+ MylarStatusHandler.fail(e, "could not create bugzilla outline", true);
+ }
+ getSite().getPage().addSelectionListener(selectionListener);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ getSite().getPage().removeSelectionListener(selectionListener);
+ }
+
+ public TreeViewer getOutlineTreeViewer() {
+ return viewer;
+ }
+
+ /**
+ * A content provider for the tree for this view.
+ *
+ * @see ITreeContentProvider
+ */
+ protected class BugTaskOutlineContentProvider implements ITreeContentProvider {
+
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof RepositoryTaskOutlineNode) {
+ Object[] children = ((RepositoryTaskOutlineNode) parentElement).getChildren();
+ if (children.length > 0) {
+ return children;
+ }
+ }
+ return new Object[0];
+ }
+
+ public Object getParent(Object element) {
+ return null;
+ }
+
+ public boolean hasChildren(Object element) {
+ if (element instanceof RepositoryTaskOutlineNode) {
+ return ((RepositoryTaskOutlineNode) element).getChildren().length > 0;
+ }
+ return false;
+ }
+
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof RepositoryTaskOutlineNode) {
+ Object[] children = ((RepositoryTaskOutlineNode) inputElement).getChildren();
+ if (children.length > 0) {
+ return children;
+ }
+ }
+ return new Object[0];
+ }
+
+ public void dispose() {
+ // don't care when we are disposed
+ }
+
+ public void inputChanged(Viewer viewerChanged, Object oldInput, Object newInput) {
+ // don't care when the input changes
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskSelection.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskSelection.java
new file mode 100644
index 000000000..a9d48f708
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTaskSelection.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * 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.tasklist.ui.editors;
+
+import org.eclipse.mylar.internal.tasklist.Comment;
+
+/**
+ * A selection of an element in a view.
+ */
+public class RepositoryTaskSelection implements IRepositoryTaskSelection {
+
+ /**
+ * The id of the Bugzilla object that the selection was on.
+ */
+ protected int id;
+
+ /** The server of the Bugzilla object that the selection was on. */
+ protected String server;
+
+ /** The contents of the selection. */
+ protected String contents;
+
+ protected String bugSummary;
+
+ /**
+ * The comment, if a comment was selected. If the selection was not a
+ * comment, then this is <code>null</code>.
+ */
+ protected Comment comment;
+
+ /**
+ * Creates a new <code>RepositoryTaskSelection</code> with no supplied
+ * contents or comment.
+ *
+ * @param id
+ * The id of the Bugzilla object that the selection was on.
+ * @param server
+ * The server of the Bugzilla object that the selection was on.
+ */
+ public RepositoryTaskSelection(int id, String server, String summary) {
+ this(id, server, null, null, summary);
+ }
+
+ /**
+ * Creates a new <code>RepositoryTaskSelection</code> with no supplied
+ * comment.
+ *
+ * @param id
+ * The id of the Bugzilla object that the selection was on.
+ * @param server
+ * The server of the Bugzilla object that the selection was on.
+ * @param contents
+ * The contents of the selection.
+ */
+ public RepositoryTaskSelection(int id, String server, String contents, boolean isDescription, String summary) {
+ this(id, server, contents, null, summary);
+ this.isDescription = isDescription;
+ }
+
+ /**
+ * Creates a new <code>RepositoryTaskSelection</code> with no supplied
+ * contents.
+ *
+ * @param id
+ * The id of the Bugzilla object that the selection was on.
+ * @param server
+ * The server of the Bugzilla object that the selection was on.
+ * @param comment
+ * The <code>Comment</code> object for this selection. If a
+ * comment was not selected, then this should be
+ * <code>null</code>.
+ */
+ public RepositoryTaskSelection(int id, String server, Comment comment, String summary) {
+ this(id, server, null, comment, summary);
+ }
+
+ /**
+ * Creates a new <code>RepositoryTaskSelection</code>.
+ *
+ * @param id
+ * The id of the Bugzilla object that the selection was on.
+ * @param server
+ * The server of the Bugzilla object that the selection was on.
+ * @param contents
+ * The contents of the selection.
+ * @param comment
+ * The <code>Comment</code> object for this selection. If a
+ * comment was not selected, then this should be
+ * <code>null</code>.
+ */
+ public RepositoryTaskSelection(int id, String server, String contents, Comment comment, String summary) {
+ this.id = id;
+ this.server = server;
+ this.contents = contents;
+ this.comment = comment;
+ this.bugSummary = summary;
+ }
+
+ public boolean hasComment() {
+ return comment != null;
+ }
+
+ public Comment getComment() {
+ return comment;
+ }
+
+ public void setComment(Comment comment) {
+ this.comment = comment;
+ }
+
+ public String getContents() {
+ return contents;
+ }
+
+ public void setContents(String contents) {
+ this.contents = contents;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getServer() {
+ return server;
+ }
+
+ public void setServer(String server) {
+ this.server = server;
+ }
+
+ public boolean isEmpty() {
+ return (server == null) || ((contents == null) && (comment == null));
+ }
+
+ private boolean isCommentHeader = false;
+
+ private boolean isDescription = false;
+
+ public boolean isCommentHeader() {
+ return isCommentHeader;
+ }
+
+ public boolean isDescription() {
+ return isDescription;
+ }
+
+ public void setIsCommentHeader(boolean isCommentHeader) {
+ this.isCommentHeader = isCommentHeader;
+ }
+
+ public void setIsDescription(boolean isDescription) {
+ this.isDescription = isDescription;
+ }
+
+ public String getBugSummary() {
+ return bugSummary;
+ }
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTextViewer.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTextViewer.java
new file mode 100644
index 000000000..795e116ad
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/RepositoryTextViewer.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * 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.tasklist.ui.editors;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.jface.text.hyperlink.IHyperlinkPresenter;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.MultiLineRule;
+import org.eclipse.jface.text.rules.RuleBasedScanner;
+import org.eclipse.jface.text.rules.SingleLineRule;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.mylar.provisional.tasklist.MylarTaskListPlugin;
+import org.eclipse.mylar.provisional.tasklist.TaskRepository;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
+import org.eclipse.ui.internal.editors.text.URLHyperlinkDetector;
+
+/**
+ * @author Rob Elves
+ */
+public class RepositoryTextViewer extends SourceViewer {
+
+ private TaskRepository repository;
+
+ public RepositoryTextViewer(TaskRepository repository, Composite composite, int style) {
+ super(composite, null, style);
+ this.configure(new RepositoryViewerConfig());
+ this.repository = repository;
+ }
+
+ public TaskRepository getRepository() {
+ return repository;
+ }
+
+ public void setRepository(TaskRepository repository) {
+ this.repository = repository;
+ }
+
+ class RepositoryViewerConfig extends TextSourceViewerConfiguration {
+
+ private RepositoryTextScanner scanner = null;
+
+ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
+ PresentationReconciler reconciler = new PresentationReconciler();
+ reconciler.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
+
+ DefaultDamagerRepairer dr = new DefaultDamagerRepairer(getDefaultScanner());
+ reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
+ reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
+
+ return reconciler;
+ }
+
+ private RepositoryTextScanner getDefaultScanner() {
+ if (scanner == null) {
+ scanner = new RepositoryTextScanner();
+ }
+ return scanner;
+ }
+
+ public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
+ URLHyperlinkDetector hyperlinkDetector = new URLHyperlinkDetector();
+ List<IHyperlinkDetector> detectors = new ArrayList<IHyperlinkDetector>();
+ detectors.add(hyperlinkDetector);
+ detectors.addAll(Arrays.asList(MylarTaskListPlugin.getDefault().getTaskHyperlinkDetectors()));
+ return detectors.toArray(new IHyperlinkDetector[detectors.size()]);
+// return MylarTaskListPlugin.getDefault().getTaskHyperlinkDetectors();
+ }
+
+ public IHyperlinkPresenter getHyperlinkPresenter(ISourceViewer sourceViewer) {
+ return new DefaultHyperlinkPresenter(new RGB(0, 0, 200));
+ }
+
+ public int getHyperlinkStateMask(ISourceViewer sourceViewer) {
+ return SWT.NONE;
+ }
+ }
+
+ class RepositoryTextScanner extends RuleBasedScanner {
+ private Color URL_COLOR = new Color(Display.getCurrent(), new RGB(0, 0, 200));
+
+ public RepositoryTextScanner() {
+ IToken bugToken = new Token(new TextAttribute(URL_COLOR));
+ IRule[] rules = new IRule[7];
+ rules[0] = (new SingleLineRule("http://", " ", bugToken));
+ rules[1] = (new SingleLineRule("https://", " ", bugToken));
+ rules[2] = (new MultiLineRule("bug#", " ", bugToken));
+ rules[3] = (new MultiLineRule("bug #", " ", bugToken));
+ rules[4] = (new SingleLineRule("bug #", "\n", bugToken));
+ rules[5] = (new SingleLineRule("http://", "\n", bugToken));
+ rules[6] = (new SingleLineRule("https://", "\n", bugToken));
+// rules[7] = (new MultiLineRule(" bug ", " ", bugToken));
+// rules[8] = (new SingleLineRule(" at ", ")", bugToken));
+ setRules(rules);
+ }
+
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/SpellingDialog.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/SpellingDialog.java
new file mode 100644
index 000000000..82ec9311e
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasklist/ui/editors/SpellingDialog.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * 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.tasklist.ui.editors;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * TODO this is used only for spell checking which is not yet implemented,
+ * therefore this is not properly tested
+ *
+ * @author Shawn Minto
+ */
+public class SpellingDialog extends Dialog {
+
+ private String title;
+
+ private Text wordToFix;
+
+ private List suggestions;
+
+ private IDocument document;
+
+ private ICompletionProposal[] proposals;
+
+ protected SpellingDialog(Shell parentShell, String title, IDocument document) {
+ super(parentShell);
+ this.title = title;
+ this.document = document;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Control c = super.createDialogArea(parent);
+
+ Composite spellingComposite = new Composite(parent, SWT.NONE);
+
+ GridLayout spellingLayout = new GridLayout();
+ spellingLayout.numColumns = 1;
+ spellingComposite.setLayout(spellingLayout);
+
+ wordToFix = new Text(spellingComposite, SWT.BORDER | SWT.READ_ONLY);
+ GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ gd.widthHint = 150;
+ wordToFix.setLayoutData(gd);
+
+ suggestions = new List(spellingComposite, SWT.BORDER);
+ gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ gd.widthHint = 150;
+ gd.heightHint = AbstractRepositoryTaskEditor.WRAP_LENGTH;
+ suggestions.setLayoutData(gd);
+
+ return c;
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+ newShell.setText(title);
+ }
+
+ public void open(String word, ICompletionProposal[] proposals) {
+ create();
+
+ this.proposals = proposals;
+
+ wordToFix.setText(word);
+ suggestions.removeAll();
+
+ for (int i = 0; i < proposals.length; i++) {
+ suggestions.setItem(i, proposals[i].getDisplayString());
+ }
+
+ super.open();
+ }
+
+ @Override
+ protected void handleShellCloseEvent() {
+ if (getReturnCode() == Dialog.OK) {
+ int i = suggestions.getSelectionIndex();
+ if (i > 0 && i < proposals.length)
+ proposals[i].apply(document);
+ }
+ super.handleShellCloseEvent();
+ }
+
+}
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryConnector.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryConnector.java
index ab1904162..8b40e1a58 100644
--- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryConnector.java
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/provisional/tasklist/AbstractRepositoryConnector.java
@@ -27,6 +27,7 @@ import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.mylar.internal.core.util.DateUtil;
@@ -117,11 +118,31 @@ public abstract class AbstractRepositoryConnector {
public abstract List<AbstractQueryHit> performQuery(AbstractRepositoryQuery query, IProgressMonitor monitor,
MultiStatus queryStatus);
+
// Precondition of note: offline file is removed upon submit to repository resulting in a synchronized state.
- protected void updateOfflineState(AbstractRepositoryTask repositoryTask, boolean forceSync) {
+ protected void updateOfflineState(final AbstractRepositoryTask repositoryTask, boolean forceSync) {
RepositoryTaskSyncState status = repositoryTask.getSyncState();
+ RepositoryTaskData downloadedTaskData;
+
+ final TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(
+ repositoryTask.getRepositoryKind(), repositoryTask.getRepositoryUrl());
- final RepositoryTaskData downloadedTaskData = downloadTaskData(repositoryTask);
+ if (repository == null) {
+ MylarStatusHandler
+ .log("No repository associated with task "+repositoryTask.getDescription()+". Unable to retrieve timezone information.", this);
+ return;
+ }
+
+ try {
+ downloadedTaskData = downloadTaskData(repositoryTask);
+ } catch (final CoreException e) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ ErrorDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Error Downloading Report", "Unable to synchronize "+repositoryTask.getDescription()+" on "+repository.getUrl(), e.getStatus());
+ }
+ });
+ return;
+ }
if (downloadedTaskData == null) {
MylarStatusHandler.log("Download of " + repositoryTask.getDescription() + " from "
@@ -132,14 +153,6 @@ public abstract class AbstractRepositoryConnector {
RepositoryTaskData offlineTaskData = OfflineTaskManager.findBug(downloadedTaskData.getRepositoryUrl(),
downloadedTaskData.getId());
- TaskRepository repository = MylarTaskListPlugin.getRepositoryManager().getRepository(
- repositoryTask.getRepositoryKind(), repositoryTask.getRepositoryUrl());
-
- if (repository == null) {
- MylarStatusHandler
- .log("No repository associated with task. Unable to retrieve timezone information.", this);
- return;
- }
TimeZone repositoryTimeZone = DateUtil.getTimeZone(repository.getTimeZoneId());
if (offlineTaskData != null) {
@@ -155,9 +168,9 @@ public abstract class AbstractRepositoryConnector {
null,
"Update Local Copy",
"Local copy of Report "
- + downloadedTaskData.getId()
+ + repositoryTask.getDescription()
+ " on "
- + downloadedTaskData.getRepositoryUrl()
+ + repositoryTask.getRepositoryUrl()
+ " has changes.\nWould you like to override local changes? \n\nNote: if you select No, only the new comment will be saved with the updated bug, all other changes will be lost.");
}
});
@@ -186,12 +199,12 @@ public abstract class AbstractRepositoryConnector {
status = RepositoryTaskSyncState.SYNCHRONIZED;
}
repositoryTask.setLastSynchronized(downloadedTaskData.getLastModified(repositoryTimeZone));
- repositoryTask.setTaskData(downloadedTaskData);
+ repositoryTask.setTaskData(downloadedTaskData);
repositoryTask.setSyncState(status);
- saveOffline(downloadedTaskData, forceSync);
+ saveOffline(downloadedTaskData);
}
- protected abstract RepositoryTaskData downloadTaskData(AbstractRepositoryTask bugzillaTask);
+ protected abstract RepositoryTaskData downloadTaskData(AbstractRepositoryTask bugzillaTask) throws CoreException;
public abstract String getLabel();
@@ -387,11 +400,10 @@ public abstract class AbstractRepositoryConnector {
public AbstractAttributeFactory getAttributeFactory() {
return attributeFactory;
}
-
- public void saveOffline(final RepositoryTaskData report, final boolean forceSync) {
- try {
- MylarTaskListPlugin.getDefault().getOfflineReportsFile().add(report, forceSync);
- // report.setOfflineState(true);
+
+ public void saveOffline(RepositoryTaskData taskData) {
+ try {
+ MylarTaskListPlugin.getDefault().getOfflineReportsFile().add(taskData);
} catch (CoreException e) {
MylarStatusHandler.fail(e, e.getMessage(), false);
}

Back to the top