Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.mylyn.bugzilla.ui')
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF4
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/plugin.xml14
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/BugzillaUiPlugin.java43
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/CreateBugzillaQueryCategoryAction.java71
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/CreateBugzillaTaskAction.java81
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/RefreshBugzillaAction.java73
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/RefreshBugzillaReportsAction.java153
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/search/BugzillaResultCollector.java184
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaCacheFile.java131
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaCategorySearchOperation.java139
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaContentProvider.java58
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaHit.java96
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaQueryCategory.java164
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaQueryDialog.java225
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaReportNode.java182
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTask.java500
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskEditor.java292
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskEditorInput.java134
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskExternalizer.java130
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskListManager.java40
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/StackTrace.java373
-rw-r--r--org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/TaskListActionContributor.java37
22 files changed, 3117 insertions, 7 deletions
diff --git a/org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF b/org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF
index 67c3e646e..e0809f1d0 100644
--- a/org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.mylyn.bugzilla.ui/META-INF/MANIFEST.MF
@@ -10,20 +10,22 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.core.resources,
org.eclipse.compare,
+ org.eclipse.mylar.tasks,
org.eclipse.search,
org.eclipse.ui.views,
org.eclipse.ui.ide,
org.eclipse.mylar.bugzilla.core,
+ org.eclipse.mylar.core,
org.eclipse.ui.browser,
org.eclipse.ui.forms
Eclipse-AutoStart: true
Export-Package: org.eclipse.mylar.bugzilla.ui,
org.eclipse.mylar.bugzilla.ui.actions,
org.eclipse.mylar.bugzilla.ui.editor,
- org.eclipse.mylar.bugzilla.ui.favorites,
org.eclipse.mylar.bugzilla.ui.favorites.actions,
org.eclipse.mylar.bugzilla.ui.outline,
org.eclipse.mylar.bugzilla.ui.query,
org.eclipse.mylar.bugzilla.ui.search,
+ org.eclipse.mylar.bugzilla.ui.tasks,
org.eclipse.mylar.bugzilla.ui.wizard
Bundle-ClassPath: bugzilla-ui.jar
diff --git a/org.eclipse.mylyn.bugzilla.ui/plugin.xml b/org.eclipse.mylyn.bugzilla.ui/plugin.xml
index 2aee1614d..ecc79aa55 100644
--- a/org.eclipse.mylyn.bugzilla.ui/plugin.xml
+++ b/org.eclipse.mylyn.bugzilla.ui/plugin.xml
@@ -4,6 +4,11 @@
<plugin>
<extension
+ name="Bugzilla startup"
+ point="org.eclipse.ui.startup">
+ </extension>
+
+ <extension
id="org.eclipse.mylar.bugzilla.wizards"
name="Bug Wizard"
point="org.eclipse.ui.newWizards">
@@ -18,7 +23,7 @@
id="org.eclipse.mylar.bugzilla.bugWizard"
name="New Bug Report">
<description>
- Create a new bug report
+ Create a new bug report
</description>
</wizard>
</extension>
@@ -63,7 +68,7 @@
id="org.eclipse.mylar.bugzilla.core.search.bugzillaSearchPage"
label="Bugzilla Search"
tabPosition="999"/>
- </extension>
+ </extension>
<extension
point="org.eclipse.ui.editors">
<editor
@@ -78,6 +83,11 @@
class="org.eclipse.mylar.bugzilla.ui.editor.NewBugEditor"
id="org.eclipse.mylar.bugzilla.ui.newBugEditor">
</editor>
+ <editor
+ icon="icons/elcl16/bug.gif"
+ name="Bugzilla task viewer"
+ class="org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTaskEditor"
+ id="org.eclipse.mylar.bugzilla.ui.tasks.bugzillaTaskEditor"/>
</extension>
<extension
id="org.eclipse.mylar.bugzilla.help.context"
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/BugzillaUiPlugin.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/BugzillaUiPlugin.java
index 37b2b640b..e9980248b 100644
--- a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/BugzillaUiPlugin.java
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/BugzillaUiPlugin.java
@@ -2,16 +2,25 @@ package org.eclipse.mylar.bugzilla.ui;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.mylar.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaContentProvider;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTaskExternalizer;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTaskListManager;
+import org.eclipse.mylar.tasks.MylarTasksPlugin;
+import org.eclipse.ui.IStartup;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The main plugin class to be used in the desktop.
*/
-public class BugzillaUiPlugin extends AbstractUIPlugin {
+public class BugzillaUiPlugin extends AbstractUIPlugin implements IStartup {
- //The shared instance.
- private static BugzillaUiPlugin plugin;
+ private BugzillaContentProvider bugzillaProvider;
+ private BugzillaTaskListManager bugzillaTaskListManager;
+ private static BugzillaUiPlugin plugin;
+
/**
* The constructor.
@@ -20,12 +29,26 @@ public class BugzillaUiPlugin extends AbstractUIPlugin {
plugin = this;
}
+ public void earlyStartup() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ workbench.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ BugzillaPlugin.setResultEditorMatchAdapter(new BugzillaResultMatchAdapter());
+ bugzillaProvider = new BugzillaContentProvider();
+ bugzillaTaskListManager = new BugzillaTaskListManager();
+
+ MylarTasksPlugin.getDefault().getTaskListExternalizer().addExternalizer(
+ new BugzillaTaskExternalizer()
+ );
+ }
+ });
+ }
+
/**
* This method is called upon plug-in activation
*/
public void start(BundleContext context) throws Exception {
super.start(context);
- BugzillaPlugin.setResultEditorMatchAdapter(new BugzillaResultMatchAdapter());
}
/**
@@ -53,4 +76,16 @@ public class BugzillaUiPlugin extends AbstractUIPlugin {
public static ImageDescriptor getImageDescriptor(String path) {
return AbstractUIPlugin.imageDescriptorFromPlugin("org.eclipse.mylar.bugzilla.ui", path);
}
+
+ public BugzillaContentProvider getBugzillaProvider() {
+ return bugzillaProvider;
+ }
+
+ public void setBugzillaProvider(BugzillaContentProvider bugzillaProvider) {
+ this.bugzillaProvider = bugzillaProvider;
+ }
+
+ public BugzillaTaskListManager getBugzillaTaskListManager() {
+ return bugzillaTaskListManager;
+ }
}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/CreateBugzillaQueryCategoryAction.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/CreateBugzillaQueryCategoryAction.java
new file mode 100644
index 000000000..85808f7fd
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/CreateBugzillaQueryCategoryAction.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaQueryCategory;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaQueryDialog;
+import org.eclipse.mylar.core.MylarPlugin;
+import org.eclipse.mylar.tasks.TaskListImages;
+import org.eclipse.mylar.tasks.MylarTasksPlugin;
+import org.eclipse.mylar.tasks.ui.views.TaskListView;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.progress.IProgressService;
+
+/**
+ * @author Mik Kersten and Ken Sueda
+ */
+public class CreateBugzillaQueryCategoryAction extends Action {
+
+ public static final String ID = "org.eclipse.mylar.tasks.actions.create.bug.query";
+
+ private final TaskListView view;
+
+ public CreateBugzillaQueryCategoryAction(TaskListView view) {
+ this.view = view;
+ setText("Add Bugzilla Query");
+ setToolTipText("Add Bugzilla Query");
+ setId(ID);
+ setImageDescriptor(TaskListImages.CATEGORY_QUERY_NEW);
+ }
+
+ @Override
+ public void run() {
+
+ // ask the user for the query string and a name
+// MylarPlugin.getDefault().actionObserved(this);
+ BugzillaQueryDialog sqd = new BugzillaQueryDialog(Display.getCurrent().getActiveShell());
+ if(sqd.open() == Dialog.OK){
+ final BugzillaQueryCategory queryCategory = new BugzillaQueryCategory(sqd.getName(), sqd.getUrl());
+
+ MylarTasksPlugin.getTaskListManager().getTaskList().addCategory(queryCategory);
+ WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ protected void execute(IProgressMonitor monitor) throws CoreException {
+ queryCategory.refreshBugs();
+ }
+ };
+
+ IProgressService service = PlatformUI.getWorkbench().getProgressService();
+ try {
+ service.run(true, true, op);
+ } catch (Exception e) {
+ MylarPlugin.log(e, "There was a problem executing the query refresh");
+ }
+ this.view.getViewer().refresh();
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/CreateBugzillaTaskAction.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/CreateBugzillaTaskAction.java
new file mode 100644
index 000000000..8bfe181fd
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/CreateBugzillaTaskAction.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.mylar.bugzilla.ui.BugzillaUiPlugin;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTask;
+import org.eclipse.mylar.tasks.ITask;
+import org.eclipse.mylar.tasks.TaskListImages;
+import org.eclipse.mylar.tasks.MylarTasksPlugin;
+import org.eclipse.mylar.tasks.TaskCategory;
+import org.eclipse.mylar.tasks.ui.views.TaskListView;
+
+/**
+ * @author Mik Kersten and Ken Sueda
+ */
+public class CreateBugzillaTaskAction extends Action {
+
+ public static final String ID = "org.eclipse.mylar.tasks.actions.create.bug";
+
+ private final TaskListView view;
+
+ public CreateBugzillaTaskAction(TaskListView view) {
+ this.view = view;
+ setText("Add Bugzilla Report");
+ setToolTipText("Add Bugzilla Report");
+ setId(ID);
+ setImageDescriptor(TaskListImages.TASK_BUGZILLA_NEW);
+ }
+
+ @Override
+ public void run() {
+// MylarPlugin.getDefault().actionObserved(this);
+ String bugIdString = this.view.getBugIdFromUser();
+ int bugId = -1;
+ try {
+ if (bugIdString != null) {
+ bugId = Integer.parseInt(bugIdString);
+ } else {
+ return;
+ }
+ } catch (NumberFormatException nfe) {
+ this.view.showMessage("Please enter a valid report number");
+ return;
+ }
+
+ // XXX we don't care about duplicates since we use a registrey
+ // Check the existing tasks to see if the id is used already.
+ // This is to prevent the creation of mutliple Bugzilla tasks
+ // for the same Bugzilla report.
+// boolean doesIdExistAlready = false;
+// doesIdExistAlready = lookForId("Bugzilla-" + bugId);
+// if (doesIdExistAlready) {
+// showMessage("A Bugzilla task with ID Bugzilla-" + bugId + " already exists.");
+// return;
+// }
+
+ BugzillaTask newBugTask = new BugzillaTask("Bugzilla-"+bugId, "<bugzilla info>");
+ BugzillaTask bugTask = BugzillaUiPlugin.getDefault().getBugzillaTaskListManager().getFromBugzillaTaskRegistry(newBugTask.getHandle());
+ if(bugTask == null) {
+ BugzillaUiPlugin.getDefault().getBugzillaTaskListManager().addToBugzillaTaskRegistry((BugzillaTask)bugTask);
+ }
+ Object selectedObject = ((IStructuredSelection)this.view.getViewer().getSelection()).getFirstElement();
+ if (selectedObject instanceof TaskCategory){
+ ((TaskCategory)selectedObject).addTask((ITask)bugTask);
+ } else {
+ MylarTasksPlugin.getTaskListManager().getTaskList().addRootTask((ITask)bugTask);
+ }
+ this.view.getViewer().refresh();
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/RefreshBugzillaAction.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/RefreshBugzillaAction.java
new file mode 100644
index 000000000..58fb20f7d
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/RefreshBugzillaAction.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.actions;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaQueryCategory;
+import org.eclipse.mylar.core.MylarPlugin;
+import org.eclipse.mylar.tasks.TaskListImages;
+import org.eclipse.mylar.tasks.ui.views.TaskListView;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.progress.IProgressService;
+
+/**
+ * @author Ken Sueda
+ */
+public class RefreshBugzillaAction extends Action {
+
+ public static final String ID = "org.eclipse.mylar.tasks.actions.refresh.bugzilla";
+
+ private final TaskListView view;
+ public RefreshBugzillaAction(TaskListView view) {
+ this.view = view;
+ setText("Bugzilla Rrefresh");
+ setToolTipText("Bugzilla Refresh");
+ setId(ID);
+ setImageDescriptor(TaskListImages.TASK_BUG_REFRESH);
+ }
+ @Override
+ public void run() {
+ ISelection selection = this.view.getViewer().getSelection();
+ Object obj = ((IStructuredSelection) selection).getFirstElement();
+ final BugzillaQueryCategory cat = (BugzillaQueryCategory) obj;
+ if (obj instanceof BugzillaQueryCategory) {
+ WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ protected void execute(IProgressMonitor monitor) throws CoreException {
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
+ public void run() {
+ cat.refreshBugs();
+ RefreshBugzillaAction.this.view.getViewer().refresh();
+ }
+ });
+ }
+ };
+ // Use the progess service to execute the runnable
+ IProgressService service = PlatformUI.getWorkbench().getProgressService();
+ try {
+ service.run(true, false, op);
+ } catch (InvocationTargetException e) {
+ // Operation was canceled
+ MylarPlugin.log(e, e.getMessage());
+ } catch (InterruptedException e) {
+ // Handle the wrapped exception
+ MylarPlugin.log(e, e.getMessage());
+ }
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/RefreshBugzillaReportsAction.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/RefreshBugzillaReportsAction.java
new file mode 100644
index 000000000..ef6dedef0
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/actions/RefreshBugzillaReportsAction.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.actions;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.Action;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.core.BugzillaRepository;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaQueryCategory;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTask;
+import org.eclipse.mylar.tasks.AbstractCategory;
+import org.eclipse.mylar.tasks.ITask;
+import org.eclipse.mylar.tasks.TaskListImages;
+import org.eclipse.mylar.tasks.MylarTasksPlugin;
+import org.eclipse.mylar.tasks.TaskCategory;
+import org.eclipse.mylar.tasks.ui.views.TaskListView;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.progress.IProgressService;
+
+/**
+ * @author Mik Kersten and Ken Sueda
+ */
+public class RefreshBugzillaReportsAction extends Action {
+
+ public static final String ID = "org.eclipse.mylar.tasks.actions.refresh.bugdb";
+
+ private final TaskListView view;
+
+ private boolean showProgress = true;
+
+ public RefreshBugzillaReportsAction(TaskListView view) {
+ this.view = view;
+ setText("Refresh Bugzilla reports");
+ setToolTipText("Refresh Bugzilla reports");
+ setId(ID);
+ setImageDescriptor(TaskListImages.TASK_BUG_REFRESH);
+ }
+
+ public void setShowProgress(boolean show) {
+ this.showProgress = show;
+ }
+
+ @Override
+ public void run() {
+// MylarPlugin.getDefault().actionObserved(this);
+ // TODO background?
+ // perform the update in an operation so that we get a progress monitor
+ // update the structure bridge cache with the reference provider cached
+ // bugs
+ if (showProgress) {
+ runWithProgressBar();
+ } else {
+ refreshTasksAndQueries();
+ }
+ }
+
+ private void runWithProgressBar() {
+ WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
+ protected void execute(IProgressMonitor monitor)
+ throws CoreException {
+
+ refreshTasksAndQueries();
+
+ // clear the caches
+ Set<String> cachedHandles = new HashSet<String>();
+
+ // XXX refactored
+// cachedHandles.addAll(MylarTasksPlugin.getDefault().getStructureBridge().getCachedHandles());
+// cachedHandles.addAll(MylarTasksPlugin.getReferenceProvider().getCachedHandles());
+// MylarTasksPlugin.getDefault().getStructureBridge().clearCache();
+// MylarTasksPlugin.getReferenceProvider().clearCachedReports();
+// BugzillaStructureBridge bridge = MylarTasksPlugin.getDefault().getStructureBridge();
+
+ monitor.beginTask("Downloading Bugs", cachedHandles.size());
+ for (String key : cachedHandles) {
+ try {
+ String[] parts = key.split(";");
+ final int id = Integer.parseInt(parts[1]);
+ BugReport bug = BugzillaRepository.getInstance().getCurrentBug(id);
+ if (bug != null) {
+ // XXX refactored
+ throw new RuntimeException("unimplemented");
+// bridge.cache(key, bug);
+ }
+ } catch (Exception e) {
+ }
+
+ monitor.worked(1);
+ }
+ monitor.done();
+ RefreshBugzillaReportsAction.this.view.getViewer().refresh();
+ }
+ };
+
+ // Use the progess service to execute the runnable
+ IProgressService service = PlatformUI.getWorkbench()
+ .getProgressService();
+ try {
+ service.run(true, false, op);
+ } catch (InvocationTargetException e) {
+ // Operation was canceled
+ } catch (InterruptedException e) {
+ // Handle the wrapped exception
+ }
+ }
+
+ private void refreshTasksAndQueries() {
+ List<ITask> tasks = MylarTasksPlugin.getTaskListManager().getTaskList().getRootTasks();
+
+ for (ITask task : tasks) {
+ if (task instanceof BugzillaTask) {
+ ((BugzillaTask) task).refresh();
+ }
+ }
+ for (AbstractCategory cat : MylarTasksPlugin
+ .getTaskListManager().getTaskList().getCategories()) {
+ if (cat instanceof TaskCategory) {
+ for (ITask task : ((TaskCategory) cat).getChildren()) {
+ if (task instanceof BugzillaTask) {
+ ((BugzillaTask) task).refresh();
+ }
+ }
+ RefreshBugzillaReportsAction.this.view.refreshChildren(((TaskCategory) cat).getChildren());
+ } else if (cat instanceof BugzillaQueryCategory) {
+ final BugzillaQueryCategory bqc = (BugzillaQueryCategory) cat;
+ PlatformUI.getWorkbench().getDisplay().syncExec(
+ new Runnable() {
+ public void run() {
+ bqc.refreshBugs();
+ RefreshBugzillaReportsAction.this.view.getViewer().refresh();
+ }
+ });
+ }
+ }
+ RefreshBugzillaReportsAction.this.view.getViewer().refresh();
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/search/BugzillaResultCollector.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/search/BugzillaResultCollector.java
new file mode 100644
index 000000000..8429dcf2f
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/search/BugzillaResultCollector.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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
+ *******************************************************************************/
+/*
+ * Created on Oct 4, 2004
+ */
+package org.eclipse.mylar.bugzilla.ui.search;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchHit;
+import org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchOperation;
+import org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchResultCollector;
+
+
+/**
+ * Collector for the bugzilla search results
+ *
+ * @author Shawn Minto
+ */
+public class BugzillaResultCollector implements IBugzillaSearchResultCollector {
+ /** A list of all of the search results found */
+ private List<BugzillaSearchHit> results = new ArrayList<BugzillaSearchHit>();
+
+ /** The progress monitor for the search operation */
+ private IProgressMonitor monitor;
+
+ /** The number of matches found */
+ private int matchCount;
+
+ /** The bugzilla search operation */
+ private IBugzillaSearchOperation operation;
+
+ /** The string to display to the user while querying */
+ private static final String STARTING = "querying the server";
+
+ /** The string to display to the user when the query is done */
+ private static final String DONE = "done";
+
+ /** The string to display when there is one match from the search */
+ private static final String MATCH = "Bugzilla Mylar search - 1 match";
+
+ /** The string to display when there is more than one match from the search */
+ private static final String MATCHES = "Bugzilla Mylar search - {0} matches";
+
+ /**
+ * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchResultCollector#aboutToStart()
+ */
+ public void aboutToStart(int startMatchCount) throws CoreException {
+ // initiailize the number of matches
+ matchCount = startMatchCount;
+
+ // set the progress monitor to say that we are querying the server
+ monitor.setTaskName(STARTING);
+ }
+
+ /**
+ * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchResultCollector#accept(org.eclipse.mylar.bugzilla.core.search.BugzillaSearchHit)
+ */
+ public void accept(BugzillaSearchHit hit) throws CoreException {
+ // add the result to the list of results
+ results.add(hit);
+
+ // increment the match count
+ matchCount++;
+
+ if (getProgressMonitor() != null) {
+ if (!getProgressMonitor().isCanceled()) {
+ // if the operation is cancelled finish with whatever data was
+ // already found
+ getProgressMonitor().subTask(
+ getFormattedMatchesString(matchCount));
+ getProgressMonitor().worked(1);
+ }
+ }
+ }
+
+ /**
+ * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchResultCollector#done()
+ */
+ public void done() {
+ if (getProgressMonitor() != null) {
+ if (!monitor.isCanceled()) {
+ // if the operation is cancelled, finish with the data that we
+ // already have
+ String matchesString = getFormattedMatchesString(matchCount);
+ monitor.setTaskName(MessageFormat.format(DONE,
+ new Object[] { matchesString }));
+ }
+ }
+
+ monitor = null;
+ }
+
+ /**
+ * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchResultCollector#getProgressMonitor()
+ */
+ public IProgressMonitor getProgressMonitor() {
+ return monitor;
+ }
+
+ /**
+ * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchResultCollector#setProgressMonitor(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void setProgressMonitor(IProgressMonitor monitor) {
+ this.monitor = monitor;
+ }
+
+ /**
+ * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchResultCollector#setOperation(org.eclipse.mylar.bugzilla.core.search.BugzillaSearchOperation)
+ */
+ public void setOperation(IBugzillaSearchOperation operation) {
+ this.operation = operation;
+ }
+
+ /**
+ * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchResultCollector#getOperation()
+ */
+ public IBugzillaSearchOperation getOperation() {
+ return operation;
+ }
+
+ /**
+ * Get the string specifying the number of matches found
+ *
+ * @param count
+ * The number of matches found
+ * @return The <code>String</code> specifying the number of matches found
+ */
+ private String getFormattedMatchesString(int count) {
+ // if only 1 match, return the singular match string
+ String name = "";
+
+ // XXX refactored
+// if(operation instanceof BugzillaMylarSearchOperation)
+// name = " - " + ((BugzillaMylarSearchOperation)operation).getName();
+ if (count == 1)
+ return MATCH + name;
+
+ // format the matches string and return it
+ Object[] messageFormatArgs = { new Integer(count) };
+ return MessageFormat.format(MATCHES + name,
+ messageFormatArgs);
+ }
+
+ /**
+ * Get the list of results
+ *
+ * @return A List of BugzillaSearchHit
+ */
+ public List<BugzillaSearchHit> getResults() {
+ return results;
+ }
+
+ /**
+ * Get the number of matches from the operation
+ *
+ * @return Returns the matchCount.
+ */
+ public int getMatchCount() {
+ return matchCount;
+ }
+
+ /**
+ * Set the starting number of matches for the search operation
+ *
+ * @param matchCount
+ * The matchCount to set.
+ */
+ public void setMatchCount(int matchCount) {
+ this.matchCount = matchCount;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaCacheFile.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaCacheFile.java
new file mode 100644
index 000000000..6a5fbab0f
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaCacheFile.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.mylar.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.bugzilla.core.IBugzillaBug;
+
+/**
+ * COPIED FROM @see org.eclipse.mylar.bugzilla.offlineReports.OfflineReportsFile
+ *
+ * @author Shawn Minto
+ */
+public class BugzillaCacheFile {
+
+ private File file;
+
+ private ArrayList<IBugzillaBug> list = new ArrayList<IBugzillaBug>();
+
+ protected int latestNewBugId = 0;
+
+ public BugzillaCacheFile(File file) throws ClassNotFoundException, IOException {
+ this.file = file;
+ if (file.exists()) {
+ readFile();
+ }
+ }
+
+ public void add(IBugzillaBug entry) {
+ // add the entry to the list and write the file to disk
+ list.add(entry);
+ writeFile();
+ }
+
+ public void update() {
+ writeFile();
+ }
+
+ public int getNextOfflineBugId() {
+ latestNewBugId++;
+ return latestNewBugId;
+ }
+
+ public int find(int id) {
+ for (int i = 0; i < list.size(); i++) {
+ IBugzillaBug currBug = list.get(i);
+ if (currBug != null && (currBug.getId() == id) && !currBug.isLocallyCreated())
+ return i;
+ }
+ return -1;
+ }
+
+ public ArrayList<IBugzillaBug> elements() {
+ return list;
+ }
+
+ private void writeFile() {
+ try {
+ ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
+
+ // Write the size of the list so that we can read it back in easier
+ out.writeInt(list.size());
+
+ out.writeInt(latestNewBugId);
+
+ // write each element in the array list
+ for (int i = 0; i < list.size(); i++) {
+ Object item = list.get(i);
+ out.writeObject(item);
+ }
+ out.close();
+ }
+ catch (IOException e) {
+ // put up a message and log the error if there is a problem writing to the file
+ MessageDialog.openError(null,
+ "I/O Error",
+ "Bugzilla could not write to offline reports file.");
+ BugzillaPlugin.log(e);
+ }
+ }
+
+ private void readFile() throws ClassNotFoundException, IOException {
+ ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
+
+ // get the number of offline reports in the file
+ int size = in.readInt();
+
+ // get the bug id of the most recently created offline report
+ latestNewBugId = in.readInt();
+
+ // read in each of the offline reports in the file
+ for (int nX = 0; nX < size; nX++) {
+ IBugzillaBug item = (IBugzillaBug) in.readObject();
+ // add the offline report to the offlineReports list
+ list.add(item);
+ }
+ in.close();
+ }
+
+ public void remove(List<IBugzillaBug> sel) {
+ list.removeAll(sel);
+
+ // rewrite the file so that the data is persistant
+ writeFile();
+ }
+
+ public void removeAll() {
+ list.clear();
+
+ // rewrite the file so that the data is persistant
+ writeFile();
+ }
+}
+
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaCategorySearchOperation.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaCategorySearchOperation.java
new file mode 100644
index 000000000..b27c5c498
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaCategorySearchOperation.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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
+ *******************************************************************************/
+/*
+ * Created on Oct 14, 2004
+ */
+package org.eclipse.mylar.bugzilla.ui.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchEngine;
+import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchQuery;
+import org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchOperation;
+import org.eclipse.mylar.bugzilla.ui.search.BugzillaResultCollector;
+import org.eclipse.mylar.core.MylarPlugin;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+
+
+/**
+ * Bugzilla search operation for Mylar
+ *
+ * @author Shawn Minto
+ */
+public class BugzillaCategorySearchOperation extends WorkspaceModifyOperation
+ implements IBugzillaSearchOperation {
+ /** The IMember we are doing the search for */
+
+ public interface ICategorySearchListener {
+ public void searchCompleted(BugzillaResultCollector collector);
+ }
+
+ /** The bugzilla collector for the search */
+ private BugzillaResultCollector collector = null;
+
+ /** The status of the search operation */
+ private IStatus status;
+
+ /** The LoginException that was thrown when trying to do the search */
+ private LoginException loginException = null;
+
+ private String url;
+
+ /**
+ * Constructor
+ *
+ * @param m
+ * The member that we are doing the search for
+ */
+ public BugzillaCategorySearchOperation(String url) {
+ this.url = url;
+ }
+
+ @Override
+ public void execute(IProgressMonitor monitor) {
+ collector = new BugzillaResultCollector();
+ collector.setOperation(this);
+ collector.setProgressMonitor(monitor);
+ search(url, monitor);
+ for(ICategorySearchListener listener: listeners)
+ listener.searchCompleted(collector);
+ }
+
+ /**
+ * Perform the actual search on the Bugzilla server
+ * @param url The url to use for the search
+ * @param searchCollector The collector to put the search results into
+ * @param monitor The progress monitor to use for the search
+ * @return The BugzillaResultCollector with the search results
+ */
+ private BugzillaResultCollector search(String url, IProgressMonitor monitor){
+
+ // set the initial number of matches to 0
+ int matches = 0;
+ // setup the progress monitor and start the search
+ collector.setProgressMonitor(monitor);
+ BugzillaSearchEngine engine = new BugzillaSearchEngine(url);
+ try {
+
+ // perform the search
+ status = engine.search(collector, matches);
+
+ // check the status so that we don't keep searching if there
+ // is a problem
+ if (status.getCode() == IStatus.CANCEL) {
+ MylarPlugin.log("search cancelled", this);
+ return null;
+ } else if (!status.isOK()) {
+ MylarPlugin.log("search error", this);
+ MylarPlugin.log(status);
+ return null;
+ }
+ return collector;
+ } catch (LoginException e) {
+ //save this exception to throw later
+ this.loginException = e;
+ }
+ return null;
+ }
+
+ /**
+ * @see org.eclipse.mylar.bugzilla.core.search.IBugzillaSearchOperation#getStatus()
+ */
+ public IStatus getStatus() throws LoginException {
+ // if a LoginException was thrown while trying to search, throw this
+ if (loginException == null)
+ return status;
+ else
+ throw loginException;
+ }
+
+ public ImageDescriptor getImageDescriptor() {
+ return null;
+ }
+
+ public BugzillaSearchQuery getQuery() {
+ return null;
+ }
+
+ public void setQuery(BugzillaSearchQuery newQuery) {}
+
+ private List<ICategorySearchListener> listeners = new ArrayList<ICategorySearchListener>();
+
+ public void addResultsListener(ICategorySearchListener listener){
+ listeners.add(listener);
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaContentProvider.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaContentProvider.java
new file mode 100644
index 000000000..2f5bf4cc7
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaContentProvider.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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
+ *******************************************************************************/
+/*
+ * Created on Jan 13, 2005
+ */
+package org.eclipse.mylar.bugzilla.ui.tasks;
+
+import org.eclipse.mylar.bugzilla.core.BugReport;
+
+
+/**
+ * @author Mik Kersten
+ * @author Eric Booth
+ */
+public class BugzillaContentProvider {
+
+ public BugzillaContentProvider() {
+ // don't have any initialization to do
+ }
+
+ /**
+ * @return String containing bug priority and label, e.g. "[12345] P2: fix failing test"
+ */
+ public String getBugzillaDescription(BugzillaTask bugTask) {
+ if (bugTask == null) return "<no info>";
+
+ String prefix = //((bugTask.isDirty()) ? ">" : "") +
+ BugzillaTask.getBugId(bugTask.getHandle()) + ": ";
+
+ if (bugTask.getState() == BugzillaTask.BugTaskState.DOWNLOADING) {
+ return prefix + "<Downloading bug report from server...>";
+ } else if (bugTask.getState() == BugzillaTask.BugTaskState.OPENING) {
+ return prefix + "<Opening bug report in editor...>";
+ } else if (bugTask.getState() == BugzillaTask.BugTaskState.COMPARING) {
+ return prefix + "<Comparing bug report with server...>";
+ } else if (bugTask.getState() == BugzillaTask.BugTaskState.WAITING) {
+ return prefix + "<Waiting to check server...>";
+ }
+
+ // generate the label
+ if (bugTask.isBugDownloaded()) {
+ BugReport report = bugTask.getBugReport();
+ return prefix + report.getSummary();
+ }
+ else {
+ return prefix + "<Could not find bug>";
+ }
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaHit.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaHit.java
new file mode 100644
index 000000000..d68ea337b
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaHit.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+
+import org.eclipse.mylar.bugzilla.core.BugzillaRepository;
+import org.eclipse.mylar.bugzilla.ui.BugzillaImages;
+import org.eclipse.mylar.tasks.ITaskListElement;
+import org.eclipse.mylar.tasks.TaskListImages;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * @author Ken Sueda
+ */
+public class BugzillaHit implements ITaskListElement {
+
+ private String description;
+ private String priority;
+ private int id;
+ private BugzillaTask task;
+
+ public BugzillaHit(String description, String priority, int id, BugzillaTask task) {
+ this.description = description;
+ this.priority = priority;
+ this.id = id;
+ this.task = task;
+ }
+
+ public boolean isTask(){
+ return task != null;
+ }
+
+ public BugzillaTask getAssociatedTask(){
+ return task;
+ }
+
+ public void setAssociatedTask(BugzillaTask task){
+ this.task = task;
+ }
+
+ public Image getIcon() {
+ if(isTask()){
+ return task.getIcon();
+ } else {
+ return BugzillaImages.getImage(BugzillaImages.BUG);
+ }
+ }
+
+ public Image getStatusIcon() {
+ if (isTask()) {
+ return task.getStatusIcon();
+ } else {
+ return TaskListImages.getImage(TaskListImages.TASK_INACTIVE);
+ }
+ }
+
+ public String getPriority() {
+ return priority;
+ }
+
+ public String getDescription(boolean label) {
+ return description;
+ }
+
+ public String getHandle() {
+ return getServerName()+"-"+getID();
+ }
+ public void setDescription(String description) {
+ this.description = description;
+ }
+ public String getServerName() {
+ // TODO need the right server name - get from the handle
+ return "Bugzilla";
+ }
+ public int getID() {
+
+ return id;
+ }
+
+ public String getIDString() {
+ Integer bugId = new Integer(this.id);
+ return bugId.toString();
+ }
+
+ public String getBugUrl() {
+ return BugzillaRepository.getBugUrl(id);
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaQueryCategory.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaQueryCategory.java
new file mode 100644
index 000000000..f8b43d478
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaQueryCategory.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.mylar.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.bugzilla.core.IBugzillaConstants;
+import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchHit;
+import org.eclipse.mylar.bugzilla.ui.BugzillaUiPlugin;
+import org.eclipse.mylar.bugzilla.ui.search.BugzillaResultCollector;
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaCategorySearchOperation.ICategorySearchListener;
+import org.eclipse.mylar.tasks.AbstractCategory;
+import org.eclipse.mylar.tasks.TaskListImages;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author Shawn Minto
+ */
+public class BugzillaQueryCategory extends AbstractCategory {
+
+ private static final long serialVersionUID = 5517146402031743253L;
+ private String url;
+ private List<BugzillaHit> hits = new ArrayList<BugzillaHit>();
+ private boolean hasBeenRefreshed = false;
+
+ public class BugzillaQueryCategorySearchListener implements ICategorySearchListener {
+
+ Map<Integer, BugzillaSearchHit> hits = new HashMap<Integer, BugzillaSearchHit>();
+
+ public void searchCompleted(BugzillaResultCollector collector) {
+ for(BugzillaSearchHit hit: collector.getResults()){
+
+ // HACK need the server name and handle properly
+ addHit(new BugzillaHit(hit.getId() + ": " + hit.getDescription(), hit.getPriority(), hit.getId(), null));
+ }
+ }
+
+ }
+
+ private ICategorySearchListener listener = new BugzillaQueryCategorySearchListener();
+
+ public BugzillaQueryCategory(String label, String url) {
+ super(label);
+ this.url = url;
+ }
+
+ public String getDescription(boolean label) {
+ if (hits.size() > 0 || !label) {
+ return super.getDescription(label);
+ } else if (!hasBeenRefreshed) {
+ return super.getDescription(label) + " <needs refresh>";
+ } else {
+ return super.getDescription(label) + " <no hits>";
+ }
+ }
+
+
+ public Image getIcon() {
+ return TaskListImages.getImage(TaskListImages.CATEGORY_QUERY);
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public List<BugzillaHit> getHits() {
+ return hits;
+ }
+
+ public void addHit(BugzillaHit hit) {
+ BugzillaTask task = BugzillaUiPlugin.getDefault().getBugzillaTaskListManager().getFromBugzillaTaskRegistry(hit.getHandle());
+ hit.setAssociatedTask(task);
+ hits.add(hit);
+ }
+
+ public void removeHit(BugzillaHit hit) {
+ hits.remove(hit);
+ }
+
+ public void refreshBugs() {
+ hits.clear();
+ final BugzillaCategorySearchOperation catSearch = new BugzillaCategorySearchOperation(
+ getUrl());
+ catSearch.addResultsListener(listener);
+ final IStatus[] status = new IStatus[1];
+
+ try {
+ // execute the search operation
+ catSearch.execute(new NullProgressMonitor());
+ hasBeenRefreshed = true;
+
+ // get the status of the search operation
+ status[0] = catSearch.getStatus();
+
+ // determine if there was an error, if it was cancelled, or if it is
+ // ok
+ if (status[0].getCode() == IStatus.CANCEL) {
+ // it was cancelled, so just return
+ status[0] = Status.OK_STATUS;
+ // return status[0];
+ return;
+ } else if (!status[0].isOK()) {
+ // there was an error, so display an error message
+ PlatformUI.getWorkbench().getDisplay().asyncExec(
+ new Runnable() {
+ public void run() {
+ ErrorDialog.openError(null,
+ "Bugzilla Search Error", null,
+ status[0]);
+ }
+ });
+ status[0] = Status.OK_STATUS;
+ return;
+ // return status[0];
+ }
+ } catch (LoginException e) {
+ // we had a problem while searching that seems like a login info
+ // problem
+ // thrown in BugzillaSearchOperation
+ MessageDialog
+ .openError(
+ null,
+ "Login Error",
+ "Bugzilla could not log you in to get the information you requested since login name or password is incorrect.\nPlease check your settings in the bugzilla preferences. ");
+ BugzillaPlugin.log(new Status(IStatus.ERROR,
+ IBugzillaConstants.PLUGIN_ID, IStatus.OK, "", e));
+ }
+ return;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getPriority() {
+ String highestPriority = "P5";
+ for (BugzillaHit hit : hits) {
+ if (highestPriority.compareTo(hit.getPriority()) > 0) {
+ highestPriority = hit.getPriority();
+ }
+ }
+ return highestPriority;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaQueryDialog.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaQueryDialog.java
new file mode 100644
index 000000000..ff2e1cbb5
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaQueryDialog.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.mylar.bugzilla.ui.query.GetQueryDialog;
+import org.eclipse.mylar.bugzilla.ui.query.SaveQueryDialog;
+import org.eclipse.mylar.bugzilla.ui.search.BugzillaSearchPage;
+import org.eclipse.search.ui.ISearchPageContainer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkingSet;
+
+/**
+ * @author Shawn Minto
+ */
+public class BugzillaQueryDialog extends Dialog {
+
+ private String url;
+ private String name;
+ private BugzillaSearchOptionPage searchOptionPage;
+
+ public BugzillaQueryDialog(Shell parentShell) {
+ super(parentShell);
+ searchOptionPage = new BugzillaSearchOptionPage();
+
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ searchOptionPage.createControl(parent);
+ searchOptionPage.setVisible(true); // called to initialize the values
+ return super.createContents(parent);
+ }
+
+ @Override
+ protected void okPressed(){
+ url = searchOptionPage.getSearchURL();
+ if(url == null || url.equals("")){
+ /*
+ * Should never get here. Every implementation of the Java platform is required
+ * to support the standard charset "UTF-8"
+ */
+ return;
+ }
+ InputDialog getNameDialog = new InputDialog(Display.getCurrent().getActiveShell(), "Bugzilla Query Category Name", "Please enter a name for the bugzilla query category","", new IInputValidator(){
+
+ public String isValid(String newText) {
+ if(newText != null && !newText.equals("")){
+ return null;
+ } else {
+ return "You must enter a name for the category";
+ }
+ }
+
+ });
+ getNameDialog.setBlockOnOpen(true);
+ if(getNameDialog.open() == InputDialog.OK){
+ name = getNameDialog.getValue();
+
+ super.okPressed();
+ } else {
+ super.cancelPressed();
+ }
+ }
+
+ private class BugzillaSearchOptionPage extends BugzillaSearchPage{
+
+ public BugzillaSearchOptionPage(){
+ scontainer = new ISearchPageContainer(){
+ public ISelection getSelection() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public IRunnableContext getRunnableContext() {
+ return null;
+ }
+
+ public void setPerformActionEnabled(boolean state) {
+ Button ok = BugzillaQueryDialog.this.getButton(Dialog.OK);
+ if(ok != null)
+ ok.setEnabled(state);
+ }
+
+ public int getSelectedScope() {
+ return 0;
+ }
+
+ public void setSelectedScope(int scope) {}
+
+ public boolean hasValidScope() {
+ return true;
+ }
+
+ public IWorkingSet[] getSelectedWorkingSets() {
+ return null;
+ }
+
+ public void setSelectedWorkingSets(IWorkingSet[] workingSets) {}
+ };
+ }
+
+ public String getSearchURL() {
+ try{
+ if(rememberedQuery){
+ return getQueryURL(new StringBuffer(input.getQueryParameters(selIndex)));
+ } else {
+ return getQueryURL(getQueryParameters());
+ }
+ } catch (UnsupportedEncodingException e){
+ /*
+ * Do nothing. Every implementation of the Java platform is required
+ * to support the standard charset "UTF-8"
+ */
+ }
+ return "";
+ }
+
+ @Override
+ protected Control createSaveQuery(Composite control) {
+ GridLayout layout;
+ GridData gd;
+
+ Group group = new Group(control, SWT.NONE);
+ layout = new GridLayout(3, false);
+ group.setLayout(layout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ gd = new GridData(GridData.BEGINNING | GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
+ gd.horizontalSpan = 2;
+ group.setLayoutData(gd);
+
+ loadButton = new Button(group, SWT.PUSH | SWT.LEFT);
+ loadButton.setText("Saved Queries...");
+ loadButton.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ GetQueryDialog qd = new GetQueryDialog(getShell(),
+ "Saved Queries", input){
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ super.createButtonsForButtonBar(parent);
+ Button okButton = super.getButton(IDialogConstants.OK_ID);
+ if(okButton != null)
+ okButton.setText("Select");
+ }
+ };
+
+ if (qd.open() == InputDialog.OK) {
+ selIndex = qd.getSelected();
+ if (selIndex != -1) {
+ rememberedQuery = true;
+ }
+ } else {
+ rememberedQuery = false;
+ }
+ }
+ });
+ loadButton.setEnabled(true);
+ loadButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+
+ saveButton = new Button(group, SWT.PUSH | SWT.LEFT);
+ saveButton.setText("Remember...");
+ saveButton.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ SaveQueryDialog qd = new SaveQueryDialog(getShell(),
+ "Remember Query");
+ if (qd.open() == InputDialog.OK) {
+ String qName = qd.getText();
+ if (qName != null && qName.compareTo("") != 0) {
+ try {
+ input.add(getQueryParameters().toString(), qName, summaryPattern.getText());
+ }
+ catch (UnsupportedEncodingException e) {
+ /*
+ * Do nothing. Every implementation of the Java platform is required
+ * to support the standard charset "UTF-8"
+ */
+ }
+ }
+ }
+ }
+ });
+ saveButton.setEnabled(true);
+ saveButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+
+ return group;
+ }
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaReportNode.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaReportNode.java
new file mode 100644
index 000000000..5adcaa8aa
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaReportNode.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.core.BugzillaRepository;
+import org.eclipse.mylar.bugzilla.core.search.BugzillaSearchHit;
+
+
+/**
+ * Class to store the DoiInfo of a BugzillaSearchHit
+ *
+ * @author Shawn Minto
+ */
+public class BugzillaReportNode {
+
+ private static final long serialVersionUID = 3257004367222419506L;
+
+ /** The BugzillaSearchHit associated with this DoiInfo */
+ private BugzillaSearchHit hit;
+
+ /** Whether this search hit was from an exact search like a stack trace */
+ private boolean isExact = false;
+
+ /** List of all of the StackTrace's in the given bug */
+ private List<StackTrace> stackTraces;
+
+ /** The bug report associated with this DoiInfo */
+ private BugReport bug;
+
+ /**
+ * Constructor
+ *
+ * @param initialValue
+ * The initial Doi value
+ * @param hit
+ * The BugzillaSearchHit associated with this DoiInfo
+ * @param isExact
+ * Whether the search was exact or not
+ */
+ public BugzillaReportNode(float initialValue, BugzillaSearchHit hit,
+ boolean isExact) {
+ this.hit = hit;
+ this.isExact = isExact;
+ bug = null;
+ stackTraces = new ArrayList<StackTrace>();
+ }
+
+ /**
+ * Get the bugzilla search hit relating to this DoiInfo
+ *
+ * @return The BugzillaSearchHit related to this DoiInfo
+ */
+ public BugzillaSearchHit getHit() {
+ return hit;
+ }
+
+ @Override
+ public String toString() {
+ return hit.toString();
+ }
+
+ /**
+ * Determine if the search hit this represents is exact or not
+ *
+ * @return <code>true</code> if the search was exact otherwise
+ * <code>false</code>
+ */
+ public boolean isExact() {
+ return isExact;
+ }
+
+ /**
+ * Set whether this bug has any exact elements in it - the search used was fully qualified
+ *
+ * @param isExact -
+ * Whether there are any exact element matches in it
+ */
+ public void setExact(boolean isExact) {
+ this.isExact = isExact;
+ }
+
+ /**
+ * Get the bug report associated with this DoiInfo<br>
+ * The bug is downloaded if it was not previously
+ *
+ * @return Returns the BugReport
+ *
+ * @throws IOException
+ * @throws LoginException
+ * @throws MalformedURLException
+ */
+ public BugReport getBug() throws MalformedURLException, LoginException, IOException {
+ if(bug == null){
+
+ // get the bug report
+ bug = BugzillaRepository.getInstance().getBug(
+ hit.getId());
+ }
+ return bug;
+ }
+
+ /**
+ * Set the bug report associated with this DoiInfo
+ *
+ * @param bug -
+ * BugReport that this is associated with
+ */
+ public void setBug(BugReport bug) {
+ this.bug = bug;
+ }
+
+ /**
+ * Get all of the stack traces contained in the bug
+ *
+ * @return Returns a list of StackTrace's
+ */
+ public List<StackTrace> getStackTraces() {
+ return stackTraces;
+ }
+
+ /**
+ * Determine whether the doi info has any stack traces associated with it
+ * @return <code>true</code> if there are some stack traces else <code>false</code>
+ */
+ public boolean hasStackTraces(){
+ return !stackTraces.isEmpty();
+ }
+
+ /**
+ * Add a stack trace to this DoiInfo
+ *
+ * @param stackTrace -
+ * The StackTrace to add
+ */
+ public void addStackTrace(StackTrace stackTrace) {
+ this.stackTraces.add(stackTrace);
+ }
+
+ /**
+ * Add an array of stack traces to this DoiInfo
+ *
+ * @param stackTracesToAdd -
+ * The StackTraces to add
+ */
+ public void addStackTraces(StackTrace[] stackTracesToAdd) {
+ for (int i = 0; i < stackTracesToAdd.length; i++)
+ this.stackTraces.add(stackTracesToAdd[i]);
+ }
+
+ /**
+ * Get the name of the bug report
+ * @return The name of the bug report, max 20 characters
+ */
+ public String getName() {
+ final int MAX_LENGTH = 100;
+ String description = hit.getDescription();
+ int length = description.length();
+ if (length > MAX_LENGTH) description = description.substring(0, MAX_LENGTH) + "..";
+ return "bug " + hit.getId() + ": " + description;
+ }
+
+ public String getElementHandle() {
+ return hit.getServer() + ";" + hit.getId();
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTask.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTask.java
new file mode 100644
index 000000000..17497787f
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTask.java
@@ -0,0 +1,500 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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
+ *******************************************************************************/
+/*
+ * Created on 14-Jan-2005
+ */
+package org.eclipse.mylar.bugzilla.ui.tasks;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.core.BugzillaPlugin;
+import org.eclipse.mylar.bugzilla.core.BugzillaRepository;
+import org.eclipse.mylar.bugzilla.core.IBugzillaBug;
+import org.eclipse.mylar.bugzilla.core.offline.OfflineReportsFile;
+import org.eclipse.mylar.bugzilla.ui.BugzillaUiPlugin;
+import org.eclipse.mylar.bugzilla.ui.OfflineView;
+import org.eclipse.mylar.core.MylarPlugin;
+import org.eclipse.mylar.tasks.TaskListImages;
+import org.eclipse.mylar.tasks.MylarTasksPlugin;
+import org.eclipse.mylar.tasks.Task;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.Workbench;
+
+
+/**
+ * @author Mik Kersten
+ */
+public class BugzillaTask extends Task {
+
+ /**
+ * Comment for <code>serialVersionUID</code>
+ */
+ private static final long serialVersionUID = 3257007648544469815L;
+
+ public static final String FILE_EXTENSION = ".bug_reports";
+
+ public enum BugTaskState {FREE, WAITING, DOWNLOADING, COMPARING, OPENING}
+ private transient BugTaskState state;
+
+ /**
+ * The bug report for this BugzillaTask. This is <code>null</code> if the
+ * bug report with the specified ID was unable to download.
+ */
+ protected transient BugReport bugReport = null;
+
+ /**
+ * Value is <code>true</code> if the bug report has saved changes that
+ * need synchronizing with the Bugzilla server.
+ */
+ private boolean isDirty;
+
+ /** The last time this task's bug report was downloaded from the server. */
+ protected Date lastRefresh;
+
+ public static final ISchedulingRule rule = new ISchedulingRule() {
+ public boolean isConflicting(ISchedulingRule schedulingRule) {
+ return schedulingRule == this;
+ }
+ public boolean contains(ISchedulingRule schedulingRule) {
+ return schedulingRule == this;
+ }
+ };
+
+ public BugzillaTask(String id, String label) {
+ super(id, label);
+ isDirty = false;
+ GetBugReportJob job = new GetBugReportJob("Downloading from Bugzilla server...");
+ job.schedule();
+ }
+
+ public BugzillaTask(String id, String label, boolean noDownload) {
+ super(id, label);
+ isDirty = false;
+ if (!noDownload) {
+ GetBugReportJob job = new GetBugReportJob("Downloading from Bugzilla server...");
+ job.schedule();
+ }
+ }
+
+ public BugzillaTask(BugzillaHit hit) {
+ this(hit.getHandle(), hit.getDescription(false));
+ }
+
+ @Override
+ public String getLabel() {
+ return BugzillaUiPlugin.getDefault().getBugzillaProvider().getBugzillaDescription(this);
+ }
+
+ /**
+ * @return Returns the bugReport.
+ */
+ public BugReport getBugReport() {
+ return bugReport;
+ }
+
+ /**
+ * @param bugReport The bugReport to set.
+ */
+ public void setBugReport(BugReport bugReport) {
+ this.bugReport = bugReport;
+ }
+
+ /**
+ * @return Returns the serialVersionUID.
+ */
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+ /**
+ * @return Returns the lastRefresh.
+ */
+ public Date getLastRefresh() {
+ return lastRefresh;
+ }
+ /**
+ * @param lastRefresh The lastRefresh to set.
+ */
+ public void setLastRefresh(Date lastRefresh) {
+ this.lastRefresh = lastRefresh;
+ }
+ /**
+ * @param state The state to set.
+ */
+ public void setState(BugTaskState state) {
+ this.state = state;
+ }
+ /**
+ * @return Returns <code>true</code> if the bug report has saved changes
+ * that need synchronizing with the Bugzilla server.
+ */
+ public boolean isDirty() {
+ return isDirty;
+ }
+
+ /**
+ * @param isDirty The isDirty to set.
+ */
+ public void setDirty(boolean isDirty) {
+ this.isDirty = isDirty;
+ notifyTaskDataChange();
+ }
+
+ /**
+ * @return Returns the state of the Bugzilla task.
+ */
+ public BugTaskState getState() {
+ return state;
+ }
+
+ /**
+ * Try to download the bug from the server.
+ * @param bugId The ID of the bug report to download.
+ *
+ * @return The bug report, or <code>null</code> if it was unsuccessfully
+ * downloaded.
+ */
+ public BugReport downloadReport() {
+// BugzillaTaskEditorInput input = new BugzillaTaskEditorInput(this);
+ try {
+ // XXX make sure to send in the server name if there are multiple repositories
+ return BugzillaRepository.getInstance().getBug(getBugId(getHandle()));
+ } catch (LoginException e) {
+ MylarPlugin.log(e, "download failed");
+ } catch (IOException e) {
+ MylarPlugin.log(e, "download failed");
+ }
+ return null;
+ }
+
+ @Override
+ public void openTaskInEditor(){
+ openTask(-1);
+ }
+
+ /**
+ * Opens this task's bug report in an editor revealing the selected comment.
+ * @param commentNumber The comment number to reveal
+ */
+ public void openTask(int commentNumber) {
+ if (state != BugTaskState.FREE) {
+ return;
+ }
+
+ state = BugTaskState.OPENING;
+ notifyTaskDataChange();
+ OpenBugTaskJob job = new OpenBugTaskJob("Opening Bugzilla task in editor...", this);
+ job.schedule();
+ job.addJobChangeListener(new IJobChangeListener(){
+
+ public void aboutToRun(IJobChangeEvent event) {
+ // don't care about this event
+ }
+
+ public void awake(IJobChangeEvent event) {
+ // don't care about this event
+ }
+
+ public void done(IJobChangeEvent event) {
+ state = BugTaskState.FREE;
+ notifyTaskDataChange();
+ }
+
+ public void running(IJobChangeEvent event) {
+ // don't care about this event
+ }
+
+ public void scheduled(IJobChangeEvent event) {
+ // don't care about this event
+ }
+
+ public void sleeping(IJobChangeEvent event) {
+ // don't care about this event
+ }
+ });
+ }
+
+ /**
+ * @return <code>true</code> if the bug report for this BugzillaTask was
+ * successfully downloaded.
+ */
+ public boolean isBugDownloaded() {
+ return bugReport != null;
+ }
+
+ @Override
+ public String toString() {
+ return "bugzilla report id: " + getHandle();
+ }
+
+ protected void openTaskEditor(final IEditorInput input) {
+ if (isBugDownloaded()) {
+
+ Workbench.getInstance().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ // get the active workbench page
+ IWorkbenchPage page = MylarTasksPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
+
+ // if we couldn't get the page, get out of here
+ if (page == null)
+ return;
+
+ try {
+ // try to open an editor on the input bug
+ //page.openEditor(input, IBugzillaConstants.EXISTING_BUG_EDITOR_ID);
+ page.openEditor(input, "org.eclipse.mylar.tasks.ui.bugzillaTaskEditor");
+ }
+ catch (PartInitException ex) {
+ MylarPlugin.log(ex, "couldn't open");
+ return;
+ }
+ }
+ });
+ }
+ else {
+ Workbench.getInstance().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ MessageDialog.openInformation(Workbench.getInstance().getActiveWorkbenchWindow().getShell(),
+ "Could not open bug.", "Bug #" + getHandle()
+ + " could not be read from the server. Try refreshing the bug task.");
+ }
+ });
+ }
+ }
+
+ /**
+ * @return Returns the last time this task's bug report was downloaded from
+ * the server.
+ */
+ public Date getLastRefreshTime() {
+ return lastRefresh;
+ }
+
+ /**
+ * @return The number of seconds ago that this task's bug report was
+ * downloaded from the server.
+ */
+ public long getTimeSinceLastRefresh() {
+ Date timeNow = new Date();
+ return (timeNow.getTime() - lastRefresh.getTime())/1000;
+ }
+
+ private class GetBugReportJob extends Job {
+ public GetBugReportJob(String name) {
+ super(name);
+ setRule(rule);
+ state = BugTaskState.WAITING;
+ notifyTaskDataChange();
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ state = BugTaskState.DOWNLOADING;
+ notifyTaskDataChange();
+ // Update time this bugtask was last downloaded.
+ lastRefresh = new Date();
+ bugReport = downloadReport();
+ state = BugTaskState.FREE;
+ updateTaskDetails();
+ notifyTaskDataChange();
+ saveBugReport(true);
+ return new Status(IStatus.OK, MylarPlugin.IDENTIFIER, IStatus.OK, "", null);
+ }
+ }
+
+ public void updateTaskDetails() {
+ try {
+ setPriority(bugReport.getAttribute("Priority").getValue());
+ String status = bugReport.getAttribute("Status").getValue();
+ if (status.equals("RESOLVED")) {
+ setCompleted(true);
+ }
+ } catch (NullPointerException npe) {
+ // TODO: handle this better
+ }
+ }
+
+ private class OpenBugTaskJob extends Job {
+
+ protected BugzillaTask bugTask;
+
+ public OpenBugTaskJob(String name, BugzillaTask bugTask) {
+ super(name);
+ this.bugTask = bugTask;
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try{
+ final IEditorInput input = new BugzillaTaskEditorInput(bugTask);
+ state = BugTaskState.OPENING;
+ notifyTaskDataChange();
+ openTaskEditor(input);
+
+ state = BugTaskState.FREE;
+ notifyTaskDataChange();
+ return new Status(IStatus.OK, MylarPlugin.IDENTIFIER, IStatus.OK, "", null);
+ }catch(Exception e){
+ MylarPlugin.log(e, "couldn't open");
+ }
+ return Status.CANCEL_STATUS;
+ }
+ }
+
+ /**
+ * Refreshes the bug report with the Bugzilla server.
+ */
+ public void refresh() {
+ // The bug report must be untouched, and this task must not be busy.
+ if (isDirty() || (state != BugTaskState.FREE)) {
+ return;
+ }
+ GetBugReportJob job = new GetBugReportJob("Refreshing with Bugzilla server...");
+ job.schedule();
+ }
+
+ @Override
+ public String getToolTipText() {
+ if(lastRefresh == null)
+ return "";
+ // Get the current time.
+ Date timeNow = new Date();
+
+ // Get the number of minutes between the current time
+ // and the last time the bug report was downloaded
+ long timeDifference = (timeNow.getTime() - lastRefresh.getTime())/60000;
+
+ // Calculate the number of minutes and hours.
+ // The amount left in "timeDifference" is the
+ // days' difference.
+ long minutes = timeDifference % 60;
+ timeDifference /= 60;
+ long hours = timeDifference % 24;
+ timeDifference /= 24;
+
+ // Gradually generate the tooltip string...
+ String toolTip;
+ if (bugReport == null) {
+ toolTip = "Last attempted download ";
+ }
+ else {
+ toolTip = "Last downloaded ";
+ }
+
+ if (timeDifference > 0) {
+ toolTip += timeDifference + ((timeDifference == 1) ? " day " : " days ");
+ }
+ if (hours > 0 || timeDifference > 0) {
+ toolTip += hours + ((hours == 1) ? " hour " : " hours ");
+ }
+ toolTip += minutes + ((minutes == 1) ? " minute " : " minutes ") + "ago";
+
+ return toolTip;
+ }
+
+ public boolean readBugReport() {
+ // XXX server name needs to be with the bug report
+ int location = BugzillaPlugin.getDefault().getOfflineReports().find(getBugId(getHandle()));
+ if(location == -1){
+ bugReport = null;
+ return true;
+ }
+ bugReport = (BugReport)BugzillaPlugin.getDefault().getOfflineReports().elements().get(location);
+ return true;
+ }
+
+ public void saveBugReport(boolean refresh) {
+ if(bugReport == null)
+ return;
+
+ // XXX use the server name for multiple repositories
+ OfflineReportsFile offlineReports = BugzillaPlugin.getDefault().getOfflineReports();
+ int location = offlineReports.find(getBugId(getHandle()));
+ if(location != -1){
+ IBugzillaBug tmpBugReport = offlineReports.elements().get(location);
+ List<IBugzillaBug> l = new ArrayList<IBugzillaBug>(1);
+ l.add(tmpBugReport);
+ offlineReports.remove(l);
+ }
+ offlineReports.add(bugReport);
+
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (refresh && !workbench.getDisplay().isDisposed()) {
+ workbench.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ OfflineView.refresh();
+ }
+ });
+ }
+ }
+
+ public void removeReport() {
+ OfflineReportsFile offlineReports = BugzillaPlugin.getDefault().getOfflineReports();
+ int location = offlineReports.find(getBugId(getHandle()));
+ if(location != -1){
+ IBugzillaBug tmpBugReport = offlineReports.elements().get(location);
+ List<IBugzillaBug> l = new ArrayList<IBugzillaBug>(1);
+ l.add(tmpBugReport);
+ offlineReports.remove(l);
+ }
+ }
+
+ public static String getServerName(String handle) {
+ int index = handle.lastIndexOf('-');
+ if(index != -1){
+ return handle.substring(0, index);
+ }
+ return null;
+ }
+
+ public static int getBugId(String handle) {
+ int index = handle.lastIndexOf('-');
+ if(index != -1){
+ String id = handle.substring(index+1);
+ return Integer.parseInt(id);
+ }
+ return -1;
+ }
+
+ public Image getIcon() {
+ return TaskListImages.getImage(TaskListImages.TASK_BUGZILLA);
+ }
+
+ public String getBugUrl() {
+ return BugzillaRepository.getBugUrl(getBugId(handle));
+ }
+
+ public boolean canEditDescription() {
+ return false;
+ }
+
+ public String getDeleteConfirmationMessage() {
+ return "Remove this report from the task list, and discard any task context or local notes?";
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskEditor.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskEditor.java
new file mode 100644
index 000000000..950a7766d
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskEditor.java
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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
+ *******************************************************************************/
+/*
+ * Created on 31-Jan-2005
+ */
+package org.eclipse.mylar.bugzilla.ui.tasks;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.core.IBugzillaAttributeListener;
+import org.eclipse.mylar.bugzilla.ui.editor.AbstractBugEditor;
+import org.eclipse.mylar.bugzilla.ui.editor.ExistingBugEditor;
+import org.eclipse.mylar.bugzilla.ui.editor.ExistingBugEditorInput;
+import org.eclipse.mylar.core.MylarPlugin;
+import org.eclipse.mylar.tasks.TaskListImages;
+import org.eclipse.mylar.tasks.MylarTasksPlugin;
+import org.eclipse.mylar.tasks.ui.TaskEditorInput;
+import org.eclipse.mylar.tasks.ui.TaskSummaryEditor;
+import org.eclipse.mylar.tasks.ui.views.TaskListView;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.part.MultiPageEditorPart;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+
+/**
+ * @author Eric Booth
+ */
+public class BugzillaTaskEditor extends MultiPageEditorPart {
+
+ /** The task that created this editor */
+ protected BugzillaTask bugTask;
+
+ /** This bug report can be modified by the user and saved offline. */
+ protected BugReport offlineBug;
+
+ private ExistingBugEditor bugzillaEditor;
+
+ private BugzillaTaskEditorInput bugzillaEditorInput;
+
+ private TaskSummaryEditor taskSummaryEditor = new TaskSummaryEditor();
+
+ protected IContentOutlinePage outlinePage = null;
+
+ private IBugzillaAttributeListener ATTRIBUTE_LISTENER = new IBugzillaAttributeListener() {
+ public void attributeChanged(String attribute, String value) {
+ if (attribute.equals("Priority")) {
+ bugTask.setPriority(value);
+ if (TaskListView.getDefault() != null) TaskListView.getDefault().notifyTaskDataChanged(bugTask);
+ }
+ }
+ };
+
+
+ public BugzillaTaskEditor() {
+ super();
+
+ // get the workbench page and add a listener so we can detect when it closes
+ IWorkbench wb = MylarTasksPlugin.getDefault().getWorkbench();
+ IWorkbenchWindow aw = wb.getActiveWorkbenchWindow();
+ IWorkbenchPage ap = aw.getActivePage();
+ BugzillaTaskEditorListener listener = new BugzillaTaskEditorListener();
+ ap.addPartListener(listener);
+
+ bugzillaEditor = new ExistingBugEditor();
+ bugzillaEditor.addAttributeListener(ATTRIBUTE_LISTENER);
+ taskSummaryEditor = new TaskSummaryEditor();
+ }
+
+ public AbstractBugEditor getBugzillaEditor(){
+ return bugzillaEditor;
+ }
+
+ public TaskSummaryEditor getTaskEditor(){
+ return taskSummaryEditor;
+ }
+
+
+ public void gotoMarker(IMarker marker) {
+ // don't do anything
+ }
+
+ /**
+ * Creates page 1 of the multi-page editor,
+ * which allows you to change the font used in page 2.
+ */
+ private void createBugzillaSubmitPage() {
+ bugzillaEditor.createPartControl(getContainer());
+ Composite composite = bugzillaEditor.getEditorComposite();
+ int index = addPage(composite);
+ setPageText(index, "Bugzilla");
+ }
+
+
+ private void createSummaryPage() {
+ try{
+ int index = addPage(taskSummaryEditor, new TaskEditorInput(bugTask));
+ setPageText(index, "Summary");
+ }catch(Exception e){
+ MylarPlugin.log(e, "summary failed");
+ }
+ }
+
+ /**
+ * Creates the pages of the multi-page editor.
+ */
+ @Override
+ protected void createPages() {
+ createBugzillaSubmitPage();
+ createSummaryPage();
+ }
+
+ /**
+ * Saves the multi-page editor's document.
+ */
+ @Override
+ public void doSave(IProgressMonitor monitor) {
+ getEditor(0).doSave(monitor);
+ }
+
+ /**
+ * Saves the multi-page editor's document as another file.
+ * Also updates the text for page 0's tab, and updates this multi-page editor's input
+ * to correspond to the nested editor's.
+ */
+ @Override
+ public void doSaveAs() {
+ IEditorPart editor = getEditor(0);
+ editor.doSaveAs();
+ setPageText(0, editor.getTitle());
+ setInput(editor.getEditorInput());
+ }
+
+ @Override
+ public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {
+ if (!(editorInput instanceof BugzillaTaskEditorInput))
+ throw new PartInitException("Invalid Input: Must be BugzillaTaskEditorInput");
+ bugzillaEditorInput = (BugzillaTaskEditorInput) editorInput;
+ bugTask = bugzillaEditorInput.getBugTask();
+
+ offlineBug = bugzillaEditorInput.getOfflineBug();
+ super.init(site, editorInput);
+ super.setSite(site);
+ super.setInput(editorInput);
+
+ try {
+ bugzillaEditor.init(this.getEditorSite(), this.getEditorInput());
+ }
+ catch (Exception e) {
+ throw new PartInitException(e.getMessage());
+ }
+
+ // Set the title on the editor's tab
+ this.setPartName("Bug #" + bugzillaEditorInput.getBugId());
+ this.setTitleImage(TaskListImages.getImage(TaskListImages.TASK_BUGZILLA));
+ }
+
+ @Override
+ public boolean isSaveAsAllowed() {
+ return false;
+ }
+
+ /**
+ * Calculates the contents of page 2 when the it is activated.
+ */
+ @Override
+ protected void pageChange(int newPageIndex) {
+ super.pageChange(newPageIndex);
+ }
+
+ /**
+ * Sets the font related data to be applied to the text in page 2.
+ */
+ @Override
+ public void setFocus() {
+ // The default focus for this editor is the submit page
+ bugzillaEditor.setFocus();
+ }
+
+ /**
+ * @return Returns the bugTask.
+ */
+ public BugzillaTask getBugTask() {
+ return bugTask;
+ }
+
+ /**
+ * @return Returns the offlineBug.
+ */
+ public BugReport getOfflineBug() {
+ return offlineBug;
+ }
+
+ /**
+ * 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.
+ * @param isDirty
+ * is true when the bug report has been modified but not saved
+ */
+ public void showDirtyStatus(boolean isDirty) {
+ String prefix = (isDirty) ? "*" : "" ;
+ setPartName(prefix + "Bug #" + bugzillaEditorInput.getBugId());
+ }
+
+ /**
+ * Class to listen for editor events
+ */
+ private class BugzillaTaskEditorListener implements IPartListener
+ {
+
+ public void partActivated(IWorkbenchPart part) {
+ // don't care about this event
+ }
+
+ public void partBroughtToTop(IWorkbenchPart part) {
+ // don't care about this event
+ }
+
+ public void partClosed(IWorkbenchPart part) {
+
+ // if we are closing a bug editor
+ if (part instanceof BugzillaTaskEditor) {
+ BugzillaTaskEditor taskEditor = (BugzillaTaskEditor)part;
+
+ // check if it needs to be saved
+ if (taskEditor.bugzillaEditor.isDirty) {
+ // ask the user whether they want to save it or not and perform the appropriate action
+ taskEditor.bugzillaEditor.changeDirtyStatus(false);
+ boolean response = MessageDialog.openQuestion(null, "Save Changes",
+ "You have made some changes to the bug, do you want to save them?");
+ if (response) {
+ taskEditor.bugzillaEditor.saveBug();
+ } else {
+ ExistingBugEditorInput input = (ExistingBugEditorInput)taskEditor.bugzillaEditor.getEditorInput();
+ bugTask.setPriority(input.getBug().getAttribute("Priority").getValue());
+ }
+ }
+ }
+ }
+
+ public void partDeactivated(IWorkbenchPart part) {
+ // don't care about this event
+ }
+
+ public void partOpened(IWorkbenchPart part) {
+ // don't care about this event
+ }
+ }
+
+ public void makeNewPage(BugReport serverBug, String newCommentText) {
+ if (serverBug == null) {
+ MessageDialog.openInformation(Workbench.getInstance().getActiveWorkbenchWindow().getShell(),
+ "Could not open bug.", "Bug #" + offlineBug.getId()
+ + " could not be read from the server. Try refreshing the bug task.");
+ return;
+ }
+ }
+
+ @Override
+ public Object getAdapter(Class adapter) {
+ return bugzillaEditor.getAdapter(adapter);
+ }
+
+ public void close() {
+ Display display= getSite().getShell().getDisplay();
+ display.asyncExec(new Runnable() {
+ public void run() {
+ getSite().getPage().closeEditor(BugzillaTaskEditor.this, false);
+ }
+ });
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskEditorInput.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskEditorInput.java
new file mode 100644
index 000000000..4a4b0aba9
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskEditorInput.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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
+ *******************************************************************************/
+/*
+ * Created on 1-Feb-2005
+ */
+package org.eclipse.mylar.bugzilla.ui.tasks;
+
+import java.io.IOException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.mylar.bugzilla.core.BugReport;
+import org.eclipse.mylar.bugzilla.ui.editor.ExistingBugEditorInput;
+import org.eclipse.ui.IPersistableElement;
+
+
+/**
+ * @author Eric Booth
+ */
+public class BugzillaTaskEditorInput extends ExistingBugEditorInput {
+
+
+ private String bugTitle;
+
+ private BugReport offlineBug;
+
+ private BugzillaTask bugTask;
+
+ public BugzillaTaskEditorInput(BugzillaTask bugTask) throws LoginException, IOException {
+ super(BugzillaTask.getBugId(bugTask.getHandle()));
+ this.bugTask = bugTask;
+ offlineBug = bugTask.getBugReport();
+ bugId = BugzillaTask.getBugId(bugTask.getHandle());
+ bugTitle = "";
+ }
+
+ protected void setBugTitle(String str) {
+ // 03-20-03 Allows editor to store title (once it is known)
+ bugTitle = str;
+ }
+
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public ImageDescriptor getImageDescriptor() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return "Bug #" + bugId;
+ }
+
+ @Override
+ public IPersistableElement getPersistable() {
+ return null;
+ }
+
+ @Override
+ public String getToolTipText() {
+ return bugTitle;
+ }
+
+ @Override
+ public Object getAdapter(Class adapter) {
+ return null;
+ }
+
+ @Override
+ public int getBugId() {
+ return bugId;
+ }
+
+ /**
+ * Returns the online server bug for this input
+ *
+ * @see BugzillaRepository
+ * @see BugReport
+ */
+// public BugReport getServerBug() {
+// return serverBug;
+// }
+
+ /**
+ * Returns the offline bug for this input's Bugzilla task
+ */
+ public BugReport getOfflineBug() {
+ return offlineBug;
+ }
+
+ /**
+ * Gets the bug page input stream
+ */
+// public InputStream getInputStream() throws IOException {
+// try {
+// return url.openStream();
+// }
+// catch (Exception e) {
+// throw new IOException(e.getMessage());
+// }
+//
+// }
+
+ /**
+ * Returns true if the argument is a bug report editor input on the same bug id.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BugzillaTaskEditorInput) {
+ BugzillaTaskEditorInput input = (BugzillaTaskEditorInput) o;
+ return getBugId() == input.getBugId();
+ }
+ return false;
+ }
+
+ /**
+ * @return Returns the <code>BugzillaTask</code>
+ */
+ public BugzillaTask getBugTask() {
+ return bugTask;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskExternalizer.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskExternalizer.java
new file mode 100644
index 000000000..4db885c95
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskExternalizer.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+
+import java.util.Date;
+import java.util.List;
+
+import org.eclipse.mylar.bugzilla.ui.tasks.BugzillaTask.BugTaskState;
+import org.eclipse.mylar.core.MylarPlugin;
+import org.eclipse.mylar.tasks.AbstractCategory;
+import org.eclipse.mylar.tasks.ITask;
+import org.eclipse.mylar.tasks.Task;
+import org.eclipse.mylar.tasks.TaskCategory;
+import org.eclipse.mylar.tasks.TaskList;
+import org.eclipse.mylar.tasks.util.DefaultTaskListExternalizer;
+import org.eclipse.mylar.tasks.util.ITaskListExternalizer;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @author Mik Kersten and Ken Sueda
+ */
+public class BugzillaTaskExternalizer extends DefaultTaskListExternalizer {
+
+ private static final String BUGZILLA = "Bugzilla";
+ private static final String LAST_DATE = "LastDate";
+ private static final String DIRTY = "Dirty";
+ private static final String URL = "URL";
+ private static final String DESCRIPTION = "Description";
+
+ private static final String TAG_BUGZILLA_CATEGORY = "BugzillaQuery" + TAG_CATEGORY;
+ private static final String TAG_TASK = "BugzillaReport";
+
+ @Override
+ public boolean canReadCategory(Node node) {
+ return node.getNodeName().equals(getCategoryTagName());
+ }
+
+ @Override
+ public void readCategory(Node node, TaskList tlist) {
+ Element e = (Element) node;
+ BugzillaQueryCategory cat = new BugzillaQueryCategory(e.getAttribute(DESCRIPTION), e.getAttribute(URL));
+ tlist.addCategory(cat);
+ }
+
+ public boolean canCreateElementFor(AbstractCategory category) {
+ return category instanceof BugzillaQueryCategory;
+ }
+
+ public Element createCategoryElement(AbstractCategory category, Document doc, Element parent) {
+ BugzillaQueryCategory queryCategory = (BugzillaQueryCategory)category;
+ Element node = doc.createElement(getCategoryTagName());
+ node.setAttribute(DESCRIPTION, queryCategory.getDescription(false));
+ node.setAttribute(URL, queryCategory.getUrl());
+ parent.appendChild(node);
+ return node;
+ }
+
+ public boolean canCreateElementFor(ITask task) {
+ return task instanceof BugzillaTask;
+ }
+
+ public Element createTaskElement(ITask task, Document doc, Element parent) {
+ Element node = super.createTaskElement(task, doc, parent);
+ BugzillaTask bt = (BugzillaTask) task;
+ node.setAttribute(BUGZILLA, TRUE);
+ if (bt.getLastRefresh() != null) {
+ node.setAttribute(LAST_DATE, new Long(bt.getLastRefreshTime()
+ .getTime()).toString());
+ } else {
+ node.setAttribute(LAST_DATE, new Long(new Date().getTime()).toString());
+ }
+
+ if (bt.isDirty()) {
+ node.setAttribute(DIRTY, TRUE);
+ } else {
+ node.setAttribute(DIRTY, FALSE);
+ }
+ bt.saveBugReport(false);
+ return node;
+ }
+
+ @Override
+ public boolean canReadTask(Node node) {
+ return node.getNodeName().equals(getTaskTagName());
+ }
+
+ @Override
+ public ITask readTask(Node node, TaskList tlist, AbstractCategory category, ITask parent) {
+ Element element = (Element) node;
+ String handle = element.getAttribute(HANDLE);
+ String label = element.getAttribute(LABEL);
+ BugzillaTask task = new BugzillaTask(handle, label, true);
+ readTaskInfo(task, tlist, element, category, parent);
+
+ task.setState(BugTaskState.FREE);
+ task.setLastRefresh(new Date(new Long(element.getAttribute("LastDate"))
+ .longValue()));
+ if (element.getAttribute("Dirty").compareTo("true") == 0) {
+ task.setDirty(true);
+ } else {
+ task.setDirty(false);
+ }
+ if (task.readBugReport() == false) {
+ MylarPlugin.log("Failed to read bug report", null);
+ }
+ return task;
+ }
+
+ @Override
+ public String getCategoryTagName() {
+ return TAG_BUGZILLA_CATEGORY;
+ }
+
+ @Override
+ public String getTaskTagName() {
+ return TAG_TASK;
+ }
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskListManager.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskListManager.java
new file mode 100644
index 000000000..353d2804c
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/BugzillaTaskListManager.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Mik Kersten and Ken Sueda
+ */
+public class BugzillaTaskListManager {
+
+ private Map<String, BugzillaTask> bugzillaTaskRegistry = new HashMap<String, BugzillaTask>();
+
+ // XXX we never delete anything from this registry
+
+ public void addToBugzillaTaskRegistry(BugzillaTask task){
+ if(bugzillaTaskRegistry.get(task.getHandle()) == null){
+ bugzillaTaskRegistry.put(task.getHandle(), task);
+ }
+ }
+
+ public BugzillaTask getFromBugzillaTaskRegistry(String handle){
+ return bugzillaTaskRegistry.get(handle);
+ }
+
+ public Map<String, BugzillaTask> getBugzillaTaskRegistry(){
+ return bugzillaTaskRegistry;
+ }
+
+}
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/StackTrace.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/StackTrace.java
new file mode 100644
index 000000000..617599738
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/StackTrace.java
@@ -0,0 +1,373 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class to hold all of the information about a stack trace
+ *
+ * @author Shawn Minto
+ */
+public class StackTrace {
+
+ /** The length of the stack trace in the original string */
+ private int length;
+
+ /** The offset of the stack trace in the orignal string */
+ private int offset;
+
+ /** The string of the stack trace */
+ private String stackTrace;
+
+ /** This is the comment that the stack trace appeared in. String if desciption else Comment */
+ private Object comment;
+
+ /**
+ * Constructor
+ *
+ * @param stackTrace
+ * The stack trace string
+ * @param offset
+ * The offset of the stack trace in the original string
+ * @param length
+ * The length of the stack trace in the original string
+ * @param comment
+ * The comment that the stack trace came from
+ */
+ public StackTrace(String stackTrace, int offset, int length, Object comment) {
+ this.stackTrace = stackTrace;
+ this.offset = offset;
+ this.length = length;
+ this.comment = comment;
+ }
+
+ /**
+ * Get the offset for the stack trace
+ *
+ * @return Returns the offset.
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Get the stack trace for the bug
+ *
+ * @return Returns the stackTrace.
+ */
+ public String getStackTrace() {
+ return stackTrace;
+ }
+
+ /**
+ * Get the length of the bug
+ *
+ * @return Returns the length.
+ */
+ public int getLength() {
+ return length;
+ }
+
+ /**
+ * Get the Comment that this stack trace came from
+ *
+ * @return Returns the Comment if it was a comment else a String if it was the description
+ */
+ public Object getComment() {
+ return comment;
+ }
+
+ /**
+ * Find a standard java stack trace in the given string
+ *
+ *
+ * @param s
+ * The string to search for stack traces
+ * @param comment
+ * The comment that the text came from.<br>
+ * Comment if a comment else a String
+ * @return String[] of stack traces - each element is 1 trace
+ */
+ public static StackTrace[] getStackTrace(String s, Object comment) {
+
+ // setup the regex used to determine if it looks like we are at a
+ // stack trace and whether it is something that should be skipped
+ String regexExceptionType = "^(.*\\.)+.+(Exception|Error|Throwable).*";
+ String regexSkip = ".*\\.\\..*";
+
+ // get all of the individual lines for the string
+ String[] lines = s.split("\r\n");
+
+ // the character start of the current stack trace
+ int charStackStart = 0;
+
+ // the current character in the string - used for the start and the
+ // offset
+ int[] charPos = { 0 }; // array so pass by reference
+
+ boolean inStackTrace = false;
+ List<String> stackTrace = null;
+ List<StackTrace> stackTraces = new ArrayList<StackTrace>();
+
+ // go through each of the lines of the string
+ for (int i = 0; i < lines.length; i++) {
+
+ if (lines[i].matches(regexSkip)){
+
+ // update the current character position
+ charPos[0] += lines[i].length() + 2;
+
+ }else if (lines[i].trim().matches(regexExceptionType) && !inStackTrace) {
+
+ // we have matched the stack trace and we are not already in one
+
+ // add the old stack trace to the list of stack traces
+ if (stackTrace != null && stackTrace.size() > 1) {
+ stackTraces.add(getStackTrace(stackTrace, charStackStart,
+ charPos[0] - charStackStart, comment));
+ }
+
+ // prepare for a new stack trace
+ stackTrace = new ArrayList<String>();
+ inStackTrace = true;
+
+ // the current line is the start of our stack trace
+ stackTrace.add(lines[i]);
+ charStackStart = charPos[0];
+ charPos[0] += lines[i].length() + 2;
+ } else if (inStackTrace) {
+ // we are in a stack trace
+
+ int[] pos = { i }; // array so pass by reference
+
+ // get the next at clause of the stack trace
+ String stack = getNextAt(lines, pos, charPos);
+
+ // check if there was an at
+ if (stack == null) {
+
+ // there wasn't so we are done this stack trace
+ inStackTrace = false;
+ if (stackTrace != null && stackTrace.size() > 1) {
+ stackTraces.add(getStackTrace(stackTrace,
+ charStackStart, charPos[0] - charStackStart, comment));
+ }
+ stackTrace = null;
+ } else {
+
+ // we had one, so add it to this stack trace
+ stackTrace.add(stack);
+ }
+
+ // update the position
+ i = pos[0];
+ } else {
+ // update the current character position
+ charPos[0] += lines[i].length() + 2;
+ }
+ }
+
+ // make sure to add the stack trace if it was the last in the string
+ if (stackTrace != null && stackTrace.size() > 1) {
+ stackTraces.add(getStackTrace(stackTrace, charStackStart,
+ charPos[0] - charStackStart, comment));
+ }
+
+ if (stackTraces.size() == 0)
+ return null;
+
+ // get the string values of the stack traces and return it
+ return getTracesFromList(stackTraces);
+ }
+
+ /**
+ * Get the next at clause from a potential stack trace -- looks ahead 4
+ * lines
+ *
+ * @param lines
+ * The array of all of the lines in the bug
+ * @param i
+ * The current position to start at
+ * @param charPos
+ * The current character position in the original string
+ * @return The next at clause, or <code>null</code><br>
+ * If an at line is matched, but the end isn't within the 4 lines,
+ * only the first line is returned. Also, charPos is updated as well
+ * as i
+ */
+ private static String getNextAt(String[] lines, int[] i, int[] charPos) {
+ String regexAtString = "^at.*";
+ String regexEndString = ".*:\\d+\\)$";
+ int index = i[0];
+ String l1, l2, l3, l4;
+ l1 = l2 = l3 = l4 = null;
+ String res = null;
+
+ // get the first line to look at
+ if (lines.length > index) {
+ l1 = lines[index];
+ } else {
+ // if the first line doesn't exist, we are done and should
+ // return
+ return null;
+ }
+
+ // get the next 3 lines
+ if (lines.length > index + 1) {
+ l2 = lines[index + 1];
+ }
+ if (lines.length > index + 2) {
+ l3 = lines[index + 2];
+ }
+ if (lines.length > index + 3) {
+ l4 = lines[index + 3];
+ }
+
+ // make sure that the first line is the start of an at
+ // if not, return null
+ if (l1.trim().matches(regexAtString)) {
+ charPos[0] += l1.length() + 2;
+ res = l1;
+ } else
+ return null;
+
+ // now determine where the end is if it wasn't on 1 line
+ if (!res.trim().matches(regexEndString)) {
+
+ if (l2 != null && l2.trim().matches(regexEndString)) {
+
+ // it was on the second line
+ // update the current position and the result string
+ i[0] = index + 1;
+ charPos[0] += l2.length() + 2;
+ res += l2.trim();
+ } else if (l3 != null && l3.trim().matches(regexEndString)) {
+
+ // it was on the third line
+ // update the current position and the result string
+ i[0] = index + 2;
+ charPos[0] += l2.length() + l3.length() + 4;
+ res += l2.trim();
+ res += l3.trim();
+ } else if (l4 != null && l4.trim().matches(regexEndString)) {
+
+ // it was on the fourth line
+ // update the current position and the result string
+ i[0] = index + 3;
+ charPos[0] += l2.length() + l3.length() + l4.length() + 6;
+ res += l2.trim();
+ res += l3.trim();
+ res += l4.trim();
+ }
+ }
+
+ // return the result
+ return res;
+ }
+
+ /**
+ * Get the StackTrace
+ *
+ * @param l
+ * the list of lines that contain the trace
+ * @param start
+ * the start of the stack trace
+ * @param offset
+ * the offset of the stack trace
+ * @param comment
+ * The comment that the stack trace came from
+ * @return The StackTrace for the given data
+ */
+ private static StackTrace getStackTrace(List<String> l, int offset, int length, Object comment) {
+ String s = "";
+ for(String s2 : l) {
+ s += s2 + "\r\n";
+ }
+
+ return new StackTrace(s, offset, length, comment);
+ }
+
+ /**
+ * Convert a List StackTraces to a StackTrace[] <br>
+ *
+ * @param l
+ * The List of StackTraces
+ * @return StackTrace[] of the List
+ */
+ private static StackTrace[] getTracesFromList(List<StackTrace> l) {
+
+ // make sure that there is something to convert, else return null
+ if (l == null || l.size() == 0)
+ return null;
+
+ // convert the list of strings to an array of strings
+ int i = 0;
+ StackTrace[] s = new StackTrace[l.size()];
+
+ for(StackTrace st : l) {
+ s[i] = st;
+ i++;
+ }
+
+ // return the string array
+ return s;
+ }
+
+ /**
+ * Escape all of the special regex characters from the string
+ *
+ * @param s
+ * The string to escape the characters for
+ * @return A string with all of the special characters escaped <br>
+ * <code>
+ * . => \.<br>
+ * $ => \$<br>
+ * ? => \?<br>
+ * { => \{<br>
+ * } => \}<br>
+ * ( => \(<br>
+ * ) => \)<br>
+ * [ => \[<br>
+ * ] => \]<br>
+ * + => \+<br>
+ * * => \*<br>
+ * | => \|<br>
+ * ^ => \^<br>
+ * \ => \\<br>
+ * / => \/<br>
+ * </code>
+ */
+ public static String escapeForRegex(String s) {
+ String sFixed = s;
+
+ // replace all special regex characters
+ sFixed = sFixed.replaceAll("\\\\", "\\\\\\\\");
+ sFixed = sFixed.replaceAll("\\$", "\\\\\\$");
+ sFixed = sFixed.replaceAll("\\.", "\\\\.");
+ sFixed = sFixed.replaceAll("\\?", "\\\\?");
+ sFixed = sFixed.replaceAll("\\{", "\\\\{");
+ sFixed = sFixed.replaceAll("\\}", "\\\\}");
+ sFixed = sFixed.replaceAll("\\(", "\\\\(");
+ sFixed = sFixed.replaceAll("\\)", "\\\\)");
+ sFixed = sFixed.replaceAll("\\[", "\\\\[");
+ sFixed = sFixed.replaceAll("\\]", "\\\\]");
+ sFixed = sFixed.replaceAll("\\+", "\\\\+");
+ sFixed = sFixed.replaceAll("\\*", "\\\\*");
+ sFixed = sFixed.replaceAll("\\|", "\\\\|");
+ sFixed = sFixed.replaceAll("\\^", "\\\\^");
+ sFixed = sFixed.replaceAll("\\/", "\\\\/");
+
+ return sFixed;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/TaskListActionContributor.java b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/TaskListActionContributor.java
new file mode 100644
index 000000000..e5afdcb54
--- /dev/null
+++ b/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/bugzilla/ui/tasks/TaskListActionContributor.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2004 - 2005 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.bugzilla.ui.tasks;
+
+import org.eclipse.mylar.bugzilla.ui.actions.CreateBugzillaQueryCategoryAction;
+import org.eclipse.mylar.bugzilla.ui.actions.CreateBugzillaTaskAction;
+import org.eclipse.mylar.bugzilla.ui.actions.RefreshBugzillaAction;
+import org.eclipse.mylar.bugzilla.ui.actions.RefreshBugzillaReportsAction;
+import org.eclipse.mylar.tasks.ui.views.TaskListView;
+
+/**
+ * @author Mik Kersten and Ken Sueda
+ */
+public class TaskListActionContributor {
+
+ private RefreshBugzillaReportsAction refresh;
+ private CreateBugzillaQueryCategoryAction createBugzillaQueryCategory;
+ private CreateBugzillaTaskAction createBugzillaTask;
+ private RefreshBugzillaAction refreshQuery;
+
+ public TaskListActionContributor(TaskListView view) {
+ refresh = new RefreshBugzillaReportsAction(view);
+ createBugzillaQueryCategory = new CreateBugzillaQueryCategoryAction(view);
+ createBugzillaTask = new CreateBugzillaTaskAction(view);
+ refreshQuery = new RefreshBugzillaAction(view);
+ }
+
+}

Back to the top